@opencxh/domain 1.302.0 → 1.304.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/dist/entities/agreement/from-quote.d.ts +8 -8
- package/dist/entities/agreement/index.d.ts +2 -0
- package/dist/entities/agreement/invoice-head.d.ts +21 -0
- package/dist/entities/agreement/lifecycle.d.ts +10 -0
- package/dist/entities/agreement/period.d.ts +8 -0
- package/dist/entities/agreement/prices.d.ts +43 -0
- package/dist/entities/agreement/prices.test.d.ts +1 -0
- package/dist/entities/agreement/types.d.ts +55 -10
- package/dist/entities/bank/match.d.ts +16 -2
- package/dist/entities/bank/types.d.ts +12 -0
- package/dist/entities/bookkeeping/receipt.d.ts +45 -6
- package/dist/entities/bookkeeping/types.d.ts +1 -2
- package/dist/entities/business-entity/types.d.ts +11 -15
- package/dist/entities/catalog/pricing.d.ts +14 -12
- package/dist/entities/catalog/types.d.ts +20 -9
- package/dist/entities/company/role.d.ts +14 -0
- package/dist/entities/financing/schedule.d.ts +9 -3
- package/dist/entities/financing/types.d.ts +17 -6
- package/dist/entities/fulfilment/adopt.d.ts +149 -0
- package/dist/entities/fulfilment/configuration.d.ts +99 -0
- package/dist/entities/fulfilment/configuration.test.d.ts +1 -0
- package/dist/entities/fulfilment/customers.d.ts +63 -0
- package/dist/entities/fulfilment/execute.d.ts +67 -0
- package/dist/entities/fulfilment/fulfilment.test.d.ts +1 -0
- package/dist/entities/fulfilment/goods.d.ts +72 -0
- package/dist/entities/fulfilment/index.d.ts +9 -0
- package/dist/entities/fulfilment/path.d.ts +8 -0
- package/dist/entities/fulfilment/path.test.d.ts +1 -0
- package/dist/entities/fulfilment/rules.d.ts +124 -0
- package/dist/entities/fulfilment/target.d.ts +133 -0
- package/dist/entities/fulfilment/types.d.ts +293 -0
- package/dist/entities/ledger/entry.d.ts +47 -9
- package/dist/entities/ledger/types.d.ts +33 -35
- package/dist/entities/ledger/xaf.d.ts +3 -0
- package/dist/entities/money/tax.d.ts +6 -0
- package/dist/entities/money/totals.d.ts +5 -5
- package/dist/entities/purchase/choose.d.ts +62 -0
- package/dist/entities/purchase/choose.test.d.ts +1 -0
- package/dist/entities/purchase/contract.d.ts +44 -25
- package/dist/entities/purchase/demand.d.ts +24 -40
- package/dist/entities/purchase/feed.d.ts +53 -5
- package/dist/entities/purchase/index.d.ts +2 -0
- package/dist/entities/purchase/kinds.d.ts +2 -1
- package/dist/entities/purchase/logic.d.ts +32 -7
- package/dist/entities/purchase/match.d.ts +48 -6
- package/dist/entities/purchase/packing-slip.d.ts +23 -0
- package/dist/entities/purchase/types.d.ts +90 -42
- package/dist/entities/purchase/upsell.d.ts +20 -0
- package/dist/entities/purchase/upsell.test.d.ts +1 -0
- package/dist/entities/reports/vat.d.ts +20 -5
- package/dist/entities/transaction/booking.d.ts +4 -4
- package/dist/entities/transaction/convert.d.ts +10 -10
- package/dist/entities/transaction/document.d.ts +8 -3
- package/dist/entities/transaction/dunning.d.ts +12 -1
- package/dist/entities/transaction/facets.test.d.ts +1 -0
- package/dist/entities/transaction/keys.d.ts +3 -0
- package/dist/entities/transaction/kinds.d.ts +11 -10
- package/dist/entities/transaction/receivable.d.ts +5 -2
- package/dist/entities/transaction/settlement.d.ts +7 -7
- package/dist/entities/transaction/types.d.ts +128 -68
- package/dist/index.cjs +25 -25
- package/dist/index.d.ts +2 -1
- package/dist/index.js +5300 -4033
- package/dist/platform/bookkeeping.d.ts +8 -8
- package/dist/platform/provisioning.d.ts +292 -17
- package/package.json +1 -1
- /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
|
|
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,99 @@
|
|
|
1
|
+
import { AnswerSpec, OfferRef, Preparation, ProvisioningAnswers, Requirement, RequirementGate } from '../../platform/provisioning';
|
|
2
|
+
import { Commitment, LineRhythm } from '../agreement/types';
|
|
3
|
+
/**
|
|
4
|
+
* One article configured for one customer (plan 053): the answers, the offer chosen and what the
|
|
5
|
+
* provider last said. Sales carries only its id; fulfilment freezes the answers into the request.
|
|
6
|
+
*/
|
|
7
|
+
export interface Configuration {
|
|
8
|
+
id: string;
|
|
9
|
+
organizationId: string;
|
|
10
|
+
businessEntityId: string;
|
|
11
|
+
customerCompanyId: string;
|
|
12
|
+
productId: string;
|
|
13
|
+
/** The offer it is bought through; its `sku` follows the `main` answer. */
|
|
14
|
+
ref?: OfferRef;
|
|
15
|
+
supplierOfferId?: string;
|
|
16
|
+
answers: ProvisioningAnswers;
|
|
17
|
+
preparation?: Preparation;
|
|
18
|
+
preparedAt?: number;
|
|
19
|
+
createdBy: string;
|
|
20
|
+
updatedAt: number;
|
|
21
|
+
}
|
|
22
|
+
export type ConfigurationStatus = "open" | "ready" | "expired";
|
|
23
|
+
/** "Via leverancier" (plan 053): a provider whose flow asks something, and what it starts with. */
|
|
24
|
+
export interface SupplierFlow {
|
|
25
|
+
app: string;
|
|
26
|
+
label: string;
|
|
27
|
+
asks: AnswerSpec[];
|
|
28
|
+
productIds: string[];
|
|
29
|
+
}
|
|
30
|
+
/** Step 1, one article on the answers so far: can it be delivered, and from what cost. */
|
|
31
|
+
export interface ArticleCheck {
|
|
32
|
+
productId: string;
|
|
33
|
+
supplierOfferId: string;
|
|
34
|
+
available: boolean;
|
|
35
|
+
/** The first unmet condition's reason; absent when only questions are left. */
|
|
36
|
+
reason?: string;
|
|
37
|
+
/** The cheapest main option, per month where it recurs. Internal: colleagues only. */
|
|
38
|
+
fromCents?: number;
|
|
39
|
+
labels: string[];
|
|
40
|
+
}
|
|
41
|
+
/** One line a configuration sells, with the upsell article it becomes — or none yet. */
|
|
42
|
+
export interface ConfiguredSale {
|
|
43
|
+
/** The answer it comes from; absent for the main line. */
|
|
44
|
+
optionKey?: string;
|
|
45
|
+
label: string;
|
|
46
|
+
sku: string;
|
|
47
|
+
quantity: number;
|
|
48
|
+
costCents?: number;
|
|
49
|
+
recurring?: "month";
|
|
50
|
+
/** Our article: the configured one for the main line, the upsell rule's for a sub-line. */
|
|
51
|
+
productId?: string;
|
|
52
|
+
commitment?: Partial<Commitment>;
|
|
53
|
+
}
|
|
54
|
+
export interface ConfigurationView {
|
|
55
|
+
configuration: Configuration;
|
|
56
|
+
status: ConfigurationStatus;
|
|
57
|
+
sales: ConfiguredSale[];
|
|
58
|
+
}
|
|
59
|
+
/** What still stands in the way of `gate`: at `order`, the quote's requirements count too. */
|
|
60
|
+
export declare function blockersOf(preparation: Preparation, gate: RequirementGate): Requirement[];
|
|
61
|
+
/** Ready for `gate` when prepared, not expired and nothing blocks it. */
|
|
62
|
+
export declare function configurationStatus(config: Pick<Configuration, "preparation">, gate: RequirementGate, now: number): ConfigurationStatus;
|
|
63
|
+
/** A chosen product: the main line's or one add-on's. Cost is per unit, internal. */
|
|
64
|
+
export interface ConfiguredLine {
|
|
65
|
+
/** The answer it comes from (`evc_2`, `sla`). */
|
|
66
|
+
key: string;
|
|
67
|
+
/** As the provider names it: what an upsell article's match reads. */
|
|
68
|
+
label: string;
|
|
69
|
+
sku: string;
|
|
70
|
+
quantity: number;
|
|
71
|
+
costCents?: number;
|
|
72
|
+
recurring?: "month";
|
|
73
|
+
commitment?: Partial<Commitment>;
|
|
74
|
+
billedEvery?: LineRhythm;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* What the answers buy: the supplier's product for the main line, and one sub-line per add-on
|
|
78
|
+
* taken (decided 05-10: an add-on is its own sales line). A `no` or a `0` is no line.
|
|
79
|
+
*/
|
|
80
|
+
export declare function linesOf(preparation: Preparation, answers: ProvisioningAnswers): {
|
|
81
|
+
main?: ConfiguredLine;
|
|
82
|
+
addons: ConfiguredLine[];
|
|
83
|
+
};
|
|
84
|
+
/** The offer as bought: the chosen main product becomes its sku, its option's commitment ours. */
|
|
85
|
+
export declare function chosenOf(ref: OfferRef, preparation: Preparation, answers: ProvisioningAnswers): {
|
|
86
|
+
ref: OfferRef;
|
|
87
|
+
commitment?: Partial<Commitment>;
|
|
88
|
+
billedEvery?: LineRhythm;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* The answers that go out, frozen on the request: only keys the provider asked for, its own
|
|
92
|
+
* proposal where nobody typed one. A stray key never reaches the supplier.
|
|
93
|
+
*/
|
|
94
|
+
export declare function orderAnswers(preparation: Preparation, answers: ProvisioningAnswers): ProvisioningAnswers;
|
|
95
|
+
/**
|
|
96
|
+
* An exclusive item configured per unit (plan 053 G2: ten SIMs, ten numbers to port): one set of
|
|
97
|
+
* answers per unit, the shared ones copied, the `perUnit` ones from `perUnitValues` in order.
|
|
98
|
+
*/
|
|
99
|
+
export declare function splitUnits(preparation: Preparation, answers: ProvisioningAnswers, quantity: number, perUnitValues?: Record<string, string[]>): ProvisioningAnswers[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -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
|
+
/**
|
|
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 {};
|