platform-types 1.10.712 → 1.10.714
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/cjs/index.js +1 -0
- package/dist/cjs/invoice.js +42 -1
- package/dist/cjs/mercadopago.js +3 -1
- package/dist/cjs/order.js +24 -0
- package/dist/cjs/orderCollectionAttempt.js +74 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/invoice.d.ts +126 -0
- package/dist/invoice.js +41 -0
- package/dist/mercadopago.d.ts +66 -4
- package/dist/mercadopago.js +3 -1
- package/dist/order.d.ts +23 -1
- package/dist/order.js +24 -0
- package/dist/orderCollectionAttempt.d.ts +163 -0
- package/dist/orderCollectionAttempt.js +71 -0
- package/dist/platform.d.ts +10 -7
- package/dist/subscription.d.ts +7 -10
- package/package.json +1 -1
package/dist/cjs/index.js
CHANGED
|
@@ -73,6 +73,7 @@ __exportStar(require("./mercadolibre.js"), exports);
|
|
|
73
73
|
__exportStar(require("./mercadopago.js"), exports);
|
|
74
74
|
__exportStar(require("./notification.js"), exports);
|
|
75
75
|
__exportStar(require("./order.js"), exports);
|
|
76
|
+
__exportStar(require("./orderCollectionAttempt.js"), exports);
|
|
76
77
|
__exportStar(require("./orderCreateAttempt.js"), exports);
|
|
77
78
|
__exportStar(require("./payment.js"), exports);
|
|
78
79
|
__exportStar(require("./platform.js"), exports);
|
package/dist/cjs/invoice.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.INVOICE_POST_VOUCHER_ERROR_CODES = void 0;
|
|
3
|
+
exports.INVOICE_ISSUANCE_REFUSAL_RECOVERY = exports.INVOICE_ISSUANCE_REFUSAL_CODES = exports.INVOICE_POST_VOUCHER_ERROR_CODES = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* The codes `POST /invoices` answers AFTER a voucher number was spent — ARCA
|
|
6
6
|
* was asked, or a CAEA number was claimed — as a runtime value the app maps.
|
|
@@ -32,3 +32,44 @@ exports.INVOICE_POST_VOUCHER_ERROR_CODES = [
|
|
|
32
32
|
'INVOICE_EXPORT_OUTCOME_UNKNOWN',
|
|
33
33
|
'CAEA_COMMIT_FAILED_AFTER_CLAIM',
|
|
34
34
|
];
|
|
35
|
+
/**
|
|
36
|
+
* The codes `POST /invoices` answers when it REFUSED to start an issuance — or
|
|
37
|
+
* could not confirm it — before any voucher of this request was recorded, as a
|
|
38
|
+
* runtime value a client maps. Distinct from
|
|
39
|
+
* {@link INVOICE_POST_VOUCHER_ERROR_CODES}: each has its own recovery, given by
|
|
40
|
+
* {@link INVOICE_ISSUANCE_REFUSAL_RECOVERY}.
|
|
41
|
+
*
|
|
42
|
+
* - `INVOICE_ISSUANCE_IN_PROGRESS` · 409 — another issuance of this order is
|
|
43
|
+
* live: the same request's idempotency lock, or another request holding the
|
|
44
|
+
* order's factura issuance guard inside its horizon. Also answered after the
|
|
45
|
+
* order read, when the guard's owner-conditioned pre-ARCA mark or attempt
|
|
46
|
+
* record finds the guard taken over by a successor — before that request's
|
|
47
|
+
* submit went on the wire, so it spent nothing. Retry the same body shortly.
|
|
48
|
+
* - `CAEA_CLAIM_AMBIGUOUS` · 503 — ARCA was down and the CAEA number claim could
|
|
49
|
+
* not be confirmed: the claim may have landed (an operator row records it), no
|
|
50
|
+
* invoice was recorded and nothing was sent to ARCA, and the request released
|
|
51
|
+
* its idempotency record. Retry the same body shortly — a retry claims again,
|
|
52
|
+
* so the worst case is one unused CAEA number, never a second voucher.
|
|
53
|
+
* - `INVOICE_IDEMPOTENCY_PAYLOAD_MISMATCH` · 409 — the request's key is bound to
|
|
54
|
+
* an issuance with a different voucher-shaping body (or to a record from
|
|
55
|
+
* before payload hashing, which matches nothing). It does NOT say a voucher
|
|
56
|
+
* exists on the order. Resend only the body that was issued, or credit the
|
|
57
|
+
* voucher first.
|
|
58
|
+
* - `INVOICE_ISSUANCE_OUTCOME_UNCERTAIN` · 409 — an earlier factura of this
|
|
59
|
+
* order was interrupted once it may have spent a voucher number, with no
|
|
60
|
+
* recorded outcome. `data`
|
|
61
|
+
* is {@link InvoiceIssuanceOutcomeUncertainErrorData}. Never retry; support
|
|
62
|
+
* reconciles.
|
|
63
|
+
*/
|
|
64
|
+
exports.INVOICE_ISSUANCE_REFUSAL_CODES = [
|
|
65
|
+
'INVOICE_ISSUANCE_IN_PROGRESS',
|
|
66
|
+
'CAEA_CLAIM_AMBIGUOUS',
|
|
67
|
+
'INVOICE_IDEMPOTENCY_PAYLOAD_MISMATCH',
|
|
68
|
+
'INVOICE_ISSUANCE_OUTCOME_UNCERTAIN',
|
|
69
|
+
];
|
|
70
|
+
exports.INVOICE_ISSUANCE_REFUSAL_RECOVERY = {
|
|
71
|
+
INVOICE_ISSUANCE_IN_PROGRESS: 'retry',
|
|
72
|
+
CAEA_CLAIM_AMBIGUOUS: 'retry',
|
|
73
|
+
INVOICE_IDEMPOTENCY_PAYLOAD_MISMATCH: 'resend-issued-body',
|
|
74
|
+
INVOICE_ISSUANCE_OUTCOME_UNCERTAIN: 'reconcile',
|
|
75
|
+
};
|
package/dist/cjs/mercadopago.js
CHANGED
|
@@ -15,7 +15,9 @@ exports.MP_DYNAMIC_QR_ERROR_CODES = void 0;
|
|
|
15
15
|
* - 503 `PLATFORM_INTEGRATION_DISABLED`; 504 `MP_DYN_QR_UNCONFIRMED`, an unknown creation outcome.
|
|
16
16
|
* A thrown error answers `400 UNHANDLED_ERROR`, never a 500. The re-sync read
|
|
17
17
|
* (`GET /mercadopago/qr/dynamic?orderId=`) uses `VALIDATION_FAILED`, `PLAN_UPGRADE_REQUIRED`,
|
|
18
|
-
* `CAPABILITY_REQUIRED`, `ORDER_NOT_FOUND` and `ORDER_CANCELLED` from this list
|
|
18
|
+
* `CAPABILITY_REQUIRED`, `ORDER_NOT_FOUND` and `ORDER_CANCELLED` from this list; its
|
|
19
|
+
* `ORDER_CANCELLED` carries `data: MpDynamicQrCancelledDetails` when the dead order holds linked
|
|
20
|
+
* MercadoPago payments.
|
|
19
21
|
*
|
|
20
22
|
* An order-bound charge holds the order's QR fence while it mints, and another charge for the
|
|
21
23
|
* same order meanwhile answers `MP_DYN_QR_IN_PROGRESS`. A `contacting` attempt (MercadoPago may
|
package/dist/cjs/order.js
CHANGED
|
@@ -235,6 +235,15 @@ exports.orderFulfilmentProgress = orderFulfilmentProgress;
|
|
|
235
235
|
* is also `mode: 'edit'`'s and the update leg's answer to a re-price that
|
|
236
236
|
* would leave the order's net señas above its new charged total. Nothing was
|
|
237
237
|
* written on any of them.
|
|
238
|
+
* - `TILL_TENDER_REQUIRES_DEPOSIT` · 400 — `mode: 'tender'` adding till money
|
|
239
|
+
* (any leg whose `source` is not `account`) to an order that is NOT yet
|
|
240
|
+
* delivered and holds no seña: money taken before delivery is a seña and
|
|
241
|
+
* goes through `mode: 'deposit'`. Decided after replays are absorbed, so a
|
|
242
|
+
* pure repeat of legs already on the ledger still answers its 200; an
|
|
243
|
+
* account-only tender is never refused. Nothing was written and no
|
|
244
|
+
* idempotency marker remains (refused ahead of the claim, or the claim is
|
|
245
|
+
* released on the 400), so a collection lookup for it answers
|
|
246
|
+
* `unknown` / `NO_EVIDENCE`.
|
|
238
247
|
* - `PAYMENT_REFERENCED_BY_DEPOSIT` · 409 — the payment link (fresh, over an
|
|
239
248
|
* entry the order already holds, or a credit upgrade) of a payment whose id a
|
|
240
249
|
* seña on the order already carries as its `reference`: the same money would
|
|
@@ -442,6 +451,19 @@ exports.orderFulfilmentProgress = orderFulfilmentProgress;
|
|
|
442
451
|
* for another store or user session (`ORDER_ATTEMPT_SCOPE_TAG_LENGTH`). Mint
|
|
443
452
|
* a new key in this session. Nothing was written.
|
|
444
453
|
*
|
|
454
|
+
* ⚠️ **A money write's attempt identity is its `Idempotency-Key`, never its
|
|
455
|
+
* `reference`.** Mint one key per tender, seña or account payment and keep it
|
|
456
|
+
* for every retry. `reference` is a duplicate-money guard with its own
|
|
457
|
+
* horizon, not an outcome, and it runs across keys: a tender absorbs a repeat
|
|
458
|
+
* leg identical on money, method and source that carries the same `reference`
|
|
459
|
+
* indefinitely, or — neither side carrying one — was recorded by the same user
|
|
460
|
+
* within 30 seconds; a seña absorbs a same-user or same-`reference` repeat
|
|
461
|
+
* only inside its 30-second replay window, and an older lookalike is
|
|
462
|
+
* `409 DEPOSIT_DUPLICATE_REFERENCE`. To learn whether a keyed
|
|
463
|
+
* write landed after a lost reply, `IDEMPOTENCY_IN_PROGRESS` or
|
|
464
|
+
* `IDEMPOTENCY_KEY_FAILED`, ask `POST /orders { mode: 'collection-attempt' }`
|
|
465
|
+
* (`OrderCollectionAttemptVerdict`) — never resend it under a new key first.
|
|
466
|
+
*
|
|
445
467
|
* Idempotency answers, all six from `withIdempotency`:
|
|
446
468
|
* - `INVALID_IDEMPOTENCY_KEY` · 400 · `IDEMPOTENCY_KEY_REUSE` · 422 (the same
|
|
447
469
|
* key with a different body)
|
|
@@ -521,6 +543,8 @@ exports.ORDER_ERROR_CODES = [
|
|
|
521
543
|
'DEPOSIT_INVOICED_ORDER_MUST_FREEZE',
|
|
522
544
|
'DEPOSIT_REFERENCE_IS_LINKED_PAYMENT',
|
|
523
545
|
'DEPOSIT_DUPLICATE_REFERENCE',
|
|
546
|
+
// Till money on an undelivered order with no seña — `mode: 'deposit'` takes it.
|
|
547
|
+
'TILL_TENDER_REQUIRES_DEPOSIT',
|
|
524
548
|
// The payment link of a payment a seña on the order already references.
|
|
525
549
|
'PAYMENT_REFERENCED_BY_DEPOSIT',
|
|
526
550
|
// Customer cancellation of an order still holding a seña.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Order-collection attempt lookup — the read a client runs when a money write
|
|
4
|
+
* on an order (a till tender, a seña, an account payment) left it without an
|
|
5
|
+
* answer: a lost reply, a timeout, or one of the two uncertain refusals
|
|
6
|
+
* `409 IDEMPOTENCY_IN_PROGRESS` and `409 IDEMPOTENCY_KEY_FAILED`.
|
|
7
|
+
*
|
|
8
|
+
* ⚠️ **The attempt's identity is its `Idempotency-Key`, never its `reference`.**
|
|
9
|
+
* Mint ONE key per collection attempt and keep it for every retry of that
|
|
10
|
+
* attempt. `reference` keeps its own, narrower meaning as a duplicate-money
|
|
11
|
+
* guard, and that guard runs ACROSS keys: a tender absorbs a repeat leg
|
|
12
|
+
* identical on money, method and source that carries the same `reference`
|
|
13
|
+
* however much later it arrives, OR — neither side carrying a reference — was
|
|
14
|
+
* recorded by the same user within 30 seconds; a seña absorbs a same-user or
|
|
15
|
+
* same-`reference` repeat only inside its 30-second replay window (an older
|
|
16
|
+
* lookalike is `409 DEPOSIT_DUPLICATE_REFERENCE`). So a NEW key is a new
|
|
17
|
+
* attempt, not a guaranteed new leg: two genuine reference-less handoffs of the
|
|
18
|
+
* same amount by one cashier inside 30 s land as ONE leg, and the second key
|
|
19
|
+
* answers `committed` all the same. Give each physical payment its own
|
|
20
|
+
* `reference` when that distinction matters. Neither guard is an outcome
|
|
21
|
+
* protocol.
|
|
22
|
+
*
|
|
23
|
+
* `POST /orders { mode: 'collection-attempt', operation, orderId, idempotencyKey }`
|
|
24
|
+
* answers from the write's own idempotency marker, scoped to the CALLER's store
|
|
25
|
+
* and user. It never claims, replays, reclaims or seals the marker, never
|
|
26
|
+
* writes the marker or any business row, and calls no provider; a claim it
|
|
27
|
+
* finds stranded past 60 s logs one deduped operator row.
|
|
28
|
+
*/
|
|
29
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
+
exports.ORDER_COLLECTION_ATTEMPT_RETENTION_MS = exports.ORDER_COLLECTION_ATTEMPT_UNKNOWN_REASONS = exports.ORDER_COLLECTION_ATTEMPT_VERDICTS = exports.ORDER_COLLECTION_ATTEMPT_OPERATIONS = void 0;
|
|
31
|
+
/** Every `operation` the lookup answers for — see `OrderCollectionAttemptLookupRequest`. */
|
|
32
|
+
exports.ORDER_COLLECTION_ATTEMPT_OPERATIONS = ['tender', 'deposit', 'account'];
|
|
33
|
+
/** Every `verdict` the lookup answers — see `OrderCollectionAttemptVerdict`. */
|
|
34
|
+
exports.ORDER_COLLECTION_ATTEMPT_VERDICTS = ['committed', 'in-progress', 'sealed', 'unknown'];
|
|
35
|
+
/**
|
|
36
|
+
* Every `reason` on an `unknown` verdict:
|
|
37
|
+
*
|
|
38
|
+
* - `NO_EVIDENCE` — no marker under this key for the caller: never sent, sent
|
|
39
|
+
* by another user or store, refused or released before it committed,
|
|
40
|
+
* already deleted by its retention expiry — or STILL IN FLIGHT and not yet
|
|
41
|
+
* claimed. A write holds no marker until its claim lands, and before that
|
|
42
|
+
* it can be queued at the gateway, in a cold start, or (a tender) running
|
|
43
|
+
* its pre-claim reads. So it is never "not collected": follow the
|
|
44
|
+
* `unknown` remedy on `OrderCollectionAttemptVerdict` — resend the same
|
|
45
|
+
* body under the same key first.
|
|
46
|
+
* - `EVIDENCE_EXPIRED` — the marker outlived
|
|
47
|
+
* {@link ORDER_COLLECTION_ATTEMPT_RETENTION_MS} and is awaiting deletion,
|
|
48
|
+
* which DynamoDB does lazily (up to days late). That is the LOOKUP's
|
|
49
|
+
* horizon, not the writer's: the write never reads the expiry, so while
|
|
50
|
+
* the row survives a same-key resend still replays a committed `200` (or
|
|
51
|
+
* refuses a sealed or stranded key) and does NOT run again. Once DynamoDB
|
|
52
|
+
* deletes the row the same resend runs as a new write — so past the
|
|
53
|
+
* horizon verify where the operation writes before resending at all.
|
|
54
|
+
* - `UNBOUND_ATTEMPT` — the key belongs to a write that is not a collection
|
|
55
|
+
* attempt (another order mode), or to one admitted before the server
|
|
56
|
+
* started recording which collection a key was for.
|
|
57
|
+
* - `ATTEMPT_MISMATCH` — the key was sent for a different `operation` or
|
|
58
|
+
* `orderId` than the lookup names.
|
|
59
|
+
* - `REFUSED` — the write's cached answer was a refusal (non-`2xx`): nothing
|
|
60
|
+
* moved under this key. No collection write caches a refusal today; this
|
|
61
|
+
* keeps one that ever does from reading as `committed`.
|
|
62
|
+
*/
|
|
63
|
+
exports.ORDER_COLLECTION_ATTEMPT_UNKNOWN_REASONS = [
|
|
64
|
+
'NO_EVIDENCE',
|
|
65
|
+
'EVIDENCE_EXPIRED',
|
|
66
|
+
'UNBOUND_ATTEMPT',
|
|
67
|
+
'ATTEMPT_MISMATCH',
|
|
68
|
+
'REFUSED',
|
|
69
|
+
];
|
|
70
|
+
/**
|
|
71
|
+
* How long the server keeps a collection attempt's evidence: 24 hours — the
|
|
72
|
+
* write's own idempotency retention. Past it the lookup answers `unknown`.
|
|
73
|
+
*/
|
|
74
|
+
exports.ORDER_COLLECTION_ATTEMPT_RETENTION_MS = 86_400_000;
|
package/dist/index.d.ts
CHANGED
|
@@ -49,6 +49,7 @@ export * from './mercadolibre.ts';
|
|
|
49
49
|
export * from './mercadopago.ts';
|
|
50
50
|
export * from './notification.ts';
|
|
51
51
|
export * from './order.ts';
|
|
52
|
+
export * from './orderCollectionAttempt.ts';
|
|
52
53
|
export * from './orderCreateAttempt.ts';
|
|
53
54
|
export * from './payment.ts';
|
|
54
55
|
export * from './platform.ts';
|
package/dist/index.js
CHANGED
|
@@ -57,6 +57,7 @@ export * from "./mercadolibre.js";
|
|
|
57
57
|
export * from "./mercadopago.js";
|
|
58
58
|
export * from "./notification.js";
|
|
59
59
|
export * from "./order.js";
|
|
60
|
+
export * from "./orderCollectionAttempt.js";
|
|
60
61
|
export * from "./orderCreateAttempt.js";
|
|
61
62
|
export * from "./payment.js";
|
|
62
63
|
export * from "./platform.js";
|
package/dist/invoice.d.ts
CHANGED
|
@@ -837,6 +837,86 @@ declare global {
|
|
|
837
837
|
/** The fortnight's CAEA code the number was claimed under. */
|
|
838
838
|
CAEA: string;
|
|
839
839
|
}
|
|
840
|
+
/**
|
|
841
|
+
* `data` of a `409 INVOICE_ISSUANCE_OUTCOME_UNCERTAIN` answer from
|
|
842
|
+
* `POST /invoices` (a factura): an earlier issuance of this order was
|
|
843
|
+
* interrupted once it may have spent a voucher number — a live or WSFEX
|
|
844
|
+
* submit was recorded, or the outage path (a CAEA stamp or a `pending_cae`
|
|
845
|
+
* degrade) began — and the server holds no evidence of its outcome: the
|
|
846
|
+
* order's `invoices[]` does not name the recorded invoice and no
|
|
847
|
+
* stranded-voucher row names it. ARCA may hold a voucher for it, or may hold
|
|
848
|
+
* nothing.
|
|
849
|
+
*
|
|
850
|
+
* ⚠️ **Never retry, and never resend the original body as proof.** An
|
|
851
|
+
* unchanged body, a refetched order with no voucher and an elapsed lock are
|
|
852
|
+
* not evidence the earlier attempt spent nothing. The order stays fenced
|
|
853
|
+
* until support reconciles the attempt at ARCA and releases it.
|
|
854
|
+
*/
|
|
855
|
+
interface InvoiceIssuanceOutcomeUncertainErrorData {
|
|
856
|
+
orderId: string;
|
|
857
|
+
/** The server's id for the interrupted invoice. No order entry names it. */
|
|
858
|
+
invoiceId?: string;
|
|
859
|
+
/**
|
|
860
|
+
* How the interrupted attempt reached ARCA: `cae` (live FECAESolicitar),
|
|
861
|
+
* `export` (WSFEX FEXAuthorize) or `outage` (a CAEA stamp or a
|
|
862
|
+
* `pending_cae` degrade). Written with `invoiceId` and `submittedAt` by
|
|
863
|
+
* the same mark, so absent only on a row edited by hand.
|
|
864
|
+
*/
|
|
865
|
+
path?: 'cae' | 'export' | 'outage';
|
|
866
|
+
/** Epoch ms the interrupted attempt was cleared to contact ARCA. */
|
|
867
|
+
submittedAt?: number;
|
|
868
|
+
/**
|
|
869
|
+
* The voucher the interrupted attempt spent or was about to spend. A
|
|
870
|
+
* `cae`/`export` answer always carries it — such a row with no recorded
|
|
871
|
+
* voucher proves no submit went out and is never refused. On `outage` it
|
|
872
|
+
* is the claimed CAEA number (`kind: 'caea'`) when that best-effort
|
|
873
|
+
* record landed, or a live submit's voucher (`kind: 'arca'`) when the
|
|
874
|
+
* outage branch fell through to it; absent, it proves nothing.
|
|
875
|
+
*/
|
|
876
|
+
voucher?: {
|
|
877
|
+
/** `arca` — submitted to ARCA (CAE or WSFEX); `caea` — a claimed CAEA number. */
|
|
878
|
+
kind: 'arca' | 'caea';
|
|
879
|
+
/** ARCA `CbteTipo` — the voucher class. */
|
|
880
|
+
CbteTipo: number;
|
|
881
|
+
/** ARCA `PtoVta` — the punto de venta it went out under. */
|
|
882
|
+
PtoVta: number;
|
|
883
|
+
/** ARCA `CbteNro` — the number ARCA may or may not hold. */
|
|
884
|
+
CbteNro: number;
|
|
885
|
+
/**
|
|
886
|
+
* The submitted voucher's `CbteFch` (`yyyymmdd`), when the attempt
|
|
887
|
+
* recorded one. `fingerprintMatches` compares it too: a voucher found
|
|
888
|
+
* at the number under another date is not this one.
|
|
889
|
+
*/
|
|
890
|
+
CbteFch?: string;
|
|
891
|
+
/**
|
|
892
|
+
* A live `FECAESolicitar` attempt's identifying fields, as submitted —
|
|
893
|
+
* compare a `FECompConsultar` answer at the number against these, never
|
|
894
|
+
* against a rebuild from the order. The receptor's `DocNro` is withheld:
|
|
895
|
+
* compare it against the order's `invoiceMethod`. Absent on a CAEA claim,
|
|
896
|
+
* a WSFEX attempt, and an attempt recorded before it was stored.
|
|
897
|
+
*/
|
|
898
|
+
fingerprint?: InvoiceIssuanceAttemptFingerprint;
|
|
899
|
+
};
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* The fields `FECompConsultar` echoes that identify a submitted voucher, as
|
|
903
|
+
* the interrupted attempt sent them, minus the receptor's `DocNro` and the
|
|
904
|
+
* date (`CbteFch`, beside it). Amounts are in the voucher currency (`MonId`).
|
|
905
|
+
*/
|
|
906
|
+
interface InvoiceIssuanceAttemptFingerprint {
|
|
907
|
+
/** ARCA `DocTipo` — the receptor's document type. */
|
|
908
|
+
DocTipo: number;
|
|
909
|
+
/** ARCA `MonId` — the voucher currency code. */
|
|
910
|
+
MonId: string;
|
|
911
|
+
/** ARCA `MonCotiz` — the rate the voucher was submitted at. */
|
|
912
|
+
MonCotiz: number;
|
|
913
|
+
ImpTotal: number;
|
|
914
|
+
ImpNeto: number;
|
|
915
|
+
ImpIVA: number;
|
|
916
|
+
ImpTotConc: number;
|
|
917
|
+
ImpOpEx: number;
|
|
918
|
+
ImpTrib: number;
|
|
919
|
+
}
|
|
840
920
|
}
|
|
841
921
|
/**
|
|
842
922
|
* The codes `POST /invoices` answers AFTER a voucher number was spent — ARCA
|
|
@@ -866,4 +946,50 @@ declare global {
|
|
|
866
946
|
*/
|
|
867
947
|
export declare const INVOICE_POST_VOUCHER_ERROR_CODES: readonly ["INVOICE_PERSIST_AFTER_CAE_FAILED", "INVOICE_EXPORT_OUTCOME_UNKNOWN", "CAEA_COMMIT_FAILED_AFTER_CLAIM"];
|
|
868
948
|
export type InvoicePostVoucherErrorCode = (typeof INVOICE_POST_VOUCHER_ERROR_CODES)[number];
|
|
949
|
+
/**
|
|
950
|
+
* The codes `POST /invoices` answers when it REFUSED to start an issuance — or
|
|
951
|
+
* could not confirm it — before any voucher of this request was recorded, as a
|
|
952
|
+
* runtime value a client maps. Distinct from
|
|
953
|
+
* {@link INVOICE_POST_VOUCHER_ERROR_CODES}: each has its own recovery, given by
|
|
954
|
+
* {@link INVOICE_ISSUANCE_REFUSAL_RECOVERY}.
|
|
955
|
+
*
|
|
956
|
+
* - `INVOICE_ISSUANCE_IN_PROGRESS` · 409 — another issuance of this order is
|
|
957
|
+
* live: the same request's idempotency lock, or another request holding the
|
|
958
|
+
* order's factura issuance guard inside its horizon. Also answered after the
|
|
959
|
+
* order read, when the guard's owner-conditioned pre-ARCA mark or attempt
|
|
960
|
+
* record finds the guard taken over by a successor — before that request's
|
|
961
|
+
* submit went on the wire, so it spent nothing. Retry the same body shortly.
|
|
962
|
+
* - `CAEA_CLAIM_AMBIGUOUS` · 503 — ARCA was down and the CAEA number claim could
|
|
963
|
+
* not be confirmed: the claim may have landed (an operator row records it), no
|
|
964
|
+
* invoice was recorded and nothing was sent to ARCA, and the request released
|
|
965
|
+
* its idempotency record. Retry the same body shortly — a retry claims again,
|
|
966
|
+
* so the worst case is one unused CAEA number, never a second voucher.
|
|
967
|
+
* - `INVOICE_IDEMPOTENCY_PAYLOAD_MISMATCH` · 409 — the request's key is bound to
|
|
968
|
+
* an issuance with a different voucher-shaping body (or to a record from
|
|
969
|
+
* before payload hashing, which matches nothing). It does NOT say a voucher
|
|
970
|
+
* exists on the order. Resend only the body that was issued, or credit the
|
|
971
|
+
* voucher first.
|
|
972
|
+
* - `INVOICE_ISSUANCE_OUTCOME_UNCERTAIN` · 409 — an earlier factura of this
|
|
973
|
+
* order was interrupted once it may have spent a voucher number, with no
|
|
974
|
+
* recorded outcome. `data`
|
|
975
|
+
* is {@link InvoiceIssuanceOutcomeUncertainErrorData}. Never retry; support
|
|
976
|
+
* reconciles.
|
|
977
|
+
*/
|
|
978
|
+
export declare const INVOICE_ISSUANCE_REFUSAL_CODES: readonly ["INVOICE_ISSUANCE_IN_PROGRESS", "CAEA_CLAIM_AMBIGUOUS", "INVOICE_IDEMPOTENCY_PAYLOAD_MISMATCH", "INVOICE_ISSUANCE_OUTCOME_UNCERTAIN"];
|
|
979
|
+
export type InvoiceIssuanceRefusalCode = (typeof INVOICE_ISSUANCE_REFUSAL_CODES)[number];
|
|
980
|
+
/**
|
|
981
|
+
* What a client may do with each {@link InvoiceIssuanceRefusalCode}:
|
|
982
|
+
*
|
|
983
|
+
* - `retry` — resend the same body after a short wait;
|
|
984
|
+
* - `resend-issued-body` — only the body of the issuance the key is bound to
|
|
985
|
+
* (or credit that voucher first); a corrected body is refused again;
|
|
986
|
+
* - `reconcile` — do not resend at all; the order is fenced until support acts.
|
|
987
|
+
*/
|
|
988
|
+
export type InvoiceIssuanceRecovery = 'retry' | 'resend-issued-body' | 'reconcile';
|
|
989
|
+
export declare const INVOICE_ISSUANCE_REFUSAL_RECOVERY: {
|
|
990
|
+
readonly INVOICE_ISSUANCE_IN_PROGRESS: "retry";
|
|
991
|
+
readonly CAEA_CLAIM_AMBIGUOUS: "retry";
|
|
992
|
+
readonly INVOICE_IDEMPOTENCY_PAYLOAD_MISMATCH: "resend-issued-body";
|
|
993
|
+
readonly INVOICE_ISSUANCE_OUTCOME_UNCERTAIN: "reconcile";
|
|
994
|
+
};
|
|
869
995
|
export {};
|
package/dist/invoice.js
CHANGED
|
@@ -29,3 +29,44 @@ export const INVOICE_POST_VOUCHER_ERROR_CODES = [
|
|
|
29
29
|
'INVOICE_EXPORT_OUTCOME_UNKNOWN',
|
|
30
30
|
'CAEA_COMMIT_FAILED_AFTER_CLAIM',
|
|
31
31
|
];
|
|
32
|
+
/**
|
|
33
|
+
* The codes `POST /invoices` answers when it REFUSED to start an issuance — or
|
|
34
|
+
* could not confirm it — before any voucher of this request was recorded, as a
|
|
35
|
+
* runtime value a client maps. Distinct from
|
|
36
|
+
* {@link INVOICE_POST_VOUCHER_ERROR_CODES}: each has its own recovery, given by
|
|
37
|
+
* {@link INVOICE_ISSUANCE_REFUSAL_RECOVERY}.
|
|
38
|
+
*
|
|
39
|
+
* - `INVOICE_ISSUANCE_IN_PROGRESS` · 409 — another issuance of this order is
|
|
40
|
+
* live: the same request's idempotency lock, or another request holding the
|
|
41
|
+
* order's factura issuance guard inside its horizon. Also answered after the
|
|
42
|
+
* order read, when the guard's owner-conditioned pre-ARCA mark or attempt
|
|
43
|
+
* record finds the guard taken over by a successor — before that request's
|
|
44
|
+
* submit went on the wire, so it spent nothing. Retry the same body shortly.
|
|
45
|
+
* - `CAEA_CLAIM_AMBIGUOUS` · 503 — ARCA was down and the CAEA number claim could
|
|
46
|
+
* not be confirmed: the claim may have landed (an operator row records it), no
|
|
47
|
+
* invoice was recorded and nothing was sent to ARCA, and the request released
|
|
48
|
+
* its idempotency record. Retry the same body shortly — a retry claims again,
|
|
49
|
+
* so the worst case is one unused CAEA number, never a second voucher.
|
|
50
|
+
* - `INVOICE_IDEMPOTENCY_PAYLOAD_MISMATCH` · 409 — the request's key is bound to
|
|
51
|
+
* an issuance with a different voucher-shaping body (or to a record from
|
|
52
|
+
* before payload hashing, which matches nothing). It does NOT say a voucher
|
|
53
|
+
* exists on the order. Resend only the body that was issued, or credit the
|
|
54
|
+
* voucher first.
|
|
55
|
+
* - `INVOICE_ISSUANCE_OUTCOME_UNCERTAIN` · 409 — an earlier factura of this
|
|
56
|
+
* order was interrupted once it may have spent a voucher number, with no
|
|
57
|
+
* recorded outcome. `data`
|
|
58
|
+
* is {@link InvoiceIssuanceOutcomeUncertainErrorData}. Never retry; support
|
|
59
|
+
* reconciles.
|
|
60
|
+
*/
|
|
61
|
+
export const INVOICE_ISSUANCE_REFUSAL_CODES = [
|
|
62
|
+
'INVOICE_ISSUANCE_IN_PROGRESS',
|
|
63
|
+
'CAEA_CLAIM_AMBIGUOUS',
|
|
64
|
+
'INVOICE_IDEMPOTENCY_PAYLOAD_MISMATCH',
|
|
65
|
+
'INVOICE_ISSUANCE_OUTCOME_UNCERTAIN',
|
|
66
|
+
];
|
|
67
|
+
export const INVOICE_ISSUANCE_REFUSAL_RECOVERY = {
|
|
68
|
+
INVOICE_ISSUANCE_IN_PROGRESS: 'retry',
|
|
69
|
+
CAEA_CLAIM_AMBIGUOUS: 'retry',
|
|
70
|
+
INVOICE_IDEMPOTENCY_PAYLOAD_MISMATCH: 'resend-issued-body',
|
|
71
|
+
INVOICE_ISSUANCE_OUTCOME_UNCERTAIN: 'reconcile',
|
|
72
|
+
};
|
package/dist/mercadopago.d.ts
CHANGED
|
@@ -98,13 +98,73 @@ declare global {
|
|
|
98
98
|
state: 'reserved' | 'contacting';
|
|
99
99
|
since?: number;
|
|
100
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* One MercadoPago payment linked to the order, as the `paid` arm of
|
|
103
|
+
* {@link MpDynamicQrStateResponse} reports it — read from the order's own
|
|
104
|
+
* `linkedPayments` entry, never matched by amount, customer or time.
|
|
105
|
+
*
|
|
106
|
+
* - `paymentId` — MercadoPago's payment id, the entry's key.
|
|
107
|
+
* - `amount` — what the store still holds for that payment, net of refunds
|
|
108
|
+
* (`LinkedPaymentEntry.total`), in `currency`.
|
|
109
|
+
* - `currency` — the payment's denomination as `LinkedPaymentEntry.currency`
|
|
110
|
+
* states it (an ISO code or a platform catalogId); for an entry naming
|
|
111
|
+
* none, the order's own currency, and `'ARS'` only when the order names
|
|
112
|
+
* none either.
|
|
113
|
+
* - `paidAt` — when the approved payment was linked to the order (epoch ms),
|
|
114
|
+
* which follows MercadoPago's approval, never precedes it.
|
|
115
|
+
*/
|
|
116
|
+
interface MpDynamicQrPaidPayment {
|
|
117
|
+
paymentId: string;
|
|
118
|
+
amount: number;
|
|
119
|
+
currency: string;
|
|
120
|
+
paidAt: number;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* `data` of the re-sync read's `409 ORDER_CANCELLED`
|
|
124
|
+
* (`GET /mercadopago/qr/dynamic?orderId=`), present only when the dead order
|
|
125
|
+
* still holds linked MercadoPago payments: the money that moved before (or
|
|
126
|
+
* despite) the cancellation, from the same consistent order read that
|
|
127
|
+
* refused. The `paid` arm of {@link MpDynamicQrStateResponse} without
|
|
128
|
+
* `pending` — a dead order's QR fence is not read. Absent when no
|
|
129
|
+
* MercadoPago payment is linked, which, exactly like `none`, is no evidence
|
|
130
|
+
* of non-payment. The POST's `409 ORDER_CANCELLED` never carries it.
|
|
131
|
+
*/
|
|
132
|
+
interface MpDynamicQrCancelledDetails {
|
|
133
|
+
state: 'paid';
|
|
134
|
+
payments: MpDynamicQrPaidPayment[];
|
|
135
|
+
serverNow: number;
|
|
136
|
+
}
|
|
101
137
|
/**
|
|
102
138
|
* `data` of `GET /mercadopago/qr/dynamic?orderId=` — the re-sync read of the order's
|
|
103
|
-
* dynamic QR. Never carries the attempt's key or owner.
|
|
104
|
-
*
|
|
105
|
-
*
|
|
139
|
+
* dynamic QR. Never carries the attempt's key or owner.
|
|
140
|
+
*
|
|
141
|
+
* - `paid` — the order holds at least one approved MercadoPago payment
|
|
142
|
+
* (`payments`, oldest link first), from a consistent read of the order.
|
|
143
|
+
* When another attempt ALSO holds the fence (a QR for the remaining
|
|
144
|
+
* balance), `pending` carries its `phase` and `since`; absent otherwise.
|
|
145
|
+
* - `pending` — an attempt holds the order's fence (`since` = its reservation
|
|
146
|
+
* instant; no `qrData`).
|
|
147
|
+
* - `none` — nothing blocks the order and no MercadoPago payment is linked
|
|
148
|
+
* YET. ⚠️ `none` is never evidence of non-payment: an approval may not be
|
|
149
|
+
* linked yet — a late webhook, a `409` the payment hook is waiting to
|
|
150
|
+
* retry, or MercadoPago processing switched off by the platform kill
|
|
151
|
+
* switch while a QR minted earlier stays payable at MercadoPago. A client
|
|
152
|
+
* must not collect again on `none`.
|
|
153
|
+
*
|
|
154
|
+
* ⚠️ Creating or showing a QR is never payment: only `paid` says money moved,
|
|
155
|
+
* and only its absence AFTER the operator has checked MercadoPago is a reason
|
|
156
|
+
* to collect again. A dead order answers `409 ORDER_CANCELLED` instead, with
|
|
157
|
+
* `data: MpDynamicQrCancelledDetails` when it holds linked payments.
|
|
106
158
|
*/
|
|
107
159
|
type MpDynamicQrStateResponse = {
|
|
160
|
+
state: 'paid';
|
|
161
|
+
payments: MpDynamicQrPaidPayment[];
|
|
162
|
+
pending?: {
|
|
163
|
+
phase: 'reserved' | 'contacting';
|
|
164
|
+
since?: number;
|
|
165
|
+
};
|
|
166
|
+
serverNow: number;
|
|
167
|
+
} | {
|
|
108
168
|
state: 'pending';
|
|
109
169
|
phase: 'reserved' | 'contacting';
|
|
110
170
|
since?: number;
|
|
@@ -191,7 +251,9 @@ declare global {
|
|
|
191
251
|
* - 503 `PLATFORM_INTEGRATION_DISABLED`; 504 `MP_DYN_QR_UNCONFIRMED`, an unknown creation outcome.
|
|
192
252
|
* A thrown error answers `400 UNHANDLED_ERROR`, never a 500. The re-sync read
|
|
193
253
|
* (`GET /mercadopago/qr/dynamic?orderId=`) uses `VALIDATION_FAILED`, `PLAN_UPGRADE_REQUIRED`,
|
|
194
|
-
* `CAPABILITY_REQUIRED`, `ORDER_NOT_FOUND` and `ORDER_CANCELLED` from this list
|
|
254
|
+
* `CAPABILITY_REQUIRED`, `ORDER_NOT_FOUND` and `ORDER_CANCELLED` from this list; its
|
|
255
|
+
* `ORDER_CANCELLED` carries `data: MpDynamicQrCancelledDetails` when the dead order holds linked
|
|
256
|
+
* MercadoPago payments.
|
|
195
257
|
*
|
|
196
258
|
* An order-bound charge holds the order's QR fence while it mints, and another charge for the
|
|
197
259
|
* same order meanwhile answers `MP_DYN_QR_IN_PROGRESS`. A `contacting` attempt (MercadoPago may
|
package/dist/mercadopago.js
CHANGED
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
* - 503 `PLATFORM_INTEGRATION_DISABLED`; 504 `MP_DYN_QR_UNCONFIRMED`, an unknown creation outcome.
|
|
13
13
|
* A thrown error answers `400 UNHANDLED_ERROR`, never a 500. The re-sync read
|
|
14
14
|
* (`GET /mercadopago/qr/dynamic?orderId=`) uses `VALIDATION_FAILED`, `PLAN_UPGRADE_REQUIRED`,
|
|
15
|
-
* `CAPABILITY_REQUIRED`, `ORDER_NOT_FOUND` and `ORDER_CANCELLED` from this list
|
|
15
|
+
* `CAPABILITY_REQUIRED`, `ORDER_NOT_FOUND` and `ORDER_CANCELLED` from this list; its
|
|
16
|
+
* `ORDER_CANCELLED` carries `data: MpDynamicQrCancelledDetails` when the dead order holds linked
|
|
17
|
+
* MercadoPago payments.
|
|
16
18
|
*
|
|
17
19
|
* An order-bound charge holds the order's QR fence while it mints, and another charge for the
|
|
18
20
|
* same order meanwhile answers `MP_DYN_QR_IN_PROGRESS`. A `contacting` attempt (MercadoPago may
|
package/dist/order.d.ts
CHANGED
|
@@ -2473,6 +2473,15 @@ export declare const orderFulfilmentProgress: (order: OrderFulfilmentProgressInp
|
|
|
2473
2473
|
* is also `mode: 'edit'`'s and the update leg's answer to a re-price that
|
|
2474
2474
|
* would leave the order's net señas above its new charged total. Nothing was
|
|
2475
2475
|
* written on any of them.
|
|
2476
|
+
* - `TILL_TENDER_REQUIRES_DEPOSIT` · 400 — `mode: 'tender'` adding till money
|
|
2477
|
+
* (any leg whose `source` is not `account`) to an order that is NOT yet
|
|
2478
|
+
* delivered and holds no seña: money taken before delivery is a seña and
|
|
2479
|
+
* goes through `mode: 'deposit'`. Decided after replays are absorbed, so a
|
|
2480
|
+
* pure repeat of legs already on the ledger still answers its 200; an
|
|
2481
|
+
* account-only tender is never refused. Nothing was written and no
|
|
2482
|
+
* idempotency marker remains (refused ahead of the claim, or the claim is
|
|
2483
|
+
* released on the 400), so a collection lookup for it answers
|
|
2484
|
+
* `unknown` / `NO_EVIDENCE`.
|
|
2476
2485
|
* - `PAYMENT_REFERENCED_BY_DEPOSIT` · 409 — the payment link (fresh, over an
|
|
2477
2486
|
* entry the order already holds, or a credit upgrade) of a payment whose id a
|
|
2478
2487
|
* seña on the order already carries as its `reference`: the same money would
|
|
@@ -2680,6 +2689,19 @@ export declare const orderFulfilmentProgress: (order: OrderFulfilmentProgressInp
|
|
|
2680
2689
|
* for another store or user session (`ORDER_ATTEMPT_SCOPE_TAG_LENGTH`). Mint
|
|
2681
2690
|
* a new key in this session. Nothing was written.
|
|
2682
2691
|
*
|
|
2692
|
+
* ⚠️ **A money write's attempt identity is its `Idempotency-Key`, never its
|
|
2693
|
+
* `reference`.** Mint one key per tender, seña or account payment and keep it
|
|
2694
|
+
* for every retry. `reference` is a duplicate-money guard with its own
|
|
2695
|
+
* horizon, not an outcome, and it runs across keys: a tender absorbs a repeat
|
|
2696
|
+
* leg identical on money, method and source that carries the same `reference`
|
|
2697
|
+
* indefinitely, or — neither side carrying one — was recorded by the same user
|
|
2698
|
+
* within 30 seconds; a seña absorbs a same-user or same-`reference` repeat
|
|
2699
|
+
* only inside its 30-second replay window, and an older lookalike is
|
|
2700
|
+
* `409 DEPOSIT_DUPLICATE_REFERENCE`. To learn whether a keyed
|
|
2701
|
+
* write landed after a lost reply, `IDEMPOTENCY_IN_PROGRESS` or
|
|
2702
|
+
* `IDEMPOTENCY_KEY_FAILED`, ask `POST /orders { mode: 'collection-attempt' }`
|
|
2703
|
+
* (`OrderCollectionAttemptVerdict`) — never resend it under a new key first.
|
|
2704
|
+
*
|
|
2683
2705
|
* Idempotency answers, all six from `withIdempotency`:
|
|
2684
2706
|
* - `INVALID_IDEMPOTENCY_KEY` · 400 · `IDEMPOTENCY_KEY_REUSE` · 422 (the same
|
|
2685
2707
|
* key with a different body)
|
|
@@ -2701,6 +2723,6 @@ export declare const orderFulfilmentProgress: (order: OrderFulfilmentProgressInp
|
|
|
2701
2723
|
* `SUBSCRIPTION_READONLY`) sit on the order CREATE leg only: an edit is not a new
|
|
2702
2724
|
* order, so `bareOrderPostHandler` routes past `requireMetered` entirely.
|
|
2703
2725
|
*/
|
|
2704
|
-
export declare const ORDER_ERROR_CODES: readonly ["ORDER_COST_DENOMINATION_UNKNOWN", "SERVICE_ORDER_DELIVERY_MANAGED", "ORDER_NOT_FOUND", "ORDER_LOCKED", "ORDER_NOT_READY", "ORDER_DELIVERED_ANOTHER_DAY", "ORDER_DELIVERY_STATE_UNCHANGED", "ORDER_ILLEGAL_TRANSITION", "ORDER_VERSION_CONFLICT", "CUSTOMER_NOT_FOUND", "CUSTOMER_MERGED", "ORDER_HAS_NO_CUSTOMER", "CUSTOMER_ANONYMIZED", "FX_CONVERSION_UNAVAILABLE", "ROLE_FORBIDDEN", "ORDER_CANCELLED", "PAYMENT_SETTLED_ON_ANOTHER_ORDER", "ORDER_HAS_SHIPMENTS", "ORDER_HAS_RETURNS", "SHIPMENT_QUANTITY_EXCEEDED", "SHIPMENT_LINE_MISMATCH", "SHIPMENT_NOT_FOUND", "SHIPMENT_LIMIT_REACHED", "SHIPMENT_TOO_LARGE", "ORDER_FULFILMENT_EXTERNAL", "SHIPMENT_FAILED", "ADMIN_REQUIRED", "IDEMPOTENCY_KEY_REQUIRED", "INVALID_IDEMPOTENCY_KEY", "IDEMPOTENCY_KEY_REUSE", "IDEMPOTENCY_IN_PROGRESS", "IDEMPOTENCY_LOCK_CONTENTION", "IDEMPOTENCY_KEY_FAILED", "IDEMPOTENT_RESPONSE_NOT_CACHED", "ORDER_CANCELLATION_NOT_PROTECTED", "ORDER_CANCELLATION_COMMITTED", "ORDER_CANCELLATION_LOCKED", "ORDER_CANCELLATION_TOO_LARGE", "ORDER_CANCELLATION_FAILED", "SALE_LEDGER_RETRACTION_REFUSED", "SALE_LEDGER_ROW_NOT_OWNED", "PRODUCT_NOT_FOUND", "PRODUCT_SALE_LIMIT_EXCEEDED", "PRODUCT_SALE_LIMIT_INVALID", "DEPOSIT_SOURCE_NOT_ALLOWED", "DEPOSIT_CURRENCY_MISMATCH", "DEPOSIT_EXCEEDS_TOTAL", "DEPOSIT_FREEZE_REQUIRES_INVOICE", "DEPOSIT_FREEZE_INVOICE_PENDING", "DEPOSIT_CHARACTERIZATION_CONFLICT", "DEPOSIT_FREEZE_INVOICE_NOT_QUALIFYING", "DEPOSIT_INVOICED_ORDER_MUST_FREEZE", "DEPOSIT_REFERENCE_IS_LINKED_PAYMENT", "DEPOSIT_DUPLICATE_REFERENCE", "PAYMENT_REFERENCED_BY_DEPOSIT", "ORDER_HAS_UNREFUNDED_DEPOSIT", "DEPOSIT_NOT_FOUND", "DEPOSIT_ALREADY_REFUNDED", "UNIT_QUANTITY_NOT_WHOLE", "UNIT_REVISION_STALE", "UNIT_QUANTITY_UNREPRESENTABLE", "KIT_RECIPE_CHANGED", "CART_PROMOTION_UNAVAILABLE", "ORDER_HAS_KIT_LINES", "ORDER_TARGET_REQUIRED", "ORDER_SOURCE_CONFLICT", "ORDER_CUSTOMER_REQUIRED", "BASKET_EMPTY", "BASKET_CHANGED_DURING_CHECKOUT", "CART_VERSION_CREATE_ONLY", "CART_VERSION_REQUIRES_CART_ID", "CART_REVISION_STALE", "CART_CUSTOMER_MISMATCH", "COUNTER_SALE_CREATE_ONLY", "SOLD_AT_CREATE_ONLY", "SOLD_AT_IN_FUTURE", "ORDER_TENDER_CREATE_ONLY", "CREDIT_OVERRIDE_CREATE_ONLY", "ON_ACCOUNT_CREATE_ONLY", "ON_ACCOUNT_WITH_TENDERS", "TENDERS_REQUIRE_COUNTER_SALE", "LINES_REQUIRE_COUNTER_SALE", "PRODUCT_COST_UNKNOWN", "PRICE_CHANGE_DISABLED", "LINE_DISCOUNT_EXCEEDS_MAX", "CUSTOMER_DISABLED", "SHIFT_NOT_AVAILABLE", "SOLD_AT_OUTSIDE_SHIFT", "ORDER_CURRENCY_NOT_SUBSCRIBED", "PAYMENT_METHODS_NOT_CONFIGURED", "PAYMENT_METHOD_NOT_FOUND", "DELIVERY_METHOD_NOT_FOUND", "ORDER_BELOW_MINIMUM_PURCHASE", "ORDER_INVALID_CART", "EMAIL_VERIFICATION_REQUIRED", "ACCOUNT_DISABLED", "CURRENCY_MISMATCH", "SHIFT_NOT_OPEN", "ORDER_DISCOUNT_AFTER_INVOICE", "ORDER_DISCOUNT_ON_SERVICE_ORDER", "ORDER_DISCOUNT_ON_MARKETPLACE_ORDER", "ORDER_INVOICE_METHOD_OUTSTANDING_FACTURA", "ORDER_SERVICE_PERIOD_AFTER_INVOICE", "ORDER_ATTEMPT_COMMITTED", "ORDER_ATTEMPT_ABANDONED", "ORDER_ATTEMPT_KEY_EXPIRED", "ORDER_ATTEMPT_KEY_SCOPE_MISMATCH"];
|
|
2726
|
+
export declare const ORDER_ERROR_CODES: readonly ["ORDER_COST_DENOMINATION_UNKNOWN", "SERVICE_ORDER_DELIVERY_MANAGED", "ORDER_NOT_FOUND", "ORDER_LOCKED", "ORDER_NOT_READY", "ORDER_DELIVERED_ANOTHER_DAY", "ORDER_DELIVERY_STATE_UNCHANGED", "ORDER_ILLEGAL_TRANSITION", "ORDER_VERSION_CONFLICT", "CUSTOMER_NOT_FOUND", "CUSTOMER_MERGED", "ORDER_HAS_NO_CUSTOMER", "CUSTOMER_ANONYMIZED", "FX_CONVERSION_UNAVAILABLE", "ROLE_FORBIDDEN", "ORDER_CANCELLED", "PAYMENT_SETTLED_ON_ANOTHER_ORDER", "ORDER_HAS_SHIPMENTS", "ORDER_HAS_RETURNS", "SHIPMENT_QUANTITY_EXCEEDED", "SHIPMENT_LINE_MISMATCH", "SHIPMENT_NOT_FOUND", "SHIPMENT_LIMIT_REACHED", "SHIPMENT_TOO_LARGE", "ORDER_FULFILMENT_EXTERNAL", "SHIPMENT_FAILED", "ADMIN_REQUIRED", "IDEMPOTENCY_KEY_REQUIRED", "INVALID_IDEMPOTENCY_KEY", "IDEMPOTENCY_KEY_REUSE", "IDEMPOTENCY_IN_PROGRESS", "IDEMPOTENCY_LOCK_CONTENTION", "IDEMPOTENCY_KEY_FAILED", "IDEMPOTENT_RESPONSE_NOT_CACHED", "ORDER_CANCELLATION_NOT_PROTECTED", "ORDER_CANCELLATION_COMMITTED", "ORDER_CANCELLATION_LOCKED", "ORDER_CANCELLATION_TOO_LARGE", "ORDER_CANCELLATION_FAILED", "SALE_LEDGER_RETRACTION_REFUSED", "SALE_LEDGER_ROW_NOT_OWNED", "PRODUCT_NOT_FOUND", "PRODUCT_SALE_LIMIT_EXCEEDED", "PRODUCT_SALE_LIMIT_INVALID", "DEPOSIT_SOURCE_NOT_ALLOWED", "DEPOSIT_CURRENCY_MISMATCH", "DEPOSIT_EXCEEDS_TOTAL", "DEPOSIT_FREEZE_REQUIRES_INVOICE", "DEPOSIT_FREEZE_INVOICE_PENDING", "DEPOSIT_CHARACTERIZATION_CONFLICT", "DEPOSIT_FREEZE_INVOICE_NOT_QUALIFYING", "DEPOSIT_INVOICED_ORDER_MUST_FREEZE", "DEPOSIT_REFERENCE_IS_LINKED_PAYMENT", "DEPOSIT_DUPLICATE_REFERENCE", "TILL_TENDER_REQUIRES_DEPOSIT", "PAYMENT_REFERENCED_BY_DEPOSIT", "ORDER_HAS_UNREFUNDED_DEPOSIT", "DEPOSIT_NOT_FOUND", "DEPOSIT_ALREADY_REFUNDED", "UNIT_QUANTITY_NOT_WHOLE", "UNIT_REVISION_STALE", "UNIT_QUANTITY_UNREPRESENTABLE", "KIT_RECIPE_CHANGED", "CART_PROMOTION_UNAVAILABLE", "ORDER_HAS_KIT_LINES", "ORDER_TARGET_REQUIRED", "ORDER_SOURCE_CONFLICT", "ORDER_CUSTOMER_REQUIRED", "BASKET_EMPTY", "BASKET_CHANGED_DURING_CHECKOUT", "CART_VERSION_CREATE_ONLY", "CART_VERSION_REQUIRES_CART_ID", "CART_REVISION_STALE", "CART_CUSTOMER_MISMATCH", "COUNTER_SALE_CREATE_ONLY", "SOLD_AT_CREATE_ONLY", "SOLD_AT_IN_FUTURE", "ORDER_TENDER_CREATE_ONLY", "CREDIT_OVERRIDE_CREATE_ONLY", "ON_ACCOUNT_CREATE_ONLY", "ON_ACCOUNT_WITH_TENDERS", "TENDERS_REQUIRE_COUNTER_SALE", "LINES_REQUIRE_COUNTER_SALE", "PRODUCT_COST_UNKNOWN", "PRICE_CHANGE_DISABLED", "LINE_DISCOUNT_EXCEEDS_MAX", "CUSTOMER_DISABLED", "SHIFT_NOT_AVAILABLE", "SOLD_AT_OUTSIDE_SHIFT", "ORDER_CURRENCY_NOT_SUBSCRIBED", "PAYMENT_METHODS_NOT_CONFIGURED", "PAYMENT_METHOD_NOT_FOUND", "DELIVERY_METHOD_NOT_FOUND", "ORDER_BELOW_MINIMUM_PURCHASE", "ORDER_INVALID_CART", "EMAIL_VERIFICATION_REQUIRED", "ACCOUNT_DISABLED", "CURRENCY_MISMATCH", "SHIFT_NOT_OPEN", "ORDER_DISCOUNT_AFTER_INVOICE", "ORDER_DISCOUNT_ON_SERVICE_ORDER", "ORDER_DISCOUNT_ON_MARKETPLACE_ORDER", "ORDER_INVOICE_METHOD_OUTSTANDING_FACTURA", "ORDER_SERVICE_PERIOD_AFTER_INVOICE", "ORDER_ATTEMPT_COMMITTED", "ORDER_ATTEMPT_ABANDONED", "ORDER_ATTEMPT_KEY_EXPIRED", "ORDER_ATTEMPT_KEY_SCOPE_MISMATCH"];
|
|
2705
2727
|
export type OrderErrorCode = (typeof ORDER_ERROR_CODES)[number];
|
|
2706
2728
|
export {};
|
package/dist/order.js
CHANGED
|
@@ -228,6 +228,15 @@ export const orderFulfilmentProgress = (order) => {
|
|
|
228
228
|
* is also `mode: 'edit'`'s and the update leg's answer to a re-price that
|
|
229
229
|
* would leave the order's net señas above its new charged total. Nothing was
|
|
230
230
|
* written on any of them.
|
|
231
|
+
* - `TILL_TENDER_REQUIRES_DEPOSIT` · 400 — `mode: 'tender'` adding till money
|
|
232
|
+
* (any leg whose `source` is not `account`) to an order that is NOT yet
|
|
233
|
+
* delivered and holds no seña: money taken before delivery is a seña and
|
|
234
|
+
* goes through `mode: 'deposit'`. Decided after replays are absorbed, so a
|
|
235
|
+
* pure repeat of legs already on the ledger still answers its 200; an
|
|
236
|
+
* account-only tender is never refused. Nothing was written and no
|
|
237
|
+
* idempotency marker remains (refused ahead of the claim, or the claim is
|
|
238
|
+
* released on the 400), so a collection lookup for it answers
|
|
239
|
+
* `unknown` / `NO_EVIDENCE`.
|
|
231
240
|
* - `PAYMENT_REFERENCED_BY_DEPOSIT` · 409 — the payment link (fresh, over an
|
|
232
241
|
* entry the order already holds, or a credit upgrade) of a payment whose id a
|
|
233
242
|
* seña on the order already carries as its `reference`: the same money would
|
|
@@ -435,6 +444,19 @@ export const orderFulfilmentProgress = (order) => {
|
|
|
435
444
|
* for another store or user session (`ORDER_ATTEMPT_SCOPE_TAG_LENGTH`). Mint
|
|
436
445
|
* a new key in this session. Nothing was written.
|
|
437
446
|
*
|
|
447
|
+
* ⚠️ **A money write's attempt identity is its `Idempotency-Key`, never its
|
|
448
|
+
* `reference`.** Mint one key per tender, seña or account payment and keep it
|
|
449
|
+
* for every retry. `reference` is a duplicate-money guard with its own
|
|
450
|
+
* horizon, not an outcome, and it runs across keys: a tender absorbs a repeat
|
|
451
|
+
* leg identical on money, method and source that carries the same `reference`
|
|
452
|
+
* indefinitely, or — neither side carrying one — was recorded by the same user
|
|
453
|
+
* within 30 seconds; a seña absorbs a same-user or same-`reference` repeat
|
|
454
|
+
* only inside its 30-second replay window, and an older lookalike is
|
|
455
|
+
* `409 DEPOSIT_DUPLICATE_REFERENCE`. To learn whether a keyed
|
|
456
|
+
* write landed after a lost reply, `IDEMPOTENCY_IN_PROGRESS` or
|
|
457
|
+
* `IDEMPOTENCY_KEY_FAILED`, ask `POST /orders { mode: 'collection-attempt' }`
|
|
458
|
+
* (`OrderCollectionAttemptVerdict`) — never resend it under a new key first.
|
|
459
|
+
*
|
|
438
460
|
* Idempotency answers, all six from `withIdempotency`:
|
|
439
461
|
* - `INVALID_IDEMPOTENCY_KEY` · 400 · `IDEMPOTENCY_KEY_REUSE` · 422 (the same
|
|
440
462
|
* key with a different body)
|
|
@@ -514,6 +536,8 @@ export const ORDER_ERROR_CODES = [
|
|
|
514
536
|
'DEPOSIT_INVOICED_ORDER_MUST_FREEZE',
|
|
515
537
|
'DEPOSIT_REFERENCE_IS_LINKED_PAYMENT',
|
|
516
538
|
'DEPOSIT_DUPLICATE_REFERENCE',
|
|
539
|
+
// Till money on an undelivered order with no seña — `mode: 'deposit'` takes it.
|
|
540
|
+
'TILL_TENDER_REQUIRES_DEPOSIT',
|
|
517
541
|
// The payment link of a payment a seña on the order already references.
|
|
518
542
|
'PAYMENT_REFERENCED_BY_DEPOSIT',
|
|
519
543
|
// Customer cancellation of an order still holding a seña.
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Order-collection attempt lookup — the read a client runs when a money write
|
|
3
|
+
* on an order (a till tender, a seña, an account payment) left it without an
|
|
4
|
+
* answer: a lost reply, a timeout, or one of the two uncertain refusals
|
|
5
|
+
* `409 IDEMPOTENCY_IN_PROGRESS` and `409 IDEMPOTENCY_KEY_FAILED`.
|
|
6
|
+
*
|
|
7
|
+
* ⚠️ **The attempt's identity is its `Idempotency-Key`, never its `reference`.**
|
|
8
|
+
* Mint ONE key per collection attempt and keep it for every retry of that
|
|
9
|
+
* attempt. `reference` keeps its own, narrower meaning as a duplicate-money
|
|
10
|
+
* guard, and that guard runs ACROSS keys: a tender absorbs a repeat leg
|
|
11
|
+
* identical on money, method and source that carries the same `reference`
|
|
12
|
+
* however much later it arrives, OR — neither side carrying a reference — was
|
|
13
|
+
* recorded by the same user within 30 seconds; a seña absorbs a same-user or
|
|
14
|
+
* same-`reference` repeat only inside its 30-second replay window (an older
|
|
15
|
+
* lookalike is `409 DEPOSIT_DUPLICATE_REFERENCE`). So a NEW key is a new
|
|
16
|
+
* attempt, not a guaranteed new leg: two genuine reference-less handoffs of the
|
|
17
|
+
* same amount by one cashier inside 30 s land as ONE leg, and the second key
|
|
18
|
+
* answers `committed` all the same. Give each physical payment its own
|
|
19
|
+
* `reference` when that distinction matters. Neither guard is an outcome
|
|
20
|
+
* protocol.
|
|
21
|
+
*
|
|
22
|
+
* `POST /orders { mode: 'collection-attempt', operation, orderId, idempotencyKey }`
|
|
23
|
+
* answers from the write's own idempotency marker, scoped to the CALLER's store
|
|
24
|
+
* and user. It never claims, replays, reclaims or seals the marker, never
|
|
25
|
+
* writes the marker or any business row, and calls no provider; a claim it
|
|
26
|
+
* finds stranded past 60 s logs one deduped operator row.
|
|
27
|
+
*/
|
|
28
|
+
declare global {
|
|
29
|
+
/** One of {@link ORDER_COLLECTION_ATTEMPT_OPERATIONS}. */
|
|
30
|
+
type OrderCollectionAttemptOperation = (typeof ORDER_COLLECTION_ATTEMPT_OPERATIONS)[number];
|
|
31
|
+
/** One of {@link ORDER_COLLECTION_ATTEMPT_VERDICTS}. */
|
|
32
|
+
type OrderCollectionAttemptVerdictKind = (typeof ORDER_COLLECTION_ATTEMPT_VERDICTS)[number];
|
|
33
|
+
/** Why a lookup could not decide — one of {@link ORDER_COLLECTION_ATTEMPT_UNKNOWN_REASONS}. */
|
|
34
|
+
type OrderCollectionAttemptUnknownReason = (typeof ORDER_COLLECTION_ATTEMPT_UNKNOWN_REASONS)[number];
|
|
35
|
+
/**
|
|
36
|
+
* `POST /orders` body for the lookup.
|
|
37
|
+
*
|
|
38
|
+
* - `operation` — which write the key was sent with: `tender`
|
|
39
|
+
* (`POST /orders { mode: 'tender' }`), `deposit`
|
|
40
|
+
* (`POST /orders { mode: 'deposit' }`) or `account` (`POST /account`, a
|
|
41
|
+
* customer-account movement sent with this `orderId`).
|
|
42
|
+
* - `orderId` — the order that write named.
|
|
43
|
+
* - `idempotencyKey` — the exact `Idempotency-Key` header the write carried.
|
|
44
|
+
*
|
|
45
|
+
* The store and user are the caller's session, never a body or header
|
|
46
|
+
* field. The lookup is not itself idempotency-keyed and is safe to repeat;
|
|
47
|
+
* an `in-progress` answer is a moment in time, so ask again after
|
|
48
|
+
* `retryAfterMs` and never cache it.
|
|
49
|
+
*/
|
|
50
|
+
interface OrderCollectionAttemptLookupRequest {
|
|
51
|
+
mode: 'collection-attempt';
|
|
52
|
+
operation: OrderCollectionAttemptOperation;
|
|
53
|
+
orderId: string;
|
|
54
|
+
idempotencyKey: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* `data` of a `200` from `POST /orders { mode: 'collection-attempt' }`.
|
|
58
|
+
*
|
|
59
|
+
* - `committed` — the write answered `2xx` (`statusCode`). `body` is the
|
|
60
|
+
* exact JSON envelope it answered — for a tender or a seña the order's
|
|
61
|
+
* post-commit echo with the updated settlement (a repeat the dedupe guard
|
|
62
|
+
* absorbed appended no leg, and the echo shows the ledger as it stands);
|
|
63
|
+
* for an account movement its ACCOUNT row. `body` is `null` when no usable
|
|
64
|
+
* envelope was cached (a body too large to keep, or not JSON);
|
|
65
|
+
* `statusCode` is `null` only on a marker that cached no response at all.
|
|
66
|
+
* `claimedAt` is the instant the write was admitted (epoch ms), at or
|
|
67
|
+
* before its commit. Do not collect again.
|
|
68
|
+
* - `in-progress` — the write is still running. Ask again after
|
|
69
|
+
* `retryAfterMs`.
|
|
70
|
+
* - `sealed` — the write may or may not have landed and can never be
|
|
71
|
+
* re-run under this key. `abandoned: false` — the key is sealed: by a
|
|
72
|
+
* throw after the transaction may have committed, or by a later same-key
|
|
73
|
+
* retry that found the claim stranded. `abandoned: true` — the claim is
|
|
74
|
+
* still stranded `in_progress` past 60 s: the invocation died mid-flight
|
|
75
|
+
* and nothing has sealed it yet. Show "unresolved — check", never
|
|
76
|
+
* "pay again", and verify where the operation writes before collecting
|
|
77
|
+
* under a NEW key: the order's `tenders` for `tender` and `deposit`; the
|
|
78
|
+
* customer's account movements carrying this `orderId` for `account`,
|
|
79
|
+
* which never writes the order.
|
|
80
|
+
* - `unknown` — the server holds no evidence for this attempt; `reason`
|
|
81
|
+
* says why. Never read it as "not written": a write released before it
|
|
82
|
+
* committed leaves no evidence, and so does one STILL IN FLIGHT that has
|
|
83
|
+
* not claimed its key yet (`NO_EVIDENCE`). The safe remedy, in this order:
|
|
84
|
+
* 1. FIRST resend the identical request — the same body under the SAME
|
|
85
|
+
* `Idempotency-Key`, as the SAME user. The write's claim is a
|
|
86
|
+
* conditional put (`attribute_not_exists`), so the resend serialises
|
|
87
|
+
* against any copy still in flight: it replays the cached `2xx` of a
|
|
88
|
+
* write that committed, or runs exactly once. A
|
|
89
|
+
* `409 IDEMPOTENCY_IN_PROGRESS` means a copy holds the claim — ask the
|
|
90
|
+
* lookup again after a pause; a `409 IDEMPOTENCY_KEY_FAILED` means the
|
|
91
|
+
* key is sealed — handle it as `sealed`. Neither is a second charge.
|
|
92
|
+
* "Identical" is what the write fingerprints: a changed body answers
|
|
93
|
+
* `422 IDEMPOTENCY_KEY_REUSE` (for `POST /account` a fresh
|
|
94
|
+
* `elevationToken` is not a change).
|
|
95
|
+
* 2. Collect under a NEW key only after the operator has verified where
|
|
96
|
+
* the operation writes (as for `sealed`) AND at least 30 seconds have
|
|
97
|
+
* passed since the last send of this key — API Gateway stops waiting at
|
|
98
|
+
* 29 s, and the writing Lambdas time out at 25 s (`tender`, `deposit`)
|
|
99
|
+
* and 20 s (`account`).
|
|
100
|
+
* This holds inside {@link ORDER_COLLECTION_ATTEMPT_RETENTION_MS} of the
|
|
101
|
+
* attempt's first send. Past it a same-key resend is no longer a safe
|
|
102
|
+
* probe (see `EVIDENCE_EXPIRED`): verify first.
|
|
103
|
+
*
|
|
104
|
+
* ⚠️ A verdict only ever describes the caller's OWN key: another user's or
|
|
105
|
+
* another store's key answers `unknown` / `NO_EVIDENCE`, never their verdict.
|
|
106
|
+
*/
|
|
107
|
+
type OrderCollectionAttemptVerdict = {
|
|
108
|
+
verdict: Extract<OrderCollectionAttemptVerdictKind, 'committed'>;
|
|
109
|
+
claimedAt: number | null;
|
|
110
|
+
statusCode: number | null;
|
|
111
|
+
body: Record<string, unknown> | null;
|
|
112
|
+
} | {
|
|
113
|
+
verdict: Extract<OrderCollectionAttemptVerdictKind, 'in-progress'>;
|
|
114
|
+
retryAfterMs: number;
|
|
115
|
+
claimedAt: number;
|
|
116
|
+
} | {
|
|
117
|
+
verdict: Extract<OrderCollectionAttemptVerdictKind, 'sealed'>;
|
|
118
|
+
claimedAt: number | null;
|
|
119
|
+
abandoned: boolean;
|
|
120
|
+
} | {
|
|
121
|
+
verdict: Extract<OrderCollectionAttemptVerdictKind, 'unknown'>;
|
|
122
|
+
reason: OrderCollectionAttemptUnknownReason;
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/** Every `operation` the lookup answers for — see `OrderCollectionAttemptLookupRequest`. */
|
|
126
|
+
export declare const ORDER_COLLECTION_ATTEMPT_OPERATIONS: readonly ["tender", "deposit", "account"];
|
|
127
|
+
/** Every `verdict` the lookup answers — see `OrderCollectionAttemptVerdict`. */
|
|
128
|
+
export declare const ORDER_COLLECTION_ATTEMPT_VERDICTS: readonly ["committed", "in-progress", "sealed", "unknown"];
|
|
129
|
+
/**
|
|
130
|
+
* Every `reason` on an `unknown` verdict:
|
|
131
|
+
*
|
|
132
|
+
* - `NO_EVIDENCE` — no marker under this key for the caller: never sent, sent
|
|
133
|
+
* by another user or store, refused or released before it committed,
|
|
134
|
+
* already deleted by its retention expiry — or STILL IN FLIGHT and not yet
|
|
135
|
+
* claimed. A write holds no marker until its claim lands, and before that
|
|
136
|
+
* it can be queued at the gateway, in a cold start, or (a tender) running
|
|
137
|
+
* its pre-claim reads. So it is never "not collected": follow the
|
|
138
|
+
* `unknown` remedy on `OrderCollectionAttemptVerdict` — resend the same
|
|
139
|
+
* body under the same key first.
|
|
140
|
+
* - `EVIDENCE_EXPIRED` — the marker outlived
|
|
141
|
+
* {@link ORDER_COLLECTION_ATTEMPT_RETENTION_MS} and is awaiting deletion,
|
|
142
|
+
* which DynamoDB does lazily (up to days late). That is the LOOKUP's
|
|
143
|
+
* horizon, not the writer's: the write never reads the expiry, so while
|
|
144
|
+
* the row survives a same-key resend still replays a committed `200` (or
|
|
145
|
+
* refuses a sealed or stranded key) and does NOT run again. Once DynamoDB
|
|
146
|
+
* deletes the row the same resend runs as a new write — so past the
|
|
147
|
+
* horizon verify where the operation writes before resending at all.
|
|
148
|
+
* - `UNBOUND_ATTEMPT` — the key belongs to a write that is not a collection
|
|
149
|
+
* attempt (another order mode), or to one admitted before the server
|
|
150
|
+
* started recording which collection a key was for.
|
|
151
|
+
* - `ATTEMPT_MISMATCH` — the key was sent for a different `operation` or
|
|
152
|
+
* `orderId` than the lookup names.
|
|
153
|
+
* - `REFUSED` — the write's cached answer was a refusal (non-`2xx`): nothing
|
|
154
|
+
* moved under this key. No collection write caches a refusal today; this
|
|
155
|
+
* keeps one that ever does from reading as `committed`.
|
|
156
|
+
*/
|
|
157
|
+
export declare const ORDER_COLLECTION_ATTEMPT_UNKNOWN_REASONS: readonly ["NO_EVIDENCE", "EVIDENCE_EXPIRED", "UNBOUND_ATTEMPT", "ATTEMPT_MISMATCH", "REFUSED"];
|
|
158
|
+
/**
|
|
159
|
+
* How long the server keeps a collection attempt's evidence: 24 hours — the
|
|
160
|
+
* write's own idempotency retention. Past it the lookup answers `unknown`.
|
|
161
|
+
*/
|
|
162
|
+
export declare const ORDER_COLLECTION_ATTEMPT_RETENTION_MS = 86400000;
|
|
163
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Order-collection attempt lookup — the read a client runs when a money write
|
|
3
|
+
* on an order (a till tender, a seña, an account payment) left it without an
|
|
4
|
+
* answer: a lost reply, a timeout, or one of the two uncertain refusals
|
|
5
|
+
* `409 IDEMPOTENCY_IN_PROGRESS` and `409 IDEMPOTENCY_KEY_FAILED`.
|
|
6
|
+
*
|
|
7
|
+
* ⚠️ **The attempt's identity is its `Idempotency-Key`, never its `reference`.**
|
|
8
|
+
* Mint ONE key per collection attempt and keep it for every retry of that
|
|
9
|
+
* attempt. `reference` keeps its own, narrower meaning as a duplicate-money
|
|
10
|
+
* guard, and that guard runs ACROSS keys: a tender absorbs a repeat leg
|
|
11
|
+
* identical on money, method and source that carries the same `reference`
|
|
12
|
+
* however much later it arrives, OR — neither side carrying a reference — was
|
|
13
|
+
* recorded by the same user within 30 seconds; a seña absorbs a same-user or
|
|
14
|
+
* same-`reference` repeat only inside its 30-second replay window (an older
|
|
15
|
+
* lookalike is `409 DEPOSIT_DUPLICATE_REFERENCE`). So a NEW key is a new
|
|
16
|
+
* attempt, not a guaranteed new leg: two genuine reference-less handoffs of the
|
|
17
|
+
* same amount by one cashier inside 30 s land as ONE leg, and the second key
|
|
18
|
+
* answers `committed` all the same. Give each physical payment its own
|
|
19
|
+
* `reference` when that distinction matters. Neither guard is an outcome
|
|
20
|
+
* protocol.
|
|
21
|
+
*
|
|
22
|
+
* `POST /orders { mode: 'collection-attempt', operation, orderId, idempotencyKey }`
|
|
23
|
+
* answers from the write's own idempotency marker, scoped to the CALLER's store
|
|
24
|
+
* and user. It never claims, replays, reclaims or seals the marker, never
|
|
25
|
+
* writes the marker or any business row, and calls no provider; a claim it
|
|
26
|
+
* finds stranded past 60 s logs one deduped operator row.
|
|
27
|
+
*/
|
|
28
|
+
/** Every `operation` the lookup answers for — see `OrderCollectionAttemptLookupRequest`. */
|
|
29
|
+
export const ORDER_COLLECTION_ATTEMPT_OPERATIONS = ['tender', 'deposit', 'account'];
|
|
30
|
+
/** Every `verdict` the lookup answers — see `OrderCollectionAttemptVerdict`. */
|
|
31
|
+
export const ORDER_COLLECTION_ATTEMPT_VERDICTS = ['committed', 'in-progress', 'sealed', 'unknown'];
|
|
32
|
+
/**
|
|
33
|
+
* Every `reason` on an `unknown` verdict:
|
|
34
|
+
*
|
|
35
|
+
* - `NO_EVIDENCE` — no marker under this key for the caller: never sent, sent
|
|
36
|
+
* by another user or store, refused or released before it committed,
|
|
37
|
+
* already deleted by its retention expiry — or STILL IN FLIGHT and not yet
|
|
38
|
+
* claimed. A write holds no marker until its claim lands, and before that
|
|
39
|
+
* it can be queued at the gateway, in a cold start, or (a tender) running
|
|
40
|
+
* its pre-claim reads. So it is never "not collected": follow the
|
|
41
|
+
* `unknown` remedy on `OrderCollectionAttemptVerdict` — resend the same
|
|
42
|
+
* body under the same key first.
|
|
43
|
+
* - `EVIDENCE_EXPIRED` — the marker outlived
|
|
44
|
+
* {@link ORDER_COLLECTION_ATTEMPT_RETENTION_MS} and is awaiting deletion,
|
|
45
|
+
* which DynamoDB does lazily (up to days late). That is the LOOKUP's
|
|
46
|
+
* horizon, not the writer's: the write never reads the expiry, so while
|
|
47
|
+
* the row survives a same-key resend still replays a committed `200` (or
|
|
48
|
+
* refuses a sealed or stranded key) and does NOT run again. Once DynamoDB
|
|
49
|
+
* deletes the row the same resend runs as a new write — so past the
|
|
50
|
+
* horizon verify where the operation writes before resending at all.
|
|
51
|
+
* - `UNBOUND_ATTEMPT` — the key belongs to a write that is not a collection
|
|
52
|
+
* attempt (another order mode), or to one admitted before the server
|
|
53
|
+
* started recording which collection a key was for.
|
|
54
|
+
* - `ATTEMPT_MISMATCH` — the key was sent for a different `operation` or
|
|
55
|
+
* `orderId` than the lookup names.
|
|
56
|
+
* - `REFUSED` — the write's cached answer was a refusal (non-`2xx`): nothing
|
|
57
|
+
* moved under this key. No collection write caches a refusal today; this
|
|
58
|
+
* keeps one that ever does from reading as `committed`.
|
|
59
|
+
*/
|
|
60
|
+
export const ORDER_COLLECTION_ATTEMPT_UNKNOWN_REASONS = [
|
|
61
|
+
'NO_EVIDENCE',
|
|
62
|
+
'EVIDENCE_EXPIRED',
|
|
63
|
+
'UNBOUND_ATTEMPT',
|
|
64
|
+
'ATTEMPT_MISMATCH',
|
|
65
|
+
'REFUSED',
|
|
66
|
+
];
|
|
67
|
+
/**
|
|
68
|
+
* How long the server keeps a collection attempt's evidence: 24 hours — the
|
|
69
|
+
* write's own idempotency retention. Past it the lookup answers `unknown`.
|
|
70
|
+
*/
|
|
71
|
+
export const ORDER_COLLECTION_ATTEMPT_RETENTION_MS = 86_400_000;
|
package/dist/platform.d.ts
CHANGED
|
@@ -846,15 +846,15 @@ export interface TenantBillingRollupRow {
|
|
|
846
846
|
}
|
|
847
847
|
/**
|
|
848
848
|
* @deprecated Nothing produces one any more. The copy↔entitlement consistency
|
|
849
|
-
* check went with the free-text plan copy it checked,
|
|
850
|
-
*
|
|
851
|
-
* type stays only
|
|
852
|
-
*
|
|
849
|
+
* check went with the free-text plan copy it checked, and the `warnings` array
|
|
850
|
+
* that carried its findings is gone from the `POST` / `PATCH
|
|
851
|
+
* /platform/billing/plans` replies. The type stays only for the archived check
|
|
852
|
+
* under `stacks/services/_retired/` and for a consumer still naming it.
|
|
853
853
|
*/
|
|
854
854
|
export type CatalogWarningCode = 'NUMERIC_MISMATCH' | 'UNLIMITED_ADVERTISED_AS_CAPPED' | 'UNBACKED_CAPABILITY' | 'MISSING_FEATURE_ROW';
|
|
855
855
|
/**
|
|
856
|
-
* @deprecated See {@link CatalogWarningCode} — no writer emits one
|
|
857
|
-
* `warnings` array
|
|
856
|
+
* @deprecated See {@link CatalogWarningCode} — no writer emits one, and no
|
|
857
|
+
* reply carries a `warnings` array of them any more.
|
|
858
858
|
*/
|
|
859
859
|
export interface CatalogWarning {
|
|
860
860
|
code: CatalogWarningCode;
|
|
@@ -1053,7 +1053,10 @@ export interface PlatformMrrMetrics {
|
|
|
1053
1053
|
* the safer direction for a number an operator acts on.
|
|
1054
1054
|
*/
|
|
1055
1055
|
countedStatuses: SubscriptionStatus[];
|
|
1056
|
-
/**
|
|
1056
|
+
/**
|
|
1057
|
+
* `priceAnnualCents` is the yearly total charged once per year, so
|
|
1058
|
+
* `priceAnnualCents / annualDivisor` is one annual subscription's monthly contribution.
|
|
1059
|
+
*/
|
|
1057
1060
|
annualDivisor: number;
|
|
1058
1061
|
/** Subscriptions in a counted status. The denominator for `excluded`. */
|
|
1059
1062
|
countedSubscriptions: number;
|
package/dist/subscription.d.ts
CHANGED
|
@@ -249,7 +249,7 @@ declare global {
|
|
|
249
249
|
*
|
|
250
250
|
* Prices are integers in the `currency` smallest unit (centavos for ARS,
|
|
251
251
|
* cents for USD). `null` = "Contactar ventas" (AVANZADO annual at launch
|
|
252
|
-
* is sales-led; basico
|
|
252
|
+
* is sales-led; basico is free) per spec §6.4.
|
|
253
253
|
*
|
|
254
254
|
* **Breaking change vs 1.1.x:** the catalog Plan interface was reshaped
|
|
255
255
|
* to match the BE wire format. Renames & removals:
|
|
@@ -293,7 +293,12 @@ declare global {
|
|
|
293
293
|
displayOrder: number;
|
|
294
294
|
/** Monthly price in `currency` smallest units. `null` = sales-led / free. */
|
|
295
295
|
priceMonthlyCents: number | null;
|
|
296
|
-
/**
|
|
296
|
+
/**
|
|
297
|
+
* The YEARLY TOTAL, charged once per year, in `currency` smallest units —
|
|
298
|
+
* never a per-month figure. Divide by 12 for a monthly equivalent.
|
|
299
|
+
* Nothing enforces its ratio to `priceMonthlyCents`; the operator sets
|
|
300
|
+
* both. `null` = sales-led / free.
|
|
301
|
+
*/
|
|
297
302
|
priceAnnualCents: number | null;
|
|
298
303
|
/**
|
|
299
304
|
* Currency the prices are denominated in. `'ARS'` at launch; `'USD'`
|
|
@@ -313,14 +318,6 @@ declare global {
|
|
|
313
318
|
* `limit`.
|
|
314
319
|
*/
|
|
315
320
|
features: PlanFeature[];
|
|
316
|
-
/**
|
|
317
|
-
* @deprecated ALWAYS `[]`. The free-text card copy was retired: a plan
|
|
318
|
-
* card renders {@link Plan.highlights} instead, and no write accepts
|
|
319
|
-
* `bullets` any more (`POST`/`PATCH /platform/billing/plans` answer 400
|
|
320
|
-
* `VALIDATION_FAILED`). A value an old row still stores is ignored, never
|
|
321
|
-
* echoed. The key will be removed once the app's copy editor is gone.
|
|
322
|
-
*/
|
|
323
|
-
bullets: string[];
|
|
324
321
|
/**
|
|
325
322
|
* Keys worth calling out on this tier's card: highlight-eligible keys with
|
|
326
323
|
* status `live` or `service` whose grant improves on the next lower
|