Skip to main content

Billing

In this page, essential Billing entities are documented, as well as their relationships and internal logics.

BillingProduct​

A BillingProduct represents a product we can sell to a partner. They form a two level hierarchy through the association stored in the table parent_billing_products_child_billing_products. Note that a product can have more than one parent (the same addon can be sold with more than one plan).
A BillingProduct can be configured using its billing_settings_bits bit field (see uala-main/app/models/billing_products/bitfields.rb). If a BillingProduct is both basic and official (flags in the billing_settings_bits bit field) it is a "Venue Plan", it represents one of the standard plan sold to partners (i.e. Starter, Advanced, and Premium).

Activations​

A triggered_action can be set to the BillingProduct, and it defines what happen when a child BillingCompanyProduct transitions to active state and from active state.
For all possible actions, a logic is defined: :::code source="../../uala-main/app/models/billing_products/activations.rb" title="uala-main/app/models/billing_products/activations.rb" range="1-50" :::

BillingCompanyProduct​

A BillingCompanyProduct represents a BillingProduct sold to BillingCompany (and linked to a Venue). They also form a two level hierarchy matching the associated BillingProduct hierarchy, but a product have only one parent (the plan that is actually sold to the venue).

Invoicing​

The automatic_billing boolean field identifies BillingCompanyProducts which follow the automatic billing flow (TODO).

When Venue purchase a BillingCompanyProduct autonomously, the online payment flow is used, and the paying records will use the confirmation_token identifier.
Similarly, the self_provisioned defines a BillingCompanyProduct autonomously configured by the Venue.

It's possible to hide a BillingCompanyProduct line from the generated invoices, using the visible_in_invoice field (default true).

The revenue_source field is available to finance team to set a custom revenue source label that will be sent to external systems.

Validity​

The active_from and active_to (nullable) are used to configure the validity period of the BillingCompanyProduct, and bill_every defines how many months should be billed at once (integer, default 1).
With early_payment boolean field it's possible to set a BillingCompanyProduct to be paid in advance or not (default false).

It's possible to configure it to generate an invoice forcing the forced_bill_at field. This will create an invoice at the day ending, billing this BillingCompanyProduct only. The forced_invoice_due_date will set a custom due_date to the created invoice.

Commissions​

Multiple fields are available to configure commission on bookings of the billed period:

Recurrent not paid online from marketplace:

  • commission_absolute_amount_cents
  • commission_percent_amount

First booking not paid online from marketplace:

  • commission_first_appointment_absolute_amount_cents
  • commission_first_appointment_percent_amount

First booking or recurrent not paid online from marketplace:

  • commission_paid_online_absolute_amount_cents
  • commission_paid_online_percent_amount

Recurrent from Reserve with Google:

  • commission_rwg_absolute_amount_cents
  • commission_rwg_percent_amount

First booking from Reserve with Google:

  • commission_rwg_first_appointment_absolute_amount_cents
  • commission_rwg_first_appointment_percent_amount

Price​

The unit_price_cents defines what is the unit price of this BillingCompanyProduct, and the total amount is calculated multiplying it with quantity (default 1).
The final price can have a discount applied, discount_absolute_amount_cents or discount_percent_amount (defined with discount_type).

There can also be a prepaid period, in which the BillingCompanyProduct will be excluded from periodic billing, defining a ending prepaid_until_to and the prepaid_amount_cents accordingly.

With the payment_method field it's possible to configure the desired payment method (payment_slip, credit_card, transfer, cash, external_paypal, automatic).

State machine​

The starting point is the pending state, where the BillingCompanyProduct is totally "unharmed".

When active_from is set to a future date, the state will be scheduled, meaning that from a specific date, it becomes active.

It's possible that a created record is wrong, and needs to be discarded. That state make the BillingCompanyProduct totally inactive (as for pending), but marking it as a record that has manually been discarded.

The main state is active, where actions take place and billing will consider it when run.

When active_to (if set) is reached, it expires transitioning the state to expired. At this point, actions activated will be deactivated.

It's also possible to suspend (and then unsusped) the BillingCompanyProduct, and this operation is useful to temporarily block actions activated (an use case is when old BillingCompanyInvoice isn't paid).

If suspending the BillingCompanyProduct won't unlock BillingCompany's billing status, it's possible to terminate all billing plans of it, shutting down the service for it.

BillingCompany​

The BillingCompany model represents a fiscal entity and it's the central point of the Billing flow.
Multiple Venues can be linked to a single BillingCompany (but each Venue can have 0..1 BillingCompany).

There are fiscal fields that identify it, such as vat_number, fiscal_code and iban (also fiscal_unique_email and fiscal_unique_identifier in some countries), it needs to be geolocalized with an address.
It has an agreement_date which specifies when the BillingCompany firstly signed the contract with our company.

BillingCompanyInvoice​

It represents a invoice issues for a BillingCompany, it contains many details (each one of them is linked to a BillingCompanyProduct and to a Venue).

The invoice covers a period from from_time to to_time, and those represent the minimum and maximum from and to time of BillingCompanyProducts billed in it. The due_date defines the due date of the invoice.

Status​

An invoice can have multiple statuses:

  • when cumulative, it means that one or more BillingCompanyInvoices have been merged_to this invoice, letting them be no-op and moving details to this invoice. In uala-main/app/services/payments/invoice_payment_service.rb, the create_cumulative_billing_company_invoice method defines logic to merge invoices.
  • an invoice can be hold, meaning that it won't be synched or notified to the customer due to a little due amount: :::code source="../../uala-main/app/jobs/billing/generate_invoice_job.rb" title="uala-main/app/jobs/billing/generate_invoice_job.rb" range="154-155" :::
  • when synched to an external system, the uploaded_at timestamp will be set.
  • the notified_at timestamp defines the notification date and time
  • if the invoice has been paid, the paid_at field will contain the respective timestamp
  • when the invoice is paid by credit_card, payment_slip or with a BillingCompanyPaymentSummary, the processed_at field contains information about the timestamp it happened

Price​

The invoice has a due_amount_cents that consists in the sum of its details' total_amount_cents. This amount can have a discount applied, discount_absolute_amount_cents or discount_percent_amount (defined with discount_type), and the final amount is stored in discounted_due_amount_cents.
This amount is vat-excluded, and its vat is then computed using vat_percentage (and vat_code) fields.

In the payment_method field the details' payment method is reflected (payment_slip, credit_card, transfer, cash, external_paypal, automatic).
Similarly, the revenue_source will be set in the invoice, based on its details.

A JSONB field contains payment_details, information about payment transactions made on this invoice.

The invoice can be automatically paid using automatic_payment_scheduled_at, when payment_method = automatic, and when set, the online payment flow is used to pay it using the payment_confirmation_token field as support field.

External system​

The invoice can be synched to an external system, and when that happens, multiple fields are set on it:

  • external_doc
  • external_token
  • number
  • external_id
  • external_payment_id

An internal PDF will also be created and the relative path is stored in pdf_path.

When the external system supports the e-invoice, the electronic_invoice_sent_at timestamp contains information about when that happened.

Details​

The BillingCompanyInvoiceDetail model links the BillingCompanyInvoice to paid entities, that can be Appointment or OnlineCheckout (to buy gift/vip cards from UALA Marketplace).

The total_amount_cents is computed based on the BillingCompanyProduct configuration and paid entities. :::code source="../../uala-main/app/models/billing_company_invoice.rb" title="uala-main/app/models/billing_company_invoice.rb" range="106-125" :::

BillingCompanyTransfer​

The BillingCompanyTransfer entity represents what our company owe to the customer. This includes money got through UALA Marketplace for bookings and or gift/vip cards bought.

The transfer covers a period from from_time to to_time, and those represent the minimum and maximum from and to time of details included.

It has a disposable_amount_cents that consists in the sum of its details' total_amount_cents.

Once created, it can both be disposed (verified) or voided (declined).

When the transfer is closed with a BillingCompanyPaymentSummary, the processed_at field contains information about the timestamp it happened.

BillingCompanyPaymentSummary​

A BillingCompany can have both BillingCompanyInvoice and BillingCompanyTransfer for the same period, and to avoid sending money (transfer) to then ask them back (invoice), a unified document is created that can have a positive amount_cents (invoice, money owed from the salon), negative amount_cents (transfer, money due to the salon) or zero amount_cents (invoice amount = transfer amount).

This entity is created by Billing::GenerateBillingCompanyPaymentSummaryJob during the billing flow.

PaymentSlip​

Many banks support the upload of a XML containing a set of inbound or outbound payments.

To do that, we create a PaymentSlip record which includes a xml field that contains all the details needed from the bank. Different countries need a different XML format, so different providers are present in uala-main/app/services/payments/payment_slip_payment folder.