@opencxh/domain 1.302.0 → 1.303.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.
Files changed (63) hide show
  1. package/dist/entities/agreement/from-quote.d.ts +8 -8
  2. package/dist/entities/agreement/index.d.ts +2 -0
  3. package/dist/entities/agreement/invoice-head.d.ts +21 -0
  4. package/dist/entities/agreement/lifecycle.d.ts +10 -0
  5. package/dist/entities/agreement/period.d.ts +8 -0
  6. package/dist/entities/agreement/prices.d.ts +43 -0
  7. package/dist/entities/agreement/prices.test.d.ts +1 -0
  8. package/dist/entities/agreement/types.d.ts +54 -10
  9. package/dist/entities/bank/match.d.ts +16 -2
  10. package/dist/entities/bank/types.d.ts +12 -0
  11. package/dist/entities/bookkeeping/receipt.d.ts +45 -6
  12. package/dist/entities/bookkeeping/types.d.ts +1 -2
  13. package/dist/entities/business-entity/types.d.ts +11 -15
  14. package/dist/entities/catalog/pricing.d.ts +11 -11
  15. package/dist/entities/catalog/types.d.ts +15 -9
  16. package/dist/entities/company/role.d.ts +14 -0
  17. package/dist/entities/financing/schedule.d.ts +9 -3
  18. package/dist/entities/financing/types.d.ts +17 -6
  19. package/dist/entities/fulfilment/adopt.d.ts +149 -0
  20. package/dist/entities/fulfilment/customers.d.ts +63 -0
  21. package/dist/entities/fulfilment/execute.d.ts +67 -0
  22. package/dist/entities/fulfilment/fulfilment.test.d.ts +1 -0
  23. package/dist/entities/fulfilment/goods.d.ts +72 -0
  24. package/dist/entities/fulfilment/index.d.ts +8 -0
  25. package/dist/entities/fulfilment/path.d.ts +8 -0
  26. package/dist/entities/fulfilment/path.test.d.ts +1 -0
  27. package/dist/entities/fulfilment/rules.d.ts +124 -0
  28. package/dist/entities/fulfilment/target.d.ts +131 -0
  29. package/dist/entities/fulfilment/types.d.ts +321 -0
  30. package/dist/entities/ledger/entry.d.ts +47 -9
  31. package/dist/entities/ledger/types.d.ts +33 -35
  32. package/dist/entities/ledger/xaf.d.ts +3 -0
  33. package/dist/entities/money/tax.d.ts +6 -0
  34. package/dist/entities/money/totals.d.ts +5 -5
  35. package/dist/entities/purchase/choose.d.ts +57 -0
  36. package/dist/entities/purchase/choose.test.d.ts +1 -0
  37. package/dist/entities/purchase/contract.d.ts +44 -25
  38. package/dist/entities/purchase/demand.d.ts +22 -40
  39. package/dist/entities/purchase/feed.d.ts +53 -5
  40. package/dist/entities/purchase/index.d.ts +1 -0
  41. package/dist/entities/purchase/kinds.d.ts +2 -1
  42. package/dist/entities/purchase/logic.d.ts +32 -7
  43. package/dist/entities/purchase/match.d.ts +48 -6
  44. package/dist/entities/purchase/packing-slip.d.ts +23 -0
  45. package/dist/entities/purchase/types.d.ts +71 -38
  46. package/dist/entities/reports/vat.d.ts +20 -5
  47. package/dist/entities/transaction/booking.d.ts +4 -4
  48. package/dist/entities/transaction/convert.d.ts +10 -10
  49. package/dist/entities/transaction/document.d.ts +8 -3
  50. package/dist/entities/transaction/dunning.d.ts +12 -1
  51. package/dist/entities/transaction/facets.test.d.ts +1 -0
  52. package/dist/entities/transaction/keys.d.ts +3 -0
  53. package/dist/entities/transaction/kinds.d.ts +11 -10
  54. package/dist/entities/transaction/receivable.d.ts +5 -2
  55. package/dist/entities/transaction/settlement.d.ts +7 -7
  56. package/dist/entities/transaction/types.d.ts +123 -68
  57. package/dist/index.cjs +25 -25
  58. package/dist/index.d.ts +2 -1
  59. package/dist/index.js +5160 -4026
  60. package/dist/platform/bookkeeping.d.ts +8 -8
  61. package/dist/platform/provisioning.d.ts +210 -13
  62. package/package.json +1 -1
  63. /package/dist/entities/{purchase/demand.test.d.ts → agreement/invoice-head.test.d.ts} +0 -0
@@ -52,6 +52,11 @@ type PlannedPosting = Omit<ScheduledPosting, "id" | "organizationId" | "business
52
52
  export declare function monthEnd(day: string): string;
53
53
  /** `totalCents` over `months` equal parts; the last takes the rounding, so the parts add up exactly. */
54
54
  export declare function spread(totalCents: Cents, months: number): Cents[];
55
+ /**
56
+ * Where the schedule starts over: a revision, or else an opening taken over (the month after
57
+ * `on`, from the book value then, numbered on from the months already done).
58
+ */
59
+ export declare function restartOf(t: FixedAssetTerms): FixedAssetTerms["restart"];
55
60
  /**
56
61
  * The monthly amounts, from the acquisition (or the restart after a revision) on. Linear spreads
57
62
  * (start − residual) over the months left; declining takes the monthly share of a yearly
@@ -60,7 +65,7 @@ export declare function spread(totalCents: Cents, months: number): Cents[];
60
65
  */
61
66
  export declare function depreciationParts(t: FixedAssetTerms): Cents[];
62
67
  /** Depreciation per month by the asset's method; a disposed asset plans nothing more. */
63
- export declare function depreciationPostings(item: Pick<FinancingItem, "id" | "name"> & {
68
+ export declare function depreciationPostings(item: Pick<FinancingItem, "id" | "name" | "counterpartyCompanyId" | "dimensions"> & {
64
69
  terms: FixedAssetTerms;
65
70
  }, through: string): PlannedPosting[];
66
71
  /**
@@ -78,12 +83,13 @@ export declare function disposalLines(item: Pick<FinancingItem, "id" | "name" |
78
83
  disposalAccountId: string;
79
84
  }): PlannedPosting["lines"];
80
85
  /** A transitorium released month by month onto its result account. */
81
- export declare function accrualPostings(item: Pick<FinancingItem, "id" | "name" | "ledgerAccountId"> & {
86
+ export declare function accrualPostings(item: Pick<FinancingItem, "id" | "name" | "ledgerAccountId" | "counterpartyCompanyId" | "dimensions"> & {
82
87
  terms: AccrualTerms;
83
88
  }, through: string): PlannedPosting[];
84
89
  /**
85
90
  * Where a fixed asset or transitorium stands without its own opening lines: the booked movements
86
- * on the item plus what its terms say was there to begin with (cost, or an amount paid upfront).
91
+ * on the item plus what its terms say was there to begin with (cost less a taken-over
92
+ * accumulated depreciation, or an amount paid upfront).
87
93
  */
88
94
  export declare function startingCents(terms: FixedAssetTerms | AccrualTerms): Cents;
89
95
  /**
@@ -1,4 +1,6 @@
1
+ import { JournalLineData } from '../ledger/types';
1
2
  import { Cents } from '../money/money';
3
+ import { LineDimensions } from '../transaction/types';
2
4
  /**
3
5
  * Balance items with detail under a ledger account (plan 039 §3.6b, datamodel §5): loans, the
4
6
  * director's current account, participations and deposits. One row per item; `kind` says which
@@ -88,6 +90,16 @@ export interface FixedAssetTerms {
88
90
  bookValueCents: Cents;
89
91
  fromSequence: number;
90
92
  };
93
+ /**
94
+ * Taken over with depreciation already booked elsewhere (Exact `AlreadyDepreciated`): the
95
+ * schedule starts the month after `on`, numbered on from `monthsDone`, over the book value left.
96
+ * The accumulated amount sits in the opening balance, not on the item's sub-account.
97
+ */
98
+ opening?: {
99
+ on: string;
100
+ accumulatedCents: Cents;
101
+ monthsDone: number;
102
+ };
91
103
  /**
92
104
  * Part of a batch that left (3 of 12 laptops): each took its share of cost, residual and
93
105
  * accumulated depreciation off; `costCents`, `residualCents` and `quantity` are what is left.
@@ -190,6 +202,8 @@ export interface FinancingItem {
190
202
  /** The other party: a crm company (bank, participation, landlord) or a person by name (the director). */
191
203
  counterpartyCompanyId?: string;
192
204
  counterpartyName?: string;
205
+ /** From the line it was made of: its releases and depreciation carry them, as its lines did. */
206
+ dimensions?: LineDimensions;
193
207
  currency: string;
194
208
  terms: FinancingTerms;
195
209
  openedOn?: string;
@@ -200,6 +214,8 @@ export interface FinancingItem {
200
214
  createdAt?: number;
201
215
  updatedAt?: number;
202
216
  }
217
+ /** A journal line before the run fills its currency and functional amount. */
218
+ export type PlannedLine = Omit<JournalLineData, "currency" | "functionalCents" | "fxRate">;
203
219
  /**
204
220
  * A prepared posting from an item's schedule (datamodel §5.2): an instalment, a quarter's
205
221
  * interest. One per (item, sequence), so a repeated run makes no twin.
@@ -215,12 +231,7 @@ export interface ScheduledPosting {
215
231
  * The lines as they become an entry. For `bank_line` these are the non-bank side only: the bank
216
232
  * line that pays it adds its own side. Their sum is what the bank line must be, signed.
217
233
  */
218
- lines: {
219
- accountId: string;
220
- amountCents: Cents;
221
- subAccountId?: string;
222
- description?: string;
223
- }[];
234
+ lines: PlannedLine[];
224
235
  /** What the bank line should show: − for an instalment paid, + for one received. */
225
236
  expectedBankCents: Cents;
226
237
  /** planned: in the future · due: today or earlier · posted · skipped (by a person, with a reason). */
@@ -0,0 +1,149 @@
1
+ import { ProvidedResource, ProviderAccount, ProvisionableOffer, ReportedSubscription } from '../../platform/provisioning';
2
+ import { SupplierOffer } from '../purchase/types';
3
+ import { StructureProblem } from './rules';
4
+ import { ProvisionedItem } from './types';
5
+ /**
6
+ * One thing that already runs, as a source gives it (047 step 9): a provider's list, a file, and
7
+ * later another PSA — every source yields these rows, and one flow takes them over.
8
+ */
9
+ export interface AdoptRow {
10
+ /** The platform it runs on: the provider app, or what a file names (`3cx`). */
11
+ app: string;
12
+ externalRef: string;
13
+ /** The provider's offer key, or the supplier's article number (a file). */
14
+ offer: string;
15
+ level: "account" | "item";
16
+ quantity: number;
17
+ /** Who it runs for, as the supplier names them: matched to a crm company. */
18
+ account: {
19
+ ref: string;
20
+ name: string;
21
+ kvkNumber?: string;
22
+ domain?: string;
23
+ };
24
+ /** Already known: the account it runs under is ours, so is its customer. */
25
+ customerCompanyId?: string;
26
+ /** The account it runs under at the same app (an Eylo account): that account's `externalRef`. */
27
+ under?: string;
28
+ uses?: ProvidedResource[];
29
+ /** The original start at the supplier: kept on the item, never billed from (vraag 6). */
30
+ since?: number;
31
+ termEndsAt?: number;
32
+ status?: ReportedSubscription["status"];
33
+ fulfillment?: Record<string, string>;
34
+ /** What the provider listed, whole: becomes `reported`. */
35
+ reported?: ReportedSubscription;
36
+ }
37
+ export interface CustomerCandidate {
38
+ id: string;
39
+ name: string;
40
+ }
41
+ /** A customer's agreements as sales lists them for linking (`/provider/agreement/for-customer`). */
42
+ export interface AdoptAgreement {
43
+ id: string;
44
+ status: string;
45
+ lines: {
46
+ seriesId: string;
47
+ productId: string;
48
+ }[];
49
+ }
50
+ export interface AdoptContext {
51
+ organizationId: string;
52
+ businessEntityId: string;
53
+ now: number;
54
+ offers: readonly SupplierOffer[];
55
+ described: ReadonlyMap<string, ProvisionableOffer>;
56
+ /** crm's candidates per account key (`<app>:<account ref>`). */
57
+ customers: ReadonlyMap<string, readonly CustomerCandidate[]>;
58
+ /** A person's pick per account key, where crm had more than one. */
59
+ chosen?: Readonly<Record<string, string>>;
60
+ /** Live items the rows may be, run under, use, or link to. */
61
+ items: readonly ProvisionedItem[];
62
+ agreements: ReadonlyMap<string, readonly AdoptAgreement[]>;
63
+ /** The draft lines sales made for rows, by row key (commit, second pass). */
64
+ drafted?: ReadonlyMap<string, {
65
+ agreementId: string;
66
+ seriesId: string;
67
+ }>;
68
+ }
69
+ export type AdoptProblem = StructureProblem
70
+ /** Numbers, devices: one item per unit (D5). */
71
+ | {
72
+ code: "one_unit_per_item";
73
+ quantity: number;
74
+ }
75
+ /** What its offer needs to run (an account) is in neither the import nor the register. */
76
+ | {
77
+ code: "requires_missing";
78
+ role: string;
79
+ };
80
+ export type AdoptState = "known" | "ready" | "choose_customer" | "no_product" | "ended" | "blocked";
81
+ /** What one row becomes. Nothing is written: {@link adoptPlan} is the preview and the commit's plan. */
82
+ export interface AdoptLine {
83
+ key: string;
84
+ row: AdoptRow;
85
+ state: AdoptState;
86
+ knownItemId?: string;
87
+ customer?: {
88
+ companyId?: string;
89
+ create: boolean;
90
+ candidates: readonly CustomerCandidate[];
91
+ };
92
+ offerId?: string;
93
+ productId?: string;
94
+ /** A running series it joins, or a line on the customer's draft agreement; absent = a resource. */
95
+ sale?: {
96
+ agreementId: string;
97
+ seriesId: string;
98
+ } | {
99
+ draft: true;
100
+ };
101
+ item?: ProvisionedItem;
102
+ problems: AdoptProblem[];
103
+ }
104
+ /** The series id of a draft line made for a row: one per supplier identity, so a repeat finds it. */
105
+ export declare const adoptSeriesId: (key: string) => string;
106
+ export declare const isAdoptSeries: (seriesId: string) => boolean;
107
+ /**
108
+ * What taking these rows over makes, per row (047 step 9): which customer (crm's one candidate, a
109
+ * person's pick, else a new company), which article (the offer at the supplier), which agreement
110
+ * (a free running series of that article, else a line on the customer's draft), and the item —
111
+ * `active`, its key at the supplier, what it runs under and uses. A key a live item already holds
112
+ * is "known"; a structure that does not hold is "blocked" with its problems. Pure: no store, no call.
113
+ */
114
+ export declare function adoptPlan(rows: readonly AdoptRow[], ctx: AdoptContext): AdoptLine[];
115
+ /** The preview's head count: what comes, what is already there, what still needs a person. */
116
+ export declare function adoptSummary(lines: readonly AdoptLine[]): {
117
+ items: number;
118
+ draftLines: number;
119
+ linked: number;
120
+ contractLines: number;
121
+ newCustomers: number;
122
+ known: number;
123
+ choose: number;
124
+ noProduct: number;
125
+ blocked: number;
126
+ };
127
+ /** A provider's account as a row: the account itself is taken over too (an Eylo account, a tenant). */
128
+ export declare const accountRow: (app: string, account: ProviderAccount) => AdoptRow;
129
+ /** One listed subscription under an account, as a row. */
130
+ export declare const subscriptionRow: (app: string, account: AdoptRow["account"], subscription: ReportedSubscription, customerCompanyId?: string) => AdoptRow;
131
+ /** The columns a file can hold (047 step 9): customer, article, count, reference, dates. */
132
+ export declare const ADOPT_COLUMNS: readonly ["customer", "product", "quantity", "externalRef", "since", "termEndsAt", "kvkNumber", "domain", "under"];
133
+ export type AdoptColumn = (typeof ADOPT_COLUMNS)[number];
134
+ export type AdoptMapping = Partial<Record<AdoptColumn, string>>;
135
+ /** A first mapping from the header: exact words first, then a header that starts with one. */
136
+ export declare function guessAdoptMapping(header: readonly string[]): AdoptMapping;
137
+ /** `2026-03-01`, `1-3-2026` or `01/03/2026` as UTC midnight; anything else is `undefined`. */
138
+ export declare function parseDay(text: string): number | undefined;
139
+ /**
140
+ * A file's cells as rows, through the mapping. A line without a customer, article or reference,
141
+ * or with a count or date that does not read, is an error with its line number — never a guess.
142
+ */
143
+ export declare function adoptRowsFromTable(table: readonly string[][], mapping: AdoptMapping, app: string): {
144
+ rows: AdoptRow[];
145
+ errors: {
146
+ line: number;
147
+ message: string;
148
+ }[];
149
+ };
@@ -0,0 +1,63 @@
1
+ import { supplyChain } from './rules';
2
+ import { ProvisionedItem, ProvisioningRequest } from './types';
3
+ /** Where the five columns disagree, and what a person can do about it (047 step 5). */
4
+ export type ProductSignal =
5
+ /** The supplier runs another count than we think: "overnemen" or "terugzetten". */
6
+ {
7
+ kind: "supplier_differs";
8
+ reported: number;
9
+ active: number;
10
+ }
11
+ /** What runs is not what was agreed; `busy` = a request is already on it. */
12
+ | {
13
+ kind: "agreed_differs";
14
+ agreed: number;
15
+ active: number;
16
+ busy: boolean;
17
+ }
18
+ /** We pay for another count than runs. */
19
+ | {
20
+ kind: "not_bought";
21
+ bought: number;
22
+ active: number;
23
+ }
24
+ /** The last period billed another count than agreed. */
25
+ | {
26
+ kind: "not_billed";
27
+ billed: number;
28
+ agreed: number;
29
+ };
30
+ export interface CustomerProductRow {
31
+ itemId: string;
32
+ productId: string;
33
+ customerCompanyId: string;
34
+ status: ProvisionedItem["status"];
35
+ serial?: string;
36
+ /** Afgesproken: the agreement's count now; `null` when it is not a fixed count (or an order). */
37
+ agreed: number | null;
38
+ /** Actief: what we know runs. */
39
+ active: number;
40
+ /** Bij de leverancier: what the supplier reports, when it reports. */
41
+ reported?: number;
42
+ /** Ingekocht: the contract line's count. */
43
+ bought?: number;
44
+ /** Gefactureerd: the last period's count. */
45
+ billed?: number;
46
+ signals: ProductSignal[];
47
+ /** What it rests on ("Technische resources"), once each, with its product and whether shared. */
48
+ resources: (ReturnType<typeof supplyChain>[number] & {
49
+ productId: string;
50
+ })[];
51
+ }
52
+ /**
53
+ * "Producten bij klanten": every item a customer takes, its five counts side by side, and a signal
54
+ * where two disagree (047 step 5). Compared per item and per product, never summed over roles
55
+ * (§10.4): one account and ten licences are not eleven bought.
56
+ */
57
+ export declare function customerProducts(input: {
58
+ items: readonly ProvisionedItem[];
59
+ requests: readonly ProvisioningRequest[];
60
+ agreed: ReadonlyMap<string, number | null>;
61
+ billed: ReadonlyMap<string, number>;
62
+ bought: ReadonlyMap<string, number>;
63
+ }): CustomerProductRow[];
@@ -0,0 +1,67 @@
1
+ import { ProvisionableOffer, ProvisioningAction, ProvisioningResult, ReportedSubscription, RoleNeed } from '../../platform/provisioning';
2
+ import { NotReady } from './rules';
3
+ import { ProvisionedItem, ProvisioningRequest, ReportedState, RequestState, SentCommand } from './types';
4
+ /** Released by a person, not yet out: the engine moves these on its own (§2.2). */
5
+ export declare const RELEASED_STATES: readonly RequestState[];
6
+ export declare const nextAttemptAt: (attempts: number, now: number) => number;
7
+ export type Admission = {
8
+ state: "scheduled";
9
+ } | {
10
+ state: "queued" | "waiting";
11
+ why: NotReady;
12
+ } | {
13
+ state: "send";
14
+ inputs: NonNullable<ProvisioningRequest["inputs"]>;
15
+ };
16
+ /**
17
+ * Where a released request goes now: `scheduled` until its `submitAt`, `queued` behind another
18
+ * open request on its item, `waiting` for what comes first or for a role (§10.1), else out.
19
+ */
20
+ export declare function admit(input: {
21
+ request: ProvisioningRequest;
22
+ item: ProvisionedItem;
23
+ needs: readonly RoleNeed[];
24
+ items: ReadonlyMap<string, ProvisionedItem>;
25
+ requests: readonly ProvisioningRequest[];
26
+ now: number;
27
+ }): Admission;
28
+ /**
29
+ * What goes out, frozen (§2.2): a retry sends exactly this. The account the item runs under goes
30
+ * as `parent` for every act — a cancel needs to know where, even when it demands nothing active.
31
+ */
32
+ export declare function commandOf(input: {
33
+ request: ProvisioningRequest;
34
+ item: ProvisionedItem;
35
+ inputs: NonNullable<ProvisioningRequest["inputs"]>;
36
+ items: ReadonlyMap<string, ProvisionedItem>;
37
+ now: number;
38
+ }): SentCommand;
39
+ export type Recovery = "resend" | "status" | "listing" | "person";
40
+ /**
41
+ * How an `unknown` outcome is found out, per act, as the provider declares (§2.3). Undeclared is
42
+ * a person: guessing could buy twice. A `lookup_by_listing` purchase is never sent again.
43
+ */
44
+ export declare function recoveryOf(action: ProvisioningAction, offer?: ProvisionableOffer): Recovery;
45
+ /**
46
+ * What an approved request does to its item (§2.1): a purchase makes it active (the first time
47
+ * sets `activatedAt`, §10.2), a partial success counts what succeeded, a cancel ends it — on its
48
+ * day, `terminating` until then. Anything but `approved` leaves the item as it is.
49
+ */
50
+ export declare function settle(item: ProvisionedItem, request: ProvisioningRequest, result: ProvisioningResult, now: number): Partial<ProvisionedItem>;
51
+ /**
52
+ * A purchase whose answer was lost, looked for in what the supplier lists (`lookup_by_listing`,
53
+ * §2.3): by our reference where it keeps one, else the one subscription of that offer and count
54
+ * that no item knows. Two candidates, or none yet: a person decides — never a second purchase.
55
+ */
56
+ export declare function findInListing(request: Pick<ProvisioningRequest, "requestId" | "offer" | "quantity" | "sent">, listed: readonly ReportedSubscription[], knownRefs: ReadonlySet<string>): {
57
+ state: "found";
58
+ subscription: ReportedSubscription;
59
+ } | {
60
+ state: "none";
61
+ } | {
62
+ state: "ambiguous";
63
+ count: number;
64
+ candidates: ReportedSubscription[];
65
+ };
66
+ /** What the supplier says about one item, as `reported` keeps it. */
67
+ export declare function reportOf(subscription: ReportedSubscription, now: number): ReportedState;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,72 @@
1
+ import { TransactionDraft } from '../transaction/convert';
2
+ import { SalesTransaction } from '../transaction/types';
3
+ import { Allocation, Delivery, FulfilmentOrder } from './types';
4
+ /**
5
+ * A partial receipt shared over the allocations on one PO line, oldest first (§4): 6 of 10 in,
6
+ * with A holding 6 and B 4, gives A its 6 and B nothing yet. Per allocation what arrived for it,
7
+ * and what of that can still go out: `min(allocated, received share) − delivered`.
8
+ */
9
+ export declare function shareReceipts(allocations: readonly Allocation[], received: number, delivered: ReadonlyMap<string, number>): Map<string, {
10
+ received: number;
11
+ available: number;
12
+ }>;
13
+ /** The counts of one fulfilment order (§5), in base units. */
14
+ export interface GoodsTallies {
15
+ ordered: number;
16
+ allocated: number;
17
+ onOrder: number;
18
+ available: number;
19
+ delivered: number;
20
+ returned: number;
21
+ }
22
+ export declare function tallies(order: Pick<FulfilmentOrder, "id" | "quantity">, allocations: readonly Allocation[], deliveries: readonly Delivery[], share: ReadonlyMap<string, {
23
+ received: number;
24
+ available: number;
25
+ }>): GoodsTallies;
26
+ /**
27
+ * Whether two fulfilment orders may share one PO line (§4): the same offer (so the same supplier,
28
+ * product, administration and currency), the same administration on our side, and the same
29
+ * destination. A drop shipment to two customers is never one line.
30
+ */
31
+ export declare const mergeable: (a: Pick<FulfilmentOrder, "offerId" | "businessEntityId" | "deliverTo">, b: Pick<FulfilmentOrder, "offerId" | "businessEntityId" | "deliverTo">) => boolean;
32
+ /** One order line: what was ordered, delivered, invoiced, and what a draft holds (§5). */
33
+ export interface LineProgress {
34
+ lineId: string;
35
+ ordered: number;
36
+ delivered: number;
37
+ /** Net of credit notes, issued documents only. */
38
+ invoiced: number;
39
+ /** On a draft invoice: counted as invoiced, so two partial runs never bill it twice. */
40
+ reserved: number;
41
+ }
42
+ /**
43
+ * Per line of `order`, from the deliveries (by order line) and every invoice and credit note that
44
+ * points back. A credit note points at its invoice line, so the chain is followed to the order
45
+ * line it came from (Codex 8). Quantities in the line's own unit; a credit counts negative.
46
+ */
47
+ export declare function orderProgress(order: Pick<SalesTransaction, "id" | "lines">, delivered: ReadonlyMap<string, number>, documents: readonly Pick<SalesTransaction, "id" | "kindKey" | "status" | "issuedAt" | "lines">[]): LineProgress[];
48
+ /** What is still to invoice on a line: delivered (or ordered) minus invoiced and reserved. */
49
+ export declare const toInvoice: (row: LineProgress, mode: "delivered" | "ordered") => number;
50
+ /** none · partial · full, per axis — what the order list shows next to its status. */
51
+ export declare function progressState(rows: readonly LineProgress[], axis: "delivered" | "invoiced"): "none" | "partial" | "full";
52
+ type Billable = Pick<SalesTransaction, "id" | "kindKey" | "status" | "issuedAt" | "lines" | "companyId" | "businessEntityId" | "currency">;
53
+ /**
54
+ * Invoices from orders (047 step 4, §5): per product line what is still to invoice — delivered
55
+ * (or ordered) minus invoiced and what draft invoices already hold — each line pointing back at
56
+ * its order line. `order`: one invoice per order; `customer`: one per customer and debtor, billing
57
+ * address, payment term, VAT treatment, administration and currency, whose lines each point at
58
+ * their own order. The delivery date is the last delivery in
59
+ * it (the VAT point), on delivered; else the order's. Nothing to invoice: no draft.
60
+ */
61
+ export declare function invoicesFromOrders(input: {
62
+ orders: readonly SalesTransaction[];
63
+ /** Per order, delivered per order line in the line's own unit. */
64
+ delivered: ReadonlyMap<string, ReadonlyMap<string, number>>;
65
+ /** The last day something went out, per order. */
66
+ deliveredAt?: ReadonlyMap<string, number>;
67
+ /** Every invoice and credit note that may point back at these orders. */
68
+ documents: readonly Billable[];
69
+ mode: "delivered" | "ordered";
70
+ groupBy: "order" | "customer";
71
+ }): TransactionDraft[];
72
+ export {};
@@ -0,0 +1,8 @@
1
+ export * from './adopt';
2
+ export * from './customers';
3
+ export * from './execute';
4
+ export * from './goods';
5
+ export * from './path';
6
+ export * from './rules';
7
+ export * from './target';
8
+ export * from './types';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * A fulfilment id in a URL path. Ours hold `#` and `:` (`sale:a1#s1:purchase:3`) and a path cuts
3
+ * at `#`, so the id travels base64url-encoded; the page reads it back. Browser-only (`btoa`).
4
+ */
5
+ export declare const toPathKey: (id: string) => string;
6
+ export declare const fromPathKey: (key: string) => string;
7
+ /** Where a request's page is, for an app that links to it (purchase's order lines). */
8
+ export declare const requestPath: (id: string) => string;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,124 @@
1
+ import { ProvidedResource, ProvisioningAction, RoleNeed } from '../../platform/provisioning';
2
+ import { ProvisionedItem, ProvisioningRequest } from './types';
3
+ /** `<itemId>:<action>:<revision>`: stable over retries and repeated events, new per change. */
4
+ export declare const requestIdOf: (itemId: string, action: ProvisioningAction, revision: string) => string;
5
+ export type NotReady = {
6
+ reason: "after";
7
+ requestIds: string[];
8
+ } | {
9
+ reason: "busy";
10
+ requestId: string;
11
+ } | {
12
+ reason: "missing_role";
13
+ role: string;
14
+ } | {
15
+ reason: "too_many";
16
+ role: string;
17
+ } | {
18
+ reason: "not_active";
19
+ role: string;
20
+ itemId: string;
21
+ } | {
22
+ reason: "wrong_kind";
23
+ role: string;
24
+ itemId: string;
25
+ };
26
+ /**
27
+ * Whether a request may go out now, and the inputs it carries (§10.1). Per act: only the roles
28
+ * whose `for` names this act must be bound and active — a cancel needs nothing active, so an Eylo
29
+ * link can be cleared after the Telnyx number already ended. Inputs are bound by role (the
30
+ * relation), then the kind is checked: two numbers may play different roles.
31
+ */
32
+ export declare function ready(request: Pick<ProvisioningRequest, "id" | "itemId" | "action" | "after">, item: Pick<ProvisionedItem, "requires">, needs: readonly RoleNeed[], items: ReadonlyMap<string, ProvisionedItem>, requests: readonly Pick<ProvisioningRequest, "id" | "itemId" | "state">[]): {
33
+ ok: true;
34
+ inputs: NonNullable<ProvisioningRequest["inputs"]>;
35
+ } | ({
36
+ ok: false;
37
+ } & NotReady);
38
+ /**
39
+ * The day sales billing starts, when an item's status moves (§10.2). Only `billingStart:
40
+ * activation`, only an item the customer takes (`sale`), and only the first activation: a resume
41
+ * after a suspension keeps the original start.
42
+ */
43
+ export declare function billingStartOf(item: Pick<ProvisionedItem, "sale" | "activatedAt">, from: ProvisionedItem["status"], to: ProvisionedItem["status"], billingStart: "date" | "delivery" | "activation", at: number): number | undefined;
44
+ /** The items still using `itemId`: anything not ended, pending included (§10.3). */
45
+ export declare function usersOf(itemId: string, items: Iterable<ProvisionedItem>): ProvisionedItem[];
46
+ /**
47
+ * Ending something, in the two directions of §10.3:
48
+ * - **down** (a customer service ends): the items it uses become a *draft* cancel, but only when
49
+ * nothing else uses them afterwards and they are not to be kept;
50
+ * - **up** (a resource ends): the services that use it are the impact — never cancelled for you.
51
+ * Re-run before sending: a draft may be stale by then.
52
+ */
53
+ export declare function cancelPlan(target: ProvisionedItem, items: ReadonlyMap<string, ProvisionedItem>): {
54
+ release: string[];
55
+ keep: {
56
+ itemId: string;
57
+ why: "kept" | "in_use";
58
+ }[];
59
+ impact: string[];
60
+ };
61
+ /**
62
+ * Whether a cancel on `item` may go now (§10.3, checked again at sending): not while anything
63
+ * still uses it, pending and ending included — the service that ends in November keeps its number
64
+ * until then. A proposal that came from ending what used it also respects "keep".
65
+ */
66
+ export declare function endable(item: Pick<ProvisionedItem, "id" | "keep">, all: Iterable<ProvisionedItem>, proposed: boolean): {
67
+ ok: true;
68
+ } | {
69
+ ok: false;
70
+ reason: "in_use";
71
+ users: string[];
72
+ } | {
73
+ ok: false;
74
+ reason: "kept";
75
+ };
76
+ export type StructureProblem = {
77
+ code: "unknown_item";
78
+ itemId: string;
79
+ } | {
80
+ code: "cycle";
81
+ path: string[];
82
+ } | {
83
+ code: "wrong_kind";
84
+ role: string;
85
+ itemId: string;
86
+ } | {
87
+ code: "duplicate_key";
88
+ externalKey: string;
89
+ itemId: string;
90
+ } | {
91
+ code: "wrong_entity";
92
+ itemId: string;
93
+ };
94
+ /**
95
+ * What saving this item and its relations would break (§10.5, and adopting in step 9): a relation
96
+ * to nothing, a cycle, a resource of the wrong kind for its role, a supplier identity another live
97
+ * item already holds, a relation into another administration. Coverage (`min`/`max`) is not
98
+ * checked here — a draft may still miss a role; {@link ready} demands it before sending.
99
+ */
100
+ export declare function structureProblems(item: Pick<ProvisionedItem, "id" | "requires" | "externalKey" | "businessEntityId">, needs: readonly RoleNeed[], items: ReadonlyMap<string, ProvisionedItem>): StructureProblem[];
101
+ /**
102
+ * What a sold item rests on, for comparing sold and bought (§10.4): every item it uses, once
103
+ * (deduplicated by id), with whether it is shared with another sold item. A shared resource stays
104
+ * out of a cost per customer until there is an explicit allocation rule.
105
+ */
106
+ export declare function supplyChain(sold: ProvisionedItem, items: ReadonlyMap<string, ProvisionedItem>): {
107
+ itemId: string;
108
+ role: string;
109
+ supplied: boolean;
110
+ shared: boolean;
111
+ }[];
112
+ /**
113
+ * Whether a decrease to `quantity` may happen now. Microsoft NCE gives every add-on its own
114
+ * window (`reported.refundable`); without that report the supplier has no window to respect.
115
+ * Outside it, the decrease waits for the term's end.
116
+ */
117
+ export declare function canDecrease(item: Pick<ProvisionedItem, "quantity" | "reported">, quantity: number, at: number): {
118
+ now: true;
119
+ } | {
120
+ now: false;
121
+ at?: number;
122
+ };
123
+ /** The first resource of `kind` an item provides. */
124
+ export declare const providedOf: (item: Pick<ProvisionedItem, "provides">, kind: ProvidedResource["kind"]) => ProvidedResource | undefined;