forked from uncloud/uncloud
3.2 KiB
3.2 KiB
How to handle billing in general
Orders
- Orders are the heart of uncloud billing
- Have a starting date
- Have an ending date
- Orders are immutable
-
Can usually not be cancelled / cancellation is not a refund
- Customer/user commits on a certain period -> gets discount based on it
-
Can be upgraded
- Create a new order
- We link the new order to the old order and say this one replaces it
- If the price of the new order is HIGHER than the OLD order, then we charge the difference until the end of the order period
- In the next billing run we set the OLD order to not to bill anymore
- And only the NEW order will be billed afterwards
-
Can be downgraded in the next period (but not for this period)
- We create a new order, same as for upgrade
- The new order starts directly after the OLD order
- As the amount is LOWER than the OLD order, no additional charge is done during this order period
-
We might need to have an activate datetime
- When to implement this
- Order periods can be
Statuses
- CREATING/PREPARING
- INACTIVE (?)
- TO_BILL
- NOT_TO_BILL: we use this to accelerate queries to the DB
Updating status of orders
- If has succeeding order and billing date is last month -> set inactive
Bills
- Are always for a month
- Can be preliminary
Which orders to include
- Not the cancelled ones / not active ones
Flows / Approach
Finding all orders for a bill
-
Get all orders, state != NOT_TO_BILL; for each order do:
-
is it a one time order?
-
has it a bill assigned?
- yes: set to NOT_TO_BILL
-
no:
- get_or_create_bill_for_this_month
- assign bill to this order
- set to NOT_TO_BILL
-
-
is it a recurring order?
-
if it has a REPLACING order:
-
-
- First of month
- Last of month
Handling replacement of orders
- The OLD order will appear in the month that it was cancelled on the bill
- The OLD order needs to be set to NOT_TO_BILL after it was billed the last time
- The NEW order will be added pro rata if the amount is higher in the same month
- The NEW order will be used next month
Disabling the old order
- On billing run
-
If order.replacement_order (naming!) is set
-
if the order.replacement_order starts during THIS_MONTH
- add order to bill
-
if NOT:
- the order was already replaced in a previous billing period
- set the order to NOT_TO_BILL
-
Billing the new order
- If order.previous_order
Handling multiple times a recurring order
-
For each recurring order check the order.period
-
Find out when it was billed last
- lookup latest bill
-
Calculate how many times it has been used until 2359, last day of month
- For preliminary bill: until datetime.now()
- Call the bill_end_datetime
-
Getting duration: bill_end_datetime - order.last_billed
- Amount in seconds; duration_in_seconds
-
Divide duration_in_seconds by order.period; amount_used:
- If >= 1: add amount_used * order.recurring_amount to bill
-