sinfactura-types 1.10.520 → 1.10.522

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.
@@ -593,7 +593,8 @@ declare global {
593
593
  | 'CUSTOMER_LEDGER_TRUNCATED'
594
594
  /**
595
595
  * A concurrent LEDGER write moved `balance` or `eventSeq` between the
596
- * erasure's pre-read and its conditional write, so the write cancelled.
596
+ * erasure's pre-read and its conditional write, so the write cancelled —
597
+ * or, far rarer, the row's email claim changed owner in that window.
597
598
  *
598
599
  * ⚠️ **NOTHING was erased, and this is the one refusal that is safe to
599
600
  * retry immediately.** It is distinct from `CUSTOMER_ALREADY_ANONYMIZED`
@@ -620,7 +621,80 @@ declare global {
620
621
  * The storefront twin answers this code with a generic message that never
621
622
  * mentions a merge; the operator surface names it.
622
623
  */
623
- | 'CUSTOMER_ERASURE_MERGE_IN_PROGRESS';
624
+ | 'CUSTOMER_ERASURE_MERGE_IN_PROGRESS'
625
+ /**
626
+ * The customer was merged into another one, so the erasure must go through
627
+ * that survivor (see `AnonymizeCustomerResult.erasedCustomerId`), and the
628
+ * survivor cannot be erased WHOLE. NOTHING was written, on either row.
629
+ * `data` is `CustomerErasureIncompleteData`; its `erasureIncompleteReason`
630
+ * says why. A deduped ERROR row (`CUSTOMER_ERASURE_INCOMPLETE`) tells staff,
631
+ * on both surfaces.
632
+ */
633
+ | 'CUSTOMER_ERASURE_INCOMPLETE'
634
+ /**
635
+ * 409, STOREFRONT ONLY (`POST /user` mode `anonymize`). The calling
636
+ * customer's own account was merged away into another one, and the
637
+ * storefront never erases through a survivor: only staff do, on
638
+ * `POST /customers` mode `anonymize`. NOTHING was written. `data` is
639
+ * `CustomerErasureRequiresStaffData` — the caller's own id and nothing else.
640
+ * One ERROR row (`CUSTOMER_ERASURE_REQUIRES_STAFF`), deduped per customer per
641
+ * day, tells staff that the customer asked. The client tells the shopper to
642
+ * contact the shop; retrying cannot succeed.
643
+ */
644
+ | 'CUSTOMER_ERASURE_REQUIRES_STAFF';
645
+ /**
646
+ * Why an erasure of a merged-away customer was refused as incomplete.
647
+ *
648
+ * - `MERGE_CHAIN` — the survivor was itself merged into a third customer (A
649
+ * into B, then B into C). Chains are never walked: erase the end of the
650
+ * chain by hand.
651
+ * - `MERGE_SURVIVOR_UNRESOLVED` — the survivor the customer names is gone.
652
+ * - `MERGE_LOOKUP_TRUNCATED` — NOT a refusal: only on a 200's
653
+ * `AnonymizeCustomerResult.erasureIncompleteReason`. The store's customers
654
+ * could not be read to the end to rule out a survivor, or a chain past one
655
+ * (an erased customer naming no survivor, or a survivor erased before its own
656
+ * survivor id was kept). The rows known were erased — the survivor the
657
+ * customer's own row names included, when that survivor was already erased.
658
+ * Re-issue. ⚠️ The re-issue can erase ANOTHER account whole: when the lookup
659
+ * then completes and finds the customer was merged, it goes through that
660
+ * survivor. Wins over `MERGED_ROW_NOT_ERASED` when both hold.
661
+ * - `MERGED_ROW_NOT_ERASED` — NOT a refusal either: the target was erased but
662
+ * the erasure of a merged-away row folded into it is unfinished — its write
663
+ * failed, the erasure ran out of time before reaching it, or one of its
664
+ * completion steps reported incomplete. `incompleteCustomerIds` names the
665
+ * rows. Re-issue.
666
+ */
667
+ type CustomerErasureIncompleteReason = 'MERGE_CHAIN' | 'MERGE_SURVIVOR_UNRESOLVED' | 'MERGE_LOOKUP_TRUNCATED' | 'MERGED_ROW_NOT_ERASED';
668
+ /** The reasons a 200 erasure can carry (`AnonymizeCustomerResult.erasureIncompleteReason`). */
669
+ type CustomerErasureResultIncompleteReason = Extract<CustomerErasureIncompleteReason, 'MERGE_LOOKUP_TRUNCATED' | 'MERGED_ROW_NOT_ERASED'>;
670
+ /** `data` of a `409 CUSTOMER_ERASURE_INCOMPLETE` refusal, on both erasure surfaces. Ids only. */
671
+ interface CustomerErasureIncompleteData {
672
+ /** The id the request named. */
673
+ customerId: string;
674
+ erasureIncompleteReason: Exclude<CustomerErasureIncompleteReason, CustomerErasureResultIncompleteReason>;
675
+ }
676
+ /** `data` of the storefront's `409 CUSTOMER_ERASURE_REQUIRES_STAFF`: the caller's OWN id, nothing else. */
677
+ interface CustomerErasureRequiresStaffData {
678
+ customerId: string;
679
+ }
680
+ /**
681
+ * Extra `data` keys of an OPERATOR erasure refusal (`POST /customers` mode
682
+ * `anonymize`) that is about ANOTHER row than the one the request named. The
683
+ * refusal's own keys are unchanged: `customerId` is still the row the refusal
684
+ * belongs to (whose balance, whose open orders), which on these refusals is
685
+ * not the customer the operator named. Never on the storefront wire.
686
+ */
687
+ interface CustomerErasureRefusalContext {
688
+ /** The id the request named. Present whenever either key below applies. */
689
+ requestedCustomerId?: string;
690
+ /**
691
+ * The merge survivor the erasure goes through — the account that would be
692
+ * erased whole. Present only on a redirect (the named customer was merged
693
+ * away). Absent when the refusal is a merged-away row's, folded into the
694
+ * customer that was named.
695
+ */
696
+ survivorCustomerId?: string;
697
+ }
624
698
  /**
625
699
  * Every refusal `POST /customers { mode: 'merge' }` can answer, as the bare
626
700
  * SCREAMING_SNAKE `error` code on the wire. Thrown by
@@ -726,10 +800,15 @@ declare global {
726
800
  */
727
801
  type CustomerBalanceWriteErrorCode = 'CUSTOMER_MERGED'
728
802
  /**
729
- * `DELETE /payments/{source}/{paymentId}/link` only: the credit row is a
730
- * LEGACY row naming no customer, and the payment's customer was erased —
731
- * so whether it had been merged first (and where its money went) is no
732
- * longer provable. `409`, nothing written; `data` is absent.
803
+ * `409`, nothing written; `data` is absent. Answered by:
804
+ * - `DELETE /payments/{source}/{paymentId}/link`: the credit row is a
805
+ * LEGACY row naming no customer, and the payment's customer was erased —
806
+ * so whether it had been merged first (and where its money went) is no
807
+ * longer provable;
808
+ * - `POST /account`, for a movement that carries the customer's name: the
809
+ * customer was erased between the handler's read of the name and its
810
+ * write. Re-issue it: the retry reads the erasure and books the movement
811
+ * with no name.
733
812
  */
734
813
  | 'CUSTOMER_ANONYMIZED';
735
814
  /**
@@ -1012,9 +1091,55 @@ declare global {
1012
1091
  * row is anonymised in place and KEPT — see `Customer.anonymizedAt`.
1013
1092
  */
1014
1093
  interface AnonymizeCustomerResult {
1094
+ /** The id the request named. */
1015
1095
  customerId: string;
1016
- /** ms epoch stamped on the row. */
1096
+ /**
1097
+ * The id whose personal data this erasure removed. Equal to `customerId`,
1098
+ * except — on the OPERATOR route only — for a customer that a FINISHED merge
1099
+ * folded into another one: the person's orders, ledger, notes, addresses and
1100
+ * contacts then live on that survivor, so the WHOLE survivor is erased (its
1101
+ * own refusals apply), and `customerId`'s own row with it
1102
+ * (`alsoErasedCustomerIds`). A client must say so FIRST whenever the two
1103
+ * differ, naming this id: another account than the one named was erased. The
1104
+ * storefront never redirects (`CUSTOMER_ERASURE_REQUIRES_STAFF`), so there the
1105
+ * two are always equal. The counts below are summed over every row this
1106
+ * erasure ran, and each `*Complete` flag holds only when it holds for every
1107
+ * one.
1108
+ */
1109
+ erasedCustomerId: string;
1110
+ /**
1111
+ * The merged-away customers a finished merge folded into `erasedCustomerId`
1112
+ * (its `mergedFrom`, followed row by row) whose erasure this call ran: each
1113
+ * is a record of the same person. A row not yet anonymised is anonymised; one
1114
+ * an earlier erasure anonymised has its completion steps re-run, on every
1115
+ * call. On a redirect it includes `customerId` — unless that row's own write
1116
+ * failed (then `incompleteCustomerIds` names it) or a concurrent erasure
1117
+ * took it. Likewise any folded row that failed, was taken by a concurrent
1118
+ * erasure, or was not reached before the erasure ran out of time is NOT
1119
+ * listed. Absent when this erasure ran only `erasedCustomerId`. A client must
1120
+ * name them.
1121
+ */
1122
+ alsoErasedCustomerIds?: string[];
1123
+ /**
1124
+ * The rows whose erasure this call left UNFINISHED: `erasedCustomerId` when
1125
+ * one of its completion steps reported incomplete, and every merged-away row
1126
+ * that failed, was not reached before the erasure ran out of time, or has a
1127
+ * completion step incomplete. Set only on an erasure of more than one row (a
1128
+ * redirect, or a target with merged-away rows) — for a single row the
1129
+ * `*Complete` flags already say whose they are. Absent when every row
1130
+ * finished. Re-issuing the erasure takes them up; the
1131
+ * `CUSTOMER_ERASURE_INCOMPLETE` ERROR row carries the same ids.
1132
+ */
1133
+ incompleteCustomerIds?: string[];
1134
+ /** ms epoch stamped on the row — the erased (survivor's) row when redirected. */
1017
1135
  anonymizedAt: number;
1136
+ /**
1137
+ * Set when this erasure is, or may be, INCOMPLETE as a whole — see
1138
+ * `CustomerErasureIncompleteReason`. A client must say the erasure is not
1139
+ * complete; both handlers write the deduped `CUSTOMER_ERASURE_INCOMPLETE`
1140
+ * ERROR row.
1141
+ */
1142
+ erasureIncompleteReason?: CustomerErasureResultIncompleteReason;
1018
1143
  /**
1019
1144
  * The attribute NAMES removed — names only, never values, so this is
1020
1145
  * safe to return, log and audit. Evidence that the sweep covered a field
@@ -1066,9 +1191,7 @@ declare global {
1066
1191
  * per customer per day, naming the unproven drawer rows by `cashId`;
1067
1192
  * re-issuing the erasure resumes the scrub where it stopped. An unproven
1068
1193
  * row stays reported until it is gone or its `description` is empty or the
1069
- * movement's motivo alone (an operator's `POST /cash` edit). For a
1070
- * merged-away customer it also covers the mirrors of the movements the
1071
- * merge moved to the survivor.
1194
+ * movement's motivo alone (an operator's `POST /cash` edit).
1072
1195
  * Optional only so the field is additive — every erasure from this version
1073
1196
  * on sets it.
1074
1197
  */
@@ -1144,10 +1267,7 @@ declare global {
1144
1267
  * `comment` the same step blanks — could not be read or written to the end,
1145
1268
  * so a row carrying the name or the subject's free text may remain. BOTH
1146
1269
  * erasure handlers write an un-deduped `ERROR` row
1147
- * (`CUSTOMER_ANONYMIZE_ORDERS_INCOMPLETE`). ALWAYS `false` for a merged-away
1148
- * customer (`mergedInto`): the merge re-pointed their orders to the survivor
1149
- * with no provenance to find them by, so only erasing the survivor reaches
1150
- * those orders' frozen recipient.
1270
+ * (`CUSTOMER_ANONYMIZE_ORDERS_INCOMPLETE`).
1151
1271
  */
1152
1272
  orderScrubComplete: boolean;
1153
1273
  }
package/dist/invoice.d.ts CHANGED
@@ -157,8 +157,8 @@ declare global {
157
157
  * frozen exactly as declared to ARCA rather than re-derived at read time.
158
158
  *
159
159
  * Stored alongside the array on purpose: `buildTributos` rounds each entry
160
- * and then rounds the sum, so a reader summing the array reproduces it, but
161
- * only while it uses the same rounding. This is the value ARCA reconciled
160
+ * and sums the rounded entries, so a reader summing the array reproduces it,
161
+ * but only while it uses the same rounding. This is the value ARCA reconciled
162
162
  * `ImpTotal == ImpTotConc + ImpNeto + ImpOpEx + ImpTrib + ImpIVA` against,
163
163
  * and that identity is what makes `total` decomposable.
164
164
  *
@@ -179,6 +179,27 @@ declare global {
179
179
  * (`stacks/lambdas/reports/_format.ts`'s `ventasPesoFactor`).
180
180
  */
181
181
  total: number;
182
+ /**
183
+ * The rounding rule this voucher's amounts were built under.
184
+ *
185
+ * `'decimal'` — every per-unit figure, alícuota bucket and voucher total
186
+ * rounded to centavos half away from zero on the DECIMAL value (unit 0.35
187
+ * at 50 % off is 0.18). Written on every Invoice row built under it since
188
+ * the field shipped — factura, CAEA, `pending_cae`, `rejected`, export, and
189
+ * a credit note whose factura carries it.
190
+ *
191
+ * ABSENT ⇒ the row was built under the LEGACY rule, `Number(x.toFixed(2))`
192
+ * on the binary double (the same 0.35 at 50 % off is 0.17). Forward-only,
193
+ * never backfilled: every row written before the field exists is legacy,
194
+ * and so is a NEW credit note crediting such a factura, which is built
195
+ * under its factura's rule so it can credit it exactly.
196
+ *
197
+ * Read where a voucher is rebuilt or re-rendered rather than read back: a
198
+ * credit note's economics follow its factura's rule, the pending-CAE drain
199
+ * rebuilds a row under its own, and the PDF / ESC/POS receipt replay a
200
+ * line under it.
201
+ */
202
+ amountRounding?: 'decimal';
182
203
  cae: string;
183
204
  caeExpiration: string;
184
205
  observations?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sinfactura-types",
3
- "version": "1.10.520",
3
+ "version": "1.10.522",
4
4
  "description": "Shared wire and entity contracts for the SINFACTURA platform.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",