Section 8: Phase 6 -- 3PL Billing
Goal: Activity-based billing for 3PL operators. Billing activities are generated automatically from task completion hooks.
8.1 Enums
BillingActivityType
| ID |
Value |
Label |
| 1 |
RECEIVING_PER_UNIT |
Receiving (per unit) |
| 2 |
RECEIVING_PER_PALLET |
Receiving (per pallet) |
| 3 |
STORAGE_PER_PALLET_DAY |
Storage (per pallet/day) |
| 4 |
STORAGE_PER_BIN_DAY |
Storage (per bin/day) |
| 5 |
PICK_PER_ORDER |
Pick (per order) |
| 6 |
PICK_PER_LINE |
Pick (per line) |
| 7 |
PICK_PER_UNIT |
Pick (per unit) |
| 8 |
PACK_PER_ORDER |
Pack (per order) |
| 9 |
SHIP_PER_ORDER |
Ship (per order) |
| 10 |
KITTING_PER_UNIT |
Kitting (per unit) |
| 11 |
RETURN_PER_UNIT |
Return (per unit) |
| 12 |
SPECIAL_HANDLING |
Special Handling |
| 13 |
MINIMUM_MONTHLY |
Monthly Minimum |
File: billing/enums/BillingActivityType.java
BillingRateCardStatus
| ID |
Value |
Label |
| 1 |
DRAFT |
Draft |
| 2 |
ACTIVE |
Active |
| 3 |
EXPIRED |
Expired |
File: billing/enums/BillingRateCardStatus.java
InvoiceStatus
| ID |
Value |
Label |
Chip Color |
| 1 |
DRAFT |
Draft |
grey |
| 2 |
SENT |
Sent |
blue |
| 3 |
PAID |
Paid |
green |
| 4 |
OVERDUE |
Overdue |
red |
| 5 |
DISPUTED |
Disputed |
orange |
| 6 |
VOID |
Void |
grey |
File: billing/enums/InvoiceStatus.java
8.2 Entities
BillingRateCardEntity
File: billing/model/BillingRateCardEntity.java
TABLE_NAME: "wmsBillingRateCard"
Key fields: id, clientId (FK), name, effectiveDate, expirationDate, status (PVS).
Child tables: BillingRateEntity
BillingRateEntity
File: billing/model/BillingRateEntity.java
TABLE_NAME: "wmsBillingRate"
Key fields: id, rateCardId (FK), activityType (PVS), rate, minimumCharge, notes.
BillingActivityEntity
File: billing/model/BillingActivityEntity.java
TABLE_NAME: "wmsBillingActivity"
Key fields: id, warehouseId, clientId (FK), activityType (PVS), activityDate, quantity, referenceType, referenceId, taskId (FK -> wmsTask), rateId (FK), unitRate, totalCharge, invoiceId (FK nullable), isBilled.
InvoiceEntity
File: billing/model/InvoiceEntity.java
TABLE_NAME: "wmsInvoice"
Key fields: id, clientId (FK), invoiceNumber (unique), billingPeriodStart, billingPeriodEnd, subtotal, tax, total, status (PVS), generatedDate, sentDate, dueDate, paidDate, notes, externalInvoiceId.
Child tables: InvoiceLineEntity
InvoiceLineEntity
File: billing/model/InvoiceLineEntity.java
TABLE_NAME: "wmsInvoiceLine"
Key fields: id, invoiceId (FK), activityType (PVS), description, quantity, unitRate, lineTotal.
8.3 Processes
GenerateInvoiceProcess
| Step |
Type |
Description |
1. selectClient |
Frontend |
Select client and billing period (start/end dates) |
2. aggregateActivities |
Backend |
Query unbilled wms_billing_activity for client and period. Group by activity type. Calculate totals. Apply minimum charges from rate card. |
3. reviewInvoice |
Frontend |
Display draft invoice with line items |
4. createInvoice |
Backend |
Create wms_invoice DRAFT. Create wms_invoice_line records. Update wms_billing_activity.invoiceId and isBilled=true. |
Process name: "wmsGenerateInvoice"
StorageSnapshotProcess
| Step |
Type |
Description |
| 1. (scheduled, no frontend) |
Backend |
Query wms_inventory grouped by clientId and location type. Count occupied positions per client. Look up active rate card. Insert wms_billing_activity records (STORAGE_PER_PALLET_DAY or STORAGE_PER_BIN_DAY). |
Process name: "wmsStorageSnapshot"
Schedule: Nightly (cron: 0 2 * * *)
SyncInvoiceToAccountingProcess
| Step |
Type |
Description |
1. selectInvoice |
Frontend |
Select invoice to sync |
2. syncToAccounting |
Backend |
Call configurable integration hook. Record externalInvoiceId. |
Process name: "wmsSyncInvoiceToAccounting"
8.4 Widgets
- RevenueThisPeriodWidget (StatisticsData): Total billed, unbilled, outstanding
- RevenueByClientWidget (ChartData pie): Revenue by client
- UnbilledActivitiesWidget (AlertData): Unbilled activities by client
- InvoiceStatusWidget (ChartData stacked bar): Invoices by status
- StorageUtilizationByClientWidget (ChartData bar): Pallet positions per client
8.5 Webhook Events
| Event Type |
Category |
Table |
Field |
Value |
wms.invoice.generated |
INSERT |
wms_invoice |
-- |
-- |
wms.invoice.sent |
UPDATE_WITH_VALUE |
wms_invoice |
status |
SENT |
8.6 Quick Search
| Table |
Indexed Fields |
Weight |
| wms_invoice |
invoice_number (2) |
Invoice lookup |
8.7 DDL
File: 0006-phase6-billing.sql
Tables: wms_billing_rate_card, wms_billing_rate, wms_billing_activity, wms_invoice, wms_invoice_line.
All tables have client_id FK to wms_client.
8.8 File Listing
billing/
model/
BillingRateCardEntity.java
BillingRateEntity.java
BillingActivityEntity.java
InvoiceEntity.java
InvoiceLineEntity.java
enums/
BillingActivityType.java
BillingRateCardStatus.java
InvoiceStatus.java
processes/
GenerateInvoiceProcessMetaDataProducer.java
GenerateInvoiceAggregateStep.java
GenerateInvoiceCreateStep.java
StorageSnapshotProcessMetaDataProducer.java
StorageSnapshotStep.java
SyncInvoiceToAccountingProcessMetaDataProducer.java
SyncInvoiceToAccountingStep.java
webhooks/
WmsInvoiceGeneratedEventCustomizer.java
widgets/
RevenueThisPeriodWidgetMetaDataProducer.java
RevenueThisPeriodWidgetRenderer.java
RevenueByClientWidgetMetaDataProducer.java
RevenueByClientWidgetRenderer.java
UnbilledActivitiesWidgetMetaDataProducer.java
UnbilledActivitiesWidgetRenderer.java
InvoiceStatusWidgetMetaDataProducer.java
InvoiceStatusWidgetRenderer.java
StorageUtilizationByClientWidgetMetaDataProducer.java
StorageUtilizationByClientWidgetRenderer.java
Phase 6 adds ~25 Java files
v2 -- Parent issue: #420
Section 8: Phase 6 -- 3PL Billing
Goal: Activity-based billing for 3PL operators. Billing activities are generated automatically from task completion hooks.
8.1 Enums
BillingActivityTypeFile:
billing/enums/BillingActivityType.javaBillingRateCardStatusFile:
billing/enums/BillingRateCardStatus.javaInvoiceStatusFile:
billing/enums/InvoiceStatus.java8.2 Entities
BillingRateCardEntityFile:
billing/model/BillingRateCardEntity.javaTABLE_NAME:
"wmsBillingRateCard"Key fields: id, clientId (FK), name, effectiveDate, expirationDate, status (PVS).
Child tables: BillingRateEntity
BillingRateEntityFile:
billing/model/BillingRateEntity.javaTABLE_NAME:
"wmsBillingRate"Key fields: id, rateCardId (FK), activityType (PVS), rate, minimumCharge, notes.
BillingActivityEntityFile:
billing/model/BillingActivityEntity.javaTABLE_NAME:
"wmsBillingActivity"Key fields: id, warehouseId, clientId (FK), activityType (PVS), activityDate, quantity, referenceType, referenceId, taskId (FK -> wmsTask), rateId (FK), unitRate, totalCharge, invoiceId (FK nullable), isBilled.
InvoiceEntityFile:
billing/model/InvoiceEntity.javaTABLE_NAME:
"wmsInvoice"Key fields: id, clientId (FK), invoiceNumber (unique), billingPeriodStart, billingPeriodEnd, subtotal, tax, total, status (PVS), generatedDate, sentDate, dueDate, paidDate, notes, externalInvoiceId.
Child tables: InvoiceLineEntity
InvoiceLineEntityFile:
billing/model/InvoiceLineEntity.javaTABLE_NAME:
"wmsInvoiceLine"Key fields: id, invoiceId (FK), activityType (PVS), description, quantity, unitRate, lineTotal.
8.3 Processes
GenerateInvoiceProcessselectClientaggregateActivitiesreviewInvoicecreateInvoiceProcess name:
"wmsGenerateInvoice"StorageSnapshotProcessProcess name:
"wmsStorageSnapshot"Schedule: Nightly (cron:
0 2 * * *)SyncInvoiceToAccountingProcessselectInvoicesyncToAccountingProcess name:
"wmsSyncInvoiceToAccounting"8.4 Widgets
8.5 Webhook Events
wms.invoice.generatedwms.invoice.sent8.6 Quick Search
8.7 DDL
File:
0006-phase6-billing.sqlTables:
wms_billing_rate_card,wms_billing_rate,wms_billing_activity,wms_invoice,wms_invoice_line.All tables have client_id FK to wms_client.
8.8 File Listing
Phase 6 adds ~25 Java files
v2 -- Parent issue: #420