@fiado/type-kit 3.576.0 → 3.578.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 (27) hide show
  1. package/_test_/unit/remittance/RemittanceProviderCost.test.ts +78 -0
  2. package/_test_/unit/retailWizard/customerTableShapes.test.ts +22 -0
  3. package/bin/remittance/dtos/RemittanceBackofficeTransaction.d.ts +8 -0
  4. package/bin/remittance/dtos/RemittancePayerConfig.d.ts +3 -0
  5. package/bin/remittance/dtos/RemittancePricing.d.ts +26 -0
  6. package/bin/remittance/dtos/RemittancePricing.js +53 -1
  7. package/bin/remittance/dtos/RemittanceProviderCost.d.ts +72 -0
  8. package/bin/remittance/dtos/RemittanceProviderCost.js +127 -0
  9. package/bin/remittance/dtos/index.d.ts +1 -0
  10. package/bin/remittance/dtos/index.js +1 -0
  11. package/bin/remittance/dtos/internal/RemittancePricingResolve.d.ts +12 -0
  12. package/bin/remittance/dtos/internal/RemittancePricingResolve.js +12 -0
  13. package/bin/remittance/dtos/internal/RemittancePricingSchedule.d.ts +4 -0
  14. package/bin/remittance/dtos/internal/RemittancePricingSchedule.js +11 -0
  15. package/bin/retailCustomer/dtos/requests/UpsertCustomerFromKycRequest.d.ts +2 -0
  16. package/bin/retailCustomer/dtos/requests/UpsertCustomerFromKycRequest.js +6 -0
  17. package/bin/retailWizard/dtos/responses/BackofficeCustomerTableResponse.d.ts +18 -5
  18. package/package.json +1 -1
  19. package/src/remittance/dtos/RemittanceBackofficeTransaction.ts +11 -0
  20. package/src/remittance/dtos/RemittancePayerConfig.ts +3 -0
  21. package/src/remittance/dtos/RemittancePricing.ts +60 -0
  22. package/src/remittance/dtos/RemittanceProviderCost.ts +139 -0
  23. package/src/remittance/dtos/index.ts +1 -0
  24. package/src/remittance/dtos/internal/RemittancePricingResolve.ts +19 -0
  25. package/src/remittance/dtos/internal/RemittancePricingSchedule.ts +10 -0
  26. package/src/retailCustomer/dtos/requests/UpsertCustomerFromKycRequest.ts +6 -0
  27. package/src/retailWizard/dtos/responses/BackofficeCustomerTableResponse.ts +19 -5
@@ -0,0 +1,78 @@
1
+ import "reflect-metadata";
2
+ import { plainToInstance } from "class-transformer";
3
+ import { validateSync } from "class-validator";
4
+ import { ProviderCostUpdateRequest } from "../../../src/remittance/dtos/RemittanceProviderCost";
5
+ import { SimulatePricingRequest, UpdatePricingRequest } from "../../../src/remittance/dtos/RemittancePricing";
6
+ import { PricingResolveRequest } from "../../../src/remittance/dtos/internal/RemittancePricingResolve";
7
+
8
+ const errorsOf = <T extends object>(cls: new () => T, plain: object) =>
9
+ validateSync(plainToInstance(cls, plain), { whitelist: true, forbidNonWhitelisted: true });
10
+
11
+ describe("ProviderCostUpdateRequest", () => {
12
+ it("acepta grupos con tres precios, tramo y asignaciones", () => {
13
+ expect(errorsOf(ProviderCostUpdateRequest, {
14
+ costTier: 1,
15
+ groups: [{ groupId: "A", costsUSD: [3, 2.75, 2.6] }],
16
+ assignments: [
17
+ { payerCode: "GCA8", receptionMethod: "CASH_PICKUP", groupId: "B" },
18
+ { payerCode: "GCA12", receptionMethod: "CASH_PICKUP", groupId: null },
19
+ ],
20
+ })).toHaveLength(0);
21
+ });
22
+
23
+ it("rechaza un grupo sin los tres precios", () => {
24
+ expect(errorsOf(ProviderCostUpdateRequest, { groups: [{ groupId: "A", costsUSD: [3, 2.75] }] })).not.toHaveLength(0);
25
+ });
26
+
27
+ it("rechaza ids de grupo que no son una letra mayúscula", () => {
28
+ expect(errorsOf(ProviderCostUpdateRequest, { groups: [{ groupId: "AB", costsUSD: [3, 2.75, 2.6] }] })).not.toHaveLength(0);
29
+ expect(errorsOf(ProviderCostUpdateRequest, { assignments: [{ payerCode: "GCA8", receptionMethod: "CASH_PICKUP", groupId: "b" }] })).not.toHaveLength(0);
30
+ });
31
+
32
+ it("rechaza precios con más de dos decimales o fuera de rango", () => {
33
+ expect(errorsOf(ProviderCostUpdateRequest, { groups: [{ groupId: "A", costsUSD: [3.001, 2.75, 2.6] }] })).not.toHaveLength(0);
34
+ expect(errorsOf(ProviderCostUpdateRequest, { groups: [{ groupId: "A", costsUSD: [-1, 2.75, 2.6] }] })).not.toHaveLength(0);
35
+ });
36
+
37
+ it("rechaza un tramo fuera de 1..3", () => {
38
+ expect(errorsOf(ProviderCostUpdateRequest, { costTier: 4 })).not.toHaveLength(0);
39
+ });
40
+ });
41
+
42
+ describe("ajustes de fee por grupo", () => {
43
+ const tramos = [{ amountMin: 25, amountMax: null, serviceFee: 2.99, effectiveFrom: "2026-10-23" }];
44
+
45
+ it("UpdatePricingRequest acepta groupFeeAdjustments con signo", () => {
46
+ expect(errorsOf(UpdatePricingRequest, {
47
+ markupBps: 120, tramos,
48
+ groupFeeAdjustments: [{ groupId: "C", adjustmentUSD: 1 }, { groupId: "A", adjustmentUSD: -0.5 }],
49
+ })).toHaveLength(0);
50
+ });
51
+
52
+ it("UpdatePricingRequest sigue válido sin groupFeeAdjustments", () => {
53
+ expect(errorsOf(UpdatePricingRequest, { markupBps: 120, tramos })).toHaveLength(0);
54
+ });
55
+
56
+ it("SimulatePricingRequest acepta payer y método", () => {
57
+ expect(errorsOf(SimulatePricingRequest, {
58
+ corridor: "USD-GTQ", amountUSD: 200, markupBps: 120, tramos,
59
+ payerCode: "GCA10", receptionMethod: "CASH_PICKUP",
60
+ })).toHaveLength(0);
61
+ });
62
+ });
63
+
64
+ describe("PricingResolveRequest", () => {
65
+ it("acepta payer y método opcionales", () => {
66
+ expect(errorsOf(PricingResolveRequest, {
67
+ directoryId: "8f14e45f-ceea-467f-a8f8-3c1a3f6b1d2e", corridor: "USD-GTQ", amountUSD: 200,
68
+ payerCode: "GCA10", receptionMethod: "ACCOUNT_CREDIT",
69
+ })).toHaveLength(0);
70
+ });
71
+
72
+ it("rechaza un método que no existe", () => {
73
+ expect(errorsOf(PricingResolveRequest, {
74
+ directoryId: "8f14e45f-ceea-467f-a8f8-3c1a3f6b1d2e", corridor: "USD-GTQ", amountUSD: 200,
75
+ receptionMethod: "CARRIER_PIGEON",
76
+ })).not.toHaveLength(0);
77
+ });
78
+ });
@@ -12,9 +12,12 @@ describe('BackofficeCustomerTableResponse', () => {
12
12
  to: '2026-10-07T18:00:00.000Z',
13
13
  nextToken: 'abc',
14
14
  sources: { sales: SellerTableSourceStatusEnum.OK, credit: SellerTableSourceStatusEnum.UNAVAILABLE },
15
+ counts: { withSales: 1, accountOnly: 1 },
15
16
  items: [
16
17
  {
17
18
  retailCustomerId: 'RC-1',
19
+ accountOnly: false,
20
+ originStoreId: 'ST-1',
18
21
  name: 'Ana',
19
22
  phone: null,
20
23
  purchaseCount: 2,
@@ -28,9 +31,28 @@ describe('BackofficeCustomerTableResponse', () => {
28
31
  skLevel: ClientLevelEnum.GOLD,
29
32
  activeCreditsCount: null,
30
33
  },
34
+ {
35
+ retailCustomerId: 'RC-2',
36
+ accountOnly: true,
37
+ originStoreId: 'ST-1',
38
+ name: 'Luz',
39
+ phone: null,
40
+ purchaseCount: 0,
41
+ totalSpentCents: 0,
42
+ averageTicketCents: null,
43
+ firstPurchaseAt: null,
44
+ lastPurchaseAt: null,
45
+ lastStoreName: null,
46
+ favoriteStoreId: null,
47
+ favoriteStoreName: null,
48
+ skLevel: null,
49
+ activeCreditsCount: null,
50
+ },
31
51
  ],
32
52
  };
33
53
  expect(response.items[0].skLevel).toBe('GOLD');
34
54
  expect(response.sources.credit).toBe('UNAVAILABLE');
55
+ expect(response.items[1].accountOnly).toBe(true);
56
+ expect(response.counts.accountOnly).toBe(1);
35
57
  });
36
58
  });
@@ -95,4 +95,12 @@ export declare class RemittanceBackofficeTransaction {
95
95
  reconStatus?: RemittanceReconStatus;
96
96
  /** Detalle textual de los diffs cuando reconStatus !== OK. */
97
97
  reconDiffDetail?: string;
98
+ /** Costo UniTeller esperado en USD según el grupo y el tramo vigente al enviar. */
99
+ unitellerCostExpected?: number;
100
+ /** Grupo de costo del payer × método al enviar. */
101
+ costGroup?: string;
102
+ /** Tramo de volumen vigente al enviar (1..3). */
103
+ costTier?: number;
104
+ /** Ajuste del grupo que se sumó al fee de esta remesa. */
105
+ groupFeeAdjustment?: number;
98
106
  }
@@ -1,4 +1,5 @@
1
1
  import { ReceptionMethod } from "../enums/ReceptionMethod";
2
+ import { CostGroupByMethod } from "./RemittanceProviderCost";
2
3
  /**
3
4
  * DTOs de la administración de payers desde el backoffice (v1: enabled + override de nombre).
4
5
  * La lista de payers la dicta el catálogo UniTeller; la config es un overlay por payerCode.
@@ -18,6 +19,8 @@ export declare class RemittancePayerConfigItem {
18
19
  configured: boolean;
19
20
  /** Logo de UniTeller, solo lectura (identificación visual en la lista). */
20
21
  logoUrl?: string;
22
+ /** Grupo de costo UniTeller de cada método (solo lectura aquí; se edita en Costos UniTeller). */
23
+ costGroupByMethod?: CostGroupByMethod;
21
24
  }
22
25
  /** Response de GET /backoffice/config/payers (config chica, sin paginación). */
23
26
  export declare class RemittancePayerConfigListResponse {
@@ -1,4 +1,5 @@
1
1
  import { RemittanceCorridor } from "../enums/RemittanceCorridor";
2
+ import { ReceptionMethod } from "../enums/ReceptionMethod";
2
3
  /**
3
4
  * DTOs de Precio Base (Dashboard Ops · Variables Operativas §1).
4
5
  *
@@ -20,6 +21,12 @@ export declare class PricingTier {
20
21
  /** ISO date (YYYY-MM-DD) "FEE DESDE" — informativo. */
21
22
  effectiveFrom: string;
22
23
  }
24
+ /** Ajuste en USD que se suma al fee del tramo cuando el payer × método cae en ese grupo de costo. */
25
+ export declare class PricingGroupFeeAdjustment {
26
+ groupId: string;
27
+ /** CON SIGNO: negativo descuenta. El fee final nunca baja de 0. */
28
+ adjustmentUSD: number;
29
+ }
23
30
  /** Body de POST /backoffice/pricing/base. */
24
31
  export declare class CreatePricingRequest {
25
32
  corridor: RemittanceCorridor;
@@ -29,6 +36,8 @@ export declare class CreatePricingRequest {
29
36
  tramos: PricingTier[];
30
37
  name?: string;
31
38
  notes?: string;
39
+ /** Ajuste del fee por grupo de costo del payer. Ausente = conserva los actuales; [] = sin ajustes. */
40
+ groupFeeAdjustments?: PricingGroupFeeAdjustment[];
32
41
  }
33
42
  /** Body de PUT /backoffice/pricing/base/{id} (reemplazo completo; corridor/segmentId inmutables). */
34
43
  export declare class UpdatePricingRequest {
@@ -36,6 +45,8 @@ export declare class UpdatePricingRequest {
36
45
  tramos: PricingTier[];
37
46
  name?: string;
38
47
  notes?: string;
48
+ /** Ajuste del fee por grupo de costo del payer. Ausente = conserva los actuales; [] = sin ajustes. */
49
+ groupFeeAdjustments?: PricingGroupFeeAdjustment[];
39
50
  }
40
51
  /** Combinación completa (response de list/create/update). */
41
52
  export declare class PricingCombination {
@@ -48,6 +59,8 @@ export declare class PricingCombination {
48
59
  tramos: PricingTier[];
49
60
  /** # promos activas que aplican a la combinación. 0 hasta que exista Promociones. */
50
61
  promosCount: number;
62
+ /** Ajuste del fee por grupo de costo. Ausente o [] = sin ajustes. */
63
+ groupFeeAdjustments?: PricingGroupFeeAdjustment[];
51
64
  name: string | null;
52
65
  notes: string | null;
53
66
  createdAt: string;
@@ -72,6 +85,11 @@ export declare class SimulatePricingRequest {
72
85
  amountUSD: number;
73
86
  markupBps: number;
74
87
  tramos: PricingTier[];
88
+ /** Ajustes del panel (pueden no estar guardados). Solo aplican si viene payer y método. */
89
+ groupFeeAdjustments?: PricingGroupFeeAdjustment[];
90
+ /** Payer y método opcionales: con ellos la simulación suma el ajuste del grupo y calcula costo y margen. */
91
+ payerCode?: string;
92
+ receptionMethod?: ReceptionMethod;
75
93
  }
76
94
  export declare class SimulatePricingResponse {
77
95
  /** ExternalQuickQuotes (vivo). */
@@ -90,6 +108,14 @@ export declare class SimulatePricingResponse {
90
108
  revenueUsd: number;
91
109
  /** ISO del quote. */
92
110
  asOf: string;
111
+ /** Grupo de costo del payer × método simulado. */
112
+ costGroup?: string;
113
+ /** Ajuste del grupo ya sumado en serviceFee. */
114
+ groupFeeAdjustment?: number;
115
+ /** Costo UniTeller esperado (Exhibit A, tramo vigente del país). */
116
+ unitellerCostExpected?: number;
117
+ /** revenueUsd − unitellerCostExpected. */
118
+ netMarginUsd?: number;
93
119
  }
94
120
  /** Response de GET /backoffice/pricing/wholesale?corridor= (rb passthrough del connector). */
95
121
  export declare class WholesaleRateResponse {
@@ -9,10 +9,12 @@ var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.WholesaleRateResponse = exports.SimulatePricingResponse = exports.SimulatePricingRequest = exports.PricingCombinationMetrics = exports.PricingListResponse = exports.PricingCombination = exports.UpdatePricingRequest = exports.CreatePricingRequest = exports.PricingTier = void 0;
12
+ exports.WholesaleRateResponse = exports.SimulatePricingResponse = exports.SimulatePricingRequest = exports.PricingCombinationMetrics = exports.PricingListResponse = exports.PricingCombination = exports.UpdatePricingRequest = exports.CreatePricingRequest = exports.PricingGroupFeeAdjustment = exports.PricingTier = void 0;
13
13
  const class_transformer_1 = require("class-transformer");
14
14
  const class_validator_1 = require("class-validator");
15
15
  const RemittanceCorridor_1 = require("../enums/RemittanceCorridor");
16
+ const ReceptionMethod_1 = require("../enums/ReceptionMethod");
17
+ const RemittanceProviderCost_1 = require("./RemittanceProviderCost");
16
18
  /**
17
19
  * DTOs de Precio Base (Dashboard Ops · Variables Operativas §1).
18
20
  *
@@ -55,6 +57,21 @@ __decorate([
55
57
  (0, class_validator_1.Length)(10, 10),
56
58
  __metadata("design:type", String)
57
59
  ], PricingTier.prototype, "effectiveFrom", void 0);
60
+ /** Ajuste en USD que se suma al fee del tramo cuando el payer × método cae en ese grupo de costo. */
61
+ class PricingGroupFeeAdjustment {
62
+ }
63
+ exports.PricingGroupFeeAdjustment = PricingGroupFeeAdjustment;
64
+ __decorate([
65
+ (0, class_validator_1.IsString)(),
66
+ (0, class_validator_1.Matches)(RemittanceProviderCost_1.PROVIDER_COST_GROUP_ID_PATTERN),
67
+ __metadata("design:type", String)
68
+ ], PricingGroupFeeAdjustment.prototype, "groupId", void 0);
69
+ __decorate([
70
+ (0, class_validator_1.IsNumber)({ maxDecimalPlaces: 2 }),
71
+ (0, class_validator_1.Min)(-100),
72
+ (0, class_validator_1.Max)(100),
73
+ __metadata("design:type", Number)
74
+ ], PricingGroupFeeAdjustment.prototype, "adjustmentUSD", void 0);
58
75
  /** Body de POST /backoffice/pricing/base. */
59
76
  class CreatePricingRequest {
60
77
  }
@@ -94,6 +111,14 @@ __decorate([
94
111
  (0, class_validator_1.MaxLength)(500),
95
112
  __metadata("design:type", String)
96
113
  ], CreatePricingRequest.prototype, "notes", void 0);
114
+ __decorate([
115
+ (0, class_validator_1.IsOptional)(),
116
+ (0, class_validator_1.IsArray)(),
117
+ (0, class_validator_1.ArrayMaxSize)(10),
118
+ (0, class_validator_1.ValidateNested)({ each: true }),
119
+ (0, class_transformer_1.Type)(() => PricingGroupFeeAdjustment),
120
+ __metadata("design:type", Array)
121
+ ], CreatePricingRequest.prototype, "groupFeeAdjustments", void 0);
97
122
  /** Body de PUT /backoffice/pricing/base/{id} (reemplazo completo; corridor/segmentId inmutables). */
98
123
  class UpdatePricingRequest {
99
124
  }
@@ -124,6 +149,14 @@ __decorate([
124
149
  (0, class_validator_1.MaxLength)(500),
125
150
  __metadata("design:type", String)
126
151
  ], UpdatePricingRequest.prototype, "notes", void 0);
152
+ __decorate([
153
+ (0, class_validator_1.IsOptional)(),
154
+ (0, class_validator_1.IsArray)(),
155
+ (0, class_validator_1.ArrayMaxSize)(10),
156
+ (0, class_validator_1.ValidateNested)({ each: true }),
157
+ (0, class_transformer_1.Type)(() => PricingGroupFeeAdjustment),
158
+ __metadata("design:type", Array)
159
+ ], UpdatePricingRequest.prototype, "groupFeeAdjustments", void 0);
127
160
  /** Combinación completa (response de list/create/update). */
128
161
  class PricingCombination {
129
162
  }
@@ -163,6 +196,25 @@ __decorate([
163
196
  (0, class_transformer_1.Type)(() => PricingTier),
164
197
  __metadata("design:type", Array)
165
198
  ], SimulatePricingRequest.prototype, "tramos", void 0);
199
+ __decorate([
200
+ (0, class_validator_1.IsOptional)(),
201
+ (0, class_validator_1.IsArray)(),
202
+ (0, class_validator_1.ArrayMaxSize)(10),
203
+ (0, class_validator_1.ValidateNested)({ each: true }),
204
+ (0, class_transformer_1.Type)(() => PricingGroupFeeAdjustment),
205
+ __metadata("design:type", Array)
206
+ ], SimulatePricingRequest.prototype, "groupFeeAdjustments", void 0);
207
+ __decorate([
208
+ (0, class_validator_1.IsOptional)(),
209
+ (0, class_validator_1.IsString)(),
210
+ (0, class_validator_1.Length)(1, 40),
211
+ __metadata("design:type", String)
212
+ ], SimulatePricingRequest.prototype, "payerCode", void 0);
213
+ __decorate([
214
+ (0, class_validator_1.IsOptional)(),
215
+ (0, class_validator_1.IsEnum)(ReceptionMethod_1.ReceptionMethod),
216
+ __metadata("design:type", String)
217
+ ], SimulatePricingRequest.prototype, "receptionMethod", void 0);
166
218
  class SimulatePricingResponse {
167
219
  }
168
220
  exports.SimulatePricingResponse = SimulatePricingResponse;
@@ -0,0 +1,72 @@
1
+ import { ReceptionMethod } from "../enums/ReceptionMethod";
2
+ /**
3
+ * DTOs de Costos UniTeller (Exhibit A del contrato): lo que UniTeller le cobra a Fiado por remesa.
4
+ * Por país hay grupos con un precio por tramo de volumen y un tramo vigente; cada payer × método
5
+ * cae en un grupo. Se guarda en RemittanceCountryConfig_GT (grupos y tramo) y en
6
+ * RemittancePayerConfig_GT (grupo por método). Dueño: remittance-business.
7
+ */
8
+ /** Cantidad de tramos de volumen del Exhibit A. */
9
+ export declare const PROVIDER_COST_TIER_COUNT = 3;
10
+ /** Id de grupo: una letra mayúscula (A, B, C…). */
11
+ export declare const PROVIDER_COST_GROUP_ID_PATTERN: RegExp;
12
+ /** Grupo de costo: un precio en USD por tramo de volumen (posición 0 = tramo 1). */
13
+ export declare class ProviderCostGroup {
14
+ groupId: string;
15
+ costsUSD: number[];
16
+ }
17
+ /** Grupo de cada método de un payer. Método ausente = sin grupo (sin costo esperado ni ajuste de fee). */
18
+ export declare class CostGroupByMethod {
19
+ ACCOUNT_CREDIT?: string;
20
+ CASH_PICKUP?: string;
21
+ WALLET?: string;
22
+ }
23
+ /** Un payer × método del catálogo del país, con su grupo si tiene. */
24
+ export declare class ProviderCostAssignment {
25
+ payerCode: string;
26
+ /** Nombre efectivo del payer (override de Ops o el de UniTeller). */
27
+ name: string;
28
+ receptionMethod: ReceptionMethod;
29
+ /** Ausente = sin grupo. */
30
+ groupId?: string;
31
+ }
32
+ /** Volumen del mes calendario en curso (UTC), sin canceladas. Guía para elegir el tramo vigente. */
33
+ export declare class ProviderCostMonthVolume {
34
+ txCount: number;
35
+ volumeUSD: number;
36
+ }
37
+ /** Costos de un país (vista de backoffice). */
38
+ export declare class ProviderCostCountryItem {
39
+ countryISO: string;
40
+ name: string;
41
+ /** Tramo vigente 1..3; null = sin configurar. */
42
+ costTier: number | null;
43
+ groups: ProviderCostGroup[];
44
+ /** Todos los payer × método del catálogo del país, con o sin grupo. */
45
+ assignments: ProviderCostAssignment[];
46
+ /** Ausente si no se pudo calcular. */
47
+ monthVolume?: ProviderCostMonthVolume;
48
+ updatedAt?: string;
49
+ updatedBy?: string;
50
+ }
51
+ /** Response de GET /backoffice/config/provider-costs. */
52
+ export declare class ProviderCostListResponse {
53
+ /** Etiquetas de los tramos de volumen del contrato, en orden (tramo 1 primero). */
54
+ tierLabels: string[];
55
+ items: ProviderCostCountryItem[];
56
+ }
57
+ /** Cambio de grupo de un payer × método. groupId null o ausente = quitarlo de su grupo. */
58
+ export declare class ProviderCostAssignmentUpdate {
59
+ payerCode: string;
60
+ receptionMethod: ReceptionMethod;
61
+ groupId?: string | null;
62
+ }
63
+ /**
64
+ * Body de PUT /backoffice/config/provider-costs/{countryISO}. Todo opcional.
65
+ * `groups` reemplaza la lista completa; `assignments` solo toca los payer × método que trae.
66
+ * Response: ProviderCostCountryItem.
67
+ */
68
+ export declare class ProviderCostUpdateRequest {
69
+ costTier?: number;
70
+ groups?: ProviderCostGroup[];
71
+ assignments?: ProviderCostAssignmentUpdate[];
72
+ }
@@ -0,0 +1,127 @@
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.ProviderCostUpdateRequest = exports.ProviderCostAssignmentUpdate = exports.ProviderCostListResponse = exports.ProviderCostCountryItem = exports.ProviderCostMonthVolume = exports.ProviderCostAssignment = exports.CostGroupByMethod = exports.ProviderCostGroup = exports.PROVIDER_COST_GROUP_ID_PATTERN = exports.PROVIDER_COST_TIER_COUNT = void 0;
13
+ const class_transformer_1 = require("class-transformer");
14
+ const class_validator_1 = require("class-validator");
15
+ const ReceptionMethod_1 = require("../enums/ReceptionMethod");
16
+ /**
17
+ * DTOs de Costos UniTeller (Exhibit A del contrato): lo que UniTeller le cobra a Fiado por remesa.
18
+ * Por país hay grupos con un precio por tramo de volumen y un tramo vigente; cada payer × método
19
+ * cae en un grupo. Se guarda en RemittanceCountryConfig_GT (grupos y tramo) y en
20
+ * RemittancePayerConfig_GT (grupo por método). Dueño: remittance-business.
21
+ */
22
+ /** Cantidad de tramos de volumen del Exhibit A. */
23
+ exports.PROVIDER_COST_TIER_COUNT = 3;
24
+ /** Id de grupo: una letra mayúscula (A, B, C…). */
25
+ exports.PROVIDER_COST_GROUP_ID_PATTERN = /^[A-Z]$/;
26
+ /** Grupo de costo: un precio en USD por tramo de volumen (posición 0 = tramo 1). */
27
+ class ProviderCostGroup {
28
+ }
29
+ exports.ProviderCostGroup = ProviderCostGroup;
30
+ __decorate([
31
+ (0, class_validator_1.IsString)(),
32
+ (0, class_validator_1.Matches)(exports.PROVIDER_COST_GROUP_ID_PATTERN),
33
+ __metadata("design:type", String)
34
+ ], ProviderCostGroup.prototype, "groupId", void 0);
35
+ __decorate([
36
+ (0, class_validator_1.IsArray)(),
37
+ (0, class_validator_1.ArrayMinSize)(exports.PROVIDER_COST_TIER_COUNT),
38
+ (0, class_validator_1.ArrayMaxSize)(exports.PROVIDER_COST_TIER_COUNT),
39
+ (0, class_validator_1.IsNumber)({ maxDecimalPlaces: 2 }, { each: true }),
40
+ (0, class_validator_1.Min)(0, { each: true }),
41
+ (0, class_validator_1.Max)(50, { each: true }),
42
+ __metadata("design:type", Array)
43
+ ], ProviderCostGroup.prototype, "costsUSD", void 0);
44
+ /** Grupo de cada método de un payer. Método ausente = sin grupo (sin costo esperado ni ajuste de fee). */
45
+ class CostGroupByMethod {
46
+ }
47
+ exports.CostGroupByMethod = CostGroupByMethod;
48
+ __decorate([
49
+ (0, class_validator_1.IsOptional)(),
50
+ (0, class_validator_1.Matches)(exports.PROVIDER_COST_GROUP_ID_PATTERN),
51
+ __metadata("design:type", String)
52
+ ], CostGroupByMethod.prototype, "ACCOUNT_CREDIT", void 0);
53
+ __decorate([
54
+ (0, class_validator_1.IsOptional)(),
55
+ (0, class_validator_1.Matches)(exports.PROVIDER_COST_GROUP_ID_PATTERN),
56
+ __metadata("design:type", String)
57
+ ], CostGroupByMethod.prototype, "CASH_PICKUP", void 0);
58
+ __decorate([
59
+ (0, class_validator_1.IsOptional)(),
60
+ (0, class_validator_1.Matches)(exports.PROVIDER_COST_GROUP_ID_PATTERN),
61
+ __metadata("design:type", String)
62
+ ], CostGroupByMethod.prototype, "WALLET", void 0);
63
+ /** Un payer × método del catálogo del país, con su grupo si tiene. */
64
+ class ProviderCostAssignment {
65
+ }
66
+ exports.ProviderCostAssignment = ProviderCostAssignment;
67
+ /** Volumen del mes calendario en curso (UTC), sin canceladas. Guía para elegir el tramo vigente. */
68
+ class ProviderCostMonthVolume {
69
+ }
70
+ exports.ProviderCostMonthVolume = ProviderCostMonthVolume;
71
+ /** Costos de un país (vista de backoffice). */
72
+ class ProviderCostCountryItem {
73
+ }
74
+ exports.ProviderCostCountryItem = ProviderCostCountryItem;
75
+ /** Response de GET /backoffice/config/provider-costs. */
76
+ class ProviderCostListResponse {
77
+ }
78
+ exports.ProviderCostListResponse = ProviderCostListResponse;
79
+ /** Cambio de grupo de un payer × método. groupId null o ausente = quitarlo de su grupo. */
80
+ class ProviderCostAssignmentUpdate {
81
+ }
82
+ exports.ProviderCostAssignmentUpdate = ProviderCostAssignmentUpdate;
83
+ __decorate([
84
+ (0, class_validator_1.IsString)(),
85
+ (0, class_validator_1.Length)(1, 40),
86
+ __metadata("design:type", String)
87
+ ], ProviderCostAssignmentUpdate.prototype, "payerCode", void 0);
88
+ __decorate([
89
+ (0, class_validator_1.IsEnum)(ReceptionMethod_1.ReceptionMethod),
90
+ __metadata("design:type", String)
91
+ ], ProviderCostAssignmentUpdate.prototype, "receptionMethod", void 0);
92
+ __decorate([
93
+ (0, class_validator_1.IsOptional)(),
94
+ (0, class_validator_1.Matches)(exports.PROVIDER_COST_GROUP_ID_PATTERN),
95
+ __metadata("design:type", String)
96
+ ], ProviderCostAssignmentUpdate.prototype, "groupId", void 0);
97
+ /**
98
+ * Body de PUT /backoffice/config/provider-costs/{countryISO}. Todo opcional.
99
+ * `groups` reemplaza la lista completa; `assignments` solo toca los payer × método que trae.
100
+ * Response: ProviderCostCountryItem.
101
+ */
102
+ class ProviderCostUpdateRequest {
103
+ }
104
+ exports.ProviderCostUpdateRequest = ProviderCostUpdateRequest;
105
+ __decorate([
106
+ (0, class_validator_1.IsOptional)(),
107
+ (0, class_validator_1.IsInt)(),
108
+ (0, class_validator_1.Min)(1),
109
+ (0, class_validator_1.Max)(exports.PROVIDER_COST_TIER_COUNT),
110
+ __metadata("design:type", Number)
111
+ ], ProviderCostUpdateRequest.prototype, "costTier", void 0);
112
+ __decorate([
113
+ (0, class_validator_1.IsOptional)(),
114
+ (0, class_validator_1.IsArray)(),
115
+ (0, class_validator_1.ArrayMaxSize)(10),
116
+ (0, class_validator_1.ValidateNested)({ each: true }),
117
+ (0, class_transformer_1.Type)(() => ProviderCostGroup),
118
+ __metadata("design:type", Array)
119
+ ], ProviderCostUpdateRequest.prototype, "groups", void 0);
120
+ __decorate([
121
+ (0, class_validator_1.IsOptional)(),
122
+ (0, class_validator_1.IsArray)(),
123
+ (0, class_validator_1.ArrayMaxSize)(300),
124
+ (0, class_validator_1.ValidateNested)({ each: true }),
125
+ (0, class_transformer_1.Type)(() => ProviderCostAssignmentUpdate),
126
+ __metadata("design:type", Array)
127
+ ], ProviderCostUpdateRequest.prototype, "assignments", void 0);
@@ -49,6 +49,7 @@ export * from "./RemittancePricingTable";
49
49
  export * from "./RemittanceExceptionCatalog";
50
50
  export * from "./RemittanceCountryConfig";
51
51
  export * from "./RemittancePayerConfig";
52
+ export * from "./RemittanceProviderCost";
52
53
  export * from "./RemittanceFavoriteItem";
53
54
  export * from "./RemittanceFavoriteListResponse";
54
55
  export * from "./RemittanceBackofficeCancelCloseRequest";
@@ -65,6 +65,7 @@ __exportStar(require("./RemittancePricingTable"), exports);
65
65
  __exportStar(require("./RemittanceExceptionCatalog"), exports);
66
66
  __exportStar(require("./RemittanceCountryConfig"), exports);
67
67
  __exportStar(require("./RemittancePayerConfig"), exports);
68
+ __exportStar(require("./RemittanceProviderCost"), exports);
68
69
  __exportStar(require("./RemittanceFavoriteItem"), exports);
69
70
  __exportStar(require("./RemittanceFavoriteListResponse"), exports);
70
71
  __exportStar(require("./RemittanceBackofficeCancelCloseRequest"), exports);
@@ -1,4 +1,5 @@
1
1
  import { RemittanceCorridor } from "../../enums/RemittanceCorridor";
2
+ import { ReceptionMethod } from "../../enums/ReceptionMethod";
2
3
  /**
3
4
  * Request del resolver de send-time (Fase B). El connector lo llama por cada
4
5
  * quote/preview/pay. `code` = promo tecleada por el cliente en la app (opcional).
@@ -8,6 +9,9 @@ export declare class PricingResolveRequest {
8
9
  corridor: RemittanceCorridor;
9
10
  amountUSD: number;
10
11
  code?: string;
12
+ /** Payer del beneficiario. Con receptionMethod define el grupo de costo (costo esperado y ajuste de fee). */
13
+ payerCode?: string;
14
+ receptionMethod?: ReceptionMethod;
11
15
  }
12
16
  /** Regla BLOCK que rechazó la tx (VALIDATION o TX_AMOUNT con acción BLOCK). */
13
17
  export declare class PricingResolveBlocked {
@@ -32,4 +36,12 @@ export declare class PricingResolveResponse {
32
36
  /** Mínimo de envío del país destino (RemittanceCountryConfig_GT). El connector rechaza montos menores. */
33
37
  minAmountUSD: number;
34
38
  blocked?: PricingResolveBlocked;
39
+ /** Grupo de costo del payer × método. Ausente = sin grupo o sin payer en el request. */
40
+ costGroup?: string;
41
+ /** Tramo de volumen vigente del país con el que se calculó el costo (1..3). */
42
+ costTier?: number;
43
+ /** Costo UniTeller esperado en USD (Exhibit A). Ausente si no hay grupo o tramo. */
44
+ unitellerCostExpected?: number;
45
+ /** Ajuste en USD del grupo que ya está sumado en `serviceFee` (antes de promos y topes). */
46
+ groupFeeAdjustment?: number;
35
47
  }
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.PricingResolveResponse = exports.PricingResolveBlocked = exports.PricingResolveRequest = void 0;
13
13
  const class_validator_1 = require("class-validator");
14
14
  const RemittanceCorridor_1 = require("../../enums/RemittanceCorridor");
15
+ const ReceptionMethod_1 = require("../../enums/ReceptionMethod");
15
16
  /**
16
17
  * Request del resolver de send-time (Fase B). El connector lo llama por cada
17
18
  * quote/preview/pay. `code` = promo tecleada por el cliente en la app (opcional).
@@ -38,6 +39,17 @@ __decorate([
38
39
  (0, class_validator_1.Length)(3, 30),
39
40
  __metadata("design:type", String)
40
41
  ], PricingResolveRequest.prototype, "code", void 0);
42
+ __decorate([
43
+ (0, class_validator_1.IsOptional)(),
44
+ (0, class_validator_1.IsString)(),
45
+ (0, class_validator_1.Length)(1, 40),
46
+ __metadata("design:type", String)
47
+ ], PricingResolveRequest.prototype, "payerCode", void 0);
48
+ __decorate([
49
+ (0, class_validator_1.IsOptional)(),
50
+ (0, class_validator_1.IsEnum)(ReceptionMethod_1.ReceptionMethod),
51
+ __metadata("design:type", String)
52
+ ], PricingResolveRequest.prototype, "receptionMethod", void 0);
41
53
  /** Regla BLOCK que rechazó la tx (VALIDATION o TX_AMOUNT con acción BLOCK). */
42
54
  class PricingResolveBlocked {
43
55
  }
@@ -1,5 +1,6 @@
1
1
  import { RemittanceCorridor } from "../../enums/RemittanceCorridor";
2
2
  import { PromotionKind } from "../../enums/PromotionKind";
3
+ import { ReceptionMethod } from "../../enums/ReceptionMethod";
3
4
  /**
4
5
  * Request del schedule de precio por corredor (Fase B — F2 app). El connector lo
5
6
  * llama (passthrough desde benefits) para mostrarle al usuario la tabla de tramos de
@@ -8,6 +9,9 @@ import { PromotionKind } from "../../enums/PromotionKind";
8
9
  export declare class PricingScheduleRequest {
9
10
  directoryId: string;
10
11
  corridor: RemittanceCorridor;
12
+ /** Payer y método elegidos: los fees de los tramos incluyen el ajuste de su grupo. Ausentes = fee base. */
13
+ payerCode?: string;
14
+ receptionMethod?: ReceptionMethod;
11
15
  }
12
16
  /** Un tramo del schedule. `serviceFee` YA refleja la promo automática aplicada (D5). */
13
17
  export declare class PricingScheduleTier {
@@ -14,6 +14,7 @@ const class_transformer_1 = require("class-transformer");
14
14
  const class_validator_1 = require("class-validator");
15
15
  const RemittanceCorridor_1 = require("../../enums/RemittanceCorridor");
16
16
  const PromotionKind_1 = require("../../enums/PromotionKind");
17
+ const ReceptionMethod_1 = require("../../enums/ReceptionMethod");
17
18
  /**
18
19
  * Request del schedule de precio por corredor (Fase B — F2 app). El connector lo
19
20
  * llama (passthrough desde benefits) para mostrarle al usuario la tabla de tramos de
@@ -30,6 +31,16 @@ __decorate([
30
31
  (0, class_validator_1.IsEnum)(RemittanceCorridor_1.RemittanceCorridor),
31
32
  __metadata("design:type", String)
32
33
  ], PricingScheduleRequest.prototype, "corridor", void 0);
34
+ __decorate([
35
+ (0, class_validator_1.IsOptional)(),
36
+ (0, class_validator_1.IsString)(),
37
+ __metadata("design:type", String)
38
+ ], PricingScheduleRequest.prototype, "payerCode", void 0);
39
+ __decorate([
40
+ (0, class_validator_1.IsOptional)(),
41
+ (0, class_validator_1.IsEnum)(ReceptionMethod_1.ReceptionMethod),
42
+ __metadata("design:type", String)
43
+ ], PricingScheduleRequest.prototype, "receptionMethod", void 0);
33
44
  /** Un tramo del schedule. `serviceFee` YA refleja la promo automática aplicada (D5). */
34
45
  class PricingScheduleTier {
35
46
  }
@@ -10,6 +10,8 @@ import { RetailKycStatusEnum } from '../../enums/RetailKycStatusEnum';
10
10
  export declare class UpsertCustomerFromKycRequest {
11
11
  /** Tienda de alta/origen — del JWT del vendedor dueño de la sesión del wizard (F1 §3.5). */
12
12
  originStoreId: string;
13
+ /** Cadena de la tienda de alta; el wizard la manda desde la sesión. */
14
+ retailerId?: string;
13
15
  /** Nombre partido por convención Fiado (F1 §3.5) — lo entrega el OCR del INE, NO se deriva de un string. */
14
16
  names: string;
15
17
  paternalLastName: string;
@@ -30,6 +30,12 @@ __decorate([
30
30
  (0, class_validator_1.IsString)(),
31
31
  __metadata("design:type", String)
32
32
  ], UpsertCustomerFromKycRequest.prototype, "originStoreId", void 0);
33
+ __decorate([
34
+ (0, class_transformer_1.Expose)(),
35
+ (0, class_validator_1.IsOptional)(),
36
+ (0, class_validator_1.IsString)(),
37
+ __metadata("design:type", String)
38
+ ], UpsertCustomerFromKycRequest.prototype, "retailerId", void 0);
33
39
  __decorate([
34
40
  (0, class_transformer_1.Expose)(),
35
41
  (0, class_validator_1.IsString)(),
@@ -1,16 +1,23 @@
1
1
  import type { ClientLevelEnum } from '../../../loanScoring/enums/ClientLevelEnum';
2
2
  import type { SellerTableSourceStatusEnum } from '../../enums/SellerTableSourceStatusEnum';
3
- /** Una fila de la tabla de Clientes: compras en la cadena dentro de la ventana, sin canceladas, más su crédito SK. */
3
+ /**
4
+ * Una fila de la tabla de Clientes: un cliente del padrón de la cadena con sus compras en la ventana
5
+ * (sin canceladas) y su crédito SK. `accountOnly` = abrió cuenta y no tiene ninguna compra en la cadena.
6
+ */
4
7
  export interface CustomerTableRow {
5
8
  retailCustomerId: string;
9
+ accountOnly: boolean;
10
+ /** Tienda donde se dio de alta; `null` si el padrón no la tiene. */
11
+ originStoreId: string | null;
6
12
  name: string | null;
7
13
  phone: string | null;
8
14
  purchaseCount: number;
9
15
  /** Precio de lo comprado (en crédito, el precio del equipo, no el enganche). */
10
16
  totalSpentCents: number;
11
17
  averageTicketCents: number | null;
12
- firstPurchaseAt: string;
13
- lastPurchaseAt: string;
18
+ /** `null` en un cliente «solo cuenta». */
19
+ firstPurchaseAt: string | null;
20
+ lastPurchaseAt: string | null;
14
21
  lastStoreName: string | null;
15
22
  /** Tienda con más compras; en empate, la de la compra más reciente. */
16
23
  favoriteStoreId: string | null;
@@ -25,14 +32,20 @@ export interface CustomerTableSources {
25
32
  sales: SellerTableSourceStatusEnum.OK;
26
33
  credit: SellerTableSourceStatusEnum;
27
34
  }
35
+ /** Clientes del padrón leídos en la página, antes del filtro `customerType`; el front los suma por página. */
36
+ export interface CustomerTableCounts {
37
+ withSales: number;
38
+ accountOnly: number;
39
+ }
28
40
  /**
29
- * `GET /backoffice/customers/table?from&to&limit&nextToken&storeId&sellerId&value` — tabla de Clientes
30
- * del Portal Admin VL, paginada por última compra descendente. `from` en `null` es «Todo».
41
+ * `GET /backoffice/customers/table?from&to&limit&nextToken&storeId&sellerId&customerType&value` — tabla
42
+ * de Clientes del Portal Admin VL, paginada sobre el padrón por alta descendente. `from` en `null` es «Todo».
31
43
  */
32
44
  export interface BackofficeCustomerTableResponse {
33
45
  from: string | null;
34
46
  to: string;
35
47
  nextToken: string | null;
36
48
  sources: CustomerTableSources;
49
+ counts: CustomerTableCounts;
37
50
  items: CustomerTableRow[];
38
51
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiado/type-kit",
3
- "version": "3.576.0",
3
+ "version": "3.578.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",
@@ -102,4 +102,15 @@ export class RemittanceBackofficeTransaction {
102
102
  reconStatus?: RemittanceReconStatus;
103
103
  /** Detalle textual de los diffs cuando reconStatus !== OK. */
104
104
  reconDiffDetail?: string;
105
+
106
+ // ─── Costo esperado al enviar (Exhibit A, foto del confirm) ─────────
107
+
108
+ /** Costo UniTeller esperado en USD según el grupo y el tramo vigente al enviar. */
109
+ unitellerCostExpected?: number;
110
+ /** Grupo de costo del payer × método al enviar. */
111
+ costGroup?: string;
112
+ /** Tramo de volumen vigente al enviar (1..3). */
113
+ costTier?: number;
114
+ /** Ajuste del grupo que se sumó al fee de esta remesa. */
115
+ groupFeeAdjustment?: number;
105
116
  }
@@ -1,5 +1,6 @@
1
1
  import { IsBoolean, IsOptional, IsString, Length } from "class-validator";
2
2
  import { ReceptionMethod } from "../enums/ReceptionMethod";
3
+ import { CostGroupByMethod } from "./RemittanceProviderCost";
3
4
 
4
5
  /**
5
6
  * DTOs de la administración de payers desde el backoffice (v1: enabled + override de nombre).
@@ -21,6 +22,8 @@ export class RemittancePayerConfigItem {
21
22
  configured!: boolean;
22
23
  /** Logo de UniTeller, solo lectura (identificación visual en la lista). */
23
24
  logoUrl?: string;
25
+ /** Grupo de costo UniTeller de cada método (solo lectura aquí; se edita en Costos UniTeller). */
26
+ costGroupByMethod?: CostGroupByMethod;
24
27
  }
25
28
 
26
29
  /** Response de GET /backoffice/config/payers (config chica, sin paginación). */
@@ -9,12 +9,15 @@ import {
9
9
  IsOptional,
10
10
  IsString,
11
11
  Length,
12
+ Matches,
12
13
  Max,
13
14
  MaxLength,
14
15
  Min,
15
16
  ValidateNested,
16
17
  } from "class-validator";
17
18
  import { RemittanceCorridor } from "../enums/RemittanceCorridor";
19
+ import { ReceptionMethod } from "../enums/ReceptionMethod";
20
+ import { PROVIDER_COST_GROUP_ID_PATTERN } from "./RemittanceProviderCost";
18
21
 
19
22
  /**
20
23
  * DTOs de Precio Base (Dashboard Ops · Variables Operativas §1).
@@ -56,6 +59,19 @@ export class PricingTier {
56
59
  effectiveFrom!: string;
57
60
  }
58
61
 
62
+ /** Ajuste en USD que se suma al fee del tramo cuando el payer × método cae en ese grupo de costo. */
63
+ export class PricingGroupFeeAdjustment {
64
+ @IsString()
65
+ @Matches(PROVIDER_COST_GROUP_ID_PATTERN)
66
+ groupId!: string;
67
+
68
+ /** CON SIGNO: negativo descuenta. El fee final nunca baja de 0. */
69
+ @IsNumber({ maxDecimalPlaces: 2 })
70
+ @Min(-100)
71
+ @Max(100)
72
+ adjustmentUSD!: number;
73
+ }
74
+
59
75
  /** Body de POST /backoffice/pricing/base. */
60
76
  export class CreatePricingRequest {
61
77
  @IsEnum(RemittanceCorridor)
@@ -87,6 +103,14 @@ export class CreatePricingRequest {
87
103
  @IsString()
88
104
  @MaxLength(500)
89
105
  notes?: string;
106
+
107
+ /** Ajuste del fee por grupo de costo del payer. Ausente = conserva los actuales; [] = sin ajustes. */
108
+ @IsOptional()
109
+ @IsArray()
110
+ @ArrayMaxSize(10)
111
+ @ValidateNested({ each: true })
112
+ @Type(() => PricingGroupFeeAdjustment)
113
+ groupFeeAdjustments?: PricingGroupFeeAdjustment[];
90
114
  }
91
115
 
92
116
  /** Body de PUT /backoffice/pricing/base/{id} (reemplazo completo; corridor/segmentId inmutables). */
@@ -112,6 +136,14 @@ export class UpdatePricingRequest {
112
136
  @IsString()
113
137
  @MaxLength(500)
114
138
  notes?: string;
139
+
140
+ /** Ajuste del fee por grupo de costo del payer. Ausente = conserva los actuales; [] = sin ajustes. */
141
+ @IsOptional()
142
+ @IsArray()
143
+ @ArrayMaxSize(10)
144
+ @ValidateNested({ each: true })
145
+ @Type(() => PricingGroupFeeAdjustment)
146
+ groupFeeAdjustments?: PricingGroupFeeAdjustment[];
115
147
  }
116
148
 
117
149
  /** Combinación completa (response de list/create/update). */
@@ -125,6 +157,8 @@ export class PricingCombination {
125
157
  tramos!: PricingTier[];
126
158
  /** # promos activas que aplican a la combinación. 0 hasta que exista Promociones. */
127
159
  promosCount!: number;
160
+ /** Ajuste del fee por grupo de costo. Ausente o [] = sin ajustes. */
161
+ groupFeeAdjustments?: PricingGroupFeeAdjustment[];
128
162
  name!: string | null;
129
163
  notes!: string | null;
130
164
  createdAt!: string;
@@ -166,6 +200,24 @@ export class SimulatePricingRequest {
166
200
  @ValidateNested({ each: true })
167
201
  @Type(() => PricingTier)
168
202
  tramos!: PricingTier[];
203
+
204
+ /** Ajustes del panel (pueden no estar guardados). Solo aplican si viene payer y método. */
205
+ @IsOptional()
206
+ @IsArray()
207
+ @ArrayMaxSize(10)
208
+ @ValidateNested({ each: true })
209
+ @Type(() => PricingGroupFeeAdjustment)
210
+ groupFeeAdjustments?: PricingGroupFeeAdjustment[];
211
+
212
+ /** Payer y método opcionales: con ellos la simulación suma el ajuste del grupo y calcula costo y margen. */
213
+ @IsOptional()
214
+ @IsString()
215
+ @Length(1, 40)
216
+ payerCode?: string;
217
+
218
+ @IsOptional()
219
+ @IsEnum(ReceptionMethod)
220
+ receptionMethod?: ReceptionMethod;
169
221
  }
170
222
 
171
223
  export class SimulatePricingResponse {
@@ -185,6 +237,14 @@ export class SimulatePricingResponse {
185
237
  revenueUsd!: number;
186
238
  /** ISO del quote. */
187
239
  asOf!: string;
240
+ /** Grupo de costo del payer × método simulado. */
241
+ costGroup?: string;
242
+ /** Ajuste del grupo ya sumado en serviceFee. */
243
+ groupFeeAdjustment?: number;
244
+ /** Costo UniTeller esperado (Exhibit A, tramo vigente del país). */
245
+ unitellerCostExpected?: number;
246
+ /** revenueUsd − unitellerCostExpected. */
247
+ netMarginUsd?: number;
188
248
  }
189
249
 
190
250
  /** Response de GET /backoffice/pricing/wholesale?corridor= (rb passthrough del connector). */
@@ -0,0 +1,139 @@
1
+ import { Type } from "class-transformer";
2
+ import {
3
+ ArrayMaxSize,
4
+ ArrayMinSize,
5
+ IsArray,
6
+ IsEnum,
7
+ IsInt,
8
+ IsNumber,
9
+ IsOptional,
10
+ IsString,
11
+ Length,
12
+ Matches,
13
+ Max,
14
+ Min,
15
+ ValidateNested,
16
+ } from "class-validator";
17
+ import { ReceptionMethod } from "../enums/ReceptionMethod";
18
+
19
+ /**
20
+ * DTOs de Costos UniTeller (Exhibit A del contrato): lo que UniTeller le cobra a Fiado por remesa.
21
+ * Por país hay grupos con un precio por tramo de volumen y un tramo vigente; cada payer × método
22
+ * cae en un grupo. Se guarda en RemittanceCountryConfig_GT (grupos y tramo) y en
23
+ * RemittancePayerConfig_GT (grupo por método). Dueño: remittance-business.
24
+ */
25
+
26
+ /** Cantidad de tramos de volumen del Exhibit A. */
27
+ export const PROVIDER_COST_TIER_COUNT = 3;
28
+
29
+ /** Id de grupo: una letra mayúscula (A, B, C…). */
30
+ export const PROVIDER_COST_GROUP_ID_PATTERN = /^[A-Z]$/;
31
+
32
+ /** Grupo de costo: un precio en USD por tramo de volumen (posición 0 = tramo 1). */
33
+ export class ProviderCostGroup {
34
+ @IsString()
35
+ @Matches(PROVIDER_COST_GROUP_ID_PATTERN)
36
+ groupId!: string;
37
+
38
+ @IsArray()
39
+ @ArrayMinSize(PROVIDER_COST_TIER_COUNT)
40
+ @ArrayMaxSize(PROVIDER_COST_TIER_COUNT)
41
+ @IsNumber({ maxDecimalPlaces: 2 }, { each: true })
42
+ @Min(0, { each: true })
43
+ @Max(50, { each: true })
44
+ costsUSD!: number[];
45
+ }
46
+
47
+ /** Grupo de cada método de un payer. Método ausente = sin grupo (sin costo esperado ni ajuste de fee). */
48
+ export class CostGroupByMethod {
49
+ @IsOptional()
50
+ @Matches(PROVIDER_COST_GROUP_ID_PATTERN)
51
+ ACCOUNT_CREDIT?: string;
52
+
53
+ @IsOptional()
54
+ @Matches(PROVIDER_COST_GROUP_ID_PATTERN)
55
+ CASH_PICKUP?: string;
56
+
57
+ @IsOptional()
58
+ @Matches(PROVIDER_COST_GROUP_ID_PATTERN)
59
+ WALLET?: string;
60
+ }
61
+
62
+ /** Un payer × método del catálogo del país, con su grupo si tiene. */
63
+ export class ProviderCostAssignment {
64
+ payerCode!: string;
65
+ /** Nombre efectivo del payer (override de Ops o el de UniTeller). */
66
+ name!: string;
67
+ receptionMethod!: ReceptionMethod;
68
+ /** Ausente = sin grupo. */
69
+ groupId?: string;
70
+ }
71
+
72
+ /** Volumen del mes calendario en curso (UTC), sin canceladas. Guía para elegir el tramo vigente. */
73
+ export class ProviderCostMonthVolume {
74
+ txCount!: number;
75
+ volumeUSD!: number;
76
+ }
77
+
78
+ /** Costos de un país (vista de backoffice). */
79
+ export class ProviderCostCountryItem {
80
+ countryISO!: string;
81
+ name!: string;
82
+ /** Tramo vigente 1..3; null = sin configurar. */
83
+ costTier!: number | null;
84
+ groups!: ProviderCostGroup[];
85
+ /** Todos los payer × método del catálogo del país, con o sin grupo. */
86
+ assignments!: ProviderCostAssignment[];
87
+ /** Ausente si no se pudo calcular. */
88
+ monthVolume?: ProviderCostMonthVolume;
89
+ updatedAt?: string;
90
+ updatedBy?: string;
91
+ }
92
+
93
+ /** Response de GET /backoffice/config/provider-costs. */
94
+ export class ProviderCostListResponse {
95
+ /** Etiquetas de los tramos de volumen del contrato, en orden (tramo 1 primero). */
96
+ tierLabels!: string[];
97
+ items!: ProviderCostCountryItem[];
98
+ }
99
+
100
+ /** Cambio de grupo de un payer × método. groupId null o ausente = quitarlo de su grupo. */
101
+ export class ProviderCostAssignmentUpdate {
102
+ @IsString()
103
+ @Length(1, 40)
104
+ payerCode!: string;
105
+
106
+ @IsEnum(ReceptionMethod)
107
+ receptionMethod!: ReceptionMethod;
108
+
109
+ @IsOptional()
110
+ @Matches(PROVIDER_COST_GROUP_ID_PATTERN)
111
+ groupId?: string | null;
112
+ }
113
+
114
+ /**
115
+ * Body de PUT /backoffice/config/provider-costs/{countryISO}. Todo opcional.
116
+ * `groups` reemplaza la lista completa; `assignments` solo toca los payer × método que trae.
117
+ * Response: ProviderCostCountryItem.
118
+ */
119
+ export class ProviderCostUpdateRequest {
120
+ @IsOptional()
121
+ @IsInt()
122
+ @Min(1)
123
+ @Max(PROVIDER_COST_TIER_COUNT)
124
+ costTier?: number;
125
+
126
+ @IsOptional()
127
+ @IsArray()
128
+ @ArrayMaxSize(10)
129
+ @ValidateNested({ each: true })
130
+ @Type(() => ProviderCostGroup)
131
+ groups?: ProviderCostGroup[];
132
+
133
+ @IsOptional()
134
+ @IsArray()
135
+ @ArrayMaxSize(300)
136
+ @ValidateNested({ each: true })
137
+ @Type(() => ProviderCostAssignmentUpdate)
138
+ assignments?: ProviderCostAssignmentUpdate[];
139
+ }
@@ -49,6 +49,7 @@ export * from "./RemittancePricingTable";
49
49
  export * from "./RemittanceExceptionCatalog";
50
50
  export * from "./RemittanceCountryConfig";
51
51
  export * from "./RemittancePayerConfig";
52
+ export * from "./RemittanceProviderCost";
52
53
  export * from "./RemittanceFavoriteItem";
53
54
  export * from "./RemittanceFavoriteListResponse";
54
55
  export * from "./RemittanceBackofficeCancelCloseRequest";
@@ -1,5 +1,6 @@
1
1
  import { IsEnum, IsNumber, IsOptional, IsString, IsUUID, Length, Min } from "class-validator";
2
2
  import { RemittanceCorridor } from "../../enums/RemittanceCorridor";
3
+ import { ReceptionMethod } from "../../enums/ReceptionMethod";
3
4
 
4
5
  /**
5
6
  * Request del resolver de send-time (Fase B). El connector lo llama por cada
@@ -20,6 +21,16 @@ export class PricingResolveRequest {
20
21
  @IsString()
21
22
  @Length(3, 30)
22
23
  code?: string;
24
+
25
+ /** Payer del beneficiario. Con receptionMethod define el grupo de costo (costo esperado y ajuste de fee). */
26
+ @IsOptional()
27
+ @IsString()
28
+ @Length(1, 40)
29
+ payerCode?: string;
30
+
31
+ @IsOptional()
32
+ @IsEnum(ReceptionMethod)
33
+ receptionMethod?: ReceptionMethod;
23
34
  }
24
35
 
25
36
  /** Regla BLOCK que rechazó la tx (VALIDATION o TX_AMOUNT con acción BLOCK). */
@@ -46,4 +57,12 @@ export class PricingResolveResponse {
46
57
  /** Mínimo de envío del país destino (RemittanceCountryConfig_GT). El connector rechaza montos menores. */
47
58
  minAmountUSD!: number;
48
59
  blocked?: PricingResolveBlocked;
60
+ /** Grupo de costo del payer × método. Ausente = sin grupo o sin payer en el request. */
61
+ costGroup?: string;
62
+ /** Tramo de volumen vigente del país con el que se calculó el costo (1..3). */
63
+ costTier?: number;
64
+ /** Costo UniTeller esperado en USD (Exhibit A). Ausente si no hay grupo o tramo. */
65
+ unitellerCostExpected?: number;
66
+ /** Ajuste en USD del grupo que ya está sumado en `serviceFee` (antes de promos y topes). */
67
+ groupFeeAdjustment?: number;
49
68
  }
@@ -12,6 +12,7 @@ import {
12
12
  } from "class-validator";
13
13
  import { RemittanceCorridor } from "../../enums/RemittanceCorridor";
14
14
  import { PromotionKind } from "../../enums/PromotionKind";
15
+ import { ReceptionMethod } from "../../enums/ReceptionMethod";
15
16
 
16
17
  /**
17
18
  * Request del schedule de precio por corredor (Fase B — F2 app). El connector lo
@@ -24,6 +25,15 @@ export class PricingScheduleRequest {
24
25
 
25
26
  @IsEnum(RemittanceCorridor)
26
27
  corridor!: RemittanceCorridor;
28
+
29
+ /** Payer y método elegidos: los fees de los tramos incluyen el ajuste de su grupo. Ausentes = fee base. */
30
+ @IsOptional()
31
+ @IsString()
32
+ payerCode?: string;
33
+
34
+ @IsOptional()
35
+ @IsEnum(ReceptionMethod)
36
+ receptionMethod?: ReceptionMethod;
27
37
  }
28
38
 
29
39
  /** Un tramo del schedule. `serviceFee` YA refleja la promo automática aplicada (D5). */
@@ -27,6 +27,12 @@ export class UpsertCustomerFromKycRequest {
27
27
  @IsString()
28
28
  originStoreId!: string;
29
29
 
30
+ /** Cadena de la tienda de alta; el wizard la manda desde la sesión. */
31
+ @Expose()
32
+ @IsOptional()
33
+ @IsString()
34
+ retailerId?: string;
35
+
30
36
  /** Nombre partido por convención Fiado (F1 §3.5) — lo entrega el OCR del INE, NO se deriva de un string. */
31
37
  @Expose()
32
38
  @IsString()
@@ -1,17 +1,24 @@
1
1
  import type { ClientLevelEnum } from '../../../loanScoring/enums/ClientLevelEnum';
2
2
  import type { SellerTableSourceStatusEnum } from '../../enums/SellerTableSourceStatusEnum';
3
3
 
4
- /** Una fila de la tabla de Clientes: compras en la cadena dentro de la ventana, sin canceladas, más su crédito SK. */
4
+ /**
5
+ * Una fila de la tabla de Clientes: un cliente del padrón de la cadena con sus compras en la ventana
6
+ * (sin canceladas) y su crédito SK. `accountOnly` = abrió cuenta y no tiene ninguna compra en la cadena.
7
+ */
5
8
  export interface CustomerTableRow {
6
9
  retailCustomerId: string;
10
+ accountOnly: boolean;
11
+ /** Tienda donde se dio de alta; `null` si el padrón no la tiene. */
12
+ originStoreId: string | null;
7
13
  name: string | null;
8
14
  phone: string | null;
9
15
  purchaseCount: number;
10
16
  /** Precio de lo comprado (en crédito, el precio del equipo, no el enganche). */
11
17
  totalSpentCents: number;
12
18
  averageTicketCents: number | null;
13
- firstPurchaseAt: string;
14
- lastPurchaseAt: string;
19
+ /** `null` en un cliente «solo cuenta». */
20
+ firstPurchaseAt: string | null;
21
+ lastPurchaseAt: string | null;
15
22
  lastStoreName: string | null;
16
23
  /** Tienda con más compras; en empate, la de la compra más reciente. */
17
24
  favoriteStoreId: string | null;
@@ -28,14 +35,21 @@ export interface CustomerTableSources {
28
35
  credit: SellerTableSourceStatusEnum;
29
36
  }
30
37
 
38
+ /** Clientes del padrón leídos en la página, antes del filtro `customerType`; el front los suma por página. */
39
+ export interface CustomerTableCounts {
40
+ withSales: number;
41
+ accountOnly: number;
42
+ }
43
+
31
44
  /**
32
- * `GET /backoffice/customers/table?from&to&limit&nextToken&storeId&sellerId&value` — tabla de Clientes
33
- * del Portal Admin VL, paginada por última compra descendente. `from` en `null` es «Todo».
45
+ * `GET /backoffice/customers/table?from&to&limit&nextToken&storeId&sellerId&customerType&value` — tabla
46
+ * de Clientes del Portal Admin VL, paginada sobre el padrón por alta descendente. `from` en `null` es «Todo».
34
47
  */
35
48
  export interface BackofficeCustomerTableResponse {
36
49
  from: string | null;
37
50
  to: string;
38
51
  nextToken: string | null;
39
52
  sources: CustomerTableSources;
53
+ counts: CustomerTableCounts;
40
54
  items: CustomerTableRow[];
41
55
  }