# B2B invoice creation
This document explains when B2B invoices are created, how their amounts are calculated, and why the company-admin page may be empty.
The invoices are displayed at:
`/company-admin/b2b-invoices`
## Creation paths
There are three creation paths: monthly commission billing, subscription renewal billing, and a restricted manual form.
### Monthly commission invoices
The Laravel scheduler runs the following command on the first day of every month at 03:15:
```text
b2b-invoices:generate-monthly
```
Without the optional `--date` argument, the command invoices the previous calendar month. It processes every active company and calls `B2BBillingService::generate()` for the first through the last day of that month.
An eligible stay must:
- belong to the company;
- have status `completed`;
- have an actual check-in;
- have an actual check-out within the invoiced month; and
- contain a reviewed `metadata.b2b_commission` snapshot.
The snapshot is recorded when a stay is saved as completed with actual check-in and check-out values. It freezes the commission rate, base amount, calculated amount, currency, and recording timestamp. If the company's commission rate changes later, previously captured stays retain their original rate.
Generation fails for the affected company when an eligible stay has no commission snapshot or its currency differs from the company's billing currency. No invoice is created when the sum of the commission lines is zero.
The billing key has the form:
```text
commission:{company_id}:{YYYY-MM}
```
Existing invoices, including soft-deleted ones, are detected by this key. Rerunning the command therefore does not create a second invoice for the same company and month.
The month can be generated or retried manually from the command line:
```bash
php artisan b2b-invoices:generate-monthly --date=2026-08-01
```
### Subscription invoices
The scheduler runs `b2b-billing:process` hourly. For each subscription whose status is `active` or `past_due` and whose `next_billing_at` has been reached, the billing service closes the completed subscription cycle and creates an invoice in arrears.
The subscription billing key has the form:
```text
subscription:{subscription_id}:{cycle_start_date}
```
This key also makes subscription invoice creation idempotent. The lifecycle can catch up a maximum of 24 missed cycles in one hourly run; later runs continue older catch-up work.
`B2B_RECURRING_ENABLED` controls automatic payment collection, not invoice creation. The general `B2B_BILLING_ENABLED` switch controls both commission generation and the hourly billing lifecycle.
### Manual invoice form
Backend routes still exist for `/company-admin/b2b-invoices/create` and the corresponding store action. Both require `auth()->user()->isAdmin()`.
The form can optionally use a completed settlement batch. Its subtotal is the batch's total commission plus cancellation-fee commission, with 20% VAT added by the controller. Without a batch, the current form produces a zero-value draft.
The invoice list template currently has no link or button to this form. A `company_manager` user therefore sees no creation control and receives HTTP 403 if the create URL is opened directly.
## Values assigned to an automatically created invoice
Automatically generated invoices receive:
- a sequence-generated, immutable invoice number;
- type `commission` or `subscription`;
- the applicable billing period and line items;
- VAT from `B2B_VAT_RATE`, defaulting to 20%;
- the company's currency;
- status `draft` when money is due, or `paid` for a zero total;
- an issue date equal to the creation date;
- a due date 14 days after creation;
- payment terms `14_days`;
- snapshots of the seller and buyer billing details.
Invoices are not automatically sent merely because they were created. Sending is a separate lifecycle action. Draft invoices can also be edited, sent, or cancelled by an administrator through the invoice UI.
## Required configuration and scheduler
Invoice generation requires:
```dotenv
B2B_BILLING_ENABLED=true
```
The application scheduler must also be running in production. The recurring-payment flag is separate:
```dotenv
B2B_RECURRING_ENABLED=true
```
Enable it only when automatic collection through the configured recurring gateway is intended.
## Why the invoice page may be empty
An empty page does not identify the cause by itself. Check the following:
1. `B2B_BILLING_ENABLED` is enabled in the deployed environment.
2. Laravel's scheduler is running and invoked the monthly/hourly commands.
3. The company is active.
4. The previous month contains completed stays with actual check-out dates in that month.
5. Those stays contain valid `metadata.b2b_commission` snapshots.
6. Commission totals are greater than zero and currencies match.
7. For subscription invoices, `next_billing_at` is due and the subscription is `active` or `past_due`.
8. Application logs do not contain `requires commission history review` or `B2B renewal requires review` messages.
As observed on 16 September 2026, the Demo Hotel Paradise company-admin page displayed no B2B invoices. The logged-in `company_manager` account had no create button and was denied access to the manual creation URL. This observation confirms the UI state, but it does not by itself establish which configuration, scheduling, or eligibility condition prevented automatic creation.
## Implementation references
- Scheduler definitions: `routes/console.php`
- Monthly command: `app/Console/Commands/GenerateMonthlyB2BInvoices.php`
- Invoice generation and renewal calculations: `app/Services/B2BBillingService.php`
- Hourly subscription and collection lifecycle: `app/Services/Billing/BillingLifecycle.php`
- Frozen stay commission snapshot: `app/Observers/B2BStayCommissionObserver.php`
- Invoice numbering and model rules: `app/Models/B2BInvoice.php`
- Manual company-admin actions: `app/Http/Controllers/CompanyAdminController.php`
- Invoice list UI: `resources/views/company-admin/b2b-invoices/index.blade.php`
- Billing configuration: `config/b2b-billing.php`