@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.
- 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 +54 -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 +11 -11
- package/dist/entities/catalog/types.d.ts +15 -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/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 +8 -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 +131 -0
- package/dist/entities/fulfilment/types.d.ts +321 -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 +57 -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 +22 -40
- package/dist/entities/purchase/feed.d.ts +53 -5
- package/dist/entities/purchase/index.d.ts +1 -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 +71 -38
- 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 +123 -68
- package/dist/index.cjs +25 -25
- package/dist/index.d.ts +2 -1
- package/dist/index.js +5160 -4026
- package/dist/platform/bookkeeping.d.ts +8 -8
- package/dist/platform/provisioning.d.ts +210 -13
- package/package.json +1 -1
- /package/dist/entities/{purchase/demand.test.d.ts → agreement/invoice-head.test.d.ts} +0 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { ProvisionableOffer, ProvisioningAction, RoleNeed } from '../../platform/provisioning';
|
|
2
|
+
import { Agreement, Commitment } from '../agreement/types';
|
|
3
|
+
import { ItemRequirement, ProvisionedItem, ProvisioningRequest, TargetNotice } from './types';
|
|
4
|
+
/** What an item should become, read from its source now (§3). */
|
|
5
|
+
export interface ItemTarget {
|
|
6
|
+
action: ProvisioningAction;
|
|
7
|
+
productId: string;
|
|
8
|
+
quantity: number;
|
|
9
|
+
previousQuantity?: number;
|
|
10
|
+
toProductId?: string;
|
|
11
|
+
effectiveAt?: number;
|
|
12
|
+
submitAt?: number;
|
|
13
|
+
notice?: TargetNotice;
|
|
14
|
+
}
|
|
15
|
+
/** The terms of the contract line that pays for the item (§3): when it can end or go down. */
|
|
16
|
+
export interface SupplyTerms {
|
|
17
|
+
/** Where its term counts from: the subscription's first line. */
|
|
18
|
+
start: number;
|
|
19
|
+
commitment?: Commitment;
|
|
20
|
+
changeWindowDays?: number;
|
|
21
|
+
}
|
|
22
|
+
/** Why there is no target to send: the decision needs something we do not know (Codex 4). */
|
|
23
|
+
export type TargetBlock = {
|
|
24
|
+
reason: "decrease_window_unknown";
|
|
25
|
+
quantity: number;
|
|
26
|
+
}
|
|
27
|
+
/** It is paid for, but the contract's terms could not be read: no end or decrease on a guess. */
|
|
28
|
+
| {
|
|
29
|
+
reason: "supply_terms_unknown";
|
|
30
|
+
}
|
|
31
|
+
/** Its provider did not describe itself: what it needs is unknown, so nothing is planned. */
|
|
32
|
+
| {
|
|
33
|
+
reason: "provider_unknown";
|
|
34
|
+
}
|
|
35
|
+
/** More than one of something that is not interchangeable: one agreement line per unit (D5). */
|
|
36
|
+
| {
|
|
37
|
+
reason: "one_unit_per_item";
|
|
38
|
+
quantity: number;
|
|
39
|
+
}
|
|
40
|
+
/** The agreement names no administration: nothing is made on a guess (review R6). */
|
|
41
|
+
| {
|
|
42
|
+
reason: "entity_required";
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* The target of one agreement series against what runs, and which unsent requests it replaces
|
|
46
|
+
* (§3). Read from the current source, never from an event: twice the same event, or two in the
|
|
47
|
+
* wrong order, give the same answer — "12 per November, corrected to 11" is 11.
|
|
48
|
+
*
|
|
49
|
+
* - no item yet, or a pending one without a request: purchase;
|
|
50
|
+
* - the series ends: cancel at its end;
|
|
51
|
+
* - another product: convert;
|
|
52
|
+
* - another count: change, a decrease outside the supplier's window at the term's end;
|
|
53
|
+
* - an unsent request for the same act stays; one for another act is superseded;
|
|
54
|
+
* - a sent request is never withdrawn: a different target queues behind it.
|
|
55
|
+
*/
|
|
56
|
+
export declare function targetOf(input: {
|
|
57
|
+
agreement: Agreement;
|
|
58
|
+
seriesId: string;
|
|
59
|
+
item?: ProvisionedItem;
|
|
60
|
+
requests: readonly ProvisioningRequest[];
|
|
61
|
+
/** The contract line that pays for it: an end follows its notice, a decrease its window. */
|
|
62
|
+
supply?: SupplyTerms;
|
|
63
|
+
now: number;
|
|
64
|
+
}): {
|
|
65
|
+
target?: ItemTarget;
|
|
66
|
+
supersede: string[];
|
|
67
|
+
blocked?: TargetBlock;
|
|
68
|
+
};
|
|
69
|
+
/** A draft request for one act on one item: the same input gives the same id (§2.2). */
|
|
70
|
+
export declare function draftRequest(input: {
|
|
71
|
+
item: Pick<ProvisionedItem, "id" | "organizationId" | "businessEntityId">;
|
|
72
|
+
at: {
|
|
73
|
+
app: string;
|
|
74
|
+
offer: string;
|
|
75
|
+
};
|
|
76
|
+
target: ItemTarget;
|
|
77
|
+
after?: string[];
|
|
78
|
+
/** What was asked on the sale (047 step 8): the item's own purchase carries it. */
|
|
79
|
+
answers?: {
|
|
80
|
+
params: Record<string, string>;
|
|
81
|
+
qualificationId?: string;
|
|
82
|
+
};
|
|
83
|
+
revision: string;
|
|
84
|
+
requestedBy: string;
|
|
85
|
+
now: number;
|
|
86
|
+
}): ProvisioningRequest;
|
|
87
|
+
/**
|
|
88
|
+
* An offer whose unit has an identity of its own: it provides, or buys with, a number or a device.
|
|
89
|
+
* Until items exist per unit (`units: "each"`, review 5c) such an item holds one (D5): three
|
|
90
|
+
* numbers on one item would be bought as one, and billed as three.
|
|
91
|
+
*/
|
|
92
|
+
export declare const onePerItem: (offer: Pick<ProvisionableOffer, "provides" | "needs"> | undefined) => boolean;
|
|
93
|
+
/**
|
|
94
|
+
* What an offer needs from other items. A provider that still declares only `requires` (the
|
|
95
|
+
* account offer it lives under) gets that as an account role, so Eylo keeps working unchanged.
|
|
96
|
+
*/
|
|
97
|
+
export declare function needsOf(offer: ProvisionableOffer | undefined): RoleNeed[];
|
|
98
|
+
/**
|
|
99
|
+
* What a purchase of `item` sets in motion (§7): per role its offer `needs` for a purchase, bind
|
|
100
|
+
* an existing item (an account, a kept number nobody uses), or make a `pending` one with a stable
|
|
101
|
+
* key and a purchase request for it; then the item's own purchase, after those.
|
|
102
|
+
* `sourceFor` names the offer that provides a role — choosing between suppliers is 045 B.
|
|
103
|
+
*/
|
|
104
|
+
export declare function planFor(input: {
|
|
105
|
+
item: ProvisionedItem;
|
|
106
|
+
app: string;
|
|
107
|
+
offer: string;
|
|
108
|
+
needs: readonly RoleNeed[];
|
|
109
|
+
target: ItemTarget;
|
|
110
|
+
items: ReadonlyMap<string, ProvisionedItem>;
|
|
111
|
+
/** The requests already there: a pending item that is bound is waited for, not bought again. */
|
|
112
|
+
requests: readonly ProvisioningRequest[];
|
|
113
|
+
sourceFor: (need: RoleNeed) => {
|
|
114
|
+
app: string;
|
|
115
|
+
offer: string;
|
|
116
|
+
productId: string;
|
|
117
|
+
} | undefined;
|
|
118
|
+
/** The sale's answers, for the item's own request only: what it needs is made without them. */
|
|
119
|
+
answers?: {
|
|
120
|
+
params: Record<string, string>;
|
|
121
|
+
qualificationId?: string;
|
|
122
|
+
};
|
|
123
|
+
revision: string;
|
|
124
|
+
requestedBy: string;
|
|
125
|
+
now: number;
|
|
126
|
+
}): {
|
|
127
|
+
requires: ItemRequirement[];
|
|
128
|
+
newItems: ProvisionedItem[];
|
|
129
|
+
requests: ProvisioningRequest[];
|
|
130
|
+
unsourced: string[];
|
|
131
|
+
};
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { ProvidedResource, ProviderQualification, ProvisioningAction, ProvisioningCommand, ProvisioningResult } from '../../platform/provisioning';
|
|
2
|
+
import { DeliverTo } from '../purchase/types';
|
|
3
|
+
/**
|
|
4
|
+
* What runs at or for a customer (plan 047 v2): a subscription, an account, a bought number, one
|
|
5
|
+
* tracked device. One store with independent facets — `sale` (the customer takes it: "Producten
|
|
6
|
+
* bij klanten"), `supply` (we pay for it), `provides` (what it hands others, by kind) and
|
|
7
|
+
* `requires` (what it uses, by role). A paid Eylo account has `sale` and `provides` at once.
|
|
8
|
+
*/
|
|
9
|
+
export interface ProvisionedItem {
|
|
10
|
+
/**
|
|
11
|
+
* Its key ({@link itemKey}): deterministic, unique per organisation, made before the first
|
|
12
|
+
* request. The same sales event twice finds the same row, and a relation can name an item
|
|
13
|
+
* before it is stored.
|
|
14
|
+
*/
|
|
15
|
+
id: string;
|
|
16
|
+
organizationId: string;
|
|
17
|
+
businessEntityId: string;
|
|
18
|
+
customerCompanyId: string;
|
|
19
|
+
productId: string;
|
|
20
|
+
status: ProvisionedStatus;
|
|
21
|
+
/** Base units. Hardware with a serial: 1, one row per unit. */
|
|
22
|
+
quantity: number;
|
|
23
|
+
serial?: string;
|
|
24
|
+
/**
|
|
25
|
+
* `<product>#<serial>` while it runs, its own id once ended ({@link serialKeyOf}): a unique
|
|
26
|
+
* index, so one serial runs once per organisation (review R6).
|
|
27
|
+
*/
|
|
28
|
+
serialKey?: string;
|
|
29
|
+
/** What it uses, per role: the account it runs under, the number it routes. Acyclic. */
|
|
30
|
+
requires?: ItemRequirement[];
|
|
31
|
+
/** The ids in `requires`, flat: "who uses this?" is `requiresIds: $in` (review R6). */
|
|
32
|
+
requiresIds?: string[];
|
|
33
|
+
/** What it can deliver to others; the role is on the relation, not here. */
|
|
34
|
+
provides?: ProvidedResource[];
|
|
35
|
+
/** Where it runs, and the provider's own fields as handed back. */
|
|
36
|
+
at?: {
|
|
37
|
+
app: string;
|
|
38
|
+
offer?: string;
|
|
39
|
+
externalRef?: string;
|
|
40
|
+
fulfillment?: Record<string, string>;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Its identity at the supplier, `<app>:<externalRef>` ({@link externalKeyOf}), indexed. Not
|
|
44
|
+
* unique: an ended item keeps it, and a released number can be bought again.
|
|
45
|
+
*/
|
|
46
|
+
externalKey?: string;
|
|
47
|
+
/** The commercial link: only on what the customer takes. */
|
|
48
|
+
sale?: {
|
|
49
|
+
agreementId: string;
|
|
50
|
+
seriesId: string;
|
|
51
|
+
} | {
|
|
52
|
+
orderId: string;
|
|
53
|
+
lineId: string;
|
|
54
|
+
};
|
|
55
|
+
/** What we pay for it, if bought: 1:1 with a contract line. */
|
|
56
|
+
supply?: {
|
|
57
|
+
contractId: string;
|
|
58
|
+
lineId: string;
|
|
59
|
+
};
|
|
60
|
+
fixedAssetId?: string;
|
|
61
|
+
/** Keep it when what used it ends: number porting, a move to another platform. */
|
|
62
|
+
keep?: boolean;
|
|
63
|
+
/** The first time it became active; a resume does not move it (billing start, §10.2). */
|
|
64
|
+
activatedAt?: number;
|
|
65
|
+
/** What the supplier says, polled per subscription. */
|
|
66
|
+
reported?: ReportedState;
|
|
67
|
+
since: number;
|
|
68
|
+
endedAt?: number;
|
|
69
|
+
updatedAt: number;
|
|
70
|
+
}
|
|
71
|
+
export type ProvisionedStatus = "pending" | "active" | "suspended" | "terminating" | "terminated";
|
|
72
|
+
/** Not ended: counts as a user of what it requires, pending included (§10.3). */
|
|
73
|
+
export declare const LIVE_STATUSES: readonly ProvisionedStatus[];
|
|
74
|
+
export interface ItemRequirement {
|
|
75
|
+
role: string;
|
|
76
|
+
itemId: string;
|
|
77
|
+
}
|
|
78
|
+
export interface ReportedState {
|
|
79
|
+
quantity: number;
|
|
80
|
+
status: "active" | "suspended" | "ended" | "unknown";
|
|
81
|
+
termEndsAt?: number;
|
|
82
|
+
autoRenew?: boolean;
|
|
83
|
+
/** Microsoft NCE: every add-on has its own window; a decrease only within these. */
|
|
84
|
+
refundable?: {
|
|
85
|
+
quantity: number;
|
|
86
|
+
until: number;
|
|
87
|
+
}[];
|
|
88
|
+
scheduled?: {
|
|
89
|
+
quantity?: number;
|
|
90
|
+
productId?: string;
|
|
91
|
+
at: number;
|
|
92
|
+
};
|
|
93
|
+
at: number;
|
|
94
|
+
}
|
|
95
|
+
export declare const externalKeyOf: (app: string, externalRef: string) => string;
|
|
96
|
+
/** Kept beside `requires` on every write that sets it. */
|
|
97
|
+
export declare const requiresIdsOf: (requires: readonly ItemRequirement[] | undefined) => string[];
|
|
98
|
+
/** A serial is one identity per product while it runs; an ended row holds its own id. */
|
|
99
|
+
export declare const serialKeyOf: (item: Pick<ProvisionedItem, "id" | "productId" | "serial">, running: boolean) => string;
|
|
100
|
+
/** `sale:<agreement>#<series>`, `order:<order>#<line>[#<serial>]`, `resource:<item>#<role>`. */
|
|
101
|
+
export declare function itemKey(source: {
|
|
102
|
+
kind: "sale";
|
|
103
|
+
agreementId: string;
|
|
104
|
+
seriesId: string;
|
|
105
|
+
} | {
|
|
106
|
+
kind: "order";
|
|
107
|
+
orderId: string;
|
|
108
|
+
lineId: string;
|
|
109
|
+
serial?: string;
|
|
110
|
+
} | {
|
|
111
|
+
kind: "resource";
|
|
112
|
+
itemId: string;
|
|
113
|
+
role: string;
|
|
114
|
+
}): string;
|
|
115
|
+
/** One act on one item (§2.2). */
|
|
116
|
+
export interface ProvisioningRequest {
|
|
117
|
+
id: string;
|
|
118
|
+
organizationId: string;
|
|
119
|
+
/** Always a real administration: a request without one is refused (review R6). */
|
|
120
|
+
businessEntityId: string;
|
|
121
|
+
itemId: string;
|
|
122
|
+
/** `<itemId>:<action>:<revision>`: a retry and a repeated event give the same id. */
|
|
123
|
+
requestId: string;
|
|
124
|
+
action: ProvisioningAction;
|
|
125
|
+
productId: string;
|
|
126
|
+
/** Absolute target. */
|
|
127
|
+
quantity: number;
|
|
128
|
+
previousQuantity?: number;
|
|
129
|
+
toProductId?: string;
|
|
130
|
+
effectiveAt?: number;
|
|
131
|
+
/** When to send it: a decrease at renewal is sent then, not now. */
|
|
132
|
+
submitAt?: number;
|
|
133
|
+
/** Why it is on that day: the notice deadline, a next term, paying on (§3). */
|
|
134
|
+
notice?: TargetNotice;
|
|
135
|
+
/** Who performs it; `"manual"` is a person. */
|
|
136
|
+
app: string;
|
|
137
|
+
offer: string;
|
|
138
|
+
params: Record<string, string>;
|
|
139
|
+
/** The delivery check the sale was made on (047 step 8); its answers are in `params`. */
|
|
140
|
+
qualificationId?: string;
|
|
141
|
+
/** Bound by role from what the item requires, then checked by kind (§10.1). */
|
|
142
|
+
inputs?: {
|
|
143
|
+
role: string;
|
|
144
|
+
itemId: string;
|
|
145
|
+
resource: ProvidedResource;
|
|
146
|
+
}[];
|
|
147
|
+
/** Order of concrete acts only; the lasting relation is `ProvisionedItem.requires`. */
|
|
148
|
+
after: string[];
|
|
149
|
+
/** What it was computed from: re-read before it goes out (§3). */
|
|
150
|
+
basedOn: {
|
|
151
|
+
source: string;
|
|
152
|
+
revision: string;
|
|
153
|
+
};
|
|
154
|
+
/** The PO line's offer as the supplier knows it, set on release (045 D N-3). */
|
|
155
|
+
supplier?: {
|
|
156
|
+
vendorSku?: string;
|
|
157
|
+
termMonths?: number;
|
|
158
|
+
};
|
|
159
|
+
/** Who pays and who allowed it: a PO line, or the running contract line (§6). */
|
|
160
|
+
basis?: {
|
|
161
|
+
kind: "po_line";
|
|
162
|
+
orderId: string;
|
|
163
|
+
lineId: string;
|
|
164
|
+
} | {
|
|
165
|
+
kind: "contract_line";
|
|
166
|
+
contractId: string;
|
|
167
|
+
lineId: string;
|
|
168
|
+
};
|
|
169
|
+
state: RequestState;
|
|
170
|
+
/** Everything that went out, frozen: a retry sends exactly this. */
|
|
171
|
+
sent?: SentCommand;
|
|
172
|
+
result?: ProvisioningResult;
|
|
173
|
+
/** When it was carried out: the day the books follow, unchanged over every retry. */
|
|
174
|
+
doneAt?: number;
|
|
175
|
+
/**
|
|
176
|
+
* `false` from the moment it is approved until the item and the notices to purchase and sales
|
|
177
|
+
* are done: a crash in between is picked up again, never left half done.
|
|
178
|
+
*/
|
|
179
|
+
applied?: boolean;
|
|
180
|
+
/**
|
|
181
|
+
* A lost purchase whose listing showed more than one new subscription that fits: a person picks
|
|
182
|
+
* which is ours (047 step 7). Cleared once it is settled.
|
|
183
|
+
*/
|
|
184
|
+
candidates?: {
|
|
185
|
+
externalRef: string;
|
|
186
|
+
quantity: number;
|
|
187
|
+
offer: string;
|
|
188
|
+
}[];
|
|
189
|
+
/** What it costs, from purchase, before an approval weighs it. Unknown is never zero. */
|
|
190
|
+
priceCents?: number;
|
|
191
|
+
requestedBy: string;
|
|
192
|
+
attempts: number;
|
|
193
|
+
/**
|
|
194
|
+
* When the poll looks at it again (indexed): `submitAt` when scheduled, a backoff while it waits
|
|
195
|
+
* or is out the door. `0` = nothing to do by itself (draft, settled, superseded).
|
|
196
|
+
*/
|
|
197
|
+
wakeAt?: number;
|
|
198
|
+
/** Set by the store on insert. */
|
|
199
|
+
createdAt?: number;
|
|
200
|
+
updatedAt: number;
|
|
201
|
+
}
|
|
202
|
+
/** What "Te bestellen" shows next to an end or a decrease: why it is on that day. */
|
|
203
|
+
export interface TargetNotice {
|
|
204
|
+
/** The last day to send it for `effectiveAt`. */
|
|
205
|
+
deadline?: number;
|
|
206
|
+
/** The notice came too late for this term: it ends at the next one. */
|
|
207
|
+
nextTerm?: boolean;
|
|
208
|
+
/** We pay on after the customer stopped, until then. */
|
|
209
|
+
runsOnUntil?: number;
|
|
210
|
+
/** A decrease outside the change window: at the term's end, not now. */
|
|
211
|
+
atRenewal?: boolean;
|
|
212
|
+
}
|
|
213
|
+
export type RequestState = "draft" | "scheduled" | "queued" | "waiting" | "pending" | "unknown" | "inquiring" | "approved" | "failed" | "superseded";
|
|
214
|
+
/** Not yet out the door: may still be replaced when the target moves (§3). */
|
|
215
|
+
export declare const UNSENT_STATES: readonly RequestState[];
|
|
216
|
+
/** Out the door and not settled: one per item at a time. */
|
|
217
|
+
export declare const OPEN_STATES: readonly RequestState[];
|
|
218
|
+
export type SentCommand = ProvisioningCommand & {
|
|
219
|
+
at: number;
|
|
220
|
+
/** The provider's per-attempt id where it documents one (Microsoft MS-RequestId). */
|
|
221
|
+
attemptRef?: string;
|
|
222
|
+
};
|
|
223
|
+
/** Goods still to deliver for one sales order line, or a restock (§2.4). */
|
|
224
|
+
export interface FulfilmentOrder {
|
|
225
|
+
id: string;
|
|
226
|
+
organizationId: string;
|
|
227
|
+
businessEntityId: string;
|
|
228
|
+
source: {
|
|
229
|
+
kind: "order_line";
|
|
230
|
+
orderId: string;
|
|
231
|
+
lineId: string;
|
|
232
|
+
} | {
|
|
233
|
+
kind: "restock";
|
|
234
|
+
key: string;
|
|
235
|
+
};
|
|
236
|
+
customerCompanyId?: string;
|
|
237
|
+
productId: string;
|
|
238
|
+
/** Base units. */
|
|
239
|
+
quantity: number;
|
|
240
|
+
deliverTo: DeliverTo;
|
|
241
|
+
/** The offer it is bought on: a person's pick before the order, else what it was placed on. */
|
|
242
|
+
offerId?: string;
|
|
243
|
+
/** Who picked `offerId` by hand (045 B-3); absent = the server's choice. */
|
|
244
|
+
offerPickedBy?: string;
|
|
245
|
+
state: "open" | "closed" | "cancelled";
|
|
246
|
+
updatedAt: number;
|
|
247
|
+
}
|
|
248
|
+
/** Which part of which PO line or stock is meant for a fulfilment order. */
|
|
249
|
+
export interface Allocation {
|
|
250
|
+
id: string;
|
|
251
|
+
organizationId: string;
|
|
252
|
+
fulfilmentOrderId: string;
|
|
253
|
+
supply: {
|
|
254
|
+
kind: "po_line";
|
|
255
|
+
orderId: string;
|
|
256
|
+
lineId: string;
|
|
257
|
+
} | {
|
|
258
|
+
kind: "stock";
|
|
259
|
+
locationId?: string;
|
|
260
|
+
};
|
|
261
|
+
/** Base units. */
|
|
262
|
+
quantity: number;
|
|
263
|
+
state: "active" | "released";
|
|
264
|
+
/** The order a partial receipt is shared in (FIFO, §4). */
|
|
265
|
+
createdAt: number;
|
|
266
|
+
}
|
|
267
|
+
/** A physical delivery, out or back. */
|
|
268
|
+
export interface Delivery {
|
|
269
|
+
id: string;
|
|
270
|
+
organizationId: string;
|
|
271
|
+
fulfilmentOrderId: string;
|
|
272
|
+
allocationId?: string;
|
|
273
|
+
kind: "shipment" | "dropship";
|
|
274
|
+
direction?: "out" | "return";
|
|
275
|
+
/** Base units. */
|
|
276
|
+
quantity: number;
|
|
277
|
+
at: number;
|
|
278
|
+
evidence: {
|
|
279
|
+
receiptId?: string;
|
|
280
|
+
by?: string;
|
|
281
|
+
};
|
|
282
|
+
serials?: string[];
|
|
283
|
+
batches?: {
|
|
284
|
+
code: string;
|
|
285
|
+
quantity: number;
|
|
286
|
+
expiresAt?: number;
|
|
287
|
+
}[];
|
|
288
|
+
shipmentRef?: string;
|
|
289
|
+
carrier?: string;
|
|
290
|
+
trackingNumber?: string;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Deliverable here, before the promise (047 step 8, TMF679): the answers asked for one article,
|
|
294
|
+
* what each provider said (`perOffer`, with cost: internal) and that answer in our own assortment
|
|
295
|
+
* (`products`: the only part a customer may see). No address field: `site` is a crm address id.
|
|
296
|
+
*/
|
|
297
|
+
export interface Qualification {
|
|
298
|
+
id: string;
|
|
299
|
+
organizationId: string;
|
|
300
|
+
businessEntityId: string;
|
|
301
|
+
productId: string;
|
|
302
|
+
params: Record<string, string>;
|
|
303
|
+
perOffer: OfferQualification[];
|
|
304
|
+
products: QualifiedProduct[];
|
|
305
|
+
expiresAt: number;
|
|
306
|
+
createdBy: string;
|
|
307
|
+
at: number;
|
|
308
|
+
}
|
|
309
|
+
export type OfferQualification = ProviderQualification & {
|
|
310
|
+
app: string;
|
|
311
|
+
offer: string;
|
|
312
|
+
};
|
|
313
|
+
export interface QualifiedProduct {
|
|
314
|
+
productId: string;
|
|
315
|
+
available: boolean;
|
|
316
|
+
/** A code, never the supplier's words: `unavailable` or `no_answer`. */
|
|
317
|
+
reason?: "unavailable" | "no_answer";
|
|
318
|
+
}
|
|
319
|
+
/** What leaves fulfilment for a person or a portal: never the suppliers, networks or costs. */
|
|
320
|
+
export type QualificationView = Omit<Qualification, "perOffer">;
|
|
321
|
+
export declare const qualificationView: ({ perOffer: _, ...view }: Qualification) => QualificationView;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { BookingDocument } from '../../platform/bookkeeping';
|
|
2
|
-
import {
|
|
2
|
+
import { LedgerMappingRule } from '../bookkeeping/types';
|
|
3
|
+
import { TaxCode } from '../money/tax';
|
|
4
|
+
import { FiscalPeriod, JournalEntry, JournalKind, JournalLineData, LedgerAccount } from './types';
|
|
3
5
|
export type EntryProblem = {
|
|
4
6
|
code: "entry_unbalanced";
|
|
5
7
|
params: {
|
|
@@ -32,6 +34,21 @@ export type EntryProblem = {
|
|
|
32
34
|
params: {
|
|
33
35
|
day: string;
|
|
34
36
|
};
|
|
37
|
+
} | {
|
|
38
|
+
code: "entry_tax_side";
|
|
39
|
+
params: {
|
|
40
|
+
account: string;
|
|
41
|
+
};
|
|
42
|
+
} | {
|
|
43
|
+
code: "fx_rate_required";
|
|
44
|
+
params: {
|
|
45
|
+
currency: string;
|
|
46
|
+
};
|
|
47
|
+
} | {
|
|
48
|
+
code: "fx_cross_rate_unsupported";
|
|
49
|
+
params: {
|
|
50
|
+
currency: string;
|
|
51
|
+
};
|
|
35
52
|
};
|
|
36
53
|
/** Everything that stops an entry, checked in memory before the insert (plan 039 §4.4 step 1). */
|
|
37
54
|
export declare function entryProblems(entry: {
|
|
@@ -40,28 +57,41 @@ export declare function entryProblems(entry: {
|
|
|
40
57
|
}, context: {
|
|
41
58
|
accounts: readonly LedgerAccount[];
|
|
42
59
|
period?: Pick<FiscalPeriod, "status">;
|
|
43
|
-
/**
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
allow?: "closed" | "locked";
|
|
60
|
+
/** `closed`: into a closed period too (the year end, the accountant later). Never locked. */
|
|
61
|
+
allow?: "closed";
|
|
62
|
+
/** The administration's own currency; `EUR` when unset. */
|
|
63
|
+
functionalCurrency?: string;
|
|
48
64
|
}): EntryProblem[];
|
|
49
65
|
/** `"MEM-2026-0042"`. A split year numbers under the year it starts in. */
|
|
50
66
|
export declare function entryNumber(journalCode: string, fiscalYear: string, seq: number): string;
|
|
51
67
|
/** The fields the hash covers: everything that says what was booked, where, by whom, after what. */
|
|
52
68
|
export type HashedEntry = Omit<JournalEntry, "id" | "organizationId" | "hash" | "createdAt">;
|
|
69
|
+
/**
|
|
70
|
+
* Numbers through `Number()`: a store that returns INT8 as a string (Mervyn) must hash the same.
|
|
71
|
+
* Lines are taken as stored, so an entry from before a field existed keeps its hash.
|
|
72
|
+
*/
|
|
53
73
|
export declare function hashedPartOf(entry: JournalEntry | HashedEntry): HashedEntry;
|
|
54
74
|
/**
|
|
55
75
|
* Canonical JSON: keys sorted at every depth, `undefined` dropped. The same entry always gives the
|
|
56
76
|
* same string, so a re-computed hash only differs when something was changed.
|
|
57
77
|
*/
|
|
58
78
|
export declare function canonicalJson(value: unknown): string;
|
|
59
|
-
/**
|
|
79
|
+
/**
|
|
80
|
+
* The side a line's VAT counts on. A line booked before `taxSide` existed is guessed from its
|
|
81
|
+
* account, as the return used to: a revenue account is a sale, anything else a purchase.
|
|
82
|
+
*/
|
|
83
|
+
export declare function taxSideOf(line: Pick<JournalLineData, "taxSide">, account: Pick<LedgerAccount, "type"> | undefined): "sales" | "purchase";
|
|
84
|
+
/**
|
|
85
|
+
* A reversal: the same lines, every amount the other way. The tax point stays; the return it
|
|
86
|
+
* counts in follows from `JournalLine.vatDate` (the next open one when that one was filed).
|
|
87
|
+
*/
|
|
60
88
|
export declare function reversedLines(lines: readonly JournalLineData[]): JournalLineData[];
|
|
61
89
|
export interface DocumentPostingContext {
|
|
62
90
|
accounts: readonly LedgerAccount[];
|
|
63
|
-
rules
|
|
64
|
-
|
|
91
|
+
/** `BookkeepingBinding.ledgerMapping`: the only rules there are. The account id in our books. */
|
|
92
|
+
ledgerMapping?: readonly LedgerMappingRule[];
|
|
93
|
+
/** For `deductiblePercent`: the part of input VAT not deductible is cost, not VAT to reclaim. */
|
|
94
|
+
taxCodes?: readonly TaxCode[];
|
|
65
95
|
/** The administration's own currency; `EUR` when unset. */
|
|
66
96
|
functionalCurrency?: string;
|
|
67
97
|
}
|
|
@@ -74,6 +104,14 @@ export type DocumentEntry = {
|
|
|
74
104
|
ok: false;
|
|
75
105
|
problem: string;
|
|
76
106
|
};
|
|
107
|
+
/**
|
|
108
|
+
* A sale or a purchase as balanced lines (plan 039 §4.6). A sale: debtors debit the gross, revenue
|
|
109
|
+
* credit per line, VAT payable credit per code. A purchase the mirror, on creditors and VAT to
|
|
110
|
+
* reclaim. A credit note needs nothing of its own: its amounts are already negative.
|
|
111
|
+
*
|
|
112
|
+
* ponytail: a reverse-charge purchase books no self-assessed VAT yet (both sides of box 4); the
|
|
113
|
+
* VAT return in step 7 adds it.
|
|
114
|
+
*/
|
|
77
115
|
/**
|
|
78
116
|
* The lines of a sale or purchase that run over more than one calendar month: a year of M365
|
|
79
117
|
* invoiced in October is not October's revenue or cost. Own books take these through the
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BookingDocument } from '../../platform/bookkeeping';
|
|
2
2
|
import { Cents } from '../money/money';
|
|
3
|
+
import { LineDimensions } from '../transaction/types';
|
|
3
4
|
/**
|
|
4
5
|
* Our own books (plan 039 datamodel §4). One row per posting with its lines as a column, a hash
|
|
5
6
|
* chain and gapless numbers guarded by unique indexes, and a line table that is only ever derived.
|
|
@@ -36,8 +37,14 @@ export interface LedgerAccount {
|
|
|
36
37
|
}
|
|
37
38
|
export type LedgerAccountRole = "debtors" | "creditors" | "vat_payable" | "vat_receivable" | "revenue_default" | "expense_default" | "suspense" | "result"
|
|
38
39
|
/** Where the difference lands when a foreign document is paid at another rate than booked. */
|
|
39
|
-
| "fx_difference"
|
|
40
|
+
| "fx_difference"
|
|
41
|
+
/** What a filed VAT return moves 1500/1510 to: the amount owed to (or due from) the authority. */
|
|
42
|
+
| "vat_settlement"
|
|
43
|
+
/** The cents a VAT return drops by rounding to whole euros. */
|
|
44
|
+
| "vat_rounding";
|
|
40
45
|
export type JournalKind = "sales" | "purchase" | "bank" | "cash" | "memorial" | "opening";
|
|
46
|
+
/** Where a person may post by hand (Exact type 90/10): a bank journal moves only with its lines. */
|
|
47
|
+
export declare const MANUAL_JOURNAL_KINDS: readonly JournalKind[];
|
|
41
48
|
export interface Journal {
|
|
42
49
|
id: string;
|
|
43
50
|
organizationId: string;
|
|
@@ -60,7 +67,10 @@ export interface FiscalPeriod {
|
|
|
60
67
|
index: number;
|
|
61
68
|
from: string;
|
|
62
69
|
to: string;
|
|
63
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* open: post freely. closed: accountant only. locked: nobody, after the year end. A VAT return
|
|
72
|
+
* locks nothing: a late line counts in the next return through `JournalLine.vatDate`.
|
|
73
|
+
*/
|
|
64
74
|
status: "open" | "closed" | "locked";
|
|
65
75
|
}
|
|
66
76
|
/**
|
|
@@ -82,23 +92,28 @@ export interface YearEnd {
|
|
|
82
92
|
closedAt: number;
|
|
83
93
|
closedBy: string;
|
|
84
94
|
}
|
|
85
|
-
/**
|
|
86
|
-
|
|
95
|
+
/**
|
|
96
|
+
* A line as it sits in `JournalEntry.lines`. Debit positive, credit negative; the sum is zero.
|
|
97
|
+
* Hashed: this shape is frozen from the first production entry. The B1 dimensions are columns.
|
|
98
|
+
*/
|
|
99
|
+
export interface JournalLineData extends LineDimensions {
|
|
87
100
|
accountId: string;
|
|
88
101
|
amountCents: Cents;
|
|
89
102
|
currency: string;
|
|
103
|
+
/**
|
|
104
|
+
* Functional = foreign × rate, as a decimal string. Set on every line of a converted document;
|
|
105
|
+
* absent when the document is in the administration's own currency (absent means 1).
|
|
106
|
+
*/
|
|
90
107
|
fxRate?: string;
|
|
91
108
|
functionalCents: Cents;
|
|
92
109
|
/** `TaxCode.key`, the VAT of this line, and when it counts. */
|
|
93
110
|
taxCode?: string;
|
|
111
|
+
/** Which side of the return the code counts on: set with `taxCode`, never one without the other. */
|
|
112
|
+
taxSide?: "sales" | "purchase";
|
|
94
113
|
taxCents?: Cents;
|
|
95
114
|
taxPointDate?: string;
|
|
96
115
|
subAccountId?: string;
|
|
97
|
-
costCenter?: string;
|
|
98
|
-
/** A work project as cost carrier. */
|
|
99
|
-
projectId?: string;
|
|
100
116
|
counterpartyCompanyId?: string;
|
|
101
|
-
dimensions?: Record<string, string>;
|
|
102
117
|
description?: string;
|
|
103
118
|
}
|
|
104
119
|
export interface JournalEntry {
|
|
@@ -130,6 +145,11 @@ export interface JournalEntry {
|
|
|
130
145
|
dueOn?: string;
|
|
131
146
|
};
|
|
132
147
|
lines: JournalLineData[];
|
|
148
|
+
/**
|
|
149
|
+
* The party of a posted document as it went out (review R2): the EC sales list and the audit
|
|
150
|
+
* file read names and VAT numbers here, never crm. Hashed; absent on a manual entry.
|
|
151
|
+
*/
|
|
152
|
+
counterparty?: BookingDocument["counterparty"];
|
|
133
153
|
/** The entry this one reverses. The reversed entry itself is never changed. */
|
|
134
154
|
reversesEntryId?: string;
|
|
135
155
|
attachment?: {
|
|
@@ -155,31 +175,9 @@ export interface JournalLine extends JournalLineData {
|
|
|
155
175
|
date: string;
|
|
156
176
|
periodId: string;
|
|
157
177
|
journalId: string;
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
businessEntityId: string;
|
|
164
|
-
appliesTo: {
|
|
165
|
-
direction: BookingDocument["direction"];
|
|
166
|
-
kind?: BookingDocument["kind"];
|
|
167
|
-
};
|
|
168
|
-
match: {
|
|
169
|
-
productId?: string;
|
|
170
|
-
ledgerCategoryKey?: string;
|
|
171
|
-
taxRateKey?: string;
|
|
172
|
-
};
|
|
173
|
-
/** Revenue or expense account for the net line. */
|
|
174
|
-
accountId: string;
|
|
175
|
-
order: number;
|
|
176
|
-
}
|
|
177
|
-
/** Which account the VAT of a key lands on. Missing = the account with the VAT role. */
|
|
178
|
-
export interface TaxAccountMapping {
|
|
179
|
-
id: string;
|
|
180
|
-
organizationId: string;
|
|
181
|
-
businessEntityId: string;
|
|
182
|
-
taxKey: string;
|
|
183
|
-
payableAccountId?: string;
|
|
184
|
-
receivableAccountId?: string;
|
|
178
|
+
/**
|
|
179
|
+
* The day the VAT return counts this line on (lines with a `taxCode` only): its tax point, or
|
|
180
|
+
* the day after the last return filed before it was posted. Derived, outside the hash.
|
|
181
|
+
*/
|
|
182
|
+
vatDate?: string;
|
|
185
183
|
}
|
|
@@ -31,7 +31,10 @@ export interface XafInput {
|
|
|
31
31
|
};
|
|
32
32
|
};
|
|
33
33
|
relations: {
|
|
34
|
+
/** The company id: what a transaction line's `counterpartyCompanyId` points at. */
|
|
34
35
|
id: string;
|
|
36
|
+
/** Its debtor or creditor number at this administration: the `custSupID` when given. */
|
|
37
|
+
number?: string;
|
|
35
38
|
name: string;
|
|
36
39
|
commerceNr?: string;
|
|
37
40
|
vatNumber?: string;
|