@fiado/type-kit 3.470.0 → 3.471.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.
Files changed (31) hide show
  1. package/_test_/unit/moneyTransfer/accountDtos.test.ts +206 -0
  2. package/_test_/unit/moneyTransfer/dtos.test.ts +18 -8
  3. package/bin/moneyTransfer/dtos/AccountImpactResponse.d.ts +18 -0
  4. package/bin/moneyTransfer/dtos/AccountImpactResponse.js +14 -0
  5. package/bin/moneyTransfer/dtos/AccountListResponse.d.ts +6 -0
  6. package/bin/moneyTransfer/dtos/AccountListResponse.js +7 -0
  7. package/bin/moneyTransfer/dtos/AccountResponse.d.ts +23 -0
  8. package/bin/moneyTransfer/dtos/AccountResponse.js +13 -0
  9. package/bin/moneyTransfer/dtos/AccountWithImpactResponse.d.ts +11 -0
  10. package/bin/moneyTransfer/dtos/AccountWithImpactResponse.js +11 -0
  11. package/bin/moneyTransfer/dtos/CreateAccountRequest.d.ts +27 -0
  12. package/bin/moneyTransfer/dtos/CreateAccountRequest.js +75 -0
  13. package/bin/moneyTransfer/dtos/MoneyTransferProductRequest.d.ts +6 -5
  14. package/bin/moneyTransfer/dtos/MoneyTransferProductRequest.js +3 -14
  15. package/bin/moneyTransfer/dtos/SettlementResponse.d.ts +6 -0
  16. package/bin/moneyTransfer/dtos/TransactionDetailResponse.d.ts +7 -0
  17. package/bin/moneyTransfer/dtos/UpdateAccountRequest.d.ts +19 -0
  18. package/bin/moneyTransfer/dtos/UpdateAccountRequest.js +67 -0
  19. package/bin/moneyTransfer/index.d.ts +6 -0
  20. package/bin/moneyTransfer/index.js +6 -0
  21. package/package.json +1 -1
  22. package/src/moneyTransfer/dtos/AccountImpactResponse.ts +18 -0
  23. package/src/moneyTransfer/dtos/AccountListResponse.ts +7 -0
  24. package/src/moneyTransfer/dtos/AccountResponse.ts +24 -0
  25. package/src/moneyTransfer/dtos/AccountWithImpactResponse.ts +12 -0
  26. package/src/moneyTransfer/dtos/CreateAccountRequest.ts +60 -0
  27. package/src/moneyTransfer/dtos/MoneyTransferProductRequest.ts +10 -14
  28. package/src/moneyTransfer/dtos/SettlementResponse.ts +6 -0
  29. package/src/moneyTransfer/dtos/TransactionDetailResponse.ts +7 -0
  30. package/src/moneyTransfer/dtos/UpdateAccountRequest.ts +49 -0
  31. package/src/moneyTransfer/index.ts +6 -0
@@ -0,0 +1,206 @@
1
+ import "reflect-metadata";
2
+ import { plainToInstance } from "class-transformer";
3
+ import { validateSync } from "class-validator";
4
+ import {
5
+ AccountImpactResponse,
6
+ AccountListResponse,
7
+ AccountResponse,
8
+ AccountWithImpactResponse,
9
+ CreateAccountRequest,
10
+ PendingDetailsResponse,
11
+ SettlementResponse,
12
+ TransactionDetailResponse,
13
+ TransferChannelEnum,
14
+ UpdateAccountRequest,
15
+ } from "../../../src/moneyTransfer";
16
+
17
+ const propertiesWithErrors = (dto: object) => validateSync(dto).map((error) => error.property);
18
+
19
+ /** Cuenta destino válida (DEC-041). */
20
+ const CUENTA_COMPLETA = {
21
+ accountId: "ACC-BANORTE-01",
22
+ tenantId: "SPEI",
23
+ channel: TransferChannelEnum.SPEI,
24
+ account: "072180000123456789",
25
+ beneficiaryName: "ACME SA DE CV",
26
+ beneficiaryRfc: "ACM010101AB1",
27
+ bankName: "Banorte",
28
+ currency: "MXN",
29
+ enabled: true,
30
+ };
31
+
32
+ describe("CreateAccountRequest", () => {
33
+ it("una cuenta completa pasa la validación", () => {
34
+ expect(validateSync(plainToInstance(CreateAccountRequest, CUENTA_COMPLETA))).toHaveLength(0);
35
+ });
36
+
37
+ it("beneficiaryRfc es opcional", () => {
38
+ const { beneficiaryRfc: _omit, ...sinRfc } = CUENTA_COMPLETA;
39
+ expect(validateSync(plainToInstance(CreateAccountRequest, sinRfc))).toHaveLength(0);
40
+ });
41
+
42
+ it("exige todos los campos obligatorios cuando llega vacía", () => {
43
+ const props = propertiesWithErrors(plainToInstance(CreateAccountRequest, {}));
44
+ for (const campo of [
45
+ "accountId",
46
+ "tenantId",
47
+ "channel",
48
+ "account",
49
+ "beneficiaryName",
50
+ "bankName",
51
+ "currency",
52
+ "enabled",
53
+ ]) {
54
+ expect(props).toContain(campo);
55
+ }
56
+ });
57
+
58
+ it("rechaza un accountId en minúsculas o con caracteres fuera de [A-Z0-9-]", () => {
59
+ for (const accountId of ["acc-banorte-01", "ACC BANORTE", "-ACC", "ACC_01"]) {
60
+ expect(propertiesWithErrors(plainToInstance(CreateAccountRequest, { ...CUENTA_COMPLETA, accountId })))
61
+ .toContain("accountId");
62
+ }
63
+ });
64
+
65
+ it("acepta un accountId de 64 chars y rechaza 65", () => {
66
+ const enElLimite = { ...CUENTA_COMPLETA, accountId: "A".repeat(64) };
67
+ expect(validateSync(plainToInstance(CreateAccountRequest, enElLimite))).toHaveLength(0);
68
+
69
+ const pasado = { ...CUENTA_COMPLETA, accountId: "A".repeat(65) };
70
+ expect(propertiesWithErrors(plainToInstance(CreateAccountRequest, pasado))).toContain("accountId");
71
+ });
72
+
73
+ it("rechaza un canal fuera de TransferChannelEnum", () => {
74
+ expect(propertiesWithErrors(plainToInstance(CreateAccountRequest, { ...CUENTA_COMPLETA, channel: "SWIFT" })))
75
+ .toContain("channel");
76
+ });
77
+
78
+ it("rechaza beneficiaryName > 40, bankName > 60, account > 34 y currency != 3", () => {
79
+ const dto = plainToInstance(CreateAccountRequest, {
80
+ ...CUENTA_COMPLETA,
81
+ beneficiaryName: "N".repeat(41),
82
+ bankName: "B".repeat(61),
83
+ account: "9".repeat(35),
84
+ currency: "MX",
85
+ });
86
+ const props = propertiesWithErrors(dto);
87
+ expect(props).toContain("beneficiaryName");
88
+ expect(props).toContain("bankName");
89
+ expect(props).toContain("account");
90
+ expect(props).toContain("currency");
91
+ });
92
+
93
+ it("rechaza beneficiaryRfc fuera del rango 12-13 chars", () => {
94
+ for (const beneficiaryRfc of ["CORTO", "R".repeat(14)]) {
95
+ expect(propertiesWithErrors(plainToInstance(CreateAccountRequest, { ...CUENTA_COMPLETA, beneficiaryRfc })))
96
+ .toContain("beneficiaryRfc");
97
+ }
98
+ });
99
+ });
100
+
101
+ describe("UpdateAccountRequest", () => {
102
+ it("un body vacío es válido: todos los campos son opcionales", () => {
103
+ expect(validateSync(plainToInstance(UpdateAccountRequest, {}))).toHaveLength(0);
104
+ });
105
+
106
+ it("DEC-045: permite mandar solo el número de cuenta corregido", () => {
107
+ expect(validateSync(plainToInstance(UpdateAccountRequest, { account: "072180000987654321" }))).toHaveLength(0);
108
+ });
109
+
110
+ it("DEC-049: permite deshabilitar mandando solo enabled", () => {
111
+ expect(validateSync(plainToInstance(UpdateAccountRequest, { enabled: false }))).toHaveLength(0);
112
+ });
113
+
114
+ it("accountId no es una propiedad del DTO: la PK viaja en el path, no en el body", () => {
115
+ // `accountId` no está declarado ni validado; si alguien lo manda, el DTO no lo reconoce
116
+ // como campo propio y el manager no lo puede usar para reasignar la PK.
117
+ const dto = plainToInstance(UpdateAccountRequest, { accountId: "ACC-OTRA-01" });
118
+ expect(validateSync(dto)).toHaveLength(0);
119
+ expect(Object.keys(new UpdateAccountRequest())).not.toContain("accountId");
120
+ });
121
+
122
+ it("cuando un campo opcional viene, se valida igual que en el alta", () => {
123
+ const dto = plainToInstance(UpdateAccountRequest, {
124
+ channel: "SWIFT",
125
+ account: "",
126
+ beneficiaryName: "N".repeat(41),
127
+ beneficiaryRfc: "CORTO",
128
+ bankName: "B".repeat(61),
129
+ currency: "MX",
130
+ enabled: "si",
131
+ });
132
+ const props = propertiesWithErrors(dto);
133
+ for (const campo of ["channel", "account", "beneficiaryName", "beneficiaryRfc", "bankName", "currency", "enabled"]) {
134
+ expect(props).toContain(campo);
135
+ }
136
+ });
137
+ });
138
+
139
+ describe("DTOs de respuesta de cuentas", () => {
140
+ it("AccountResponse es instanciable y lleva la CLABE sin enmascarar", () => {
141
+ const response = plainToInstance(AccountResponse, {
142
+ ...CUENTA_COMPLETA,
143
+ createdBy: "system",
144
+ updatedBy: "system",
145
+ createdAt: 1_758_000_000_000,
146
+ updatedAt: 1_758_000_000_000,
147
+ });
148
+ expect(response).toBeInstanceOf(AccountResponse);
149
+ expect(response.account).toBe(CUENTA_COMPLETA.account);
150
+ expect(response.channel).toBe(TransferChannelEnum.SPEI);
151
+ });
152
+
153
+ it("AccountListResponse anida AccountResponse y nextToken es opcional", () => {
154
+ const page = plainToInstance(AccountListResponse, { items: [] });
155
+ expect(page).toBeInstanceOf(AccountListResponse);
156
+ expect(page.items).toEqual([]);
157
+ expect(page.nextToken).toBeUndefined();
158
+ });
159
+
160
+ it("AccountImpactResponse (DEC-050) lleva los 4 contadores del impacto", () => {
161
+ const impact = plainToInstance(AccountImpactResponse, {
162
+ products: 2,
163
+ pendingDetails: 7,
164
+ pendingAmount: 1500,
165
+ pendingSettlements: 1,
166
+ });
167
+ expect(impact).toBeInstanceOf(AccountImpactResponse);
168
+ expect(impact.products).toBe(2);
169
+ expect(impact.pendingDetails).toBe(7);
170
+ expect(impact.pendingAmount).toBe(1500);
171
+ expect(impact.pendingSettlements).toBe(1);
172
+ });
173
+
174
+ it("AccountWithImpactResponse compone cuenta + impacto", () => {
175
+ const dto = plainToInstance(AccountWithImpactResponse, {
176
+ account: { ...CUENTA_COMPLETA, createdBy: "system", updatedBy: "system", createdAt: 1, updatedAt: 2 },
177
+ impact: { products: 0, pendingDetails: 0, pendingAmount: 0, pendingSettlements: 0 },
178
+ });
179
+ expect(dto).toBeInstanceOf(AccountWithImpactResponse);
180
+ expect(dto.account.accountId).toBe("ACC-BANORTE-01");
181
+ expect(dto.impact.products).toBe(0);
182
+ });
183
+ });
184
+
185
+ describe("Campos nuevos en los DTOs de respuesta existentes", () => {
186
+ it("DEC-044: SettlementResponse lleva sentToAccount, opcional", () => {
187
+ const conCuenta = plainToInstance(SettlementResponse, { sentToAccount: "072180000123456789" });
188
+ expect(conCuenta.sentToAccount).toBe("072180000123456789");
189
+ expect(plainToInstance(SettlementResponse, {}).sentToAccount).toBeUndefined();
190
+ });
191
+
192
+ it("DEC-051: TransactionDetailResponse lleva blockedByAccount, opcional", () => {
193
+ expect(plainToInstance(TransactionDetailResponse, { blockedByAccount: true }).blockedByAccount).toBe(true);
194
+ expect(plainToInstance(TransactionDetailResponse, {}).blockedByAccount).toBeUndefined();
195
+ });
196
+
197
+ it("PendingDetailsResponse propaga blockedByAccount vía sus items (F9)", () => {
198
+ const page = plainToInstance(PendingDetailsResponse, {
199
+ items: [{ transactionNumber: "T-1", blockedByAccount: true }],
200
+ count: 1,
201
+ totalAmount: 100,
202
+ });
203
+ expect(page).toBeInstanceOf(PendingDetailsResponse);
204
+ expect(page.items[0].blockedByAccount).toBe(true);
205
+ });
206
+ });
@@ -22,7 +22,7 @@ const propertiesWithErrors = (dto: object) => validateSync(dto).map((error) => e
22
22
  const VALID_UUID = "3f6c2c5e-8b1a-4f3e-9d2a-1c4b5e6f7a8b";
23
23
 
24
24
  const PRODUCTO_COMPLETO = {
25
- idProducto: "SPEI-BATCH-001",
25
+ idProducto: "ACC-BANORTE-01",
26
26
  producto: "Dispersión SPEI en lote",
27
27
  precio: 0,
28
28
  amountType: AmountTypeEnum.VARIABLE,
@@ -39,8 +39,6 @@ const PRODUCTO_COMPLETO = {
39
39
  enabled: true,
40
40
  channel: TransferChannelEnum.SPEI,
41
41
  settlementMode: SettlementModeEnum.BATCH,
42
- beneficiaryName: "ACME SA DE CV",
43
- beneficiaryRfc: "ACM010101AB1",
44
42
  minAmount: 1,
45
43
  maxAmount: 50000,
46
44
  batchSchedule: { cron: "0 18 * * 1-5", timezone: "America/Mexico_City" },
@@ -131,15 +129,27 @@ describe("MoneyTransferProductRequest", () => {
131
129
  expect(propertiesWithErrors(dto)).toContain("batchSchedule");
132
130
  });
133
131
 
134
- it("rechaza beneficiaryRfc fuera de 12-13 chars y beneficiaryName > 40", () => {
132
+ it("DEC-046: ignora beneficiaryName/beneficiaryRfc, que ya no son del producto", () => {
135
133
  const dto = plainToInstance(MoneyTransferProductRequest, {
136
134
  ...PRODUCTO_COMPLETO,
137
135
  beneficiaryRfc: "CORTO",
138
136
  beneficiaryName: "N".repeat(41),
139
137
  });
140
- const props = propertiesWithErrors(dto);
141
- expect(props).toContain("beneficiaryRfc");
142
- expect(props).toContain("beneficiaryName");
138
+ expect(validateSync(dto)).toHaveLength(0);
139
+ });
140
+
141
+ it("DEC-041: idProducto acepta un accountId de hasta 64 chars y rechaza 65", () => {
142
+ const enElLimite = plainToInstance(MoneyTransferProductRequest, {
143
+ ...PRODUCTO_COMPLETO,
144
+ idProducto: "A".repeat(64),
145
+ });
146
+ expect(validateSync(enElLimite)).toHaveLength(0);
147
+
148
+ const pasado = plainToInstance(MoneyTransferProductRequest, {
149
+ ...PRODUCTO_COMPLETO,
150
+ idProducto: "A".repeat(65),
151
+ });
152
+ expect(propertiesWithErrors(pasado)).toContain("idProducto");
143
153
  });
144
154
 
145
155
  it("rechaza channel y settlementMode fuera de sus enums", () => {
@@ -175,7 +185,7 @@ describe("MoneyTransferServiceCreateRequest", () => {
175
185
  const nested = listError!.children?.[0]?.children?.map((child) => child.property) ?? [];
176
186
  expect(nested).toContain("producto");
177
187
  expect(nested).toContain("channel");
178
- expect(nested).toContain("beneficiaryName");
188
+ expect(nested).toContain("settlementMode");
179
189
  });
180
190
 
181
191
  it("exige al menos un producto", () => {
@@ -0,0 +1,18 @@
1
+ /**
2
+ * DEC-050: qué se rompe antes de romperlo. Deshabilitar o editar una cuenta NO bloquea aunque haya
3
+ * folios pendientes o liquidaciones en vuelo — pero el operador tiene que ver el número en el momento
4
+ * de apretar el botón, no descubrirlo después.
5
+ *
6
+ * `pendingSettlements` cuenta liquidaciones en estado NO terminal (CREATED, SCHEDULED, SENDING, FAILED):
7
+ * esas son las que todavía pueden salir al riel y por lo tanto resolverían la cuenta editada (DEC-042).
8
+ */
9
+ export declare class AccountImpactResponse {
10
+ /** Productos del catálogo que referencian esta cuenta por `idProducto`. */
11
+ products: number;
12
+ /** Folios en `PENDING_SETTLEMENT` de esta cuenta (GSI `pendingProductId-createdAt-index`). */
13
+ pendingDetails: number;
14
+ /** Suma de los montos de esos folios. */
15
+ pendingAmount: number;
16
+ /** Liquidaciones en estado no terminal que todavía pueden salir al riel. */
17
+ pendingSettlements: number;
18
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AccountImpactResponse = void 0;
4
+ /**
5
+ * DEC-050: qué se rompe antes de romperlo. Deshabilitar o editar una cuenta NO bloquea aunque haya
6
+ * folios pendientes o liquidaciones en vuelo — pero el operador tiene que ver el número en el momento
7
+ * de apretar el botón, no descubrirlo después.
8
+ *
9
+ * `pendingSettlements` cuenta liquidaciones en estado NO terminal (CREATED, SCHEDULED, SENDING, FAILED):
10
+ * esas son las que todavía pueden salir al riel y por lo tanto resolverían la cuenta editada (DEC-042).
11
+ */
12
+ class AccountImpactResponse {
13
+ }
14
+ exports.AccountImpactResponse = AccountImpactResponse;
@@ -0,0 +1,6 @@
1
+ import { AccountResponse } from "./AccountResponse";
2
+ /** Página de cuentas de un tenant (GSI `tenantId-createdAt-index`). Paginada por cursor opaco. */
3
+ export declare class AccountListResponse {
4
+ items: AccountResponse[];
5
+ nextToken?: string;
6
+ }
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AccountListResponse = void 0;
4
+ /** Página de cuentas de un tenant (GSI `tenantId-createdAt-index`). Paginada por cursor opaco. */
5
+ class AccountListResponse {
6
+ }
7
+ exports.AccountListResponse = AccountListResponse;
@@ -0,0 +1,23 @@
1
+ import { TransferChannelEnum } from "../enums/TransferChannelEnum";
2
+ /**
3
+ * Cuenta destino en la respuesta de backoffice. Sin decoradores `class-validator`: el consumidor la
4
+ * lee tal cual viene por la red. Timestamps en epoch ms.
5
+ *
6
+ * `account` (la CLABE) SÍ sale: el operador de backoffice necesita verla para conciliar contra el
7
+ * estado de cuenta del banco. El enmascarado aplica a los LOGS, no a esta respuesta autenticada.
8
+ */
9
+ export declare class AccountResponse {
10
+ accountId: string;
11
+ tenantId: string;
12
+ channel: TransferChannelEnum;
13
+ account: string;
14
+ beneficiaryName: string;
15
+ beneficiaryRfc?: string;
16
+ bankName: string;
17
+ currency: string;
18
+ enabled: boolean;
19
+ createdBy: string;
20
+ updatedBy: string;
21
+ createdAt: number;
22
+ updatedAt: number;
23
+ }
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AccountResponse = void 0;
4
+ /**
5
+ * Cuenta destino en la respuesta de backoffice. Sin decoradores `class-validator`: el consumidor la
6
+ * lee tal cual viene por la red. Timestamps en epoch ms.
7
+ *
8
+ * `account` (la CLABE) SÍ sale: el operador de backoffice necesita verla para conciliar contra el
9
+ * estado de cuenta del banco. El enmascarado aplica a los LOGS, no a esta respuesta autenticada.
10
+ */
11
+ class AccountResponse {
12
+ }
13
+ exports.AccountResponse = AccountResponse;
@@ -0,0 +1,11 @@
1
+ import { AccountImpactResponse } from "./AccountImpactResponse";
2
+ import { AccountResponse } from "./AccountResponse";
3
+ /**
4
+ * Respuesta del `PUT /backoffice/accounts/{accountId}` (DEC-050): la cuenta ya editada, más el impacto
5
+ * que esa edición tiene. Se devuelve el impacto incluso cuando el operador no consultó
6
+ * `/impact` antes, que es el caso que hay que cubrir.
7
+ */
8
+ export declare class AccountWithImpactResponse {
9
+ account: AccountResponse;
10
+ impact: AccountImpactResponse;
11
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AccountWithImpactResponse = void 0;
4
+ /**
5
+ * Respuesta del `PUT /backoffice/accounts/{accountId}` (DEC-050): la cuenta ya editada, más el impacto
6
+ * que esa edición tiene. Se devuelve el impacto incluso cuando el operador no consultó
7
+ * `/impact` antes, que es el caso que hay que cubrir.
8
+ */
9
+ class AccountWithImpactResponse {
10
+ }
11
+ exports.AccountWithImpactResponse = AccountWithImpactResponse;
@@ -0,0 +1,27 @@
1
+ import { TransferChannelEnum } from "../enums/TransferChannelEnum";
2
+ /**
3
+ * Alta de una cuenta destino (DEC-041). La cuenta vive en `MoneyTransferAccount_GT` y el producto
4
+ * del catálogo la referencia por `accountId`; el número de cuenta (CLABE en SPEI) es el ÚNICO campo
5
+ * que cambia cuando el tercero cambia de banco.
6
+ *
7
+ * Sin `idempotencyKey` a propósito: el alta ya tiene llave natural (`accountId` repetido → 409) y no
8
+ * mueve dinero ni lotes, así que el doble click no puede duplicar nada.
9
+ */
10
+ export declare class CreateAccountRequest {
11
+ /** Identificador estable y legible, p. ej. `ACC-BANORTE-01`. Es la PK de la tabla. */
12
+ accountId: string;
13
+ /** DEC-034: tenant (partner) dueño de la cuenta; = subcategoría del servicio. */
14
+ tenantId: string;
15
+ channel: TransferChannelEnum;
16
+ /** Número de cuenta del riel: CLABE de 18 dígitos en SPEI. El conector lo valida por canal (DEC-053). */
17
+ account: string;
18
+ /** Nombre del titular tal como viaja al riel (SPEI acepta máx. 40 chars). */
19
+ beneficiaryName: string;
20
+ /** RFC del titular: 12 chars persona moral, 13 persona física. */
21
+ beneficiaryRfc?: string;
22
+ /** Nombre del banco, para que el operador reconozca la cuenta en backoffice. */
23
+ bankName: string;
24
+ /** ISO 4217 (`MXN`, `USD`). */
25
+ currency: string;
26
+ enabled: boolean;
27
+ }
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.CreateAccountRequest = void 0;
13
+ const class_validator_1 = require("class-validator");
14
+ const TransferChannelEnum_1 = require("../enums/TransferChannelEnum");
15
+ /**
16
+ * Alta de una cuenta destino (DEC-041). La cuenta vive en `MoneyTransferAccount_GT` y el producto
17
+ * del catálogo la referencia por `accountId`; el número de cuenta (CLABE en SPEI) es el ÚNICO campo
18
+ * que cambia cuando el tercero cambia de banco.
19
+ *
20
+ * Sin `idempotencyKey` a propósito: el alta ya tiene llave natural (`accountId` repetido → 409) y no
21
+ * mueve dinero ni lotes, así que el doble click no puede duplicar nada.
22
+ */
23
+ class CreateAccountRequest {
24
+ }
25
+ exports.CreateAccountRequest = CreateAccountRequest;
26
+ __decorate([
27
+ (0, class_validator_1.IsString)(),
28
+ (0, class_validator_1.IsNotEmpty)(),
29
+ (0, class_validator_1.MaxLength)(64),
30
+ (0, class_validator_1.Matches)(/^[A-Z0-9][A-Z0-9-]*$/, { message: "accountId debe ser mayúsculas, dígitos y guiones" }),
31
+ __metadata("design:type", String)
32
+ ], CreateAccountRequest.prototype, "accountId", void 0);
33
+ __decorate([
34
+ (0, class_validator_1.IsString)(),
35
+ (0, class_validator_1.IsNotEmpty)(),
36
+ (0, class_validator_1.MaxLength)(64),
37
+ __metadata("design:type", String)
38
+ ], CreateAccountRequest.prototype, "tenantId", void 0);
39
+ __decorate([
40
+ (0, class_validator_1.IsEnum)(TransferChannelEnum_1.TransferChannelEnum),
41
+ __metadata("design:type", String)
42
+ ], CreateAccountRequest.prototype, "channel", void 0);
43
+ __decorate([
44
+ (0, class_validator_1.IsString)(),
45
+ (0, class_validator_1.IsNotEmpty)(),
46
+ (0, class_validator_1.MaxLength)(34),
47
+ __metadata("design:type", String)
48
+ ], CreateAccountRequest.prototype, "account", void 0);
49
+ __decorate([
50
+ (0, class_validator_1.IsString)(),
51
+ (0, class_validator_1.IsNotEmpty)(),
52
+ (0, class_validator_1.MaxLength)(40),
53
+ __metadata("design:type", String)
54
+ ], CreateAccountRequest.prototype, "beneficiaryName", void 0);
55
+ __decorate([
56
+ (0, class_validator_1.IsOptional)(),
57
+ (0, class_validator_1.IsString)(),
58
+ (0, class_validator_1.Length)(12, 13),
59
+ __metadata("design:type", String)
60
+ ], CreateAccountRequest.prototype, "beneficiaryRfc", void 0);
61
+ __decorate([
62
+ (0, class_validator_1.IsString)(),
63
+ (0, class_validator_1.IsNotEmpty)(),
64
+ (0, class_validator_1.MaxLength)(60),
65
+ __metadata("design:type", String)
66
+ ], CreateAccountRequest.prototype, "bankName", void 0);
67
+ __decorate([
68
+ (0, class_validator_1.IsString)(),
69
+ (0, class_validator_1.Length)(3, 3),
70
+ __metadata("design:type", String)
71
+ ], CreateAccountRequest.prototype, "currency", void 0);
72
+ __decorate([
73
+ (0, class_validator_1.IsBoolean)(),
74
+ __metadata("design:type", Boolean)
75
+ ], CreateAccountRequest.prototype, "enabled", void 0);
@@ -6,9 +6,14 @@ import { BatchScheduleRequest } from "./BatchScheduleRequest";
6
6
  /**
7
7
  * Producto de un servicio de transferencia de dinero (Centro de Beneficios). Los campos en
8
8
  * español espejan el catálogo legacy de pago de servicios; los campos en inglés son la
9
- * configuración propia del riel (canal, modo de liquidación, beneficiario, lote).
9
+ * configuración propia del riel (canal, modo de liquidación, lote). El beneficiario ya no vive
10
+ * acá: se mudó a la cuenta destino (DEC-046).
10
11
  */
11
12
  export declare class MoneyTransferProductRequest {
13
+ /**
14
+ * DEC-041: `idProducto` es el `accountId` de la cuenta destino (`ACC-BANORTE-01`), NO la CLABE.
15
+ * La CLABE vive en `MoneyTransferAccount_GT` y se resuelve al pagar (F1) y al enviar (F4).
16
+ */
12
17
  idProducto: string;
13
18
  producto: string;
14
19
  precio: number;
@@ -26,10 +31,6 @@ export declare class MoneyTransferProductRequest {
26
31
  enabled: boolean;
27
32
  channel: TransferChannelEnum;
28
33
  settlementMode: SettlementModeEnum;
29
- /** Nombre del beneficiario tal como viaja al riel (SPEI acepta máx. 40 chars). */
30
- beneficiaryName: string;
31
- /** RFC del beneficiario: 12 chars persona moral, 13 persona física. */
32
- beneficiaryRfc?: string;
33
34
  minAmount?: number;
34
35
  maxAmount?: number;
35
36
  /** Requerido operativamente cuando `settlementMode = BATCH`; lo valida el conector. */
@@ -20,7 +20,8 @@ const BatchScheduleRequest_1 = require("./BatchScheduleRequest");
20
20
  /**
21
21
  * Producto de un servicio de transferencia de dinero (Centro de Beneficios). Los campos en
22
22
  * español espejan el catálogo legacy de pago de servicios; los campos en inglés son la
23
- * configuración propia del riel (canal, modo de liquidación, beneficiario, lote).
23
+ * configuración propia del riel (canal, modo de liquidación, lote). El beneficiario ya no vive
24
+ * acá: se mudó a la cuenta destino (DEC-046).
24
25
  */
25
26
  class MoneyTransferProductRequest {
26
27
  }
@@ -28,7 +29,7 @@ exports.MoneyTransferProductRequest = MoneyTransferProductRequest;
28
29
  __decorate([
29
30
  (0, class_validator_1.IsString)(),
30
31
  (0, class_validator_1.IsNotEmpty)(),
31
- (0, class_validator_1.MaxLength)(34),
32
+ (0, class_validator_1.MaxLength)(64),
32
33
  __metadata("design:type", String)
33
34
  ], MoneyTransferProductRequest.prototype, "idProducto", void 0);
34
35
  __decorate([
@@ -99,18 +100,6 @@ __decorate([
99
100
  (0, class_validator_1.IsEnum)(SettlementModeEnum_1.SettlementModeEnum),
100
101
  __metadata("design:type", String)
101
102
  ], MoneyTransferProductRequest.prototype, "settlementMode", void 0);
102
- __decorate([
103
- (0, class_validator_1.IsString)(),
104
- (0, class_validator_1.IsNotEmpty)(),
105
- (0, class_validator_1.MaxLength)(40),
106
- __metadata("design:type", String)
107
- ], MoneyTransferProductRequest.prototype, "beneficiaryName", void 0);
108
- __decorate([
109
- (0, class_validator_1.IsOptional)(),
110
- (0, class_validator_1.IsString)(),
111
- (0, class_validator_1.Length)(12, 13),
112
- __metadata("design:type", String)
113
- ], MoneyTransferProductRequest.prototype, "beneficiaryRfc", void 0);
114
103
  __decorate([
115
104
  (0, class_validator_1.IsOptional)(),
116
105
  (0, class_validator_1.IsNumber)(),
@@ -19,6 +19,12 @@ export declare class SettlementResponse {
19
19
  scheduledAt?: number;
20
20
  /** Id de la transacción en el riel (ACH) o clave de rastreo (SPEI). */
21
21
  achTransactionId?: string;
22
+ /**
23
+ * DEC-044: cuenta (CLABE) a la que se INTENTÓ enviar este lote, escrita al tomar el lock `SENDING`.
24
+ * No significa "cuenta que recibió el dinero": la evidencia de dinero movido es este campo + un
25
+ * estado de la terna SENT/SETTLED/RETURNED + `achTransactionId`.
26
+ */
27
+ sentToAccount?: string;
22
28
  returnReason?: string;
23
29
  lastError?: string;
24
30
  /** `true` cuando el envío no obtuvo respuesta concluyente del riel (posible duplicado). */
@@ -19,6 +19,13 @@ export declare class TransactionDetailResponse {
19
19
  status: TransactionDetailStatusEnum;
20
20
  /** Presente cuando el folio ya fue agrupado en una liquidación. */
21
21
  settlementId?: string;
22
+ /**
23
+ * DEC-051: `true` cuando la cuenta de este folio no existe o está deshabilitada. El folio se queda
24
+ * en `PENDING_SETTLEMENT` (DEC-048) y no puede liquidarse hasta que operaciones arregle la cuenta;
25
+ * sin esta marca quedaría invisible en la cola y se descubriría cuando el usuario reclame.
26
+ * Solo lo calcula el listado de pendientes de backoffice (F9); en otros contextos viene ausente.
27
+ */
28
+ blockedByAccount?: boolean;
22
29
  /** Epoch ms. */
23
30
  createdAt: number;
24
31
  }
@@ -0,0 +1,19 @@
1
+ import { TransferChannelEnum } from "../enums/TransferChannelEnum";
2
+ /**
3
+ * Edición de una cuenta destino (DEC-045: actualización en el mismo registro, sin versionado).
4
+ * Todos los campos son opcionales: se envía solo lo que cambia. `accountId` no está porque es la PK
5
+ * y viaja en el path. `enabled` se cambia acá, sin endpoint propio (evita duplicar la lógica de impacto).
6
+ *
7
+ * Sin `idempotencyKey`: la edición es idempotente por naturaleza (escribe el estado deseado).
8
+ */
9
+ export declare class UpdateAccountRequest {
10
+ channel?: TransferChannelEnum;
11
+ /** El campo que hace útil todo este cambio: corregir el número no obliga a tocar ningún producto. */
12
+ account?: string;
13
+ beneficiaryName?: string;
14
+ beneficiaryRfc?: string;
15
+ bankName?: string;
16
+ currency?: string;
17
+ /** DEC-049: nunca se borra una cuenta, solo se deshabilita. */
18
+ enabled?: boolean;
19
+ }
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.UpdateAccountRequest = void 0;
13
+ const class_validator_1 = require("class-validator");
14
+ const TransferChannelEnum_1 = require("../enums/TransferChannelEnum");
15
+ /**
16
+ * Edición de una cuenta destino (DEC-045: actualización en el mismo registro, sin versionado).
17
+ * Todos los campos son opcionales: se envía solo lo que cambia. `accountId` no está porque es la PK
18
+ * y viaja en el path. `enabled` se cambia acá, sin endpoint propio (evita duplicar la lógica de impacto).
19
+ *
20
+ * Sin `idempotencyKey`: la edición es idempotente por naturaleza (escribe el estado deseado).
21
+ */
22
+ class UpdateAccountRequest {
23
+ }
24
+ exports.UpdateAccountRequest = UpdateAccountRequest;
25
+ __decorate([
26
+ (0, class_validator_1.IsOptional)(),
27
+ (0, class_validator_1.IsEnum)(TransferChannelEnum_1.TransferChannelEnum),
28
+ __metadata("design:type", String)
29
+ ], UpdateAccountRequest.prototype, "channel", void 0);
30
+ __decorate([
31
+ (0, class_validator_1.IsOptional)(),
32
+ (0, class_validator_1.IsString)(),
33
+ (0, class_validator_1.IsNotEmpty)(),
34
+ (0, class_validator_1.MaxLength)(34),
35
+ __metadata("design:type", String)
36
+ ], UpdateAccountRequest.prototype, "account", void 0);
37
+ __decorate([
38
+ (0, class_validator_1.IsOptional)(),
39
+ (0, class_validator_1.IsString)(),
40
+ (0, class_validator_1.IsNotEmpty)(),
41
+ (0, class_validator_1.MaxLength)(40),
42
+ __metadata("design:type", String)
43
+ ], UpdateAccountRequest.prototype, "beneficiaryName", void 0);
44
+ __decorate([
45
+ (0, class_validator_1.IsOptional)(),
46
+ (0, class_validator_1.IsString)(),
47
+ (0, class_validator_1.Length)(12, 13),
48
+ __metadata("design:type", String)
49
+ ], UpdateAccountRequest.prototype, "beneficiaryRfc", void 0);
50
+ __decorate([
51
+ (0, class_validator_1.IsOptional)(),
52
+ (0, class_validator_1.IsString)(),
53
+ (0, class_validator_1.IsNotEmpty)(),
54
+ (0, class_validator_1.MaxLength)(60),
55
+ __metadata("design:type", String)
56
+ ], UpdateAccountRequest.prototype, "bankName", void 0);
57
+ __decorate([
58
+ (0, class_validator_1.IsOptional)(),
59
+ (0, class_validator_1.IsString)(),
60
+ (0, class_validator_1.Length)(3, 3),
61
+ __metadata("design:type", String)
62
+ ], UpdateAccountRequest.prototype, "currency", void 0);
63
+ __decorate([
64
+ (0, class_validator_1.IsOptional)(),
65
+ (0, class_validator_1.IsBoolean)(),
66
+ __metadata("design:type", Boolean)
67
+ ], UpdateAccountRequest.prototype, "enabled", void 0);
@@ -11,7 +11,13 @@ export * from './dtos/MoneyTransferServiceUpdateRequest';
11
11
  export * from './dtos/CreateSettlementRequest';
12
12
  export * from './dtos/SettlementActionRequest';
13
13
  export * from './dtos/RescheduleSettlementRequest';
14
+ export * from './dtos/CreateAccountRequest';
15
+ export * from './dtos/UpdateAccountRequest';
14
16
  export * from './dtos/TransactionDetailResponse';
15
17
  export * from './dtos/SettlementResponse';
16
18
  export * from './dtos/PendingDetailsResponse';
17
19
  export * from './dtos/SettlementListResponse';
20
+ export * from './dtos/AccountResponse';
21
+ export * from './dtos/AccountListResponse';
22
+ export * from './dtos/AccountImpactResponse';
23
+ export * from './dtos/AccountWithImpactResponse';
@@ -33,8 +33,14 @@ __exportStar(require("./dtos/MoneyTransferServiceUpdateRequest"), exports);
33
33
  __exportStar(require("./dtos/CreateSettlementRequest"), exports);
34
34
  __exportStar(require("./dtos/SettlementActionRequest"), exports);
35
35
  __exportStar(require("./dtos/RescheduleSettlementRequest"), exports);
36
+ __exportStar(require("./dtos/CreateAccountRequest"), exports);
37
+ __exportStar(require("./dtos/UpdateAccountRequest"), exports);
36
38
  //DTOs — responses
37
39
  __exportStar(require("./dtos/TransactionDetailResponse"), exports);
38
40
  __exportStar(require("./dtos/SettlementResponse"), exports);
39
41
  __exportStar(require("./dtos/PendingDetailsResponse"), exports);
40
42
  __exportStar(require("./dtos/SettlementListResponse"), exports);
43
+ __exportStar(require("./dtos/AccountResponse"), exports);
44
+ __exportStar(require("./dtos/AccountListResponse"), exports);
45
+ __exportStar(require("./dtos/AccountImpactResponse"), exports);
46
+ __exportStar(require("./dtos/AccountWithImpactResponse"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiado/type-kit",
3
- "version": "3.470.0",
3
+ "version": "3.471.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",
@@ -0,0 +1,18 @@
1
+ /**
2
+ * DEC-050: qué se rompe antes de romperlo. Deshabilitar o editar una cuenta NO bloquea aunque haya
3
+ * folios pendientes o liquidaciones en vuelo — pero el operador tiene que ver el número en el momento
4
+ * de apretar el botón, no descubrirlo después.
5
+ *
6
+ * `pendingSettlements` cuenta liquidaciones en estado NO terminal (CREATED, SCHEDULED, SENDING, FAILED):
7
+ * esas son las que todavía pueden salir al riel y por lo tanto resolverían la cuenta editada (DEC-042).
8
+ */
9
+ export class AccountImpactResponse {
10
+ /** Productos del catálogo que referencian esta cuenta por `idProducto`. */
11
+ products!: number;
12
+ /** Folios en `PENDING_SETTLEMENT` de esta cuenta (GSI `pendingProductId-createdAt-index`). */
13
+ pendingDetails!: number;
14
+ /** Suma de los montos de esos folios. */
15
+ pendingAmount!: number;
16
+ /** Liquidaciones en estado no terminal que todavía pueden salir al riel. */
17
+ pendingSettlements!: number;
18
+ }
@@ -0,0 +1,7 @@
1
+ import { AccountResponse } from "./AccountResponse";
2
+
3
+ /** Página de cuentas de un tenant (GSI `tenantId-createdAt-index`). Paginada por cursor opaco. */
4
+ export class AccountListResponse {
5
+ items!: AccountResponse[];
6
+ nextToken?: string;
7
+ }
@@ -0,0 +1,24 @@
1
+ import { TransferChannelEnum } from "../enums/TransferChannelEnum";
2
+
3
+ /**
4
+ * Cuenta destino en la respuesta de backoffice. Sin decoradores `class-validator`: el consumidor la
5
+ * lee tal cual viene por la red. Timestamps en epoch ms.
6
+ *
7
+ * `account` (la CLABE) SÍ sale: el operador de backoffice necesita verla para conciliar contra el
8
+ * estado de cuenta del banco. El enmascarado aplica a los LOGS, no a esta respuesta autenticada.
9
+ */
10
+ export class AccountResponse {
11
+ accountId!: string;
12
+ tenantId!: string;
13
+ channel!: TransferChannelEnum;
14
+ account!: string;
15
+ beneficiaryName!: string;
16
+ beneficiaryRfc?: string;
17
+ bankName!: string;
18
+ currency!: string;
19
+ enabled!: boolean;
20
+ createdBy!: string;
21
+ updatedBy!: string;
22
+ createdAt!: number;
23
+ updatedAt!: number;
24
+ }
@@ -0,0 +1,12 @@
1
+ import { AccountImpactResponse } from "./AccountImpactResponse";
2
+ import { AccountResponse } from "./AccountResponse";
3
+
4
+ /**
5
+ * Respuesta del `PUT /backoffice/accounts/{accountId}` (DEC-050): la cuenta ya editada, más el impacto
6
+ * que esa edición tiene. Se devuelve el impacto incluso cuando el operador no consultó
7
+ * `/impact` antes, que es el caso que hay que cubrir.
8
+ */
9
+ export class AccountWithImpactResponse {
10
+ account!: AccountResponse;
11
+ impact!: AccountImpactResponse;
12
+ }
@@ -0,0 +1,60 @@
1
+ import { IsBoolean, IsEnum, IsNotEmpty, IsOptional, IsString, Length, Matches, MaxLength } from "class-validator";
2
+ import { TransferChannelEnum } from "../enums/TransferChannelEnum";
3
+
4
+ /**
5
+ * Alta de una cuenta destino (DEC-041). La cuenta vive en `MoneyTransferAccount_GT` y el producto
6
+ * del catálogo la referencia por `accountId`; el número de cuenta (CLABE en SPEI) es el ÚNICO campo
7
+ * que cambia cuando el tercero cambia de banco.
8
+ *
9
+ * Sin `idempotencyKey` a propósito: el alta ya tiene llave natural (`accountId` repetido → 409) y no
10
+ * mueve dinero ni lotes, así que el doble click no puede duplicar nada.
11
+ */
12
+ export class CreateAccountRequest {
13
+ /** Identificador estable y legible, p. ej. `ACC-BANORTE-01`. Es la PK de la tabla. */
14
+ @IsString()
15
+ @IsNotEmpty()
16
+ @MaxLength(64)
17
+ @Matches(/^[A-Z0-9][A-Z0-9-]*$/, { message: "accountId debe ser mayúsculas, dígitos y guiones" })
18
+ accountId!: string;
19
+
20
+ /** DEC-034: tenant (partner) dueño de la cuenta; = subcategoría del servicio. */
21
+ @IsString()
22
+ @IsNotEmpty()
23
+ @MaxLength(64)
24
+ tenantId!: string;
25
+
26
+ @IsEnum(TransferChannelEnum)
27
+ channel!: TransferChannelEnum;
28
+
29
+ /** Número de cuenta del riel: CLABE de 18 dígitos en SPEI. El conector lo valida por canal (DEC-053). */
30
+ @IsString()
31
+ @IsNotEmpty()
32
+ @MaxLength(34)
33
+ account!: string;
34
+
35
+ /** Nombre del titular tal como viaja al riel (SPEI acepta máx. 40 chars). */
36
+ @IsString()
37
+ @IsNotEmpty()
38
+ @MaxLength(40)
39
+ beneficiaryName!: string;
40
+
41
+ /** RFC del titular: 12 chars persona moral, 13 persona física. */
42
+ @IsOptional()
43
+ @IsString()
44
+ @Length(12, 13)
45
+ beneficiaryRfc?: string;
46
+
47
+ /** Nombre del banco, para que el operador reconozca la cuenta en backoffice. */
48
+ @IsString()
49
+ @IsNotEmpty()
50
+ @MaxLength(60)
51
+ bankName!: string;
52
+
53
+ /** ISO 4217 (`MXN`, `USD`). */
54
+ @IsString()
55
+ @Length(3, 3)
56
+ currency!: string;
57
+
58
+ @IsBoolean()
59
+ enabled!: boolean;
60
+ }
@@ -7,7 +7,6 @@ import {
7
7
  IsNumber,
8
8
  IsOptional,
9
9
  IsString,
10
- Length,
11
10
  MaxLength,
12
11
  Min,
13
12
  ValidateNested,
@@ -21,12 +20,17 @@ import { BatchScheduleRequest } from "./BatchScheduleRequest";
21
20
  /**
22
21
  * Producto de un servicio de transferencia de dinero (Centro de Beneficios). Los campos en
23
22
  * español espejan el catálogo legacy de pago de servicios; los campos en inglés son la
24
- * configuración propia del riel (canal, modo de liquidación, beneficiario, lote).
23
+ * configuración propia del riel (canal, modo de liquidación, lote). El beneficiario ya no vive
24
+ * acá: se mudó a la cuenta destino (DEC-046).
25
25
  */
26
26
  export class MoneyTransferProductRequest {
27
+ /**
28
+ * DEC-041: `idProducto` es el `accountId` de la cuenta destino (`ACC-BANORTE-01`), NO la CLABE.
29
+ * La CLABE vive en `MoneyTransferAccount_GT` y se resuelve al pagar (F1) y al enviar (F4).
30
+ */
27
31
  @IsString()
28
32
  @IsNotEmpty()
29
- @MaxLength(34)
33
+ @MaxLength(64)
30
34
  idProducto!: string;
31
35
 
32
36
  @IsString()
@@ -81,17 +85,9 @@ export class MoneyTransferProductRequest {
81
85
  @IsEnum(SettlementModeEnum)
82
86
  settlementMode!: SettlementModeEnum;
83
87
 
84
- /** Nombre del beneficiario tal como viaja al riel (SPEI acepta máx. 40 chars). */
85
- @IsString()
86
- @IsNotEmpty()
87
- @MaxLength(40)
88
- beneficiaryName!: string;
89
-
90
- /** RFC del beneficiario: 12 chars persona moral, 13 persona física. */
91
- @IsOptional()
92
- @IsString()
93
- @Length(12, 13)
94
- beneficiaryRfc?: string;
88
+ // DEC-046: `beneficiaryName` y `beneficiaryRfc` se mudaron a la cuenta (`MoneyTransferAccount_GT`).
89
+ // Son atributos del titular de la cuenta, no del producto: tenerlos acá permitía que dos productos
90
+ // a la misma cuenta divergieran en el titular sin que nada lo impidiera.
95
91
 
96
92
  @IsOptional()
97
93
  @IsNumber()
@@ -20,6 +20,12 @@ export class SettlementResponse {
20
20
  scheduledAt?: number;
21
21
  /** Id de la transacción en el riel (ACH) o clave de rastreo (SPEI). */
22
22
  achTransactionId?: string;
23
+ /**
24
+ * DEC-044: cuenta (CLABE) a la que se INTENTÓ enviar este lote, escrita al tomar el lock `SENDING`.
25
+ * No significa "cuenta que recibió el dinero": la evidencia de dinero movido es este campo + un
26
+ * estado de la terna SENT/SETTLED/RETURNED + `achTransactionId`.
27
+ */
28
+ sentToAccount?: string;
23
29
  returnReason?: string;
24
30
  lastError?: string;
25
31
  /** `true` cuando el envío no obtuvo respuesta concluyente del riel (posible duplicado). */
@@ -20,6 +20,13 @@ export class TransactionDetailResponse {
20
20
  status!: TransactionDetailStatusEnum;
21
21
  /** Presente cuando el folio ya fue agrupado en una liquidación. */
22
22
  settlementId?: string;
23
+ /**
24
+ * DEC-051: `true` cuando la cuenta de este folio no existe o está deshabilitada. El folio se queda
25
+ * en `PENDING_SETTLEMENT` (DEC-048) y no puede liquidarse hasta que operaciones arregle la cuenta;
26
+ * sin esta marca quedaría invisible en la cola y se descubriría cuando el usuario reclame.
27
+ * Solo lo calcula el listado de pendientes de backoffice (F9); en otros contextos viene ausente.
28
+ */
29
+ blockedByAccount?: boolean;
23
30
  /** Epoch ms. */
24
31
  createdAt!: number;
25
32
  }
@@ -0,0 +1,49 @@
1
+ import { IsBoolean, IsEnum, IsNotEmpty, IsOptional, IsString, Length, MaxLength } from "class-validator";
2
+ import { TransferChannelEnum } from "../enums/TransferChannelEnum";
3
+
4
+ /**
5
+ * Edición de una cuenta destino (DEC-045: actualización en el mismo registro, sin versionado).
6
+ * Todos los campos son opcionales: se envía solo lo que cambia. `accountId` no está porque es la PK
7
+ * y viaja en el path. `enabled` se cambia acá, sin endpoint propio (evita duplicar la lógica de impacto).
8
+ *
9
+ * Sin `idempotencyKey`: la edición es idempotente por naturaleza (escribe el estado deseado).
10
+ */
11
+ export class UpdateAccountRequest {
12
+ @IsOptional()
13
+ @IsEnum(TransferChannelEnum)
14
+ channel?: TransferChannelEnum;
15
+
16
+ /** El campo que hace útil todo este cambio: corregir el número no obliga a tocar ningún producto. */
17
+ @IsOptional()
18
+ @IsString()
19
+ @IsNotEmpty()
20
+ @MaxLength(34)
21
+ account?: string;
22
+
23
+ @IsOptional()
24
+ @IsString()
25
+ @IsNotEmpty()
26
+ @MaxLength(40)
27
+ beneficiaryName?: string;
28
+
29
+ @IsOptional()
30
+ @IsString()
31
+ @Length(12, 13)
32
+ beneficiaryRfc?: string;
33
+
34
+ @IsOptional()
35
+ @IsString()
36
+ @IsNotEmpty()
37
+ @MaxLength(60)
38
+ bankName?: string;
39
+
40
+ @IsOptional()
41
+ @IsString()
42
+ @Length(3, 3)
43
+ currency?: string;
44
+
45
+ /** DEC-049: nunca se borra una cuenta, solo se deshabilita. */
46
+ @IsOptional()
47
+ @IsBoolean()
48
+ enabled?: boolean;
49
+ }
@@ -19,9 +19,15 @@ export * from './dtos/MoneyTransferServiceUpdateRequest';
19
19
  export * from './dtos/CreateSettlementRequest';
20
20
  export * from './dtos/SettlementActionRequest';
21
21
  export * from './dtos/RescheduleSettlementRequest';
22
+ export * from './dtos/CreateAccountRequest';
23
+ export * from './dtos/UpdateAccountRequest';
22
24
 
23
25
  //DTOs — responses
24
26
  export * from './dtos/TransactionDetailResponse';
25
27
  export * from './dtos/SettlementResponse';
26
28
  export * from './dtos/PendingDetailsResponse';
27
29
  export * from './dtos/SettlementListResponse';
30
+ export * from './dtos/AccountResponse';
31
+ export * from './dtos/AccountListResponse';
32
+ export * from './dtos/AccountImpactResponse';
33
+ export * from './dtos/AccountWithImpactResponse';