@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
|
@@ -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;
|
|
@@ -30,6 +30,8 @@ export interface TaxRate {
|
|
|
30
30
|
* line from this, and the bookkeeping connector maps it onto its own tax code.
|
|
31
31
|
*/
|
|
32
32
|
export type TaxRateKind = "standard" | "reduced" | "zero" | "reverse_charge" | "exempt";
|
|
33
|
+
/** The rate a line falls back to when neither the article nor the caller names one. */
|
|
34
|
+
export declare const DEFAULT_TAX_RATE_KEY = "high";
|
|
33
35
|
/** The Dutch defaults an organisation starts with. It may edit them; it may not compute them. */
|
|
34
36
|
export declare const NL_TAX_RATES: readonly TaxRate[];
|
|
35
37
|
/**
|
|
@@ -67,11 +69,15 @@ export interface TaxCode {
|
|
|
67
69
|
selfAssessed?: boolean;
|
|
68
70
|
/** Counts in the EC sales list (ICP). */
|
|
69
71
|
icp?: boolean;
|
|
72
|
+
/** Which column of the EC sales list: absent on an ICP code = services. */
|
|
73
|
+
icpKind?: IcpKind;
|
|
70
74
|
/** Deductible share of input VAT, mixed use. Absent = 100. */
|
|
71
75
|
deductiblePercent?: number;
|
|
72
76
|
archived?: boolean;
|
|
73
77
|
order?: number;
|
|
74
78
|
}
|
|
79
|
+
/** The EC sales list reports goods, services and triangular (ABC) supplies apart. */
|
|
80
|
+
export type IcpKind = "goods" | "services" | "triangular";
|
|
75
81
|
export interface TaxCodeRate {
|
|
76
82
|
/** `"2019-01-01"`. Days, compared as strings. */
|
|
77
83
|
validFrom: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SalesLine, TransactionTotals } from '../transaction/types';
|
|
2
2
|
import { Cents } from './money';
|
|
3
3
|
import { TaxRate } from './tax';
|
|
4
4
|
/**
|
|
@@ -19,10 +19,10 @@ import { TaxRate } from './tax';
|
|
|
19
19
|
* of the line total — `priceOver`, so the line total is rounded once and then split by calendar.
|
|
20
20
|
* Without a service period (a quote) it is one period's amount.
|
|
21
21
|
*/
|
|
22
|
-
export declare function lineNet(line: Pick<
|
|
22
|
+
export declare function lineNet(line: Pick<SalesLine, "kind" | "quantity" | "unitPriceCents" | "discountPercent" | "pricePer" | "servicePeriod">): Cents;
|
|
23
23
|
export interface PricedTransaction {
|
|
24
24
|
/** The same lines with `netCents` and `taxCents` filled in. */
|
|
25
|
-
lines:
|
|
25
|
+
lines: SalesLine[];
|
|
26
26
|
totals: TransactionTotals;
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
@@ -36,6 +36,6 @@ export interface PricedTransaction {
|
|
|
36
36
|
* rate, because that is a property of the sale and not of the product.
|
|
37
37
|
*
|
|
38
38
|
* An **optional** line is priced like any other and then left out of every sum — see
|
|
39
|
-
* `
|
|
39
|
+
* `SalesLine.optional`.
|
|
40
40
|
*/
|
|
41
|
-
export declare function transactionTotals(lines: readonly
|
|
41
|
+
export declare function transactionTotals(lines: readonly SalesLine[], rates: readonly TaxRate[], overrideKey?: string): PricedTransaction;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { DeliverTo, SupplierOffer } from './types';
|
|
2
|
+
/** A hand-set stand ("called, they have 5") counts for a day (plan 045 B.6). */
|
|
3
|
+
export declare const MANUAL_STOCK_FRESH_MS: number;
|
|
4
|
+
/** What one need asks of a source. */
|
|
5
|
+
export interface OfferNeed {
|
|
6
|
+
/** Base units. */
|
|
7
|
+
quantity: number;
|
|
8
|
+
/** The sale's commitment (`Commitment.termMonths`); absent = cancel any time. */
|
|
9
|
+
termMonths?: number;
|
|
10
|
+
/** `own` through our warehouse, anything else straight to the customer. */
|
|
11
|
+
deliverTo?: DeliverTo["kind"];
|
|
12
|
+
/** The delivery check the sale was made on: only what it found available qualifies (6c). */
|
|
13
|
+
/**
|
|
14
|
+
* The offers a delivery check found deliverable. `vendorSku` tells products apart that share
|
|
15
|
+
* one provider offer (every Nextpertise connection is `connection`, 045 D N-4).
|
|
16
|
+
*/
|
|
17
|
+
qualified?: readonly {
|
|
18
|
+
app: string;
|
|
19
|
+
offer: string;
|
|
20
|
+
vendorSku?: string;
|
|
21
|
+
}[];
|
|
22
|
+
/** The administration's currency; prices in another one need `rates`. */
|
|
23
|
+
currency: string;
|
|
24
|
+
/** Units of `currency` per one unit of the key (ECB, of the day). */
|
|
25
|
+
rates?: Readonly<Record<string, number>>;
|
|
26
|
+
/** A person's pick: it stands, even when it no longer fits — the reason still shows. */
|
|
27
|
+
pinned?: string;
|
|
28
|
+
}
|
|
29
|
+
/** Known enough, unknown (no feed, stale, or a count the supplier does not give), known short. */
|
|
30
|
+
export type OfferStock = "enough" | "unknown" | "short";
|
|
31
|
+
export type Unsuitable = "invalid" | "term" | "dropship" | "qualification";
|
|
32
|
+
export interface RankedOffer<T extends SupplierOffer = SupplierOffer> {
|
|
33
|
+
offer: T;
|
|
34
|
+
stock: OfferStock;
|
|
35
|
+
/** What the supplier said, when fresh. */
|
|
36
|
+
qty?: number;
|
|
37
|
+
/** Per product unit over a year, in the administration's currency; `null` = no price to compare. */
|
|
38
|
+
unitCents: number | null;
|
|
39
|
+
leadDays?: number;
|
|
40
|
+
unsuitable?: Unsuitable;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Why the chosen one: the preferred offer (`preferred`), the preferred one was short
|
|
44
|
+
* (`preferred_short`, chosen is the next best), only one qualified (`only`), the best of equals
|
|
45
|
+
* (`best`), nobody has enough (`short`: chosen has the most, the rest is a person's split), or a
|
|
46
|
+
* person picked it (`picked`).
|
|
47
|
+
*/
|
|
48
|
+
export type ChoiceWhy = "preferred" | "preferred_short" | "only" | "best" | "short" | "picked";
|
|
49
|
+
export interface OfferChoice<T extends SupplierOffer = SupplierOffer> {
|
|
50
|
+
chosen: RankedOffer<T> | null;
|
|
51
|
+
why?: ChoiceWhy;
|
|
52
|
+
/** Every other offer, best first; the unsuitable last with their reason. */
|
|
53
|
+
alternatives: RankedOffer<T>[];
|
|
54
|
+
/** What `unitCents` is in: the administration's currency. */
|
|
55
|
+
currency: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The best source for one need (plan 045 B.2): suitability first, then stock, then price. Policy
|
|
59
|
+
* (Vincent 03-10): the preferred offer (`isDefault`) wins unless it is known short; the cheaper one
|
|
60
|
+
* is a hint in the alternatives. Nobody enough: the one with the most, never a split.
|
|
61
|
+
*/
|
|
62
|
+
export declare function chooseOffer<T extends SupplierOffer>(offers: readonly T[], need: OfferNeed, now: number): OfferChoice<T>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Period } from '../agreement/period';
|
|
2
|
-
import { Agreement, AgreementLine } from '../agreement/types';
|
|
2
|
+
import { Agreement, AgreementLine, LinePrice } from '../agreement/types';
|
|
3
3
|
import { Cents } from '../money/money';
|
|
4
4
|
/** A sales line, followed through its changes: the agreement and the series it belongs to. */
|
|
5
5
|
export interface SalesLineRef {
|
|
@@ -7,24 +7,28 @@ export interface SalesLineRef {
|
|
|
7
7
|
seriesId: string;
|
|
8
8
|
}
|
|
9
9
|
/**
|
|
10
|
-
* A subscription at a supplier
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* A subscription at a supplier, one row in `purchase_contract_line` (review R5): its `price` is the
|
|
11
|
+
* snapshot taken when it was made — an offer that gets dearer later changes nothing here; a new
|
|
12
|
+
* price is a successor row in the same series from a date. What was invoiced is `purchase_match`.
|
|
13
13
|
*/
|
|
14
|
-
export interface
|
|
14
|
+
export interface SupplierContractLine extends Pick<AgreementLine, "id" | "productId" | "name" | "unitKey" | "factor" | "commitment" | "quantity" | "endsAt"> {
|
|
15
|
+
/** The supplier's price, a snapshot taken when the row was made. */
|
|
16
|
+
price?: LinePrice;
|
|
17
|
+
contractId: string;
|
|
18
|
+
/** One subscription through its changes; the first row's own id. */
|
|
19
|
+
seriesId: string;
|
|
20
|
+
startsAt: number;
|
|
15
21
|
/** Provenance only: the offer it was bought on. The price is `price`, not the offer's. */
|
|
16
22
|
offerId?: string;
|
|
17
|
-
/** Their subscription id (Pax8, Microsoft). */
|
|
23
|
+
/** Their subscription id (Pax8, Microsoft): what a supplier invoice line is matched on. */
|
|
18
24
|
externalRef?: string;
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
externalRef?: string;
|
|
25
|
-
};
|
|
25
|
+
/**
|
|
26
|
+
* The fulfilment item this pays for (047 step 6): its sale, what it runs on and what the supplier
|
|
27
|
+
* handed back live there. A line without one is purchase's own (rent, a contract by hand).
|
|
28
|
+
*/
|
|
29
|
+
itemId?: string;
|
|
26
30
|
customerCompanyId?: string;
|
|
27
|
-
/**
|
|
31
|
+
/** A line by hand: the sales line that passes it on. A line with `itemId` reads the item's. */
|
|
28
32
|
salesLine?: SalesLineRef;
|
|
29
33
|
/**
|
|
30
34
|
* `variable`: no price, the invoice decides the amount (transit minutes). Nothing is expected;
|
|
@@ -34,18 +38,24 @@ export interface PurchaseAgreementLine extends AgreementLine {
|
|
|
34
38
|
expected?: "variable";
|
|
35
39
|
/** Days from each term's start in which the supplier still takes a change (NCE: 7). */
|
|
36
40
|
changeWindowDays?: number;
|
|
37
|
-
/**
|
|
41
|
+
/** `lineKey` of the order line it came from; a successor shares it, so it is not unique. */
|
|
38
42
|
sourceKey?: string;
|
|
39
|
-
/** What supplier invoices said per period (fase 7): the history a variable line is judged on. */
|
|
40
|
-
invoiced?: {
|
|
41
|
-
from: number;
|
|
42
|
-
cents: Cents;
|
|
43
|
-
}[];
|
|
44
43
|
}
|
|
45
|
-
/**
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
/**
|
|
45
|
+
* A supplier contract's header, one per supplier × administration (044): no sales fields, no
|
|
46
|
+
* lines — those are rows of their own. `companyId` is the supplier.
|
|
47
|
+
*/
|
|
48
|
+
export interface SupplierContract extends Pick<Agreement, "id" | "organizationId" | "businessEntityId" | "title" | "companyId" | "currency" | "status" | "startsAt" | "endsAt" | "commitment" | "createdBy" | "createdAt" | "updatedAt"> {
|
|
48
49
|
}
|
|
50
|
+
/** A header with its rows, read together for a computation over the whole contract. */
|
|
51
|
+
export type SupplierContractWithLines = SupplierContract & {
|
|
52
|
+
lines: readonly SupplierContractLine[];
|
|
53
|
+
};
|
|
54
|
+
/** What supplier invoices said per period, per line id: derived from `purchase_match`. */
|
|
55
|
+
export type InvoicedHistory = ReadonlyMap<string, readonly {
|
|
56
|
+
from: number;
|
|
57
|
+
cents: Cents;
|
|
58
|
+
}[]>;
|
|
49
59
|
export interface ExpectedLine {
|
|
50
60
|
lineId: string;
|
|
51
61
|
kind: "fixed" | "count" | "variable";
|
|
@@ -57,7 +67,9 @@ export interface ExpectedLine {
|
|
|
57
67
|
* the days it ran (the same `lineNet` the sales run bills with), or "count" / "variable" where the
|
|
58
68
|
* amount is not ours to know in advance.
|
|
59
69
|
*/
|
|
60
|
-
export declare function expectedFor(agreement: Pick<
|
|
70
|
+
export declare function expectedFor(agreement: Pick<SupplierContract, "startsAt" | "endsAt"> & {
|
|
71
|
+
lines: readonly SupplierContractLine[];
|
|
72
|
+
}, window: Period): ExpectedLine[];
|
|
61
73
|
/**
|
|
62
74
|
* A variable amount that moved more than `threshold` against the average of the (up to) three
|
|
63
75
|
* periods before: that is work for a person, not a number to wave through.
|
|
@@ -73,6 +85,11 @@ export interface SalesLineState extends SalesLineRef {
|
|
|
73
85
|
unbilled: Period[];
|
|
74
86
|
/** The sales line has ended or its agreement is not active. */
|
|
75
87
|
ended?: boolean;
|
|
88
|
+
/** The last period invoiced and how many it billed: "gefactureerd" on Producten bij klanten. */
|
|
89
|
+
billed?: {
|
|
90
|
+
quantity: number;
|
|
91
|
+
period: Period;
|
|
92
|
+
};
|
|
76
93
|
}
|
|
77
94
|
export type ContractSignal = {
|
|
78
95
|
kind: "not_covered";
|
|
@@ -111,6 +128,8 @@ export interface SignalOptions {
|
|
|
111
128
|
noticeDays?: number;
|
|
112
129
|
/** A change window closing this soon is a reminder. */
|
|
113
130
|
windowDays?: number;
|
|
131
|
+
/** What was invoiced per line, for the variable jump. */
|
|
132
|
+
invoiced?: InvoicedHistory;
|
|
114
133
|
}
|
|
115
134
|
/**
|
|
116
135
|
* Everything about a supplier contract a person should look at, apart:
|
|
@@ -121,4 +140,4 @@ export interface SignalOptions {
|
|
|
121
140
|
* - **notice due / change window**: reminders before the dates that decide the next term;
|
|
122
141
|
* - **variable jump**: a variable amount moved more than 30%.
|
|
123
142
|
*/
|
|
124
|
-
export declare function contractSignals(contracts: readonly
|
|
143
|
+
export declare function contractSignals(contracts: readonly SupplierContractWithLines[], sales: readonly SalesLineState[], now: number, options?: SignalOptions): ContractSignal[];
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Agreement } from '../agreement/types';
|
|
3
|
-
import { PurchaseAgreement } from './contract';
|
|
4
|
-
import { SupplierOffer } from './types';
|
|
1
|
+
import { ProvisioningAction } from '../../platform/provisioning';
|
|
2
|
+
import { Agreement, AgreementLine } from '../agreement/types';
|
|
5
3
|
/** One thing to order, change or end, as "Te bestellen" lists it. */
|
|
6
4
|
export interface DemandItem {
|
|
7
5
|
/** Stable: the sales series, or the customer's account at the supplier. */
|
|
@@ -18,14 +16,6 @@ export interface DemandItem {
|
|
|
18
16
|
targetQuantity?: number;
|
|
19
17
|
from?: number;
|
|
20
18
|
customerCompanyId: string;
|
|
21
|
-
salesLine?: {
|
|
22
|
-
agreementId: string;
|
|
23
|
-
seriesId: string;
|
|
24
|
-
};
|
|
25
|
-
contractLine?: {
|
|
26
|
-
contractId: string;
|
|
27
|
-
lineId: string;
|
|
28
|
-
};
|
|
29
19
|
/** Epoch ms it takes effect: the term's end for an end or a reduction outside the window. */
|
|
30
20
|
effectiveAt?: number;
|
|
31
21
|
/** The last day to send it for `effectiveAt`; past it, `effectiveAt` is the next term's end. */
|
|
@@ -36,33 +26,27 @@ export interface DemandItem {
|
|
|
36
26
|
nextTerm?: boolean;
|
|
37
27
|
/** The purchase runs on after the sale ends: we pay until then. */
|
|
38
28
|
runsOnUntil?: number;
|
|
39
|
-
/**
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
29
|
+
/**
|
|
30
|
+
* An end at a provider that prices it (045 D N-2): what ending costs, shown before "Maak
|
|
31
|
+
* concept" and put on the order as it was shown. `costUnknown`: the provider gave no answer.
|
|
32
|
+
*/
|
|
33
|
+
cost?: {
|
|
34
|
+
parts: {
|
|
35
|
+
label: string;
|
|
36
|
+
cents: number;
|
|
37
|
+
recurring?: "month";
|
|
38
|
+
}[];
|
|
39
|
+
warnings?: string[];
|
|
45
40
|
};
|
|
41
|
+
costUnknown?: boolean;
|
|
42
|
+
/** The term it is ordered for: the offer's, else the sale's (045 D N-3). The price is asked on it. */
|
|
43
|
+
termMonths?: number;
|
|
44
|
+
/** The request's answers (the site as a crm address id): what a per-order price is asked on. */
|
|
45
|
+
params?: Record<string, string>;
|
|
46
|
+
/** The request this waits for: the customer's account before its numbers. */
|
|
47
|
+
waitsFor?: string;
|
|
46
48
|
}
|
|
47
|
-
export
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
/** Provider describes, by `app:offer`. */
|
|
52
|
-
provisionable: ReadonlyMap<string, ProvisionableOffer>;
|
|
53
|
-
/** Keys already on an order that has not settled: never proposed twice. */
|
|
54
|
-
open: ReadonlySet<string>;
|
|
55
|
-
now: number;
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* What to order, change or end so purchase follows sales (fase 9). Per sales series with a fixed
|
|
59
|
-
* count and a default offer:
|
|
60
|
-
* - no contract line passes it on: buy the count;
|
|
61
|
-
* - the contract has fewer: one change to the new count;
|
|
62
|
-
* - the contract has more: lower it now inside the supplier's change window, else do not renew
|
|
63
|
-
* the difference at the term's end;
|
|
64
|
-
* - the sale has an end: end the purchase at the first term end the notice still reaches, with
|
|
65
|
-
* the deadline to send it by, and a signal when we pay on after the customer stopped.
|
|
66
|
-
* An item that needs the customer's account at the supplier gets that account first.
|
|
67
|
-
*/
|
|
68
|
-
export declare function demandFor(input: DemandInput): DemandItem[];
|
|
49
|
+
export declare const seriesOf: (line: AgreementLine) => string;
|
|
50
|
+
/** The line of a series that runs on `at`, else the one that starts next, else its last. */
|
|
51
|
+
export declare function currentOf<T extends AgreementLine>(parent: Pick<Agreement, "startsAt" | "endsAt">, lines: readonly T[], at: number): T;
|
|
52
|
+
export declare function bySeries<T extends AgreementLine>(lines: readonly T[]): Map<string, T[]>;
|
|
@@ -6,11 +6,12 @@ import { OfferAvailability, SupplierOffer } from './types';
|
|
|
6
6
|
* turned into a product or an offer by itself.
|
|
7
7
|
*/
|
|
8
8
|
/** The columns a feed can fill. `vendorSku` or `gtin` is the key; the rest is optional. */
|
|
9
|
-
export type FeedColumn = "vendorSku" | "gtin" | "description" | "brand" | "group" | "cost" | "list" | "currency" | "stock" | "leadDays";
|
|
9
|
+
export type FeedColumn = "vendorSku" | "gtin" | "description" | "brand" | "group" | "cost" | "list" | "currency" | "stock" | "leadDays" | "lotSize" | "dropship";
|
|
10
10
|
export declare const FEED_COLUMNS: readonly FeedColumn[];
|
|
11
11
|
/** Per column, the header it is read from. Set once (the AI proposes, a person approves). */
|
|
12
12
|
export type FeedMapping = Partial<Record<FeedColumn, string>>;
|
|
13
|
-
|
|
13
|
+
/** `api`: the assortment from a provisioning app (plan 045 D N-1) instead of a file. */
|
|
14
|
+
export type FeedSource = "upload" | "mail" | "storage" | "api";
|
|
14
15
|
/** How often a new file is expected; it decides how long a stock figure counts as fresh. */
|
|
15
16
|
export type FeedEvery = "day" | "week" | "month";
|
|
16
17
|
export declare const FEED_EVERY_MS: Record<FeedEvery, number>;
|
|
@@ -23,6 +24,11 @@ export interface SupplierFeed {
|
|
|
23
24
|
supplierCompanyId: string;
|
|
24
25
|
name?: string;
|
|
25
26
|
source: FeedSource;
|
|
27
|
+
/** For `api`: the app that lists its assortment, and which of its connections. */
|
|
28
|
+
api?: {
|
|
29
|
+
app: string;
|
|
30
|
+
accountId: string;
|
|
31
|
+
};
|
|
26
32
|
/** For `storage`: the folder it reads the newest csv from (a dated file each time is fine). */
|
|
27
33
|
storage?: {
|
|
28
34
|
mountId: string;
|
|
@@ -61,6 +67,10 @@ export interface FeedRow {
|
|
|
61
67
|
/** `null`: the file says nothing about stock, or "on request". */
|
|
62
68
|
stock?: number | null;
|
|
63
69
|
leadDays?: number;
|
|
70
|
+
lotSize?: number;
|
|
71
|
+
dropship?: SupplierOffer["dropship"];
|
|
72
|
+
/** From an `api` feed: the provider's offer key a new offer is ordered through. */
|
|
73
|
+
offer?: string;
|
|
64
74
|
}
|
|
65
75
|
export interface FeedReadResult {
|
|
66
76
|
rows: FeedRow[];
|
|
@@ -96,8 +106,9 @@ export type FeedMatch = {
|
|
|
96
106
|
export declare function matchFeed(rows: readonly FeedRow[], offers: readonly SupplierOffer[], products: readonly FeedProduct[]): FeedMatch[];
|
|
97
107
|
export interface OfferChange {
|
|
98
108
|
offerId: string;
|
|
99
|
-
set: Partial<Pick<SupplierOffer, "costCents" | "listCents" | "currency" | "vendorSku">> & {
|
|
100
|
-
|
|
109
|
+
set: Partial<Pick<SupplierOffer, "costCents" | "listCents" | "currency" | "vendorSku" | "lotSize" | "dropship" | "validTo">> & {
|
|
110
|
+
/** Absent only when an `api` feed no longer lists it: then it ends (`validTo`). */
|
|
111
|
+
availability?: OfferAvailability;
|
|
101
112
|
};
|
|
102
113
|
/** A price moved more than the feed's threshold; applied, and said. */
|
|
103
114
|
jump?: {
|
|
@@ -116,6 +127,8 @@ export interface FeedUnmatched {
|
|
|
116
127
|
costCents?: Cents;
|
|
117
128
|
/** An article we have, with no offer from this supplier yet: "make an offer" is one click. */
|
|
118
129
|
productId?: string;
|
|
130
|
+
/** From an `api` feed: the provider's offer key (045 D N-1). */
|
|
131
|
+
offer?: string;
|
|
119
132
|
}
|
|
120
133
|
export interface FeedOutcome {
|
|
121
134
|
changes: OfferChange[];
|
|
@@ -129,7 +142,7 @@ export interface FeedOutcome {
|
|
|
129
142
|
* What the run writes. Every matched offer gets a fresh stock stamp — the freshness is the
|
|
130
143
|
* point of a feed; price, advice price and currency only when the file has them.
|
|
131
144
|
*/
|
|
132
|
-
export declare function feedOutcome(matches: readonly FeedMatch[], offers: readonly SupplierOffer[], now: number, jumpPercent?: number): FeedOutcome;
|
|
145
|
+
export declare function feedOutcome(matches: readonly FeedMatch[], offers: readonly SupplierOffer[], now: number, jumpPercent?: number, every?: FeedEvery): FeedOutcome;
|
|
133
146
|
/**
|
|
134
147
|
* A first mapping from the header alone: every exact word first, then a header that starts with
|
|
135
148
|
* one — so "Productgroep" is the group before "product" claims it as the description.
|
|
@@ -168,3 +181,38 @@ export interface FeedImportStatus {
|
|
|
168
181
|
startedAt: number;
|
|
169
182
|
finishedAt?: number;
|
|
170
183
|
}
|
|
184
|
+
/** A run as a screen reads it: the work left is a count, not the list of writes. */
|
|
185
|
+
export interface FeedRunView {
|
|
186
|
+
id: string;
|
|
187
|
+
organizationId: string;
|
|
188
|
+
feedId: string;
|
|
189
|
+
state: "applying" | "done" | "failed";
|
|
190
|
+
/** Why it failed: `feed_no_key`, `feed_missing_headers`. */
|
|
191
|
+
reason?: string;
|
|
192
|
+
missingHeaders?: string[];
|
|
193
|
+
rows: number;
|
|
194
|
+
errors: {
|
|
195
|
+
line: number;
|
|
196
|
+
message: string;
|
|
197
|
+
}[];
|
|
198
|
+
/** Offers updated; `unchanged` of them only had their freshness renewed. */
|
|
199
|
+
updated: number;
|
|
200
|
+
unchanged: number;
|
|
201
|
+
gone: number;
|
|
202
|
+
jumps: {
|
|
203
|
+
offerId: string;
|
|
204
|
+
fromCents: number;
|
|
205
|
+
toCents: number;
|
|
206
|
+
percent: number;
|
|
207
|
+
}[];
|
|
208
|
+
unmatched: FeedUnmatched[];
|
|
209
|
+
/** More lines than `unmatched` holds. */
|
|
210
|
+
unmatchedTotal: number;
|
|
211
|
+
applied: number;
|
|
212
|
+
pendingCount: number;
|
|
213
|
+
importJob?: FeedImportStatus;
|
|
214
|
+
startedAt: number;
|
|
215
|
+
finishedAt?: number;
|
|
216
|
+
createdBy: string;
|
|
217
|
+
createdAt?: number;
|
|
218
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export * from './choose';
|
|
1
2
|
export * from './contract';
|
|
2
3
|
export * from './demand';
|
|
3
4
|
export * from './feed';
|
|
@@ -6,3 +7,4 @@ export * from './logic';
|
|
|
6
7
|
export * from './match';
|
|
7
8
|
export * from './packing-slip';
|
|
8
9
|
export * from './types';
|
|
10
|
+
export * from './upsell';
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { TransactionKind } from '../transaction/kinds';
|
|
2
|
+
import { PurchaseStatus } from './types';
|
|
2
3
|
/**
|
|
3
4
|
* What `apps/purchase` issues: the same engine as a quote, its own table. `sent` is issued (a
|
|
4
5
|
* number and the paper); the supplier confirms, and the goods coming in make it `received`.
|
|
5
6
|
* Walking back one step stays allowed — a return reopens a received order.
|
|
6
7
|
*/
|
|
7
|
-
export declare const PURCHASE_KINDS: readonly TransactionKind[];
|
|
8
|
+
export declare const PURCHASE_KINDS: readonly TransactionKind<PurchaseStatus>[];
|
|
8
9
|
export declare const PURCHASE_ORDER_KIND = "purchase_order";
|
|
@@ -1,21 +1,39 @@
|
|
|
1
|
+
import { ProductTracking } from '../catalog/types';
|
|
1
2
|
import { PricePer } from '../money/period-price';
|
|
2
|
-
import { GoodsReceipt, GoodsReceiptLine, PurchaseLine, SupplierOffer } from './types';
|
|
3
|
+
import { GoodsReceipt, GoodsReceiptLine, InvoiceState, PurchaseLine, SupplierOffer } from './types';
|
|
3
4
|
/** What came in for one order line: booked receipts in, returns out. */
|
|
4
5
|
export declare function receivedFor(poLineId: string, receipts: readonly GoodsReceipt[]): number;
|
|
5
6
|
export type ReceiptState = "none" | "partial" | "full";
|
|
6
7
|
/** Over the product lines of an order. */
|
|
7
|
-
export declare function receiptState(lines: readonly Pick<PurchaseLine, "kind" | "quantity" | "receivedQty">[]): "none" | "
|
|
8
|
+
export declare function receiptState(lines: readonly Pick<PurchaseLine, "kind" | "quantity" | "receivedQty">[]): "none" | "full" | "partial";
|
|
9
|
+
type Billable = Pick<PurchaseLine, "kind" | "quantity" | "billedQty" | "act" | "unitPriceCents">;
|
|
10
|
+
/** A supplier invoice is expected for this line: a buy, or a change that costs something. */
|
|
11
|
+
export declare const expectsInvoice: (line: Billable) => boolean;
|
|
12
|
+
/** `full` when every line that expects an invoice is billed; derived by whoever writes the lines. */
|
|
13
|
+
export declare function invoiceState(lines: readonly Billable[]): InvoiceState;
|
|
8
14
|
export interface GoodsReceiptProblem {
|
|
9
|
-
code: "receipt_over_ordered" | "receipt_return_over_received" | "receipt_serials_count";
|
|
15
|
+
code: "receipt_over_ordered" | "receipt_return_over_received" | "receipt_serials_count" | "receipt_serials_required" | "receipt_batches_count" | "receipt_batches_required";
|
|
10
16
|
poLineId: string;
|
|
11
17
|
}
|
|
12
18
|
/**
|
|
13
19
|
* Why a receipt cannot be booked: more in than still open, more back than came in, or serial
|
|
14
|
-
* numbers that do not match the count in base units. No serials is fine
|
|
15
|
-
* must be all.
|
|
20
|
+
* numbers that do not match the count in base units. No serials is fine for bulk goods; some
|
|
21
|
+
* serials must be all. A serial article (046 `tracking`) comes in with every serial: without them
|
|
22
|
+
* a drop shipment can never be delivered (Exact v2 nr. 8). A batch article likewise with batches
|
|
23
|
+
* that add up, in base units.
|
|
24
|
+
*/
|
|
25
|
+
export declare function goodsReceiptProblems(receipt: Pick<GoodsReceipt, "movement" | "lines">, poLines: readonly Pick<PurchaseLine, "id" | "quantity" | "factor" | "productId">[], booked: readonly GoodsReceipt[], tracking?: ReadonlyMap<string, ProductTracking>): GoodsReceiptProblem[];
|
|
26
|
+
/** `<productId>#<serial>` for every serial on these lines: a serial is unique per article. */
|
|
27
|
+
export declare function serialKeysOf(lines: readonly Pick<GoodsReceiptLine, "poLineId" | "serials">[], poLines: readonly Pick<PurchaseLine, "id" | "productId">[]): string[];
|
|
28
|
+
/**
|
|
29
|
+
* Which of `keys` are in house already: booked in more often than sent back, over every receipt
|
|
30
|
+
* (any order). A serial that went back may come in again: a swap after a repair.
|
|
31
|
+
*/
|
|
32
|
+
export declare function serialsInHouse(keys: readonly string[], receipts: readonly Pick<GoodsReceipt, "movement" | "status" | "serialKeys">[]): string[];
|
|
33
|
+
/**
|
|
34
|
+
* Lines of a receipt worth keeping: a positive quantity, serials trimmed and unique, batches with
|
|
35
|
+
* a code and a positive quantity (base units).
|
|
16
36
|
*/
|
|
17
|
-
export declare function goodsReceiptProblems(receipt: Pick<GoodsReceipt, "movement" | "lines">, poLines: readonly Pick<PurchaseLine, "id" | "quantity" | "factor">[], booked: readonly GoodsReceipt[]): GoodsReceiptProblem[];
|
|
18
|
-
/** Lines of a receipt worth keeping: a positive quantity, serials trimmed and unique. */
|
|
19
37
|
export declare function cleanReceiptLines(lines: readonly GoodsReceiptLine[]): GoodsReceiptLine[];
|
|
20
38
|
/** Valid on `at`. */
|
|
21
39
|
export declare function offerValid(offer: Pick<SupplierOffer, "validFrom" | "validTo">, at: number): boolean;
|
|
@@ -28,6 +46,12 @@ export declare function defaultOffer<T extends SupplierOffer>(offers: readonly T
|
|
|
28
46
|
export declare function toProductUnits(source: {
|
|
29
47
|
factor?: number;
|
|
30
48
|
}, qty: number): number;
|
|
49
|
+
/**
|
|
50
|
+
* Base units to purchase units: a box of 10 for 12 pieces is 2 boxes. Raised to the offer's
|
|
51
|
+
* `minQty` (Exact v2 §5), then to a multiple of its `lotSize`; what is bought beyond the need goes
|
|
52
|
+
* to stock.
|
|
53
|
+
*/
|
|
54
|
+
export declare function purchaseUnits(base: number, factor: number | undefined, offer?: Pick<SupplierOffer, "minQty" | "lotSize">): number;
|
|
31
55
|
/**
|
|
32
56
|
* The offer's cost per product unit, as amount, currency and period — what is written back to the
|
|
33
57
|
* product. Never a monthly equivalent: € 222 per year stays € 222 per year.
|
|
@@ -39,3 +63,4 @@ export declare function productCost(offer: SupplierOffer): {
|
|
|
39
63
|
};
|
|
40
64
|
/** Offers side by side: each over one year, per product unit. A one-off stays itself. */
|
|
41
65
|
export declare function costOverYear(offer: SupplierOffer): number;
|
|
66
|
+
export {};
|