@dainamite/billing 0.17.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +99 -19
- package/dist/modules/billing/acl.js +9 -1
- package/dist/modules/billing/acl.js.map +2 -2
- package/dist/modules/billing/api/accounts/[id]/balance/route.js +62 -0
- package/dist/modules/billing/api/accounts/[id]/balance/route.js.map +7 -0
- package/dist/modules/billing/api/accounts/[id]/credit-status/route.js +56 -0
- package/dist/modules/billing/api/accounts/[id]/credit-status/route.js.map +7 -0
- package/dist/modules/billing/api/accounts/[id]/topups/route.js +36 -0
- package/dist/modules/billing/api/accounts/[id]/topups/route.js.map +7 -0
- package/dist/modules/billing/api/accounts/route.js +7 -0
- package/dist/modules/billing/api/accounts/route.js.map +2 -2
- package/dist/modules/billing/api/export/account/[id]/route.js +48 -3
- package/dist/modules/billing/api/export/account/[id]/route.js.map +2 -2
- package/dist/modules/billing/api/statements/generate/route.js +68 -0
- package/dist/modules/billing/api/statements/generate/route.js.map +7 -0
- package/dist/modules/billing/api/statements/route.js +110 -0
- package/dist/modules/billing/api/statements/route.js.map +7 -0
- package/dist/modules/billing/api/topups/route.js +139 -0
- package/dist/modules/billing/api/topups/route.js.map +7 -0
- package/dist/modules/billing/api/transactions/adjust/route.js +71 -0
- package/dist/modules/billing/api/transactions/adjust/route.js.map +7 -0
- package/dist/modules/billing/api/transactions/route.js +109 -0
- package/dist/modules/billing/api/transactions/route.js.map +7 -0
- package/dist/modules/billing/api/usage/route.js +30 -6
- package/dist/modules/billing/api/usage/route.js.map +2 -2
- package/dist/modules/billing/backend/billing/accounts/[id]/page.js +16 -1
- package/dist/modules/billing/backend/billing/accounts/[id]/page.js.map +2 -2
- package/dist/modules/billing/backend/billing/accounts/create/page.js +8 -1
- package/dist/modules/billing/backend/billing/accounts/create/page.js.map +2 -2
- package/dist/modules/billing/backend/billing/accounts/page.js +26 -1
- package/dist/modules/billing/backend/billing/accounts/page.js.map +2 -2
- package/dist/modules/billing/backend/billing/statements/[id]/page.js +129 -0
- package/dist/modules/billing/backend/billing/statements/[id]/page.js.map +7 -0
- package/dist/modules/billing/backend/billing/statements/[id]/page.meta.js +21 -0
- package/dist/modules/billing/backend/billing/statements/[id]/page.meta.js.map +7 -0
- package/dist/modules/billing/backend/billing/statements/page.js +152 -0
- package/dist/modules/billing/backend/billing/statements/page.js.map +7 -0
- package/dist/modules/billing/backend/billing/statements/page.meta.js +18 -0
- package/dist/modules/billing/backend/billing/statements/page.meta.js.map +7 -0
- package/dist/modules/billing/backend/billing/topups/[id]/page.js +90 -0
- package/dist/modules/billing/backend/billing/topups/[id]/page.js.map +7 -0
- package/dist/modules/billing/backend/billing/topups/[id]/page.meta.js +21 -0
- package/dist/modules/billing/backend/billing/topups/[id]/page.meta.js.map +7 -0
- package/dist/modules/billing/backend/billing/topups/page.js +147 -0
- package/dist/modules/billing/backend/billing/topups/page.js.map +7 -0
- package/dist/modules/billing/backend/billing/topups/page.meta.js +18 -0
- package/dist/modules/billing/backend/billing/topups/page.meta.js.map +7 -0
- package/dist/modules/billing/backend/billing/transactions/[id]/page.js +114 -0
- package/dist/modules/billing/backend/billing/transactions/[id]/page.js.map +7 -0
- package/dist/modules/billing/backend/billing/transactions/[id]/page.meta.js +21 -0
- package/dist/modules/billing/backend/billing/transactions/[id]/page.meta.js.map +7 -0
- package/dist/modules/billing/backend/billing/transactions/page.js +149 -0
- package/dist/modules/billing/backend/billing/transactions/page.js.map +7 -0
- package/dist/modules/billing/backend/billing/transactions/page.meta.js +18 -0
- package/dist/modules/billing/backend/billing/transactions/page.meta.js.map +7 -0
- package/dist/modules/billing/commands/accounts.js +26 -1
- package/dist/modules/billing/commands/accounts.js.map +2 -2
- package/dist/modules/billing/commands/index.js +3 -0
- package/dist/modules/billing/commands/index.js.map +2 -2
- package/dist/modules/billing/commands/invoices.js +21 -1
- package/dist/modules/billing/commands/invoices.js.map +2 -2
- package/dist/modules/billing/commands/statements.js +74 -0
- package/dist/modules/billing/commands/statements.js.map +7 -0
- package/dist/modules/billing/commands/topups.js +139 -0
- package/dist/modules/billing/commands/topups.js.map +7 -0
- package/dist/modules/billing/commands/transactions.js +119 -0
- package/dist/modules/billing/commands/transactions.js.map +7 -0
- package/dist/modules/billing/commands/usage.js +72 -0
- package/dist/modules/billing/commands/usage.js.map +2 -2
- package/dist/modules/billing/components/AccountForm.js +53 -1
- package/dist/modules/billing/components/AccountForm.js.map +2 -2
- package/dist/modules/billing/components/PrepaidPanel.js +314 -0
- package/dist/modules/billing/components/PrepaidPanel.js.map +7 -0
- package/dist/modules/billing/components/accountNames.js +20 -0
- package/dist/modules/billing/components/accountNames.js.map +7 -0
- package/dist/modules/billing/data/entities.js +290 -0
- package/dist/modules/billing/data/entities.js.map +2 -2
- package/dist/modules/billing/data/entityIds.js +6 -1
- package/dist/modules/billing/data/entityIds.js.map +2 -2
- package/dist/modules/billing/data/validators.js +107 -2
- package/dist/modules/billing/data/validators.js.map +2 -2
- package/dist/modules/billing/events.js +52 -0
- package/dist/modules/billing/events.js.map +2 -2
- package/dist/modules/billing/i18n/en.json +112 -4
- package/dist/modules/billing/i18n/pl.json +112 -4
- package/dist/modules/billing/index.js +1 -1
- package/dist/modules/billing/index.js.map +2 -2
- package/dist/modules/billing/lib/accountStatus.js +106 -0
- package/dist/modules/billing/lib/accountStatus.js.map +7 -0
- package/dist/modules/billing/lib/balanceEvents.js +48 -0
- package/dist/modules/billing/lib/balanceEvents.js.map +7 -0
- package/dist/modules/billing/lib/balanceLedger.js +136 -0
- package/dist/modules/billing/lib/balanceLedger.js.map +7 -0
- package/dist/modules/billing/lib/balanceStatus.js +29 -0
- package/dist/modules/billing/lib/balanceStatus.js.map +7 -0
- package/dist/modules/billing/lib/billRunEngine.js +40 -2
- package/dist/modules/billing/lib/billRunEngine.js.map +2 -2
- package/dist/modules/billing/lib/creditStatus.js +65 -0
- package/dist/modules/billing/lib/creditStatus.js.map +7 -0
- package/dist/modules/billing/lib/money.js +47 -0
- package/dist/modules/billing/lib/money.js.map +7 -0
- package/dist/modules/billing/lib/prepaidConfig.js +45 -0
- package/dist/modules/billing/lib/prepaidConfig.js.map +7 -0
- package/dist/modules/billing/lib/prepaidConsume.js +214 -0
- package/dist/modules/billing/lib/prepaidConsume.js.map +7 -0
- package/dist/modules/billing/lib/prepaidPeriodClose.js +285 -0
- package/dist/modules/billing/lib/prepaidPeriodClose.js.map +7 -0
- package/dist/modules/billing/lib/topupCapture.js +62 -0
- package/dist/modules/billing/lib/topupCapture.js.map +7 -0
- package/dist/modules/billing/lib/topupReceipt.js +97 -0
- package/dist/modules/billing/lib/topupReceipt.js.map +7 -0
- package/dist/modules/billing/lib/topupTransition.js +19 -0
- package/dist/modules/billing/lib/topupTransition.js.map +7 -0
- package/dist/modules/billing/migrations/Migration20260619000000_billing_prepaid.js +110 -0
- package/dist/modules/billing/migrations/Migration20260619000000_billing_prepaid.js.map +7 -0
- package/dist/modules/billing/setup.js +32 -1
- package/dist/modules/billing/setup.js.map +2 -2
- package/dist/modules/billing/subscribers/prepaid-topup-cancelled.js +26 -0
- package/dist/modules/billing/subscribers/prepaid-topup-cancelled.js.map +7 -0
- package/dist/modules/billing/subscribers/prepaid-topup-captured.js +87 -0
- package/dist/modules/billing/subscribers/prepaid-topup-captured.js.map +7 -0
- package/dist/modules/billing/subscribers/prepaid-topup-expired.js +26 -0
- package/dist/modules/billing/subscribers/prepaid-topup-expired.js.map +7 -0
- package/dist/modules/billing/subscribers/prepaid-topup-failed.js +26 -0
- package/dist/modules/billing/subscribers/prepaid-topup-failed.js.map +7 -0
- package/dist/modules/billing/workers/reconcile-prepaid-balances.js +50 -0
- package/dist/modules/billing/workers/reconcile-prepaid-balances.js.map +7 -0
- package/package.json +9 -9
- package/src/modules/billing/__tests__/commands/invoices.test.ts +3 -3
- package/src/modules/billing/__tests__/commands/topups.test.ts +104 -0
- package/src/modules/billing/__tests__/commands/transactions.test.ts +107 -0
- package/src/modules/billing/__tests__/helpers/prepaidMockEm.ts +235 -0
- package/src/modules/billing/__tests__/lib/accountStatus.test.ts +93 -0
- package/src/modules/billing/__tests__/lib/balanceLedger.test.ts +125 -0
- package/src/modules/billing/__tests__/lib/balanceStatus.test.ts +65 -0
- package/src/modules/billing/__tests__/lib/creditStatus.test.ts +111 -0
- package/src/modules/billing/__tests__/lib/money.test.ts +56 -0
- package/src/modules/billing/__tests__/lib/prepaidConsume.test.ts +179 -0
- package/src/modules/billing/__tests__/lib/prepaidPeriodClose.test.ts +232 -0
- package/src/modules/billing/__tests__/lib/topupCapture.test.ts +123 -0
- package/src/modules/billing/__tests__/lib/topupReceipt.test.ts +84 -0
- package/src/modules/billing/__tests__/setup.test.ts +28 -2
- package/src/modules/billing/acl.ts +8 -0
- package/src/modules/billing/api/accounts/[id]/balance/route.ts +74 -0
- package/src/modules/billing/api/accounts/[id]/credit-status/route.ts +71 -0
- package/src/modules/billing/api/accounts/[id]/topups/route.ts +49 -0
- package/src/modules/billing/api/accounts/route.ts +7 -0
- package/src/modules/billing/api/export/account/[id]/route.ts +47 -2
- package/src/modules/billing/api/statements/generate/route.ts +78 -0
- package/src/modules/billing/api/statements/route.ts +117 -0
- package/src/modules/billing/api/topups/route.ts +154 -0
- package/src/modules/billing/api/transactions/adjust/route.ts +80 -0
- package/src/modules/billing/api/transactions/route.ts +116 -0
- package/src/modules/billing/api/usage/route.ts +36 -5
- package/src/modules/billing/backend/billing/accounts/[id]/page.tsx +28 -0
- package/src/modules/billing/backend/billing/accounts/create/page.tsx +7 -0
- package/src/modules/billing/backend/billing/accounts/page.tsx +32 -1
- package/src/modules/billing/backend/billing/statements/[id]/page.meta.ts +19 -0
- package/src/modules/billing/backend/billing/statements/[id]/page.tsx +198 -0
- package/src/modules/billing/backend/billing/statements/page.meta.ts +16 -0
- package/src/modules/billing/backend/billing/statements/page.tsx +190 -0
- package/src/modules/billing/backend/billing/topups/[id]/page.meta.ts +19 -0
- package/src/modules/billing/backend/billing/topups/[id]/page.tsx +151 -0
- package/src/modules/billing/backend/billing/topups/page.meta.ts +16 -0
- package/src/modules/billing/backend/billing/topups/page.tsx +182 -0
- package/src/modules/billing/backend/billing/transactions/[id]/page.meta.ts +19 -0
- package/src/modules/billing/backend/billing/transactions/[id]/page.tsx +179 -0
- package/src/modules/billing/backend/billing/transactions/page.meta.ts +16 -0
- package/src/modules/billing/backend/billing/transactions/page.tsx +187 -0
- package/src/modules/billing/commands/accounts.ts +42 -1
- package/src/modules/billing/commands/index.ts +3 -0
- package/src/modules/billing/commands/invoices.ts +26 -2
- package/src/modules/billing/commands/statements.ts +101 -0
- package/src/modules/billing/commands/topups.ts +181 -0
- package/src/modules/billing/commands/transactions.ts +152 -0
- package/src/modules/billing/commands/usage.ts +114 -4
- package/src/modules/billing/components/AccountForm.tsx +66 -0
- package/src/modules/billing/components/PrepaidPanel.tsx +382 -0
- package/src/modules/billing/components/accountNames.ts +23 -0
- package/src/modules/billing/data/entities.ts +383 -0
- package/src/modules/billing/data/entityIds.ts +5 -0
- package/src/modules/billing/data/validators.ts +144 -0
- package/src/modules/billing/events.ts +52 -0
- package/src/modules/billing/i18n/en.json +112 -4
- package/src/modules/billing/i18n/pl.json +112 -4
- package/src/modules/billing/index.ts +1 -1
- package/src/modules/billing/lib/accountStatus.ts +155 -0
- package/src/modules/billing/lib/balanceEvents.ts +74 -0
- package/src/modules/billing/lib/balanceLedger.ts +258 -0
- package/src/modules/billing/lib/balanceStatus.ts +78 -0
- package/src/modules/billing/lib/billRunEngine.ts +66 -5
- package/src/modules/billing/lib/creditStatus.ts +153 -0
- package/src/modules/billing/lib/money.ts +73 -0
- package/src/modules/billing/lib/prepaidConfig.ts +58 -0
- package/src/modules/billing/lib/prepaidConsume.ts +299 -0
- package/src/modules/billing/lib/prepaidPeriodClose.ts +453 -0
- package/src/modules/billing/lib/topupCapture.ts +117 -0
- package/src/modules/billing/lib/topupReceipt.ts +153 -0
- package/src/modules/billing/lib/topupTransition.ts +31 -0
- package/src/modules/billing/migrations/Migration20260619000000_billing_prepaid.ts +131 -0
- package/src/modules/billing/setup.ts +45 -0
- package/src/modules/billing/subscribers/prepaid-topup-cancelled.ts +31 -0
- package/src/modules/billing/subscribers/prepaid-topup-captured.ts +120 -0
- package/src/modules/billing/subscribers/prepaid-topup-expired.ts +31 -0
- package/src/modules/billing/subscribers/prepaid-topup-failed.ts +32 -0
- package/src/modules/billing/workers/reconcile-prepaid-balances.ts +68 -0
|
@@ -7,10 +7,32 @@ const BILL_RUN_OUTCOME_STATUSES = [
|
|
|
7
7
|
"success",
|
|
8
8
|
"success_with_warnings",
|
|
9
9
|
"skipped_existing_draft",
|
|
10
|
+
// SPEC-002: prepaid period close was skipped because a statement already
|
|
11
|
+
// exists for the window.
|
|
12
|
+
"skipped_existing_statement",
|
|
10
13
|
"failed"
|
|
11
14
|
];
|
|
12
15
|
const DRAFT_INVOICE_EDIT_ACTIONS = ["line_added", "line_removed", "line_edited"];
|
|
13
16
|
const INVOICE_STATUSES = ["draft", "posted", "paid", "void"];
|
|
17
|
+
const BILLING_MODES = ["postpaid", "prepaid"];
|
|
18
|
+
const TRANSACTION_TYPES = [
|
|
19
|
+
"topup",
|
|
20
|
+
"usage",
|
|
21
|
+
"recurring",
|
|
22
|
+
"one_time",
|
|
23
|
+
"adjustment",
|
|
24
|
+
"reversal"
|
|
25
|
+
];
|
|
26
|
+
const TOPUP_STATUSES = [
|
|
27
|
+
"pending",
|
|
28
|
+
"captured",
|
|
29
|
+
"failed",
|
|
30
|
+
"expired",
|
|
31
|
+
"cancelled"
|
|
32
|
+
];
|
|
33
|
+
const STATEMENT_STATUSES = ["generated", "sent"];
|
|
34
|
+
const BALANCE_STATUSES = ["ok", "low", "exhausted"];
|
|
35
|
+
const CREDIT_STATUSES = ["within_limit", "near_limit", "over_limit"];
|
|
14
36
|
const WEEKLY_ANCHORS = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"];
|
|
15
37
|
const billCycleAnchorSchema = z.string().min(1).refine(
|
|
16
38
|
(val) => {
|
|
@@ -111,6 +133,7 @@ const listPaginationBase = {
|
|
|
111
133
|
sortField: z.string().optional(),
|
|
112
134
|
sortDir: z.enum(["asc", "desc"]).optional()
|
|
113
135
|
};
|
|
136
|
+
const moneyNonNegative = z.number().finite().nonnegative();
|
|
114
137
|
const billingAccountCreateSchema = scopedSchema.extend({
|
|
115
138
|
customerId: z.string().min(1).max(255),
|
|
116
139
|
name: z.string().trim().min(1).max(255),
|
|
@@ -126,7 +149,15 @@ const billingAccountCreateSchema = scopedSchema.extend({
|
|
|
126
149
|
invoiceAddress: invoiceAddressSchema,
|
|
127
150
|
nextBillDate: z.coerce.date(),
|
|
128
151
|
lastBillDate: z.coerce.date().optional(),
|
|
129
|
-
isActive: z.boolean().optional()
|
|
152
|
+
isActive: z.boolean().optional(),
|
|
153
|
+
// SPEC-002: mode is immutable after create (like currencyCode). Default
|
|
154
|
+
// 'postpaid' so existing callers are unaffected.
|
|
155
|
+
billingMode: z.enum(BILLING_MODES).optional(),
|
|
156
|
+
// Credit line (both modes). 0 = no credit.
|
|
157
|
+
creditLimit: moneyNonNegative.optional(),
|
|
158
|
+
// Initial low-balance threshold for a prepaid account's balance row.
|
|
159
|
+
// Null = resolve the tenant config default at read time.
|
|
160
|
+
lowBalanceThreshold: moneyNonNegative.nullable().optional()
|
|
130
161
|
});
|
|
131
162
|
const billingAccountUpdateSchema = scopedSchema.extend({
|
|
132
163
|
id: z.string().uuid(),
|
|
@@ -139,7 +170,14 @@ const billingAccountUpdateSchema = scopedSchema.extend({
|
|
|
139
170
|
invoiceAddress: invoiceAddressSchema.optional(),
|
|
140
171
|
nextBillDate: z.coerce.date().optional(),
|
|
141
172
|
lastBillDate: z.coerce.date().nullable().optional(),
|
|
142
|
-
isActive: z.boolean().optional()
|
|
173
|
+
isActive: z.boolean().optional(),
|
|
174
|
+
// SPEC-002: credit_limit is editable (it's an AR/overdraft policy knob);
|
|
175
|
+
// `billingMode` is intentionally NOT updatable — mode is frozen at create
|
|
176
|
+
// (like currencyCode), no live postpaid↔prepaid switch in v1.
|
|
177
|
+
creditLimit: moneyNonNegative.optional(),
|
|
178
|
+
// Editing the prepaid balance row's low-balance threshold. Null clears it
|
|
179
|
+
// back to the tenant config default.
|
|
180
|
+
lowBalanceThreshold: moneyNonNegative.nullable().optional()
|
|
143
181
|
// `currencyCode` is intentionally NOT updatable — currency is frozen at
|
|
144
182
|
// account create time so historical invoices keep their currency context.
|
|
145
183
|
// `customerId` is also immutable; create a new account if the customer
|
|
@@ -154,6 +192,7 @@ const billingAccountListQuerySchema = z.object({
|
|
|
154
192
|
customerId: z.string().optional(),
|
|
155
193
|
currencyCode: z.string().optional(),
|
|
156
194
|
billCycle: z.enum(BILL_CYCLES).optional(),
|
|
195
|
+
billingMode: z.enum(BILLING_MODES).optional(),
|
|
157
196
|
isActive: z.coerce.boolean().optional(),
|
|
158
197
|
search: z.string().optional()
|
|
159
198
|
}).passthrough();
|
|
@@ -353,15 +392,75 @@ const billingWipeTestInvoicesSchema = scopedSchema.extend({
|
|
|
353
392
|
/** Optional — when set, wipes only test invoices from this run. */
|
|
354
393
|
billRunId: z.string().uuid().optional()
|
|
355
394
|
});
|
|
395
|
+
const billingTopupCreateSchema = scopedSchema.extend({
|
|
396
|
+
// The route maps the `/accounts/{id}/topups` path param into billAccountId.
|
|
397
|
+
billAccountId: z.string().uuid(),
|
|
398
|
+
amount: z.number().finite().positive(),
|
|
399
|
+
// Optional — defaults to the tenant config `prepaid.topup_provider`.
|
|
400
|
+
providerKey: z.string().trim().min(1).max(64).optional(),
|
|
401
|
+
successUrl: z.string().trim().url().max(2048).optional(),
|
|
402
|
+
cancelUrl: z.string().trim().url().max(2048).optional(),
|
|
403
|
+
// Optional idempotency for the initiating request.
|
|
404
|
+
sourceRef: z.string().trim().min(1).max(255).optional()
|
|
405
|
+
});
|
|
406
|
+
const billingTopupListQuerySchema = z.object({
|
|
407
|
+
...listPaginationBase,
|
|
408
|
+
id: z.string().uuid().optional(),
|
|
409
|
+
billAccountId: z.string().uuid().optional(),
|
|
410
|
+
status: z.enum(TOPUP_STATUSES).optional(),
|
|
411
|
+
search: z.string().optional()
|
|
412
|
+
}).passthrough();
|
|
413
|
+
const billingTransactionAdjustSchema = scopedSchema.extend({
|
|
414
|
+
billAccountId: z.string().uuid(),
|
|
415
|
+
// SIGNED: > 0 credit, < 0 debit. Zero is rejected.
|
|
416
|
+
amount: z.number().finite(),
|
|
417
|
+
description: z.string().trim().min(1).max(500),
|
|
418
|
+
sourceRef: z.string().trim().min(1).max(255).optional()
|
|
419
|
+
}).superRefine((val, ctx) => {
|
|
420
|
+
if (val.amount === 0) {
|
|
421
|
+
ctx.addIssue({
|
|
422
|
+
code: z.ZodIssueCode.custom,
|
|
423
|
+
path: ["amount"],
|
|
424
|
+
message: "amount must be non-zero (positive credit or negative debit)"
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
const billingTransactionListQuerySchema = z.object({
|
|
429
|
+
...listPaginationBase,
|
|
430
|
+
id: z.string().uuid().optional(),
|
|
431
|
+
billAccountId: z.string().uuid().optional(),
|
|
432
|
+
type: z.enum(TRANSACTION_TYPES).optional(),
|
|
433
|
+
createdFrom: z.coerce.date().optional(),
|
|
434
|
+
createdTo: z.coerce.date().optional()
|
|
435
|
+
}).passthrough();
|
|
436
|
+
const billingStatementGenerateSchema = scopedSchema.extend({
|
|
437
|
+
billAccountId: z.string().uuid(),
|
|
438
|
+
// "today" the close evaluates the due period against. Defaults to now.
|
|
439
|
+
asOfDate: z.coerce.date().optional()
|
|
440
|
+
});
|
|
441
|
+
const billingStatementListQuerySchema = z.object({
|
|
442
|
+
...listPaginationBase,
|
|
443
|
+
id: z.string().uuid().optional(),
|
|
444
|
+
billAccountId: z.string().uuid().optional(),
|
|
445
|
+
status: z.enum(STATEMENT_STATUSES).optional(),
|
|
446
|
+
periodEndFrom: z.coerce.date().optional(),
|
|
447
|
+
periodEndTo: z.coerce.date().optional()
|
|
448
|
+
}).passthrough();
|
|
356
449
|
export {
|
|
450
|
+
BALANCE_STATUSES,
|
|
357
451
|
BILLING_ITEM_TYPES,
|
|
452
|
+
BILLING_MODES,
|
|
358
453
|
BILL_CYCLES,
|
|
359
454
|
BILL_RUN_MODES,
|
|
360
455
|
BILL_RUN_OUTCOME_STATUSES,
|
|
361
456
|
BILL_RUN_STATUSES,
|
|
362
457
|
BILL_RUN_TRIGGERS,
|
|
458
|
+
CREDIT_STATUSES,
|
|
363
459
|
DRAFT_INVOICE_EDIT_ACTIONS,
|
|
364
460
|
INVOICE_STATUSES,
|
|
461
|
+
STATEMENT_STATUSES,
|
|
462
|
+
TOPUP_STATUSES,
|
|
463
|
+
TRANSACTION_TYPES,
|
|
365
464
|
billCycleAnchorSchema,
|
|
366
465
|
billingAccountCreateSchema,
|
|
367
466
|
billingAccountDeleteSchema,
|
|
@@ -379,6 +478,12 @@ export {
|
|
|
379
478
|
billingRunListQuerySchema,
|
|
380
479
|
billingRunRetryFailedSchema,
|
|
381
480
|
billingRunTriggerSchema,
|
|
481
|
+
billingStatementGenerateSchema,
|
|
482
|
+
billingStatementListQuerySchema,
|
|
483
|
+
billingTopupCreateSchema,
|
|
484
|
+
billingTopupListQuerySchema,
|
|
485
|
+
billingTransactionAdjustSchema,
|
|
486
|
+
billingTransactionListQuerySchema,
|
|
382
487
|
billingUsageCreateSchema,
|
|
383
488
|
billingUsageListQuerySchema,
|
|
384
489
|
billingWipeTestInvoicesSchema,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/billing/data/validators.ts"],
|
|
4
|
-
"sourcesContent": ["import { z } from 'zod'\n\n// \u2500\u2500\u2500 Enums \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const BILLING_ITEM_TYPES = ['one_time', 'recurring', 'usage'] as const\nexport type BillingItemType = (typeof BILLING_ITEM_TYPES)[number]\n\nexport const BILL_CYCLES = ['weekly', 'monthly', 'quarterly', 'annually'] as const\nexport type BillCycle = (typeof BILL_CYCLES)[number]\n\nexport const BILL_RUN_TRIGGERS = ['schedule', 'manual'] as const\nexport type BillRunTrigger = (typeof BILL_RUN_TRIGGERS)[number]\n\nexport const BILL_RUN_STATUSES = ['running', 'completed', 'partial_failure', 'failed'] as const\nexport type BillRunStatus = (typeof BILL_RUN_STATUSES)[number]\n\nexport const BILL_RUN_OUTCOME_STATUSES = [\n 'success',\n 'success_with_warnings',\n 'skipped_existing_draft',\n 'failed',\n] as const\nexport type BillRunOutcomeStatus = (typeof BILL_RUN_OUTCOME_STATUSES)[number]\n\nexport const DRAFT_INVOICE_EDIT_ACTIONS = ['line_added', 'line_removed', 'line_edited'] as const\nexport type DraftInvoiceEditAction = (typeof DRAFT_INVOICE_EDIT_ACTIONS)[number]\n\nexport const INVOICE_STATUSES = ['draft', 'posted', 'paid', 'void'] as const\nexport type InvoiceStatus = (typeof INVOICE_STATUSES)[number]\n\n// `mon`\u2013`sun` for weekly cycles; 1\u201328 (as text) for the others.\n// Why text for numeric anchors: the column type stays uniform across cycles\n// and we never do arithmetic on the raw value (the engine parses it on use).\nconst WEEKLY_ANCHORS = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'] as const\n\nexport const billCycleAnchorSchema = z\n .string()\n .min(1)\n .refine(\n (val) => {\n if ((WEEKLY_ANCHORS as readonly string[]).includes(val.toLowerCase())) return true\n const n = Number.parseInt(val, 10)\n return Number.isInteger(n) && n >= 1 && n <= 28\n },\n {\n message:\n 'bill_cycle_anchor must be 1\u201328 (monthly/quarterly/annually) or mon\u2013sun (weekly)',\n },\n )\n\n// \u2500\u2500\u2500 rate_json \u2014 pricing definitions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Validated at API ingress so the engine can trust the shape downstream.\n// Negative amounts are intentionally allowed only on `one_time` (refunds /\n// credits / proration credits). Recurring and usage unit prices MUST be\n// non-negative \u2014 discounts on those are modeled as separate `one_time`\n// credit items.\n\nconst numericNonNegative = z.number().finite().nonnegative()\nconst numericAny = z.number().finite()\n\nexport const rateJsonOneTime = z\n .object({ amount: numericAny })\n .strict()\n\nexport const rateJsonRecurring = z\n .object({ unit_price: numericNonNegative })\n .strict()\n\nexport const rateJsonUsageSimple = z\n .object({ unit_price: numericNonNegative })\n .strict()\n\nconst tierWithUnitPrice = z\n .object({\n up_to: z.union([z.number().int().positive(), z.null()]),\n unit_price: numericNonNegative,\n })\n .strict()\n\nconst tierWithFlatAmount = z\n .object({\n up_to: z.union([z.number().int().positive(), z.null()]),\n flat_amount: numericNonNegative,\n })\n .strict()\n\n// All tiers must use the same key shape (consistent with the model). Mixing\n// `unit_price` and `flat_amount` across tiers is rejected \u2014 see spec\n// validation rules.\nconst tiersUnitPrice = z\n .array(tierWithUnitPrice)\n .min(1, 'tiers must be a non-empty array')\nconst tiersFlatAmount = z\n .array(tierWithFlatAmount)\n .min(1, 'tiers must be a non-empty array')\n\nfunction refineTierProgression<T extends { up_to: number | null }>(\n tiers: T[],\n ctx: z.RefinementCtx,\n): void {\n const openTopCount = tiers.filter((t) => t.up_to === null).length\n if (openTopCount !== 1) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: 'tiers must contain exactly one open-ended top tier (up_to: null)',\n })\n return\n }\n if (tiers[tiers.length - 1].up_to !== null) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: 'the open-ended top tier (up_to: null) must be the last entry',\n })\n return\n }\n for (let i = 1; i < tiers.length - 1; i++) {\n const prev = tiers[i - 1].up_to\n const curr = tiers[i].up_to\n if (prev !== null && curr !== null && curr <= prev) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `up_to values must be strictly increasing across tiers (failed at index ${i})`,\n })\n return\n }\n }\n}\n\nexport const rateJsonUsageVolume = z\n .object({\n model: z.literal('volume'),\n tiers: tiersUnitPrice,\n })\n .strict()\n .superRefine((val, ctx) => refineTierProgression(val.tiers, ctx))\n\nexport const rateJsonUsageGraduated = z\n .object({\n model: z.literal('graduated'),\n tiers: tiersUnitPrice,\n })\n .strict()\n .superRefine((val, ctx) => refineTierProgression(val.tiers, ctx))\n\nexport const rateJsonUsageFlat = z\n .object({\n model: z.literal('flat'),\n tiers: tiersFlatAmount,\n })\n .strict()\n .superRefine((val, ctx) => refineTierProgression(val.tiers, ctx))\n\nexport const rateJsonUsageTiered = z.discriminatedUnion('model', [\n rateJsonUsageVolume,\n rateJsonUsageGraduated,\n rateJsonUsageFlat,\n])\n\nexport const rateJsonUsage = z.union([rateJsonUsageSimple, rateJsonUsageTiered])\n\n/**\n * Validate a `rate_json` payload against the rules for a given Billing Item\n * `type`. Returns the parsed value or throws a `ZodError` whose message\n * surfaces the specific shape violation.\n */\nexport function validateRateJson(\n type: BillingItemType,\n rateJson: unknown,\n):\n | z.infer<typeof rateJsonOneTime>\n | z.infer<typeof rateJsonRecurring>\n | z.infer<typeof rateJsonUsage> {\n switch (type) {\n case 'one_time':\n return rateJsonOneTime.parse(rateJson)\n case 'recurring':\n return rateJsonRecurring.parse(rateJson)\n case 'usage':\n return rateJsonUsage.parse(rateJson)\n }\n}\n\n// \u2500\u2500\u2500 Invoice address (BillingAccount.invoice_address) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const invoiceAddressSchema = z\n .object({\n line1: z.string().min(1),\n line2: z.string().optional(),\n city: z.string().min(1),\n postal_code: z.string().min(1),\n country: z.string().min(2).max(3), // ISO 3166-1 alpha-2 or alpha-3\n })\n .strict()\n\nexport type InvoiceAddress = z.infer<typeof invoiceAddressSchema>\n\n// \u2500\u2500\u2500 Scope (injected by withScopedPayload at API ingress) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst scopedSchema = z.object({\n tenantId: z.string().uuid(),\n organizationId: z.string().uuid(),\n})\n\n// \u2500\u2500\u2500 List pagination (shared shape) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst listPaginationBase = {\n page: z.coerce.number().int().min(1).default(1),\n pageSize: z.coerce.number().int().min(1).max(100).default(50),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n}\n\n// \u2500\u2500\u2500 BillingAccount payloads \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const billingAccountCreateSchema = scopedSchema.extend({\n customerId: z.string().min(1).max(255),\n name: z.string().trim().min(1).max(255),\n currencyCode: z.string().trim().toUpperCase().length(3),\n billCycle: z.enum(BILL_CYCLES),\n billCycleAnchor: billCycleAnchorSchema,\n invoiceEmail: z.string().trim().email().max(320),\n invoiceLanguage: z.string().trim().toLowerCase().min(2).max(5),\n // Nullable + optional \u2014 consistent with the update schema, and the\n // cpq-billing-connector's shell-account seed sends `taxId: null`\n // for customers with no tax id.\n taxId: z.string().trim().max(64).nullable().optional(),\n invoiceAddress: invoiceAddressSchema,\n nextBillDate: z.coerce.date(),\n lastBillDate: z.coerce.date().optional(),\n isActive: z.boolean().optional(),\n})\n\nexport type BillingAccountCreateInput = z.infer<typeof billingAccountCreateSchema>\n\nexport const billingAccountUpdateSchema = scopedSchema.extend({\n id: z.string().uuid(),\n name: z.string().trim().min(1).max(255).optional(),\n billCycle: z.enum(BILL_CYCLES).optional(),\n billCycleAnchor: billCycleAnchorSchema.optional(),\n invoiceEmail: z.string().trim().email().max(320).optional(),\n invoiceLanguage: z.string().trim().toLowerCase().min(2).max(5).optional(),\n taxId: z.string().trim().max(64).nullable().optional(),\n invoiceAddress: invoiceAddressSchema.optional(),\n nextBillDate: z.coerce.date().optional(),\n lastBillDate: z.coerce.date().nullable().optional(),\n isActive: z.boolean().optional(),\n // `currencyCode` is intentionally NOT updatable \u2014 currency is frozen at\n // account create time so historical invoices keep their currency context.\n // `customerId` is also immutable; create a new account if the customer\n // FK changes.\n})\n\nexport type BillingAccountUpdateInput = z.infer<typeof billingAccountUpdateSchema>\n\nexport const billingAccountDeleteSchema = scopedSchema.extend({\n id: z.string().uuid(),\n})\n\nexport type BillingAccountDeleteInput = z.infer<typeof billingAccountDeleteSchema>\n\nexport const billingAccountListQuerySchema = z\n .object({\n ...listPaginationBase,\n id: z.string().uuid().optional(),\n customerId: z.string().optional(),\n currencyCode: z.string().optional(),\n billCycle: z.enum(BILL_CYCLES).optional(),\n isActive: z.coerce.boolean().optional(),\n search: z.string().optional(),\n })\n .passthrough()\n\nexport type BillingAccountListQuery = z.infer<typeof billingAccountListQuerySchema>\n\n// \u2500\u2500\u2500 BillingItem payloads \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst ratePayloadByType = z\n .object({\n type: z.enum(BILLING_ITEM_TYPES),\n rateJson: z.unknown(),\n })\n .superRefine((val, ctx) => {\n try {\n validateRateJson(val.type, val.rateJson)\n } catch (err) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['rateJson'],\n message: err instanceof Error ? err.message : 'rate_json is invalid for this type',\n })\n }\n })\n\nexport const billingItemCreateSchema = scopedSchema\n .extend({\n billAccountId: z.string().uuid(),\n type: z.enum(BILLING_ITEM_TYPES),\n billStartDate: z.coerce.date(),\n billEndDate: z.coerce.date().nullable().optional(),\n description: z.string().trim().min(1).max(500),\n rateJson: z.unknown(), // shape validated via the refine below\n uomCode: z.string().trim().max(64).optional(),\n subscriptionId: z.string().trim().max(255).optional(),\n subscriptionItemId: z.string().trim().max(255).optional(),\n // `source_ref` is the idempotency key. NULL \u2192 no dedup, always create.\n sourceRef: z.string().trim().min(1).max(255).optional(),\n // currency_mismatch and billed_to_date are system-managed, never set by\n // clients on create.\n })\n .superRefine((val, ctx) => {\n try {\n validateRateJson(val.type, val.rateJson)\n } catch (err) {\n const message = err instanceof Error ? err.message : 'rate_json is invalid for this type'\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['rateJson'], message })\n }\n if (val.type === 'usage' && !val.uomCode) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['uomCode'],\n message: 'uomCode is required for type=usage',\n })\n }\n })\n\nexport type BillingItemCreateInput = z.infer<typeof billingItemCreateSchema>\n\n// \u2500\u2500\u2500 Bulk item create (Phase 4g) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// One scope envelope, N item payloads. The CPQ connector activating\n// a large subscription used to fire one `billing.items.create` per\n// charge \u2014 bulk-create collapses that into a single command with a\n// batched `source_ref` idempotency check + single flush.\n\nconst billingItemBulkEntrySchema = z\n .object({\n billAccountId: z.string().uuid(),\n type: z.enum(BILLING_ITEM_TYPES),\n billStartDate: z.coerce.date(),\n billEndDate: z.coerce.date().nullable().optional(),\n description: z.string().trim().min(1).max(500),\n rateJson: z.unknown(),\n uomCode: z.string().trim().max(64).optional(),\n subscriptionId: z.string().trim().max(255).optional(),\n subscriptionItemId: z.string().trim().max(255).optional(),\n sourceRef: z.string().trim().min(1).max(255).optional(),\n })\n .superRefine((val, ctx) => {\n try {\n validateRateJson(val.type, val.rateJson)\n } catch (err) {\n const message = err instanceof Error ? err.message : 'rate_json is invalid for this type'\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['rateJson'], message })\n }\n if (val.type === 'usage' && !val.uomCode) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['uomCode'],\n message: 'uomCode is required for type=usage',\n })\n }\n })\n\nexport type BillingItemBulkEntry = z.infer<typeof billingItemBulkEntrySchema>\n\nexport const billingItemBulkCreateSchema = scopedSchema.extend({\n // Cap at 500 per call \u2014 keeps a single bulk transaction bounded.\n // A CPQ subscription with >500 charges should be split by the\n // caller (the connector); 500 is already far past any realistic\n // single-subscription charge count.\n items: z.array(billingItemBulkEntrySchema).min(1).max(500),\n})\n\nexport type BillingItemBulkCreateInput = z.infer<typeof billingItemBulkCreateSchema>\n\nexport const billingItemUpdateSchema = scopedSchema.extend({\n id: z.string().uuid(),\n // `type` is immutable \u2014 changing one_time \u2192 recurring would silently\n // change billing semantics. Cancel the old item, create a new one.\n billStartDate: z.coerce.date().optional(),\n billEndDate: z.coerce.date().nullable().optional(),\n description: z.string().trim().min(1).max(500).optional(),\n rateJson: z.unknown().optional(),\n uomCode: z.string().trim().max(64).nullable().optional(),\n subscriptionId: z.string().trim().max(255).nullable().optional(),\n subscriptionItemId: z.string().trim().max(255).nullable().optional(),\n // `source_ref` immutable \u2014 it's the idempotency identity of the item.\n isActive: z.boolean().optional(),\n})\n\nexport type BillingItemUpdateInput = z.infer<typeof billingItemUpdateSchema>\n\nexport const billingItemDeleteSchema = scopedSchema.extend({\n id: z.string().uuid(),\n})\n\nexport type BillingItemDeleteInput = z.infer<typeof billingItemDeleteSchema>\n\nexport const billingItemListQuerySchema = z\n .object({\n ...listPaginationBase,\n id: z.string().uuid().optional(),\n search: z.string().optional(),\n billAccountId: z.string().uuid().optional(),\n type: z.enum(BILLING_ITEM_TYPES).optional(),\n subscriptionId: z.string().optional(),\n isActive: z.coerce.boolean().optional(),\n activeAt: z.coerce.date().optional(), // bill_start_date <= X AND (bill_end_date IS NULL OR bill_end_date >= X)\n })\n .passthrough()\n\nexport type BillingItemListQuery = z.infer<typeof billingItemListQuerySchema>\n\n// \u2500\u2500\u2500 BillingAccountUsage payloads \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const billingUsageCreateSchema = scopedSchema.extend({\n billAccountId: z.string().uuid(),\n uomCode: z.string().trim().min(1).max(64),\n // `quantity` arrives as a number from JSON; MikroORM stores it as\n // numeric(18,4). The service coerces to a string at persist time.\n quantity: z.number().finite().nonnegative(),\n periodStart: z.coerce.date(),\n periodEnd: z.coerce.date(),\n lineDescription: z.string().trim().min(1).max(500).optional(),\n sourceRef: z.string().trim().min(1).max(255).optional(),\n}).superRefine((val, ctx) => {\n if (val.periodEnd < val.periodStart) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['periodEnd'],\n message: 'periodEnd must be on or after periodStart',\n })\n }\n})\n\nexport type BillingUsageCreateInput = z.infer<typeof billingUsageCreateSchema>\n\nexport const billingUsageListQuerySchema = z\n .object({\n ...listPaginationBase,\n billAccountId: z.string().uuid().optional(),\n uomCode: z.string().optional(),\n rated: z.coerce.boolean().optional(), // true \u2192 already rated; false \u2192 unrated\n periodEndFrom: z.coerce.date().optional(),\n periodEndTo: z.coerce.date().optional(),\n })\n .passthrough()\n\nexport type BillingUsageListQuery = z.infer<typeof billingUsageListQuerySchema>\n\n// Suppress unused-export TS warning \u2014 `ratePayloadByType` is reserved for\n// reuse by a future per-tenant rate-validation CLI tool.\nvoid ratePayloadByType\n\n// \u2500\u2500\u2500 Bill Run trigger payloads (Phase 2) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const BILL_RUN_MODES = ['real', 'test', 'dry'] as const\nexport type BillRunMode = (typeof BILL_RUN_MODES)[number]\n\nexport const billingRunTriggerSchema = scopedSchema.extend({\n // `triggeredBy` is filled in by the route layer (always 'manual' for\n // API triggers; the cron worker sets 'schedule'). The client cannot\n // forge a 'schedule' trigger \u2014 the field is intentionally omitted\n // from the input shape.\n mode: z.enum(BILL_RUN_MODES).default('real'),\n asOfDate: z.coerce.date().optional(),\n scopedAccountIds: z.array(z.string().uuid()).optional(),\n catchUp: z.boolean().optional(),\n})\n\nexport type BillingRunTriggerInput = z.infer<typeof billingRunTriggerSchema>\n\nexport const billingRunRetryFailedSchema = scopedSchema.extend({\n billRunId: z.string().uuid(),\n mode: z.enum(BILL_RUN_MODES).default('real'),\n})\n\nexport type BillingRunRetryFailedInput = z.infer<typeof billingRunRetryFailedSchema>\n\nexport const billingRunListQuerySchema = z\n .object({\n ...listPaginationBase,\n id: z.string().uuid().optional(),\n search: z.string().optional(),\n status: z.enum(BILL_RUN_STATUSES).optional(),\n triggeredBy: z.enum(BILL_RUN_TRIGGERS).optional(),\n parentRunId: z.string().uuid().optional(),\n asOfDateFrom: z.coerce.date().optional(),\n asOfDateTo: z.coerce.date().optional(),\n })\n .passthrough()\n\nexport type BillingRunListQuery = z.infer<typeof billingRunListQuerySchema>\n\n// \u2500\u2500\u2500 Invoice post (Phase 4) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const billingInvoicePostSchema = scopedSchema.extend({\n invoiceId: z.string().uuid(),\n})\n\nexport type BillingInvoicePostInput = z.infer<typeof billingInvoicePostSchema>\n\n// \u2500\u2500\u2500 Draft invoice edits (Phase 4b) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Fields the operator may change on a draft invoice line. Per spec:\n * \"operator CAN: add lines, remove lines, edit line description /\n * quantity / unit_price / amount\". `taxRate` is owned by core/sales\n * tax service and `currencyCode` is frozen at account create \u2014 both\n * intentionally absent from this schema.\n */\nconst lineEditableFields = z.object({\n description: z.string().trim().min(1).max(500).optional(),\n quantity: z.coerce.number().finite().nonnegative().optional(),\n unitPriceNet: z.coerce.number().finite().optional(),\n // `totalNetAmount` is operator-overridable for the \"I know better\n // than `unit_price \u00D7 quantity`\" cases (rare; mostly for negative\n // credits or rounding fix-ups). When provided, it short-circuits\n // the auto-compute path.\n totalNetAmount: z.coerce.number().finite().optional(),\n})\n\nexport const billingInvoiceEditLineSchema = scopedSchema.extend({\n invoiceId: z.string().uuid(),\n invoiceLineId: z.string().uuid(),\n changes: lineEditableFields,\n})\n\nexport type BillingInvoiceEditLineInput = z.infer<typeof billingInvoiceEditLineSchema>\n\nexport const billingInvoiceAddLineSchema = scopedSchema.extend({\n invoiceId: z.string().uuid(),\n description: z.string().trim().min(1).max(500),\n quantity: z.coerce.number().finite().nonnegative(),\n unitPriceNet: z.coerce.number().finite(),\n // Optional metadata for traceability \u2014 typically operators leave\n // `billing_item_id` blank because ad-hoc lines aren't tied to a\n // Billing Item.\n billingItemId: z.string().uuid().optional(),\n billingType: z.enum(BILLING_ITEM_TYPES).optional(),\n})\n\nexport type BillingInvoiceAddLineInput = z.infer<typeof billingInvoiceAddLineSchema>\n\nexport const billingInvoiceRemoveLineSchema = scopedSchema.extend({\n invoiceId: z.string().uuid(),\n invoiceLineId: z.string().uuid(),\n})\n\nexport type BillingInvoiceRemoveLineInput = z.infer<typeof billingInvoiceRemoveLineSchema>\n\n// \u2500\u2500\u2500 Test-invoices wipe (Phase 4b) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const billingWipeTestInvoicesSchema = scopedSchema.extend({\n /** Optional \u2014 when set, wipes only test invoices from this run. */\n billRunId: z.string().uuid().optional(),\n})\n\nexport type BillingWipeTestInvoicesInput = z.infer<typeof billingWipeTestInvoicesSchema>\n\n\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { z } from 'zod'\n\n// \u2500\u2500\u2500 Enums \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const BILLING_ITEM_TYPES = ['one_time', 'recurring', 'usage'] as const\nexport type BillingItemType = (typeof BILLING_ITEM_TYPES)[number]\n\nexport const BILL_CYCLES = ['weekly', 'monthly', 'quarterly', 'annually'] as const\nexport type BillCycle = (typeof BILL_CYCLES)[number]\n\nexport const BILL_RUN_TRIGGERS = ['schedule', 'manual'] as const\nexport type BillRunTrigger = (typeof BILL_RUN_TRIGGERS)[number]\n\nexport const BILL_RUN_STATUSES = ['running', 'completed', 'partial_failure', 'failed'] as const\nexport type BillRunStatus = (typeof BILL_RUN_STATUSES)[number]\n\nexport const BILL_RUN_OUTCOME_STATUSES = [\n 'success',\n 'success_with_warnings',\n 'skipped_existing_draft',\n // SPEC-002: prepaid period close was skipped because a statement already\n // exists for the window.\n 'skipped_existing_statement',\n 'failed',\n] as const\nexport type BillRunOutcomeStatus = (typeof BILL_RUN_OUTCOME_STATUSES)[number]\n\nexport const DRAFT_INVOICE_EDIT_ACTIONS = ['line_added', 'line_removed', 'line_edited'] as const\nexport type DraftInvoiceEditAction = (typeof DRAFT_INVOICE_EDIT_ACTIONS)[number]\n\nexport const INVOICE_STATUSES = ['draft', 'posted', 'paid', 'void'] as const\nexport type InvoiceStatus = (typeof INVOICE_STATUSES)[number]\n\n// \u2500\u2500\u2500 Prepaid (SPEC-002) enums \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const BILLING_MODES = ['postpaid', 'prepaid'] as const\nexport type BillingMode = (typeof BILLING_MODES)[number]\n\nexport const TRANSACTION_TYPES = [\n 'topup',\n 'usage',\n 'recurring',\n 'one_time',\n 'adjustment',\n 'reversal',\n] as const\nexport type TransactionType = (typeof TRANSACTION_TYPES)[number]\n\nexport const TOPUP_STATUSES = [\n 'pending',\n 'captured',\n 'failed',\n 'expired',\n 'cancelled',\n] as const\nexport type TopupStatus = (typeof TOPUP_STATUSES)[number]\n\nexport const STATEMENT_STATUSES = ['generated', 'sent'] as const\nexport type StatementStatus = (typeof STATEMENT_STATUSES)[number]\n\n// Prepaid funds status (the account's own money).\nexport const BALANCE_STATUSES = ['ok', 'low', 'exhausted'] as const\nexport type BalanceStatus = (typeof BALANCE_STATUSES)[number]\n\n// Credit-line status (extended overdraft / AR exposure \u2014 both modes).\nexport const CREDIT_STATUSES = ['within_limit', 'near_limit', 'over_limit'] as const\nexport type CreditStatus = (typeof CREDIT_STATUSES)[number]\n\n// `mon`\u2013`sun` for weekly cycles; 1\u201328 (as text) for the others.\n// Why text for numeric anchors: the column type stays uniform across cycles\n// and we never do arithmetic on the raw value (the engine parses it on use).\nconst WEEKLY_ANCHORS = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'] as const\n\nexport const billCycleAnchorSchema = z\n .string()\n .min(1)\n .refine(\n (val) => {\n if ((WEEKLY_ANCHORS as readonly string[]).includes(val.toLowerCase())) return true\n const n = Number.parseInt(val, 10)\n return Number.isInteger(n) && n >= 1 && n <= 28\n },\n {\n message:\n 'bill_cycle_anchor must be 1\u201328 (monthly/quarterly/annually) or mon\u2013sun (weekly)',\n },\n )\n\n// \u2500\u2500\u2500 rate_json \u2014 pricing definitions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Validated at API ingress so the engine can trust the shape downstream.\n// Negative amounts are intentionally allowed only on `one_time` (refunds /\n// credits / proration credits). Recurring and usage unit prices MUST be\n// non-negative \u2014 discounts on those are modeled as separate `one_time`\n// credit items.\n\nconst numericNonNegative = z.number().finite().nonnegative()\nconst numericAny = z.number().finite()\n\nexport const rateJsonOneTime = z\n .object({ amount: numericAny })\n .strict()\n\nexport const rateJsonRecurring = z\n .object({ unit_price: numericNonNegative })\n .strict()\n\nexport const rateJsonUsageSimple = z\n .object({ unit_price: numericNonNegative })\n .strict()\n\nconst tierWithUnitPrice = z\n .object({\n up_to: z.union([z.number().int().positive(), z.null()]),\n unit_price: numericNonNegative,\n })\n .strict()\n\nconst tierWithFlatAmount = z\n .object({\n up_to: z.union([z.number().int().positive(), z.null()]),\n flat_amount: numericNonNegative,\n })\n .strict()\n\n// All tiers must use the same key shape (consistent with the model). Mixing\n// `unit_price` and `flat_amount` across tiers is rejected \u2014 see spec\n// validation rules.\nconst tiersUnitPrice = z\n .array(tierWithUnitPrice)\n .min(1, 'tiers must be a non-empty array')\nconst tiersFlatAmount = z\n .array(tierWithFlatAmount)\n .min(1, 'tiers must be a non-empty array')\n\nfunction refineTierProgression<T extends { up_to: number | null }>(\n tiers: T[],\n ctx: z.RefinementCtx,\n): void {\n const openTopCount = tiers.filter((t) => t.up_to === null).length\n if (openTopCount !== 1) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: 'tiers must contain exactly one open-ended top tier (up_to: null)',\n })\n return\n }\n if (tiers[tiers.length - 1].up_to !== null) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: 'the open-ended top tier (up_to: null) must be the last entry',\n })\n return\n }\n for (let i = 1; i < tiers.length - 1; i++) {\n const prev = tiers[i - 1].up_to\n const curr = tiers[i].up_to\n if (prev !== null && curr !== null && curr <= prev) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `up_to values must be strictly increasing across tiers (failed at index ${i})`,\n })\n return\n }\n }\n}\n\nexport const rateJsonUsageVolume = z\n .object({\n model: z.literal('volume'),\n tiers: tiersUnitPrice,\n })\n .strict()\n .superRefine((val, ctx) => refineTierProgression(val.tiers, ctx))\n\nexport const rateJsonUsageGraduated = z\n .object({\n model: z.literal('graduated'),\n tiers: tiersUnitPrice,\n })\n .strict()\n .superRefine((val, ctx) => refineTierProgression(val.tiers, ctx))\n\nexport const rateJsonUsageFlat = z\n .object({\n model: z.literal('flat'),\n tiers: tiersFlatAmount,\n })\n .strict()\n .superRefine((val, ctx) => refineTierProgression(val.tiers, ctx))\n\nexport const rateJsonUsageTiered = z.discriminatedUnion('model', [\n rateJsonUsageVolume,\n rateJsonUsageGraduated,\n rateJsonUsageFlat,\n])\n\nexport const rateJsonUsage = z.union([rateJsonUsageSimple, rateJsonUsageTiered])\n\n/**\n * Validate a `rate_json` payload against the rules for a given Billing Item\n * `type`. Returns the parsed value or throws a `ZodError` whose message\n * surfaces the specific shape violation.\n */\nexport function validateRateJson(\n type: BillingItemType,\n rateJson: unknown,\n):\n | z.infer<typeof rateJsonOneTime>\n | z.infer<typeof rateJsonRecurring>\n | z.infer<typeof rateJsonUsage> {\n switch (type) {\n case 'one_time':\n return rateJsonOneTime.parse(rateJson)\n case 'recurring':\n return rateJsonRecurring.parse(rateJson)\n case 'usage':\n return rateJsonUsage.parse(rateJson)\n }\n}\n\n// \u2500\u2500\u2500 Invoice address (BillingAccount.invoice_address) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const invoiceAddressSchema = z\n .object({\n line1: z.string().min(1),\n line2: z.string().optional(),\n city: z.string().min(1),\n postal_code: z.string().min(1),\n country: z.string().min(2).max(3), // ISO 3166-1 alpha-2 or alpha-3\n })\n .strict()\n\nexport type InvoiceAddress = z.infer<typeof invoiceAddressSchema>\n\n// \u2500\u2500\u2500 Scope (injected by withScopedPayload at API ingress) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst scopedSchema = z.object({\n tenantId: z.string().uuid(),\n organizationId: z.string().uuid(),\n})\n\n// \u2500\u2500\u2500 List pagination (shared shape) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst listPaginationBase = {\n page: z.coerce.number().int().min(1).default(1),\n pageSize: z.coerce.number().int().min(1).max(100).default(50),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n}\n\n// \u2500\u2500\u2500 BillingAccount payloads \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n// numeric(18,4) money inputs arrive as numbers; the command coerces to a\n// 4dp string at persist time.\nconst moneyNonNegative = z.number().finite().nonnegative()\n\nexport const billingAccountCreateSchema = scopedSchema.extend({\n customerId: z.string().min(1).max(255),\n name: z.string().trim().min(1).max(255),\n currencyCode: z.string().trim().toUpperCase().length(3),\n billCycle: z.enum(BILL_CYCLES),\n billCycleAnchor: billCycleAnchorSchema,\n invoiceEmail: z.string().trim().email().max(320),\n invoiceLanguage: z.string().trim().toLowerCase().min(2).max(5),\n // Nullable + optional \u2014 consistent with the update schema, and the\n // cpq-billing-connector's shell-account seed sends `taxId: null`\n // for customers with no tax id.\n taxId: z.string().trim().max(64).nullable().optional(),\n invoiceAddress: invoiceAddressSchema,\n nextBillDate: z.coerce.date(),\n lastBillDate: z.coerce.date().optional(),\n isActive: z.boolean().optional(),\n // SPEC-002: mode is immutable after create (like currencyCode). Default\n // 'postpaid' so existing callers are unaffected.\n billingMode: z.enum(BILLING_MODES).optional(),\n // Credit line (both modes). 0 = no credit.\n creditLimit: moneyNonNegative.optional(),\n // Initial low-balance threshold for a prepaid account's balance row.\n // Null = resolve the tenant config default at read time.\n lowBalanceThreshold: moneyNonNegative.nullable().optional(),\n})\n\nexport type BillingAccountCreateInput = z.infer<typeof billingAccountCreateSchema>\n\nexport const billingAccountUpdateSchema = scopedSchema.extend({\n id: z.string().uuid(),\n name: z.string().trim().min(1).max(255).optional(),\n billCycle: z.enum(BILL_CYCLES).optional(),\n billCycleAnchor: billCycleAnchorSchema.optional(),\n invoiceEmail: z.string().trim().email().max(320).optional(),\n invoiceLanguage: z.string().trim().toLowerCase().min(2).max(5).optional(),\n taxId: z.string().trim().max(64).nullable().optional(),\n invoiceAddress: invoiceAddressSchema.optional(),\n nextBillDate: z.coerce.date().optional(),\n lastBillDate: z.coerce.date().nullable().optional(),\n isActive: z.boolean().optional(),\n // SPEC-002: credit_limit is editable (it's an AR/overdraft policy knob);\n // `billingMode` is intentionally NOT updatable \u2014 mode is frozen at create\n // (like currencyCode), no live postpaid\u2194prepaid switch in v1.\n creditLimit: moneyNonNegative.optional(),\n // Editing the prepaid balance row's low-balance threshold. Null clears it\n // back to the tenant config default.\n lowBalanceThreshold: moneyNonNegative.nullable().optional(),\n // `currencyCode` is intentionally NOT updatable \u2014 currency is frozen at\n // account create time so historical invoices keep their currency context.\n // `customerId` is also immutable; create a new account if the customer\n // FK changes.\n})\n\nexport type BillingAccountUpdateInput = z.infer<typeof billingAccountUpdateSchema>\n\nexport const billingAccountDeleteSchema = scopedSchema.extend({\n id: z.string().uuid(),\n})\n\nexport type BillingAccountDeleteInput = z.infer<typeof billingAccountDeleteSchema>\n\nexport const billingAccountListQuerySchema = z\n .object({\n ...listPaginationBase,\n id: z.string().uuid().optional(),\n customerId: z.string().optional(),\n currencyCode: z.string().optional(),\n billCycle: z.enum(BILL_CYCLES).optional(),\n billingMode: z.enum(BILLING_MODES).optional(),\n isActive: z.coerce.boolean().optional(),\n search: z.string().optional(),\n })\n .passthrough()\n\nexport type BillingAccountListQuery = z.infer<typeof billingAccountListQuerySchema>\n\n// \u2500\u2500\u2500 BillingItem payloads \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst ratePayloadByType = z\n .object({\n type: z.enum(BILLING_ITEM_TYPES),\n rateJson: z.unknown(),\n })\n .superRefine((val, ctx) => {\n try {\n validateRateJson(val.type, val.rateJson)\n } catch (err) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['rateJson'],\n message: err instanceof Error ? err.message : 'rate_json is invalid for this type',\n })\n }\n })\n\nexport const billingItemCreateSchema = scopedSchema\n .extend({\n billAccountId: z.string().uuid(),\n type: z.enum(BILLING_ITEM_TYPES),\n billStartDate: z.coerce.date(),\n billEndDate: z.coerce.date().nullable().optional(),\n description: z.string().trim().min(1).max(500),\n rateJson: z.unknown(), // shape validated via the refine below\n uomCode: z.string().trim().max(64).optional(),\n subscriptionId: z.string().trim().max(255).optional(),\n subscriptionItemId: z.string().trim().max(255).optional(),\n // `source_ref` is the idempotency key. NULL \u2192 no dedup, always create.\n sourceRef: z.string().trim().min(1).max(255).optional(),\n // currency_mismatch and billed_to_date are system-managed, never set by\n // clients on create.\n })\n .superRefine((val, ctx) => {\n try {\n validateRateJson(val.type, val.rateJson)\n } catch (err) {\n const message = err instanceof Error ? err.message : 'rate_json is invalid for this type'\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['rateJson'], message })\n }\n if (val.type === 'usage' && !val.uomCode) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['uomCode'],\n message: 'uomCode is required for type=usage',\n })\n }\n })\n\nexport type BillingItemCreateInput = z.infer<typeof billingItemCreateSchema>\n\n// \u2500\u2500\u2500 Bulk item create (Phase 4g) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// One scope envelope, N item payloads. The CPQ connector activating\n// a large subscription used to fire one `billing.items.create` per\n// charge \u2014 bulk-create collapses that into a single command with a\n// batched `source_ref` idempotency check + single flush.\n\nconst billingItemBulkEntrySchema = z\n .object({\n billAccountId: z.string().uuid(),\n type: z.enum(BILLING_ITEM_TYPES),\n billStartDate: z.coerce.date(),\n billEndDate: z.coerce.date().nullable().optional(),\n description: z.string().trim().min(1).max(500),\n rateJson: z.unknown(),\n uomCode: z.string().trim().max(64).optional(),\n subscriptionId: z.string().trim().max(255).optional(),\n subscriptionItemId: z.string().trim().max(255).optional(),\n sourceRef: z.string().trim().min(1).max(255).optional(),\n })\n .superRefine((val, ctx) => {\n try {\n validateRateJson(val.type, val.rateJson)\n } catch (err) {\n const message = err instanceof Error ? err.message : 'rate_json is invalid for this type'\n ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['rateJson'], message })\n }\n if (val.type === 'usage' && !val.uomCode) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['uomCode'],\n message: 'uomCode is required for type=usage',\n })\n }\n })\n\nexport type BillingItemBulkEntry = z.infer<typeof billingItemBulkEntrySchema>\n\nexport const billingItemBulkCreateSchema = scopedSchema.extend({\n // Cap at 500 per call \u2014 keeps a single bulk transaction bounded.\n // A CPQ subscription with >500 charges should be split by the\n // caller (the connector); 500 is already far past any realistic\n // single-subscription charge count.\n items: z.array(billingItemBulkEntrySchema).min(1).max(500),\n})\n\nexport type BillingItemBulkCreateInput = z.infer<typeof billingItemBulkCreateSchema>\n\nexport const billingItemUpdateSchema = scopedSchema.extend({\n id: z.string().uuid(),\n // `type` is immutable \u2014 changing one_time \u2192 recurring would silently\n // change billing semantics. Cancel the old item, create a new one.\n billStartDate: z.coerce.date().optional(),\n billEndDate: z.coerce.date().nullable().optional(),\n description: z.string().trim().min(1).max(500).optional(),\n rateJson: z.unknown().optional(),\n uomCode: z.string().trim().max(64).nullable().optional(),\n subscriptionId: z.string().trim().max(255).nullable().optional(),\n subscriptionItemId: z.string().trim().max(255).nullable().optional(),\n // `source_ref` immutable \u2014 it's the idempotency identity of the item.\n isActive: z.boolean().optional(),\n})\n\nexport type BillingItemUpdateInput = z.infer<typeof billingItemUpdateSchema>\n\nexport const billingItemDeleteSchema = scopedSchema.extend({\n id: z.string().uuid(),\n})\n\nexport type BillingItemDeleteInput = z.infer<typeof billingItemDeleteSchema>\n\nexport const billingItemListQuerySchema = z\n .object({\n ...listPaginationBase,\n id: z.string().uuid().optional(),\n search: z.string().optional(),\n billAccountId: z.string().uuid().optional(),\n type: z.enum(BILLING_ITEM_TYPES).optional(),\n subscriptionId: z.string().optional(),\n isActive: z.coerce.boolean().optional(),\n activeAt: z.coerce.date().optional(), // bill_start_date <= X AND (bill_end_date IS NULL OR bill_end_date >= X)\n })\n .passthrough()\n\nexport type BillingItemListQuery = z.infer<typeof billingItemListQuerySchema>\n\n// \u2500\u2500\u2500 BillingAccountUsage payloads \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const billingUsageCreateSchema = scopedSchema.extend({\n billAccountId: z.string().uuid(),\n uomCode: z.string().trim().min(1).max(64),\n // `quantity` arrives as a number from JSON; MikroORM stores it as\n // numeric(18,4). The service coerces to a string at persist time.\n quantity: z.number().finite().nonnegative(),\n periodStart: z.coerce.date(),\n periodEnd: z.coerce.date(),\n lineDescription: z.string().trim().min(1).max(500).optional(),\n sourceRef: z.string().trim().min(1).max(255).optional(),\n}).superRefine((val, ctx) => {\n if (val.periodEnd < val.periodStart) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['periodEnd'],\n message: 'periodEnd must be on or after periodStart',\n })\n }\n})\n\nexport type BillingUsageCreateInput = z.infer<typeof billingUsageCreateSchema>\n\nexport const billingUsageListQuerySchema = z\n .object({\n ...listPaginationBase,\n billAccountId: z.string().uuid().optional(),\n uomCode: z.string().optional(),\n rated: z.coerce.boolean().optional(), // true \u2192 already rated; false \u2192 unrated\n periodEndFrom: z.coerce.date().optional(),\n periodEndTo: z.coerce.date().optional(),\n })\n .passthrough()\n\nexport type BillingUsageListQuery = z.infer<typeof billingUsageListQuerySchema>\n\n// Suppress unused-export TS warning \u2014 `ratePayloadByType` is reserved for\n// reuse by a future per-tenant rate-validation CLI tool.\nvoid ratePayloadByType\n\n// \u2500\u2500\u2500 Bill Run trigger payloads (Phase 2) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const BILL_RUN_MODES = ['real', 'test', 'dry'] as const\nexport type BillRunMode = (typeof BILL_RUN_MODES)[number]\n\nexport const billingRunTriggerSchema = scopedSchema.extend({\n // `triggeredBy` is filled in by the route layer (always 'manual' for\n // API triggers; the cron worker sets 'schedule'). The client cannot\n // forge a 'schedule' trigger \u2014 the field is intentionally omitted\n // from the input shape.\n mode: z.enum(BILL_RUN_MODES).default('real'),\n asOfDate: z.coerce.date().optional(),\n scopedAccountIds: z.array(z.string().uuid()).optional(),\n catchUp: z.boolean().optional(),\n})\n\nexport type BillingRunTriggerInput = z.infer<typeof billingRunTriggerSchema>\n\nexport const billingRunRetryFailedSchema = scopedSchema.extend({\n billRunId: z.string().uuid(),\n mode: z.enum(BILL_RUN_MODES).default('real'),\n})\n\nexport type BillingRunRetryFailedInput = z.infer<typeof billingRunRetryFailedSchema>\n\nexport const billingRunListQuerySchema = z\n .object({\n ...listPaginationBase,\n id: z.string().uuid().optional(),\n search: z.string().optional(),\n status: z.enum(BILL_RUN_STATUSES).optional(),\n triggeredBy: z.enum(BILL_RUN_TRIGGERS).optional(),\n parentRunId: z.string().uuid().optional(),\n asOfDateFrom: z.coerce.date().optional(),\n asOfDateTo: z.coerce.date().optional(),\n })\n .passthrough()\n\nexport type BillingRunListQuery = z.infer<typeof billingRunListQuerySchema>\n\n// \u2500\u2500\u2500 Invoice post (Phase 4) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const billingInvoicePostSchema = scopedSchema.extend({\n invoiceId: z.string().uuid(),\n})\n\nexport type BillingInvoicePostInput = z.infer<typeof billingInvoicePostSchema>\n\n// \u2500\u2500\u2500 Draft invoice edits (Phase 4b) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Fields the operator may change on a draft invoice line. Per spec:\n * \"operator CAN: add lines, remove lines, edit line description /\n * quantity / unit_price / amount\". `taxRate` is owned by core/sales\n * tax service and `currencyCode` is frozen at account create \u2014 both\n * intentionally absent from this schema.\n */\nconst lineEditableFields = z.object({\n description: z.string().trim().min(1).max(500).optional(),\n quantity: z.coerce.number().finite().nonnegative().optional(),\n unitPriceNet: z.coerce.number().finite().optional(),\n // `totalNetAmount` is operator-overridable for the \"I know better\n // than `unit_price \u00D7 quantity`\" cases (rare; mostly for negative\n // credits or rounding fix-ups). When provided, it short-circuits\n // the auto-compute path.\n totalNetAmount: z.coerce.number().finite().optional(),\n})\n\nexport const billingInvoiceEditLineSchema = scopedSchema.extend({\n invoiceId: z.string().uuid(),\n invoiceLineId: z.string().uuid(),\n changes: lineEditableFields,\n})\n\nexport type BillingInvoiceEditLineInput = z.infer<typeof billingInvoiceEditLineSchema>\n\nexport const billingInvoiceAddLineSchema = scopedSchema.extend({\n invoiceId: z.string().uuid(),\n description: z.string().trim().min(1).max(500),\n quantity: z.coerce.number().finite().nonnegative(),\n unitPriceNet: z.coerce.number().finite(),\n // Optional metadata for traceability \u2014 typically operators leave\n // `billing_item_id` blank because ad-hoc lines aren't tied to a\n // Billing Item.\n billingItemId: z.string().uuid().optional(),\n billingType: z.enum(BILLING_ITEM_TYPES).optional(),\n})\n\nexport type BillingInvoiceAddLineInput = z.infer<typeof billingInvoiceAddLineSchema>\n\nexport const billingInvoiceRemoveLineSchema = scopedSchema.extend({\n invoiceId: z.string().uuid(),\n invoiceLineId: z.string().uuid(),\n})\n\nexport type BillingInvoiceRemoveLineInput = z.infer<typeof billingInvoiceRemoveLineSchema>\n\n// \u2500\u2500\u2500 Test-invoices wipe (Phase 4b) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const billingWipeTestInvoicesSchema = scopedSchema.extend({\n /** Optional \u2014 when set, wipes only test invoices from this run. */\n billRunId: z.string().uuid().optional(),\n})\n\nexport type BillingWipeTestInvoicesInput = z.infer<typeof billingWipeTestInvoicesSchema>\n\n// \u2500\u2500\u2500 Prepaid: top-ups (SPEC-002 P2) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const billingTopupCreateSchema = scopedSchema.extend({\n // The route maps the `/accounts/{id}/topups` path param into billAccountId.\n billAccountId: z.string().uuid(),\n amount: z.number().finite().positive(),\n // Optional \u2014 defaults to the tenant config `prepaid.topup_provider`.\n providerKey: z.string().trim().min(1).max(64).optional(),\n successUrl: z.string().trim().url().max(2048).optional(),\n cancelUrl: z.string().trim().url().max(2048).optional(),\n // Optional idempotency for the initiating request.\n sourceRef: z.string().trim().min(1).max(255).optional(),\n})\n\nexport type BillingTopupCreateInput = z.infer<typeof billingTopupCreateSchema>\n\nexport const billingTopupListQuerySchema = z\n .object({\n ...listPaginationBase,\n id: z.string().uuid().optional(),\n billAccountId: z.string().uuid().optional(),\n status: z.enum(TOPUP_STATUSES).optional(),\n search: z.string().optional(),\n })\n .passthrough()\n\nexport type BillingTopupListQuery = z.infer<typeof billingTopupListQuerySchema>\n\n// \u2500\u2500\u2500 Prepaid: transactions / manual adjustments (SPEC-002 P1/P5) \u2500\u2500\n\nexport const billingTransactionAdjustSchema = scopedSchema\n .extend({\n billAccountId: z.string().uuid(),\n // SIGNED: > 0 credit, < 0 debit. Zero is rejected.\n amount: z.number().finite(),\n description: z.string().trim().min(1).max(500),\n sourceRef: z.string().trim().min(1).max(255).optional(),\n })\n .superRefine((val, ctx) => {\n if (val.amount === 0) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['amount'],\n message: 'amount must be non-zero (positive credit or negative debit)',\n })\n }\n })\n\nexport type BillingTransactionAdjustInput = z.infer<typeof billingTransactionAdjustSchema>\n\nexport const billingTransactionListQuerySchema = z\n .object({\n ...listPaginationBase,\n id: z.string().uuid().optional(),\n billAccountId: z.string().uuid().optional(),\n type: z.enum(TRANSACTION_TYPES).optional(),\n createdFrom: z.coerce.date().optional(),\n createdTo: z.coerce.date().optional(),\n })\n .passthrough()\n\nexport type BillingTransactionListQuery = z.infer<typeof billingTransactionListQuerySchema>\n\n// \u2500\u2500\u2500 Prepaid: statements (SPEC-002 P3) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const billingStatementGenerateSchema = scopedSchema.extend({\n billAccountId: z.string().uuid(),\n // \"today\" the close evaluates the due period against. Defaults to now.\n asOfDate: z.coerce.date().optional(),\n})\n\nexport type BillingStatementGenerateInput = z.infer<typeof billingStatementGenerateSchema>\n\nexport const billingStatementListQuerySchema = z\n .object({\n ...listPaginationBase,\n id: z.string().uuid().optional(),\n billAccountId: z.string().uuid().optional(),\n status: z.enum(STATEMENT_STATUSES).optional(),\n periodEndFrom: z.coerce.date().optional(),\n periodEndTo: z.coerce.date().optional(),\n })\n .passthrough()\n\nexport type BillingStatementListQuery = z.infer<typeof billingStatementListQuerySchema>\n\n\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -19,6 +19,58 @@ const events = [
|
|
|
19
19
|
entity: "bill_run",
|
|
20
20
|
category: "lifecycle",
|
|
21
21
|
clientBroadcast: true
|
|
22
|
+
},
|
|
23
|
+
// ─── Prepaid balance billing (SPEC-002) ──────────────────────
|
|
24
|
+
{
|
|
25
|
+
id: "billing.balance.topped_up",
|
|
26
|
+
label: "Balance Topped Up",
|
|
27
|
+
entity: "balance",
|
|
28
|
+
category: "lifecycle",
|
|
29
|
+
clientBroadcast: true
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: "billing.balance.low",
|
|
33
|
+
label: "Balance Low",
|
|
34
|
+
entity: "balance",
|
|
35
|
+
category: "lifecycle",
|
|
36
|
+
clientBroadcast: true
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: "billing.balance.exhausted",
|
|
40
|
+
label: "Balance Exhausted",
|
|
41
|
+
entity: "balance",
|
|
42
|
+
category: "lifecycle",
|
|
43
|
+
clientBroadcast: true
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
// Per-debit signal — useful for a live balance UI but potentially
|
|
47
|
+
// high-volume, so excluded from workflow triggers (see Open Question #2).
|
|
48
|
+
id: "billing.usage.rated",
|
|
49
|
+
label: "Usage Rated",
|
|
50
|
+
entity: "transaction",
|
|
51
|
+
category: "lifecycle",
|
|
52
|
+
excludeFromTriggers: true
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: "billing.statement.generated",
|
|
56
|
+
label: "Consumption Statement Generated",
|
|
57
|
+
entity: "statement",
|
|
58
|
+
category: "lifecycle",
|
|
59
|
+
clientBroadcast: true
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: "billing.credit.over_limit",
|
|
63
|
+
label: "Credit Over Limit",
|
|
64
|
+
entity: "credit",
|
|
65
|
+
category: "lifecycle",
|
|
66
|
+
clientBroadcast: true
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
id: "billing.credit.near_limit",
|
|
70
|
+
label: "Credit Near Limit",
|
|
71
|
+
entity: "credit",
|
|
72
|
+
category: "lifecycle",
|
|
73
|
+
clientBroadcast: true
|
|
22
74
|
}
|
|
23
75
|
];
|
|
24
76
|
const eventsConfig = createModuleEvents({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/modules/billing/events.ts"],
|
|
4
|
-
"sourcesContent": ["import { createModuleEvents } from '@open-mercato/shared/modules/events'\n\n/**\n * Billing module events.\n *\n * Emission contract:\n * - `billing.invoice.posted` fires once per posted draft AFTER the post\n * transaction commits (sequence number assigned, status set to `posted`\n * in core/sales). Consumed by mailers / accounting bridges / analytics.\n * - `billing.invoice.line_posted` fires once per line on a posted invoice\n * so analytics can aggregate without scanning core/sales lines directly.\n * - `billing.run.completed` fires once per Bill Run after all per-account\n * transactions finished (status is one of `completed` / `partial_failure`\n * / `failed`). Useful for \"did the nightly run go OK?\" alerts.\n */\nconst events = [\n {\n id: 'billing.invoice.posted',\n label: 'Billing Invoice Posted',\n entity: 'invoice',\n category: 'lifecycle',\n clientBroadcast: true,\n },\n {\n id: 'billing.invoice.line_posted',\n label: 'Billing Invoice Line Posted',\n entity: 'invoice_line',\n category: 'lifecycle',\n },\n {\n id: 'billing.run.completed',\n label: 'Bill Run Completed',\n entity: 'bill_run',\n category: 'lifecycle',\n clientBroadcast: true,\n },\n] as const\n\nexport const eventsConfig = createModuleEvents({\n moduleId: 'billing',\n events,\n})\n\nexport const emitBillingEvent = eventsConfig.emit\nexport type BillingEventId = (typeof events)[number]['id']\n\nexport default eventsConfig\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,0BAA0B;AAenC,MAAM,SAAS;AAAA,EACb;AAAA,IACE,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AACF;AAEO,MAAM,eAAe,mBAAmB;AAAA,EAC7C,UAAU;AAAA,EACV;AACF,CAAC;AAEM,MAAM,mBAAmB,aAAa;AAG7C,IAAO,iBAAQ;",
|
|
4
|
+
"sourcesContent": ["import { createModuleEvents } from '@open-mercato/shared/modules/events'\n\n/**\n * Billing module events.\n *\n * Emission contract:\n * - `billing.invoice.posted` fires once per posted draft AFTER the post\n * transaction commits (sequence number assigned, status set to `posted`\n * in core/sales). Consumed by mailers / accounting bridges / analytics.\n * - `billing.invoice.line_posted` fires once per line on a posted invoice\n * so analytics can aggregate without scanning core/sales lines directly.\n * - `billing.run.completed` fires once per Bill Run after all per-account\n * transactions finished (status is one of `completed` / `partial_failure`\n * / `failed`). Useful for \"did the nightly run go OK?\" alerts.\n */\nconst events = [\n {\n id: 'billing.invoice.posted',\n label: 'Billing Invoice Posted',\n entity: 'invoice',\n category: 'lifecycle',\n clientBroadcast: true,\n },\n {\n id: 'billing.invoice.line_posted',\n label: 'Billing Invoice Line Posted',\n entity: 'invoice_line',\n category: 'lifecycle',\n },\n {\n id: 'billing.run.completed',\n label: 'Bill Run Completed',\n entity: 'bill_run',\n category: 'lifecycle',\n clientBroadcast: true,\n },\n // \u2500\u2500\u2500 Prepaid balance billing (SPEC-002) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n {\n id: 'billing.balance.topped_up',\n label: 'Balance Topped Up',\n entity: 'balance',\n category: 'lifecycle',\n clientBroadcast: true,\n },\n {\n id: 'billing.balance.low',\n label: 'Balance Low',\n entity: 'balance',\n category: 'lifecycle',\n clientBroadcast: true,\n },\n {\n id: 'billing.balance.exhausted',\n label: 'Balance Exhausted',\n entity: 'balance',\n category: 'lifecycle',\n clientBroadcast: true,\n },\n {\n // Per-debit signal \u2014 useful for a live balance UI but potentially\n // high-volume, so excluded from workflow triggers (see Open Question #2).\n id: 'billing.usage.rated',\n label: 'Usage Rated',\n entity: 'transaction',\n category: 'lifecycle',\n excludeFromTriggers: true,\n },\n {\n id: 'billing.statement.generated',\n label: 'Consumption Statement Generated',\n entity: 'statement',\n category: 'lifecycle',\n clientBroadcast: true,\n },\n {\n id: 'billing.credit.over_limit',\n label: 'Credit Over Limit',\n entity: 'credit',\n category: 'lifecycle',\n clientBroadcast: true,\n },\n {\n id: 'billing.credit.near_limit',\n label: 'Credit Near Limit',\n entity: 'credit',\n category: 'lifecycle',\n clientBroadcast: true,\n },\n] as const\n\nexport const eventsConfig = createModuleEvents({\n moduleId: 'billing',\n events,\n})\n\nexport const emitBillingEvent = eventsConfig.emit\nexport type BillingEventId = (typeof events)[number]['id']\n\nexport default eventsConfig\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,0BAA0B;AAenC,MAAM,SAAS;AAAA,EACb;AAAA,IACE,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA;AAAA;AAAA,IAGE,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,qBAAqB;AAAA,EACvB;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,iBAAiB;AAAA,EACnB;AACF;AAEO,MAAM,eAAe,mBAAmB;AAAA,EAC7C,UAAU;AAAA,EACV;AACF,CAAC;AAEM,MAAM,mBAAmB,aAAa;AAG7C,IAAO,iBAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"billing.accounts.actions.open": "Open",
|
|
3
|
+
"billing.accounts.columns.credit_limit": "Credit limit",
|
|
3
4
|
"billing.accounts.columns.currency": "Currency",
|
|
4
5
|
"billing.accounts.columns.customer": "Customer",
|
|
5
6
|
"billing.accounts.columns.cycle": "Cycle",
|
|
6
7
|
"billing.accounts.columns.last_bill": "Last bill",
|
|
8
|
+
"billing.accounts.columns.mode": "Mode",
|
|
7
9
|
"billing.accounts.columns.name": "Name",
|
|
8
10
|
"billing.accounts.columns.next_bill": "Next bill",
|
|
9
11
|
"billing.accounts.columns.status": "Status",
|
|
@@ -62,6 +64,8 @@
|
|
|
62
64
|
"billing.accounts.form.error.next_bill_date_required": "Next bill date is required",
|
|
63
65
|
"billing.accounts.form.invoice_email": "Invoice email",
|
|
64
66
|
"billing.accounts.form.invoice_language": "Invoice language (ISO 639-1)",
|
|
67
|
+
"billing.accounts.form.mode.locked": "Immutable — frozen at account create time.",
|
|
68
|
+
"billing.accounts.form.mode.title": "Billing mode & credit",
|
|
65
69
|
"billing.accounts.form.name": "Name",
|
|
66
70
|
"billing.accounts.form.name.placeholder": "Auto-filled from customer — override e.g. \"Acme — production\"",
|
|
67
71
|
"billing.accounts.form.next_bill_date": "Next bill date",
|
|
@@ -69,6 +73,7 @@
|
|
|
69
73
|
"billing.accounts.form.saving": "Saving…",
|
|
70
74
|
"billing.accounts.form.submit_hint": "to save,",
|
|
71
75
|
"billing.accounts.form.tax_id": "Tax ID (NIP / VATIN, optional)",
|
|
76
|
+
"billing.accounts.form.threshold.hint": "Blank = tenant default",
|
|
72
77
|
"billing.accounts.title": "Billing Accounts",
|
|
73
78
|
"billing.common.active": "Active",
|
|
74
79
|
"billing.common.cancel": "Cancel",
|
|
@@ -233,6 +238,37 @@
|
|
|
233
238
|
"billing.items.type.one_time": "One-time",
|
|
234
239
|
"billing.items.type.recurring": "Recurring",
|
|
235
240
|
"billing.items.type.usage": "Usage",
|
|
241
|
+
"billing.mode.postpaid": "Postpaid",
|
|
242
|
+
"billing.mode.prepaid": "Prepaid",
|
|
243
|
+
"billing.prepaid.credit.near_limit": "Near limit",
|
|
244
|
+
"billing.prepaid.adjust.action": "Adjust",
|
|
245
|
+
"billing.prepaid.adjust.amount": "Amount (+credit / −debit)",
|
|
246
|
+
"billing.prepaid.adjust.confirm": "Apply adjustment",
|
|
247
|
+
"billing.prepaid.adjust.description": "Reason",
|
|
248
|
+
"billing.prepaid.adjust.error": "Adjustment failed",
|
|
249
|
+
"billing.prepaid.adjust.invalid_amount": "Enter a non-zero amount",
|
|
250
|
+
"billing.prepaid.adjust.invalid_description": "Enter a reason",
|
|
251
|
+
"billing.prepaid.adjust.submitting": "Applying…",
|
|
252
|
+
"billing.prepaid.adjust.success": "Balance adjusted",
|
|
253
|
+
"billing.prepaid.credit.over_limit": "Over limit",
|
|
254
|
+
"billing.prepaid.credit.within_limit": "Within limit",
|
|
255
|
+
"billing.prepaid.panel.balance": "Balance",
|
|
256
|
+
"billing.prepaid.panel.credit": "Credit",
|
|
257
|
+
"billing.prepaid.panel.last_movement": "Last movement",
|
|
258
|
+
"billing.prepaid.panel.no_transactions": "No balance movements yet.",
|
|
259
|
+
"billing.prepaid.panel.threshold": "Low threshold",
|
|
260
|
+
"billing.prepaid.panel.title": "Prepaid balance",
|
|
261
|
+
"billing.prepaid.panel.transactions": "Balance transactions",
|
|
262
|
+
"billing.prepaid.status.exhausted": "Exhausted",
|
|
263
|
+
"billing.prepaid.status.low": "Low",
|
|
264
|
+
"billing.prepaid.status.ok": "OK",
|
|
265
|
+
"billing.prepaid.topup.action": "Top up",
|
|
266
|
+
"billing.prepaid.topup.amount": "Amount",
|
|
267
|
+
"billing.prepaid.topup.confirm": "Start checkout",
|
|
268
|
+
"billing.prepaid.topup.created": "Top-up session created",
|
|
269
|
+
"billing.prepaid.topup.error": "Top-up failed",
|
|
270
|
+
"billing.prepaid.topup.invalid": "Enter a positive amount",
|
|
271
|
+
"billing.prepaid.topup.submitting": "Starting…",
|
|
236
272
|
"billing.runs.actions.open": "Open",
|
|
237
273
|
"billing.runs.columns.accounts": "Accounts",
|
|
238
274
|
"billing.runs.columns.as_of_date": "As-of date",
|
|
@@ -256,6 +292,10 @@
|
|
|
256
292
|
"billing.runs.detail.title": "Bill Run",
|
|
257
293
|
"billing.runs.filters.status": "Status",
|
|
258
294
|
"billing.runs.filters.triggered_by": "Trigger",
|
|
295
|
+
"billing.runs.mode.catch_up": "Catch-up",
|
|
296
|
+
"billing.runs.mode.dry_run": "Dry-run",
|
|
297
|
+
"billing.runs.mode.real": "Real",
|
|
298
|
+
"billing.runs.mode.test": "Test",
|
|
259
299
|
"billing.runs.outcomes.columns.account": "Account",
|
|
260
300
|
"billing.runs.outcomes.columns.error": "Error",
|
|
261
301
|
"billing.runs.outcomes.columns.invoice": "Invoice",
|
|
@@ -277,10 +317,6 @@
|
|
|
277
317
|
"billing.runs.summary.title": "Summary",
|
|
278
318
|
"billing.runs.summary.usage": "Usage rated",
|
|
279
319
|
"billing.runs.summary.warnings": "Warnings",
|
|
280
|
-
"billing.runs.mode.catch_up": "Catch-up",
|
|
281
|
-
"billing.runs.mode.dry_run": "Dry-run",
|
|
282
|
-
"billing.runs.mode.real": "Real",
|
|
283
|
-
"billing.runs.mode.test": "Test",
|
|
284
320
|
"billing.runs.title": "Bill Runs",
|
|
285
321
|
"billing.runs.trigger.action": "New run",
|
|
286
322
|
"billing.runs.trigger.dialog.as_of_date": "As-of date",
|
|
@@ -299,6 +335,78 @@
|
|
|
299
335
|
"billing.runs.trigger.manual": "Manual",
|
|
300
336
|
"billing.runs.trigger.schedule": "Schedule",
|
|
301
337
|
"billing.runs.trigger.success": "Bill Run triggered",
|
|
338
|
+
"billing.statements.breakdown.amount": "Amount",
|
|
339
|
+
"billing.statements.breakdown.item": "Item",
|
|
340
|
+
"billing.statements.breakdown.quantity": "Qty",
|
|
341
|
+
"billing.statements.breakdown.type": "Type",
|
|
342
|
+
"billing.statements.columns.adjustments": "Adjustments",
|
|
343
|
+
"billing.statements.columns.closing": "Closing",
|
|
344
|
+
"billing.statements.columns.opening": "Opening",
|
|
345
|
+
"billing.statements.columns.period": "Period",
|
|
346
|
+
"billing.statements.columns.recurring": "Recurring",
|
|
347
|
+
"billing.statements.columns.status": "Status",
|
|
348
|
+
"billing.statements.columns.account": "Account",
|
|
349
|
+
"billing.statements.columns.topups": "Top-ups",
|
|
350
|
+
"billing.statements.columns.usage": "Usage",
|
|
351
|
+
"billing.statements.detail.bill_run": "Bill Run",
|
|
352
|
+
"billing.statements.detail.breakdown": "Period-close charges",
|
|
353
|
+
"billing.statements.detail.load_error": "Failed to load statement",
|
|
354
|
+
"billing.statements.detail.loading": "Loading statement…",
|
|
355
|
+
"billing.statements.detail.no_charges": "No recurring charges this period.",
|
|
356
|
+
"billing.statements.detail.not_found": "Statement not found",
|
|
357
|
+
"billing.statements.detail.title": "Statement",
|
|
358
|
+
"billing.statements.detail.view_account": "View account",
|
|
359
|
+
"billing.statements.filters.status": "Status",
|
|
360
|
+
"billing.statements.status.generated": "Generated",
|
|
361
|
+
"billing.statements.status.sent": "Sent",
|
|
362
|
+
"billing.statements.title": "Statements",
|
|
363
|
+
"billing.topups.columns.account": "Account",
|
|
364
|
+
"billing.topups.columns.amount": "Amount",
|
|
365
|
+
"billing.topups.columns.created": "Created",
|
|
366
|
+
"billing.topups.columns.provider": "Provider",
|
|
367
|
+
"billing.topups.columns.status": "Status",
|
|
368
|
+
"billing.topups.detail.balance_txn": "Balance transaction",
|
|
369
|
+
"billing.topups.detail.gateway_txn": "Gateway transaction",
|
|
370
|
+
"billing.topups.detail.load_error": "Failed to load top-up",
|
|
371
|
+
"billing.topups.detail.loading": "Loading top-up…",
|
|
372
|
+
"billing.topups.detail.not_found": "Top-up not found",
|
|
373
|
+
"billing.topups.detail.payment_id": "Payment ID",
|
|
374
|
+
"billing.topups.detail.receipt": "VAT receipt",
|
|
375
|
+
"billing.topups.detail.title": "Top-up",
|
|
376
|
+
"billing.topups.detail.updated": "Updated",
|
|
377
|
+
"billing.topups.detail.view_account": "View account",
|
|
378
|
+
"billing.topups.filters.status": "Status",
|
|
379
|
+
"billing.topups.status.cancelled": "Cancelled",
|
|
380
|
+
"billing.topups.status.captured": "Captured",
|
|
381
|
+
"billing.topups.status.expired": "Expired",
|
|
382
|
+
"billing.topups.status.failed": "Failed",
|
|
383
|
+
"billing.topups.status.pending": "Pending",
|
|
384
|
+
"billing.topups.title": "Top-ups",
|
|
385
|
+
"billing.transactions.columns.amount": "Amount",
|
|
386
|
+
"billing.transactions.columns.balance_after": "Balance",
|
|
387
|
+
"billing.transactions.columns.description": "Description",
|
|
388
|
+
"billing.transactions.columns.type": "Type",
|
|
389
|
+
"billing.transactions.columns.when": "When",
|
|
390
|
+
"billing.transactions.type.adjustment": "Adjustment",
|
|
391
|
+
"billing.transactions.type.one_time": "One-time",
|
|
392
|
+
"billing.transactions.type.recurring": "Recurring",
|
|
393
|
+
"billing.transactions.type.reversal": "Reversal",
|
|
394
|
+
"billing.transactions.type.topup": "Top-up",
|
|
395
|
+
"billing.transactions.type.usage": "Usage",
|
|
396
|
+
"billing.transactions.columns.account": "Account",
|
|
397
|
+
"billing.transactions.detail.item": "Billing item",
|
|
398
|
+
"billing.transactions.detail.load_error": "Failed to load transaction",
|
|
399
|
+
"billing.transactions.detail.loading": "Loading transaction…",
|
|
400
|
+
"billing.transactions.detail.not_found": "Transaction not found",
|
|
401
|
+
"billing.transactions.detail.source_ref": "Source ref",
|
|
402
|
+
"billing.transactions.detail.statement": "Statement",
|
|
403
|
+
"billing.transactions.detail.title": "Transaction",
|
|
404
|
+
"billing.transactions.detail.topup": "Top-up",
|
|
405
|
+
"billing.transactions.detail.usage": "Usage record",
|
|
406
|
+
"billing.transactions.detail.user": "User",
|
|
407
|
+
"billing.transactions.detail.view_account": "View account",
|
|
408
|
+
"billing.transactions.filters.type": "Type",
|
|
409
|
+
"billing.transactions.title": "Transactions",
|
|
302
410
|
"billing.usage.columns.description": "Description",
|
|
303
411
|
"billing.usage.columns.period": "Period",
|
|
304
412
|
"billing.usage.columns.quantity": "Quantity",
|