- SaleOrder._fc_rate_usage: aggregates usage, computes overage via charge._compute_billable, upserts sale.order.line for the overage product - FusionBillingUsage._cron_rate_open_periods: hourly cron iterates active charges × in-progress subscriptions, calls _fc_rate_usage - data/ir_cron.xml: two crons — rate usage (hourly), dispatch webhooks (2 min) - __manifest__.py: registers data/ir_cron.xml in data list - test_usage.py: test_rate_open_period_creates_overage_line (TDD, FCB_EXIT=0) Reference: _create_recurring_invoice / _get_invoiceable_lines confirmed in Enterprise sale_subscription/models/sale_order.py — overage line goes onto sale.order so native invoicing picks it up via _get_invoiceable_lines.
27 lines
1.0 KiB
Python
27 lines
1.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2026 Nexa Systems Inc.
|
|
# License OPL-1
|
|
from odoo import api, fields, models
|
|
|
|
|
|
class SaleOrder(models.Model):
|
|
_inherit = "sale.order"
|
|
|
|
def _fc_rate_usage(self, charge, period_start, period_end):
|
|
"""Aggregate this subscription's usage for `charge`'s metric in the period,
|
|
compute the overage amount, and upsert a matching overage order line.
|
|
Returns the amount."""
|
|
self.ensure_one()
|
|
Usage = self.env['fusion.billing.usage']
|
|
total = Usage._aggregate(self, charge.metric_id, period_start, period_end)
|
|
_overage, amount = charge._compute_billable(total)
|
|
if charge.product_id:
|
|
line = self.order_line.filtered(lambda l: l.product_id == charge.product_id)
|
|
vals = {'product_uom_qty': 1, 'price_unit': amount}
|
|
if line:
|
|
line.write(vals)
|
|
else:
|
|
self.env['sale.order.line'].create(
|
|
{'order_id': self.id, 'product_id': charge.product_id.id, **vals})
|
|
return amount
|