Refactor payment methods: Remove system_key and related logic
- Removed `system_key` from payment method model and related files. - Updated payment method repository and services to eliminate references to `system_key`. - Deleted the BootstrapSystemPaymentMethodsService and its use case, as they are no longer needed. - Adjusted tests to reflect the removal of system payment methods and their associated logic. - Added SQL script to drop the `system_key` column and its unique index from the database.
This commit is contained in:
parent
de204fbcc9
commit
f1f329fa0d
@ -15,7 +15,6 @@ Campos persistidos y expuestos para administración:
|
|||||||
- `is_active`
|
- `is_active`
|
||||||
- `is_system`
|
- `is_system`
|
||||||
- `is_default`
|
- `is_default`
|
||||||
- `system_key`
|
|
||||||
- `created_at`
|
- `created_at`
|
||||||
- `updated_at`
|
- `updated_at`
|
||||||
- `deleted_at`
|
- `deleted_at`
|
||||||
@ -24,17 +23,8 @@ Campos persistidos y expuestos para administración:
|
|||||||
|
|
||||||
Reglas:
|
Reglas:
|
||||||
|
|
||||||
- `is_system = true` implica `system_key != null`
|
|
||||||
- `is_system = false` implica `system_key = null`
|
|
||||||
- `is_system = true` no se puede editar, desactivar ni eliminar
|
- `is_system = true` no se puede editar, desactivar ni eliminar
|
||||||
|
|
||||||
Identidad estable de métodos del sistema:
|
|
||||||
|
|
||||||
- `cash`
|
|
||||||
- `bank_transfer`
|
|
||||||
- `card`
|
|
||||||
- `direct_debit`
|
|
||||||
|
|
||||||
## Active and default
|
## Active and default
|
||||||
|
|
||||||
Reglas:
|
Reglas:
|
||||||
@ -46,26 +36,6 @@ Reglas:
|
|||||||
|
|
||||||
La unicidad del default se garantiza mediante servicio transaccional y bloqueo por empresa. No se fuerza con constraint SQL adicional para evitar una solución opaca en MariaDB.
|
La unicidad del default se garantiza mediante servicio transaccional y bloqueo por empresa. No se fuerza con constraint SQL adicional para evitar una solución opaca en MariaDB.
|
||||||
|
|
||||||
## Bootstrap
|
|
||||||
|
|
||||||
Endpoint explícito e idempotente:
|
|
||||||
|
|
||||||
- `POST /catalogs/payment-methods/bootstrap-system`
|
|
||||||
|
|
||||||
Comportamiento:
|
|
||||||
|
|
||||||
- crea los cuatro métodos del sistema que falten
|
|
||||||
- restaura un system method soft-deleted si ya existía por `system_key`
|
|
||||||
- resincroniza `name`, `is_system`, `is_active`, `is_default = false` y `system_key`
|
|
||||||
- si la empresa no tiene default, establece `cash` como default inicial
|
|
||||||
|
|
||||||
Métodos creados:
|
|
||||||
|
|
||||||
- `Efectivo`
|
|
||||||
- `Transferencia bancaria`
|
|
||||||
- `Tarjeta`
|
|
||||||
- `Domiciliación bancaria`
|
|
||||||
|
|
||||||
## Delete policy
|
## Delete policy
|
||||||
|
|
||||||
Un método solo puede eliminarse si:
|
Un método solo puede eliminarse si:
|
||||||
|
|||||||
35
docs/catalogs/sql/remove-payment-method-system-key.sql
Normal file
35
docs/catalogs/sql/remove-payment-method-system-key.sql
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
SET @index_exists := (
|
||||||
|
SELECT COUNT(1)
|
||||||
|
FROM information_schema.statistics
|
||||||
|
WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'payment_methods'
|
||||||
|
AND index_name = 'uq_payment_methods_company_system_key'
|
||||||
|
);
|
||||||
|
|
||||||
|
SET @drop_index_sql := IF(
|
||||||
|
@index_exists > 0,
|
||||||
|
'DROP INDEX `uq_payment_methods_company_system_key` ON `payment_methods`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
|
||||||
|
PREPARE stmt FROM @drop_index_sql;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
SET @column_exists := (
|
||||||
|
SELECT COUNT(1)
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'payment_methods'
|
||||||
|
AND column_name = 'system_key'
|
||||||
|
);
|
||||||
|
|
||||||
|
SET @drop_column_sql := IF(
|
||||||
|
@column_exists > 0,
|
||||||
|
'ALTER TABLE `payment_methods` DROP COLUMN `system_key`',
|
||||||
|
'SELECT 1'
|
||||||
|
);
|
||||||
|
|
||||||
|
PREPARE stmt FROM @drop_column_sql;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
@ -8,7 +8,7 @@ import {
|
|||||||
extractOrPushError,
|
extractOrPushError,
|
||||||
maybeFromNullableResult,
|
maybeFromNullableResult,
|
||||||
} from "@repo/rdx-ddd";
|
} from "@repo/rdx-ddd";
|
||||||
import { Maybe, Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
import type { CreatePaymentMethodRequestDTO } from "../../../../common";
|
import type { CreatePaymentMethodRequestDTO } from "../../../../common";
|
||||||
import type { IPaymentMethodCreateProps } from "../../../domain";
|
import type { IPaymentMethodCreateProps } from "../../../domain";
|
||||||
@ -49,7 +49,6 @@ export class CreatePaymentMethodInputMapper implements ICreatePaymentMethodInput
|
|||||||
isActive: isActive!,
|
isActive: isActive!,
|
||||||
isSystem: false,
|
isSystem: false,
|
||||||
isDefault: false,
|
isDefault: false,
|
||||||
systemKey: Maybe.none(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return Result.ok({
|
return Result.ok({
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import type { Criteria } from "@repo/rdx-criteria/server";
|
|||||||
import type { UniqueID } from "@repo/rdx-ddd";
|
import type { UniqueID } from "@repo/rdx-ddd";
|
||||||
import type { Collection, Maybe, Result } from "@repo/rdx-utils";
|
import type { Collection, Maybe, Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
import type { PaymentMethod, PaymentMethodSystemKey } from "../../../domain";
|
import type { PaymentMethod } from "../../../domain";
|
||||||
import type { PaymentMethodSummary } from "../models";
|
import type { PaymentMethodSummary } from "../models";
|
||||||
|
|
||||||
export interface IPaymentMethodRepository {
|
export interface IPaymentMethodRepository {
|
||||||
@ -32,29 +32,7 @@ export interface IPaymentMethodRepository {
|
|||||||
companyId: UniqueID,
|
companyId: UniqueID,
|
||||||
transaction?: unknown
|
transaction?: unknown
|
||||||
): Promise<Result<Maybe<PaymentMethod>, Error>>;
|
): Promise<Result<Maybe<PaymentMethod>, Error>>;
|
||||||
findBySystemKeyInCompany(
|
lockByCompanyId(companyId: UniqueID, transaction?: unknown): Promise<Result<void, Error>>;
|
||||||
companyId: UniqueID,
|
|
||||||
systemKey: PaymentMethodSystemKey,
|
|
||||||
transaction?: unknown,
|
|
||||||
options?: { includeDeleted?: boolean }
|
|
||||||
): Promise<Result<Maybe<PaymentMethod>, Error>>;
|
|
||||||
restoreByIdInCompany(
|
|
||||||
companyId: UniqueID,
|
|
||||||
id: UniqueID,
|
|
||||||
transaction?: unknown
|
|
||||||
): Promise<Result<boolean, Error>>;
|
|
||||||
syncSystemPaymentMethodState(params: {
|
|
||||||
companyId: UniqueID;
|
|
||||||
id: UniqueID;
|
|
||||||
name: string;
|
|
||||||
isDefault: boolean;
|
|
||||||
systemKey: PaymentMethodSystemKey;
|
|
||||||
transaction?: unknown;
|
|
||||||
}): Promise<Result<void, Error>>;
|
|
||||||
lockByCompanyId(
|
|
||||||
companyId: UniqueID,
|
|
||||||
transaction?: unknown
|
|
||||||
): Promise<Result<void, Error>>;
|
|
||||||
deleteByIdInCompany(
|
deleteByIdInCompany(
|
||||||
companyId: UniqueID,
|
companyId: UniqueID,
|
||||||
id: UniqueID,
|
id: UniqueID,
|
||||||
|
|||||||
@ -1,13 +1,11 @@
|
|||||||
import { describe, test } from "node:test";
|
import { describe, test } from "node:test";
|
||||||
import assert from "node:assert/strict";
|
import assert from "node:assert/strict";
|
||||||
|
|
||||||
import type { Criteria } from "@repo/rdx-criteria/server";
|
|
||||||
import { EntityNotFoundError } from "@erp/core/api";
|
import { EntityNotFoundError } from "@erp/core/api";
|
||||||
import { Name, UniqueID } from "@repo/rdx-ddd";
|
import { Name, UniqueID } from "@repo/rdx-ddd";
|
||||||
import { Collection, Maybe, Result } from "@repo/rdx-utils";
|
import { Collection, Maybe, Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
import { PaymentMethod } from "../../../../domain/payment-methods/payment-method.aggregate";
|
import { PaymentMethod } from "../../../../domain/payment-methods/payment-method.aggregate";
|
||||||
import { BootstrapSystemPaymentMethodsService } from "../bootstrap-system-payment-methods.service";
|
|
||||||
import { PaymentMethodDeleter } from "../payment-method-deleter";
|
import { PaymentMethodDeleter } from "../payment-method-deleter";
|
||||||
import { SetDefaultPaymentMethodService } from "../set-default-payment-method.service";
|
import { SetDefaultPaymentMethodService } from "../set-default-payment-method.service";
|
||||||
import type { IPaymentMethodRepository } from "../../repositories";
|
import type { IPaymentMethodRepository } from "../../repositories";
|
||||||
@ -66,7 +64,7 @@ class InMemoryPaymentMethodRepository implements IPaymentMethodRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async findByCriteriaInCompany(): Promise<Result<Collection<PaymentMethodSummary>, Error>> {
|
async findByCriteriaInCompany(): Promise<Result<Collection<PaymentMethodSummary>, Error>> {
|
||||||
return Result.ok(Collection.create<PaymentMethodSummary>([]));
|
return Result.ok(new Collection<PaymentMethodSummary>([]));
|
||||||
}
|
}
|
||||||
|
|
||||||
async findDefaultInCompany(companyId: UniqueID): Promise<Result<Maybe<PaymentMethod>, Error>> {
|
async findDefaultInCompany(companyId: UniqueID): Promise<Result<Maybe<PaymentMethod>, Error>> {
|
||||||
@ -81,80 +79,6 @@ class InMemoryPaymentMethodRepository implements IPaymentMethodRepository {
|
|||||||
return paymentMethod ? Result.ok(Maybe.some(paymentMethod)) : Result.ok(Maybe.none());
|
return paymentMethod ? Result.ok(Maybe.some(paymentMethod)) : Result.ok(Maybe.none());
|
||||||
}
|
}
|
||||||
|
|
||||||
async findBySystemKeyInCompany(
|
|
||||||
companyId: UniqueID,
|
|
||||||
systemKey: "cash" | "bank_transfer" | "card" | "direct_debit",
|
|
||||||
_transaction?: unknown,
|
|
||||||
options?: { includeDeleted?: boolean }
|
|
||||||
): Promise<Result<Maybe<PaymentMethod>, Error>> {
|
|
||||||
const paymentMethod =
|
|
||||||
[...this.items.values()].find((item) => {
|
|
||||||
const matchesCompany = item.companyId.toString() === companyId.toString();
|
|
||||||
const matchesKey = item.systemKey.match(
|
|
||||||
(value) => value === systemKey,
|
|
||||||
() => false
|
|
||||||
);
|
|
||||||
const includeDeleted = options?.includeDeleted === true;
|
|
||||||
|
|
||||||
return (
|
|
||||||
matchesCompany &&
|
|
||||||
matchesKey &&
|
|
||||||
(includeDeleted || !this.deleted.has(item.id.toString()))
|
|
||||||
);
|
|
||||||
}) ?? null;
|
|
||||||
|
|
||||||
return paymentMethod ? Result.ok(Maybe.some(paymentMethod)) : Result.ok(Maybe.none());
|
|
||||||
}
|
|
||||||
|
|
||||||
async restoreByIdInCompany(companyId: UniqueID, id: UniqueID): Promise<Result<boolean, Error>> {
|
|
||||||
const result = await this.existsByIdInCompany(companyId, id);
|
|
||||||
if (result.isFailure) {
|
|
||||||
return Result.fail(result.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result.data) {
|
|
||||||
return Result.ok(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.deleted.delete(id.toString());
|
|
||||||
return Result.ok(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
async syncSystemPaymentMethodState(params: {
|
|
||||||
companyId: UniqueID;
|
|
||||||
id: UniqueID;
|
|
||||||
name: string;
|
|
||||||
isDefault: boolean;
|
|
||||||
systemKey: "cash" | "bank_transfer" | "card" | "direct_debit";
|
|
||||||
}): Promise<Result<void, Error>> {
|
|
||||||
const paymentMethodResult = await this.getByIdInCompany(params.companyId, params.id);
|
|
||||||
if (paymentMethodResult.isFailure) {
|
|
||||||
return Result.fail(paymentMethodResult.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
const current = paymentMethodResult.data;
|
|
||||||
const nameResult = Name.create(params.name);
|
|
||||||
assert.equal(nameResult.isSuccess, true);
|
|
||||||
|
|
||||||
const updatedResult = PaymentMethod.create(
|
|
||||||
{
|
|
||||||
companyId: current.companyId,
|
|
||||||
name: nameResult.data,
|
|
||||||
description: current.description,
|
|
||||||
isActive: true,
|
|
||||||
isSystem: true,
|
|
||||||
isDefault: params.isDefault,
|
|
||||||
systemKey: Maybe.some(params.systemKey),
|
|
||||||
},
|
|
||||||
current.id
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.equal(updatedResult.isSuccess, true);
|
|
||||||
this.items.set(current.id.toString(), updatedResult.data);
|
|
||||||
|
|
||||||
return Result.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
async lockByCompanyId(): Promise<Result<void, Error>> {
|
async lockByCompanyId(): Promise<Result<void, Error>> {
|
||||||
return Result.ok();
|
return Result.ok();
|
||||||
}
|
}
|
||||||
@ -180,7 +104,6 @@ const buildPaymentMethod = (params: {
|
|||||||
isActive?: boolean;
|
isActive?: boolean;
|
||||||
isSystem?: boolean;
|
isSystem?: boolean;
|
||||||
isDefault?: boolean;
|
isDefault?: boolean;
|
||||||
systemKey?: "cash" | "bank_transfer" | "card" | "direct_debit";
|
|
||||||
}) => {
|
}) => {
|
||||||
const nameResult = Name.create(params.name);
|
const nameResult = Name.create(params.name);
|
||||||
assert.equal(nameResult.isSuccess, true);
|
assert.equal(nameResult.isSuccess, true);
|
||||||
@ -193,7 +116,6 @@ const buildPaymentMethod = (params: {
|
|||||||
isActive: params.isActive ?? true,
|
isActive: params.isActive ?? true,
|
||||||
isSystem: params.isSystem ?? false,
|
isSystem: params.isSystem ?? false,
|
||||||
isDefault: params.isDefault ?? false,
|
isDefault: params.isDefault ?? false,
|
||||||
systemKey: params.systemKey ? Maybe.some(params.systemKey) : Maybe.none(),
|
|
||||||
},
|
},
|
||||||
UniqueID.generateNewID()
|
UniqueID.generateNewID()
|
||||||
);
|
);
|
||||||
@ -302,46 +224,12 @@ describe("Payment method services", () => {
|
|||||||
assert.equal(result.isFailure, true);
|
assert.equal(result.isFailure, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("bootstrap creates four system methods and exactly one default", async () => {
|
|
||||||
const repository = new InMemoryPaymentMethodRepository();
|
|
||||||
const setDefaultService = new SetDefaultPaymentMethodService(repository);
|
|
||||||
const service = new BootstrapSystemPaymentMethodsService({
|
|
||||||
repository,
|
|
||||||
setDefaultService,
|
|
||||||
});
|
|
||||||
const companyId = UniqueID.generateNewID();
|
|
||||||
|
|
||||||
const result = await service.bootstrap({ companyId });
|
|
||||||
|
|
||||||
assert.equal(result.isSuccess, true);
|
|
||||||
assert.equal(result.data.length, 4);
|
|
||||||
assert.equal(result.data.filter((item) => item.isDefault).length, 1);
|
|
||||||
assert.equal(result.data.some((item) => item.systemKey.match((key) => key === "cash", () => false) && item.isDefault), true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("bootstrap is idempotent", async () => {
|
|
||||||
const repository = new InMemoryPaymentMethodRepository();
|
|
||||||
const setDefaultService = new SetDefaultPaymentMethodService(repository);
|
|
||||||
const service = new BootstrapSystemPaymentMethodsService({
|
|
||||||
repository,
|
|
||||||
setDefaultService,
|
|
||||||
});
|
|
||||||
const companyId = UniqueID.generateNewID();
|
|
||||||
|
|
||||||
const first = await service.bootstrap({ companyId });
|
|
||||||
const second = await service.bootstrap({ companyId });
|
|
||||||
|
|
||||||
assert.equal(first.isSuccess, true);
|
|
||||||
assert.equal(second.isSuccess, true);
|
|
||||||
assert.equal(second.data.length, 4);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("delete blocks referenced payment methods", async () => {
|
test("delete blocks referenced payment methods", async () => {
|
||||||
const repository = new InMemoryPaymentMethodRepository();
|
const repository = new InMemoryPaymentMethodRepository();
|
||||||
const deleter = new PaymentMethodDeleter({
|
const deleter = new PaymentMethodDeleter({
|
||||||
repository,
|
repository,
|
||||||
usageChecker: {
|
usageChecker: {
|
||||||
findUsage: async () => Result.ok(["customers"]),
|
findUsage: async () => Result.ok([{ source: "customers" }]),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const companyId = UniqueID.generateNewID();
|
const companyId = UniqueID.generateNewID();
|
||||||
@ -352,9 +240,32 @@ describe("Payment method services", () => {
|
|||||||
|
|
||||||
await repository.create(paymentMethod);
|
await repository.create(paymentMethod);
|
||||||
|
|
||||||
const result = await deleter.deleteById({
|
const result = await deleter.delete({
|
||||||
|
paymentMethod,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(result.isFailure, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("delete blocks system payment methods", async () => {
|
||||||
|
const repository = new InMemoryPaymentMethodRepository();
|
||||||
|
const deleter = new PaymentMethodDeleter({
|
||||||
|
repository,
|
||||||
|
usageChecker: {
|
||||||
|
findUsage: async () => Result.ok([]),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const companyId = UniqueID.generateNewID();
|
||||||
|
const paymentMethod = buildPaymentMethod({
|
||||||
companyId,
|
companyId,
|
||||||
id: paymentMethod.id,
|
name: "Transferencia",
|
||||||
|
isSystem: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
await repository.create(paymentMethod);
|
||||||
|
|
||||||
|
const result = await deleter.delete({
|
||||||
|
paymentMethod,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.equal(result.isFailure, true);
|
assert.equal(result.isFailure, true);
|
||||||
|
|||||||
@ -1,208 +0,0 @@
|
|||||||
import { Name, UniqueID } from "@repo/rdx-ddd";
|
|
||||||
import { Maybe, Result } from "@repo/rdx-utils";
|
|
||||||
|
|
||||||
import { PaymentMethod, type PaymentMethodSystemKey } from "../../../domain";
|
|
||||||
import type { IPaymentMethodRepository } from "../repositories";
|
|
||||||
import type { ISetDefaultPaymentMethodService } from "./set-default-payment-method.service";
|
|
||||||
|
|
||||||
type SystemPaymentMethodDefinition = {
|
|
||||||
systemKey: PaymentMethodSystemKey;
|
|
||||||
name: string;
|
|
||||||
isDefault: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
const SYSTEM_PAYMENT_METHOD_DEFINITIONS: SystemPaymentMethodDefinition[] = [
|
|
||||||
{
|
|
||||||
systemKey: "cash",
|
|
||||||
name: "Efectivo",
|
|
||||||
isDefault: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
systemKey: "bank_transfer",
|
|
||||||
name: "Transferencia bancaria",
|
|
||||||
isDefault: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
systemKey: "card",
|
|
||||||
name: "Tarjeta",
|
|
||||||
isDefault: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
systemKey: "direct_debit",
|
|
||||||
name: "Domiciliación bancaria",
|
|
||||||
isDefault: false,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export interface IBootstrapSystemPaymentMethodsService {
|
|
||||||
bootstrap(params: {
|
|
||||||
companyId: UniqueID;
|
|
||||||
transaction?: unknown;
|
|
||||||
}): Promise<Result<PaymentMethod[], Error>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class BootstrapSystemPaymentMethodsService implements IBootstrapSystemPaymentMethodsService {
|
|
||||||
public constructor(
|
|
||||||
private readonly deps: {
|
|
||||||
repository: IPaymentMethodRepository;
|
|
||||||
setDefaultService: ISetDefaultPaymentMethodService;
|
|
||||||
}
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public async bootstrap(params: {
|
|
||||||
companyId: UniqueID;
|
|
||||||
transaction?: unknown;
|
|
||||||
}): Promise<Result<PaymentMethod[], Error>> {
|
|
||||||
const { companyId, transaction } = params;
|
|
||||||
|
|
||||||
const lockResult = await this.deps.repository.lockByCompanyId(companyId, transaction);
|
|
||||||
if (lockResult.isFailure) {
|
|
||||||
return Result.fail(lockResult.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
const bootstrappedPaymentMethods: PaymentMethod[] = [];
|
|
||||||
|
|
||||||
for (const definition of SYSTEM_PAYMENT_METHOD_DEFINITIONS) {
|
|
||||||
const paymentMethodResult = await this.ensureSystemPaymentMethod({
|
|
||||||
companyId,
|
|
||||||
definition,
|
|
||||||
transaction,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (paymentMethodResult.isFailure) {
|
|
||||||
return Result.fail(paymentMethodResult.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bootstrappedPaymentMethods.push(paymentMethodResult.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentDefaultResult = await this.deps.repository.findDefaultInCompany(
|
|
||||||
companyId,
|
|
||||||
transaction
|
|
||||||
);
|
|
||||||
if (currentDefaultResult.isFailure) {
|
|
||||||
return Result.fail(currentDefaultResult.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentDefaultResult.data.isNone()) {
|
|
||||||
const cashPaymentMethod = bootstrappedPaymentMethods.find(
|
|
||||||
(paymentMethod) =>
|
|
||||||
paymentMethod.systemKey.match(
|
|
||||||
(systemKey) => systemKey === "cash",
|
|
||||||
() => false
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!cashPaymentMethod) {
|
|
||||||
return Result.fail(new Error("Cash system payment method bootstrap failed."));
|
|
||||||
}
|
|
||||||
|
|
||||||
const setDefaultResult = await this.deps.setDefaultService.setDefault({
|
|
||||||
companyId,
|
|
||||||
paymentMethodId: cashPaymentMethod.id,
|
|
||||||
transaction,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (setDefaultResult.isFailure) {
|
|
||||||
return Result.fail(setDefaultResult.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
const updatedItems = bootstrappedPaymentMethods.map((paymentMethod) =>
|
|
||||||
paymentMethod.id.toString() === setDefaultResult.data.id.toString()
|
|
||||||
? setDefaultResult.data
|
|
||||||
: paymentMethod
|
|
||||||
);
|
|
||||||
|
|
||||||
return Result.ok(updatedItems);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.ok(bootstrappedPaymentMethods);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async ensureSystemPaymentMethod(params: {
|
|
||||||
companyId: UniqueID;
|
|
||||||
definition: SystemPaymentMethodDefinition;
|
|
||||||
transaction?: unknown;
|
|
||||||
}): Promise<Result<PaymentMethod, Error>> {
|
|
||||||
const { companyId, definition, transaction } = params;
|
|
||||||
|
|
||||||
const existingResult = await this.deps.repository.findBySystemKeyInCompany(
|
|
||||||
companyId,
|
|
||||||
definition.systemKey,
|
|
||||||
transaction,
|
|
||||||
{ includeDeleted: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (existingResult.isFailure) {
|
|
||||||
return Result.fail(existingResult.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (existingResult.data.isSome()) {
|
|
||||||
const existingPaymentMethod = existingResult.data.unwrap();
|
|
||||||
|
|
||||||
const restoreResult = await this.deps.repository.restoreByIdInCompany(
|
|
||||||
companyId,
|
|
||||||
existingPaymentMethod.id,
|
|
||||||
transaction
|
|
||||||
);
|
|
||||||
|
|
||||||
if (restoreResult.isFailure) {
|
|
||||||
return Result.fail(restoreResult.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
const syncResult = await this.deps.repository.syncSystemPaymentMethodState({
|
|
||||||
companyId,
|
|
||||||
id: existingPaymentMethod.id,
|
|
||||||
name: definition.name,
|
|
||||||
isDefault: false,
|
|
||||||
systemKey: definition.systemKey,
|
|
||||||
transaction,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (syncResult.isFailure) {
|
|
||||||
return Result.fail(syncResult.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
const refreshedResult = await this.deps.repository.getByIdInCompany(
|
|
||||||
companyId,
|
|
||||||
existingPaymentMethod.id,
|
|
||||||
transaction
|
|
||||||
);
|
|
||||||
|
|
||||||
if (refreshedResult.isFailure) {
|
|
||||||
return Result.fail(refreshedResult.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.ok(refreshedResult.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
const nameResult = Name.create(definition.name);
|
|
||||||
if (nameResult.isFailure) {
|
|
||||||
return Result.fail(nameResult.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
const paymentMethodResult = PaymentMethod.create(
|
|
||||||
{
|
|
||||||
companyId,
|
|
||||||
name: nameResult.data,
|
|
||||||
description: Maybe.none(),
|
|
||||||
isActive: true,
|
|
||||||
isSystem: true,
|
|
||||||
isDefault: false,
|
|
||||||
systemKey: Maybe.some(definition.systemKey),
|
|
||||||
},
|
|
||||||
UniqueID.generateNewID()
|
|
||||||
);
|
|
||||||
|
|
||||||
if (paymentMethodResult.isFailure) {
|
|
||||||
return Result.fail(paymentMethodResult.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
const createResult = await this.deps.repository.create(paymentMethodResult.data, transaction);
|
|
||||||
if (createResult.isFailure) {
|
|
||||||
return Result.fail(createResult.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.ok(paymentMethodResult.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,5 +1,4 @@
|
|||||||
export * from "./payment-method-creator";
|
export * from "./payment-method-creator";
|
||||||
export * from "./bootstrap-system-payment-methods.service";
|
|
||||||
export * from "./payment-method-deleter";
|
export * from "./payment-method-deleter";
|
||||||
export * from "./payment-method-disabler";
|
export * from "./payment-method-disabler";
|
||||||
export * from "./payment-method-enabler";
|
export * from "./payment-method-enabler";
|
||||||
|
|||||||
@ -1,46 +0,0 @@
|
|||||||
import type { BootstrapSystemPaymentMethodsResponseDTO } from "@erp/catalogs/common";
|
|
||||||
import type { ITransactionManager } from "@erp/core/api";
|
|
||||||
import type { UniqueID } from "@repo/rdx-ddd";
|
|
||||||
import { Result } from "@repo/rdx-utils";
|
|
||||||
|
|
||||||
import type { IBootstrapSystemPaymentMethodsService } from "../services";
|
|
||||||
import type { IPaymentMethodFullSnapshotBuilder } from "../snapshot-builders";
|
|
||||||
|
|
||||||
export type BootstrapSystemPaymentMethodsUseCaseInput = {
|
|
||||||
companyId: UniqueID;
|
|
||||||
};
|
|
||||||
|
|
||||||
export class BootstrapSystemPaymentMethodsUseCase {
|
|
||||||
public constructor(
|
|
||||||
private readonly deps: {
|
|
||||||
bootstrapService: IBootstrapSystemPaymentMethodsService;
|
|
||||||
fullSnapshotBuilder: IPaymentMethodFullSnapshotBuilder;
|
|
||||||
transactionManager: ITransactionManager;
|
|
||||||
}
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public execute(
|
|
||||||
params: BootstrapSystemPaymentMethodsUseCaseInput
|
|
||||||
): Promise<Result<BootstrapSystemPaymentMethodsResponseDTO, Error>> {
|
|
||||||
const { companyId } = params;
|
|
||||||
|
|
||||||
return this.deps.transactionManager.complete(async (transaction: unknown) => {
|
|
||||||
try {
|
|
||||||
const result = await this.deps.bootstrapService.bootstrap({
|
|
||||||
companyId,
|
|
||||||
transaction,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (result.isFailure) {
|
|
||||||
return Result.fail(result.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.ok({
|
|
||||||
items: result.data.map((paymentMethod) => this.deps.fullSnapshotBuilder.toOutput(paymentMethod)),
|
|
||||||
});
|
|
||||||
} catch (error: unknown) {
|
|
||||||
return Result.fail(error as Error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,4 +1,3 @@
|
|||||||
export * from "./bootstrap-system-payment-methods.use-case";
|
|
||||||
export * from "./create-payment-method.use-case";
|
export * from "./create-payment-method.use-case";
|
||||||
export * from "./delete-payment-method-by-id.use-case";
|
export * from "./delete-payment-method-by-id.use-case";
|
||||||
export * from "./disable-payment-method-by-id.use-case";
|
export * from "./disable-payment-method-by-id.use-case";
|
||||||
|
|||||||
@ -22,7 +22,6 @@ const createPaymentMethod = (params?: {
|
|||||||
isActive: params?.isActive ?? true,
|
isActive: params?.isActive ?? true,
|
||||||
isSystem: params?.isSystem ?? false,
|
isSystem: params?.isSystem ?? false,
|
||||||
isDefault: params?.isDefault ?? false,
|
isDefault: params?.isDefault ?? false,
|
||||||
systemKey: Maybe.none(),
|
|
||||||
},
|
},
|
||||||
UniqueID.generateNewID()
|
UniqueID.generateNewID()
|
||||||
);
|
);
|
||||||
@ -45,7 +44,6 @@ describe("PaymentMethod aggregate", () => {
|
|||||||
isActive: false,
|
isActive: false,
|
||||||
isSystem: false,
|
isSystem: false,
|
||||||
isDefault: true,
|
isDefault: true,
|
||||||
systemKey: Maybe.none(),
|
|
||||||
},
|
},
|
||||||
UniqueID.generateNewID()
|
UniqueID.generateNewID()
|
||||||
);
|
);
|
||||||
@ -81,7 +79,6 @@ describe("PaymentMethod aggregate", () => {
|
|||||||
isActive: true,
|
isActive: true,
|
||||||
isSystem: true,
|
isSystem: true,
|
||||||
isDefault: false,
|
isDefault: false,
|
||||||
systemKey: Maybe.some("cash"),
|
|
||||||
},
|
},
|
||||||
UniqueID.generateNewID()
|
UniqueID.generateNewID()
|
||||||
);
|
);
|
||||||
@ -105,4 +102,29 @@ describe("PaymentMethod aggregate", () => {
|
|||||||
|
|
||||||
assert.equal(result.isSuccess, true);
|
assert.equal(result.isSuccess, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("blocks deleting system payment methods", () => {
|
||||||
|
const paymentMethod = createPaymentMethod({ isSystem: true });
|
||||||
|
|
||||||
|
const result = paymentMethod.ensureCanBeDeleted();
|
||||||
|
|
||||||
|
assert.equal(result.isFailure, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("blocks disabling system payment methods", () => {
|
||||||
|
const paymentMethod = createPaymentMethod({ isSystem: true });
|
||||||
|
|
||||||
|
const result = paymentMethod.disable();
|
||||||
|
|
||||||
|
assert.equal(result.isFailure, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("keeps enable idempotent for system payment methods", () => {
|
||||||
|
const paymentMethod = createPaymentMethod({ isSystem: true });
|
||||||
|
|
||||||
|
const result = paymentMethod.enable();
|
||||||
|
|
||||||
|
assert.equal(result.isSuccess, true);
|
||||||
|
assert.equal(result.data, false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
export * from "./errors";
|
export * from "./errors";
|
||||||
export * from "./payment-method.aggregate";
|
export * from "./payment-method.aggregate";
|
||||||
export * from "./payment-method-name";
|
export * from "./payment-method-name";
|
||||||
export * from "./payment-method-system-key";
|
|
||||||
|
|||||||
@ -1,12 +0,0 @@
|
|||||||
export const PAYMENT_METHOD_SYSTEM_KEYS = [
|
|
||||||
"cash",
|
|
||||||
"bank_transfer",
|
|
||||||
"card",
|
|
||||||
"direct_debit",
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
export type PaymentMethodSystemKey = (typeof PAYMENT_METHOD_SYSTEM_KEYS)[number];
|
|
||||||
|
|
||||||
export const isPaymentMethodSystemKey = (value: string): value is PaymentMethodSystemKey => {
|
|
||||||
return PAYMENT_METHOD_SYSTEM_KEYS.includes(value as PaymentMethodSystemKey);
|
|
||||||
};
|
|
||||||
@ -7,7 +7,6 @@ import {
|
|||||||
PaymentMethodCannotBeDeletedError,
|
PaymentMethodCannotBeDeletedError,
|
||||||
PaymentMethodCannotBeUpdatedError,
|
PaymentMethodCannotBeUpdatedError,
|
||||||
} from "./errors";
|
} from "./errors";
|
||||||
import type { PaymentMethodSystemKey } from "./payment-method-system-key";
|
|
||||||
|
|
||||||
export interface IPaymentMethodCreateProps {
|
export interface IPaymentMethodCreateProps {
|
||||||
companyId: UniqueID;
|
companyId: UniqueID;
|
||||||
@ -16,7 +15,6 @@ export interface IPaymentMethodCreateProps {
|
|||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
isSystem: boolean;
|
isSystem: boolean;
|
||||||
isDefault: boolean;
|
isDefault: boolean;
|
||||||
systemKey: Maybe<PaymentMethodSystemKey>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PaymentMethodPatchProps = Partial<{
|
export type PaymentMethodPatchProps = Partial<{
|
||||||
@ -71,14 +69,6 @@ export class PaymentMethod extends AggregateRoot<PaymentMethodInternalProps> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.isSystem && props.systemKey.isNone()) {
|
|
||||||
return Result.fail(new Error("System payment methods require a system key."));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!props.isSystem && props.systemKey.isSome()) {
|
|
||||||
return Result.fail(new Error("Custom payment methods cannot define a system key."));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.ok();
|
return Result.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,10 +104,6 @@ export class PaymentMethod extends AggregateRoot<PaymentMethodInternalProps> {
|
|||||||
return this.props.isDefault;
|
return this.props.isDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get systemKey(): Maybe<PaymentMethodSystemKey> {
|
|
||||||
return this.props.systemKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public update(patchProps: PaymentMethodPatchProps): Result<boolean, Error> {
|
public update(patchProps: PaymentMethodPatchProps): Result<boolean, Error> {
|
||||||
if (this.isSystem) {
|
if (this.isSystem) {
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
|
|||||||
@ -3,8 +3,6 @@ import type { Sequelize } from "sequelize";
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
type IPaymentMethodPublicFinder,
|
type IPaymentMethodPublicFinder,
|
||||||
BootstrapSystemPaymentMethodsService,
|
|
||||||
BootstrapSystemPaymentMethodsUseCase,
|
|
||||||
PaymentMethodPublicFinder,
|
PaymentMethodPublicFinder,
|
||||||
PaymentMethodPublicModelMapper,
|
PaymentMethodPublicModelMapper,
|
||||||
SetDefaultPaymentMethodByIdUseCase,
|
SetDefaultPaymentMethodByIdUseCase,
|
||||||
@ -43,7 +41,6 @@ export type PaymentMethodsInternalDeps = {
|
|||||||
disablePaymentMethodById: () => DisablePaymentMethodByIdUseCase;
|
disablePaymentMethodById: () => DisablePaymentMethodByIdUseCase;
|
||||||
enablePaymentMethodById: () => EnablePaymentMethodByIdUseCase;
|
enablePaymentMethodById: () => EnablePaymentMethodByIdUseCase;
|
||||||
setDefaultPaymentMethodById: () => SetDefaultPaymentMethodByIdUseCase;
|
setDefaultPaymentMethodById: () => SetDefaultPaymentMethodByIdUseCase;
|
||||||
bootstrapSystemPaymentMethods: () => BootstrapSystemPaymentMethodsUseCase;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -67,10 +64,6 @@ export const buildPaymentMethodsDependencies = (
|
|||||||
const deleter = buildPaymentMethodDeleter({ repository, usageChecker });
|
const deleter = buildPaymentMethodDeleter({ repository, usageChecker });
|
||||||
const statusChanger = buildPaymentMethodStatusChanger({ repository });
|
const statusChanger = buildPaymentMethodStatusChanger({ repository });
|
||||||
const setDefaultService = new SetDefaultPaymentMethodService(repository);
|
const setDefaultService = new SetDefaultPaymentMethodService(repository);
|
||||||
const bootstrapService = new BootstrapSystemPaymentMethodsService({
|
|
||||||
repository,
|
|
||||||
setDefaultService,
|
|
||||||
});
|
|
||||||
|
|
||||||
const snapshotBuilders = buildPaymentMethodSnapshotBuilders();
|
const snapshotBuilders = buildPaymentMethodSnapshotBuilders();
|
||||||
|
|
||||||
@ -130,13 +123,6 @@ export const buildPaymentMethodsDependencies = (
|
|||||||
fullSnapshotBuilder: snapshotBuilders.full,
|
fullSnapshotBuilder: snapshotBuilders.full,
|
||||||
transactionManager,
|
transactionManager,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
bootstrapSystemPaymentMethods: () =>
|
|
||||||
new BootstrapSystemPaymentMethodsUseCase({
|
|
||||||
bootstrapService,
|
|
||||||
fullSnapshotBuilder: snapshotBuilders.full,
|
|
||||||
transactionManager,
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,37 +0,0 @@
|
|||||||
import {
|
|
||||||
ExpressController,
|
|
||||||
forbidQueryFieldGuard,
|
|
||||||
requireAuthenticatedGuard,
|
|
||||||
requireCompanyContextGuard,
|
|
||||||
} from "@erp/core/api";
|
|
||||||
|
|
||||||
import type { BootstrapSystemPaymentMethodsUseCase } from "../../../../application";
|
|
||||||
import { paymentMethodsApiErrorMapper } from "../payment-methods-api-error-mapper";
|
|
||||||
|
|
||||||
export class BootstrapSystemPaymentMethodsController extends ExpressController {
|
|
||||||
constructor(private readonly useCase: BootstrapSystemPaymentMethodsUseCase) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.errorMapper = paymentMethodsApiErrorMapper;
|
|
||||||
|
|
||||||
this.registerGuards(
|
|
||||||
requireAuthenticatedGuard(),
|
|
||||||
requireCompanyContextGuard(),
|
|
||||||
forbidQueryFieldGuard("companyId")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async executeImpl() {
|
|
||||||
const companyId = this.getTenantId();
|
|
||||||
if (!companyId) {
|
|
||||||
return this.forbiddenError("Tenant ID not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await this.useCase.execute({ companyId });
|
|
||||||
|
|
||||||
return result.match(
|
|
||||||
(data) => this.ok(data),
|
|
||||||
(err) => this.handleError(err)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -4,6 +4,5 @@ export * from "./disable-payment-method-by-id.controller";
|
|||||||
export * from "./enable-payment-method-by-id.controller";
|
export * from "./enable-payment-method-by-id.controller";
|
||||||
export * from "./get-payment-method-by-id.controller";
|
export * from "./get-payment-method-by-id.controller";
|
||||||
export * from "./list-payment-methods.controller";
|
export * from "./list-payment-methods.controller";
|
||||||
export * from "./bootstrap-system-payment-methods.controller";
|
|
||||||
export * from "./set-default-payment-method-by-id.controller";
|
export * from "./set-default-payment-method-by-id.controller";
|
||||||
export * from "./update-payment-method-by-id.controller";
|
export * from "./update-payment-method-by-id.controller";
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { requireIdentityTenantMembership } from "@erp/identity/api";
|
|||||||
import { type NextFunction, type Request, type Response, Router } from "express";
|
import { type NextFunction, type Request, type Response, Router } from "express";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BootstrapSystemPaymentMethodsRequestSchema,
|
|
||||||
CreatePaymentMethodRequestSchema,
|
CreatePaymentMethodRequestSchema,
|
||||||
DeletePaymentMethodByIdRequestSchema,
|
DeletePaymentMethodByIdRequestSchema,
|
||||||
GetPaymentMethodByIdRequestSchema,
|
GetPaymentMethodByIdRequestSchema,
|
||||||
@ -15,7 +14,6 @@ import {
|
|||||||
import type { CatalogsInternalDeps } from "../../di/catalogs.di";
|
import type { CatalogsInternalDeps } from "../../di/catalogs.di";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BootstrapSystemPaymentMethodsController,
|
|
||||||
CreatePaymentMethodController,
|
CreatePaymentMethodController,
|
||||||
DeletePaymentMethodByIdController,
|
DeletePaymentMethodByIdController,
|
||||||
DisablePaymentMethodByIdController,
|
DisablePaymentMethodByIdController,
|
||||||
@ -47,17 +45,6 @@ export const paymentMethodsRouter = (params: StartParams) => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
router.post(
|
|
||||||
"/bootstrap-system",
|
|
||||||
validateRequest(BootstrapSystemPaymentMethodsRequestSchema, "body"),
|
|
||||||
(req: Request, res: Response, next: NextFunction) => {
|
|
||||||
const controller = new BootstrapSystemPaymentMethodsController(
|
|
||||||
deps.useCases.bootstrapSystemPaymentMethods()
|
|
||||||
);
|
|
||||||
return controller.execute(req, res, next);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
router.post(
|
router.post(
|
||||||
"/",
|
"/",
|
||||||
validateRequest(CreatePaymentMethodRequestSchema, "body"),
|
validateRequest(CreatePaymentMethodRequestSchema, "body"),
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import {
|
|||||||
} from "@repo/rdx-ddd";
|
} from "@repo/rdx-ddd";
|
||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
import { PaymentMethod, isPaymentMethodSystemKey } from "../../../../../domain";
|
import { PaymentMethod } from "../../../../../domain";
|
||||||
import type { PaymentMethodCreationAttributes, PaymentMethodModel } from "../models";
|
import type { PaymentMethodCreationAttributes, PaymentMethodModel } from "../models";
|
||||||
|
|
||||||
export class SequelizePaymentMethodDomainMapper extends SequelizeDomainMapper<
|
export class SequelizePaymentMethodDomainMapper extends SequelizeDomainMapper<
|
||||||
@ -44,15 +44,6 @@ export class SequelizePaymentMethodDomainMapper extends SequelizeDomainMapper<
|
|||||||
"description",
|
"description",
|
||||||
errors
|
errors
|
||||||
);
|
);
|
||||||
const systemKey = extractOrPushError(
|
|
||||||
maybeFromNullableResult(source.system_key, (value) =>
|
|
||||||
isPaymentMethodSystemKey(value)
|
|
||||||
? Result.ok(value)
|
|
||||||
: Result.fail(new Error(`Invalid payment method system key: ${value}`))
|
|
||||||
),
|
|
||||||
"system_key",
|
|
||||||
errors
|
|
||||||
);
|
|
||||||
|
|
||||||
// Si hubo errores de mapeo, devolvemos colección de validación
|
// Si hubo errores de mapeo, devolvemos colección de validación
|
||||||
if (errors.length > 0) {
|
if (errors.length > 0) {
|
||||||
@ -69,7 +60,6 @@ export class SequelizePaymentMethodDomainMapper extends SequelizeDomainMapper<
|
|||||||
isActive: source.is_active,
|
isActive: source.is_active,
|
||||||
isSystem: source.is_system,
|
isSystem: source.is_system,
|
||||||
isDefault: source.is_default,
|
isDefault: source.is_default,
|
||||||
systemKey: systemKey!,
|
|
||||||
},
|
},
|
||||||
idResult.data
|
idResult.data
|
||||||
);
|
);
|
||||||
@ -92,10 +82,6 @@ export class SequelizePaymentMethodDomainMapper extends SequelizeDomainMapper<
|
|||||||
is_active: source.isActive,
|
is_active: source.isActive,
|
||||||
is_system: source.isSystem,
|
is_system: source.isSystem,
|
||||||
is_default: source.isDefault,
|
is_default: source.isDefault,
|
||||||
system_key: source.systemKey.match(
|
|
||||||
(systemKey) => systemKey,
|
|
||||||
() => null
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,6 @@ export class PaymentMethodModel extends Model<
|
|||||||
declare is_active: boolean;
|
declare is_active: boolean;
|
||||||
declare is_system: boolean;
|
declare is_system: boolean;
|
||||||
declare is_default: boolean;
|
declare is_default: boolean;
|
||||||
declare system_key: CreationOptional<string | null>;
|
|
||||||
|
|
||||||
static associate(_database: Sequelize) {}
|
static associate(_database: Sequelize) {}
|
||||||
|
|
||||||
@ -65,11 +64,6 @@ export default (database: Sequelize) => {
|
|||||||
allowNull: false,
|
allowNull: false,
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
},
|
},
|
||||||
system_key: {
|
|
||||||
type: DataTypes.STRING(40),
|
|
||||||
allowNull: true,
|
|
||||||
defaultValue: null,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
sequelize: database,
|
sequelize: database,
|
||||||
@ -91,13 +85,6 @@ export default (database: Sequelize) => {
|
|||||||
defaultScope: {},
|
defaultScope: {},
|
||||||
|
|
||||||
scopes: {},
|
scopes: {},
|
||||||
indexes: [
|
|
||||||
{
|
|
||||||
name: "uq_payment_methods_company_system_key",
|
|
||||||
fields: ["company_id", "system_key"],
|
|
||||||
unique: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import type { Sequelize, Transaction } from "sequelize";
|
|||||||
|
|
||||||
import type { IPaymentMethodRepository } from "../../../../../application";
|
import type { IPaymentMethodRepository } from "../../../../../application";
|
||||||
import type { PaymentMethodSummary } from "../../../../../application/payment-methods/models";
|
import type { PaymentMethodSummary } from "../../../../../application/payment-methods/models";
|
||||||
import type { PaymentMethod, PaymentMethodSystemKey } from "../../../../../domain";
|
import type { PaymentMethod } from "../../../../../domain";
|
||||||
import type { SequelizePaymentMethodSummaryMapper } from "../mappers";
|
import type { SequelizePaymentMethodSummaryMapper } from "../mappers";
|
||||||
import type { SequelizePaymentMethodDomainMapper } from "../mappers/sequelize-payment-method-domain.mapper";
|
import type { SequelizePaymentMethodDomainMapper } from "../mappers/sequelize-payment-method-domain.mapper";
|
||||||
import { PaymentMethodModel } from "../models";
|
import { PaymentMethodModel } from "../models";
|
||||||
@ -202,90 +202,6 @@ export class SequelizePaymentMethodRepository
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async findBySystemKeyInCompany(
|
|
||||||
companyId: UniqueID,
|
|
||||||
systemKey: PaymentMethodSystemKey,
|
|
||||||
transaction?: Transaction,
|
|
||||||
options?: { includeDeleted?: boolean }
|
|
||||||
): Promise<Result<Maybe<PaymentMethod>, Error>> {
|
|
||||||
try {
|
|
||||||
const row = await PaymentMethodModel.findOne({
|
|
||||||
where: {
|
|
||||||
company_id: companyId.toString(),
|
|
||||||
system_key: systemKey,
|
|
||||||
},
|
|
||||||
paranoid: !(options?.includeDeleted ?? false),
|
|
||||||
transaction,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!row) {
|
|
||||||
return Result.ok(Maybe.none<PaymentMethod>());
|
|
||||||
}
|
|
||||||
|
|
||||||
const mappedResult = this.domainMapper.mapToDomain(row);
|
|
||||||
if (mappedResult.isFailure) {
|
|
||||||
return Result.fail(mappedResult.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.ok(Maybe.some(mappedResult.data));
|
|
||||||
} catch (error: unknown) {
|
|
||||||
return Result.fail(translateSequelizeError(error));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async restoreByIdInCompany(
|
|
||||||
companyId: UniqueID,
|
|
||||||
id: UniqueID,
|
|
||||||
transaction?: Transaction
|
|
||||||
): Promise<Result<boolean, Error>> {
|
|
||||||
try {
|
|
||||||
const restored = await PaymentMethodModel.restore({
|
|
||||||
where: {
|
|
||||||
id: id.toString(),
|
|
||||||
company_id: companyId.toString(),
|
|
||||||
},
|
|
||||||
transaction,
|
|
||||||
});
|
|
||||||
|
|
||||||
return Result.ok(restored > 0);
|
|
||||||
} catch (error: unknown) {
|
|
||||||
return Result.fail(translateSequelizeError(error));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async syncSystemPaymentMethodState(params: {
|
|
||||||
companyId: UniqueID;
|
|
||||||
id: UniqueID;
|
|
||||||
name: string;
|
|
||||||
isDefault: boolean;
|
|
||||||
systemKey: PaymentMethodSystemKey;
|
|
||||||
transaction?: Transaction;
|
|
||||||
}): Promise<Result<void, Error>> {
|
|
||||||
try {
|
|
||||||
await PaymentMethodModel.update(
|
|
||||||
{
|
|
||||||
name: params.name,
|
|
||||||
is_active: true,
|
|
||||||
is_system: true,
|
|
||||||
is_default: params.isDefault,
|
|
||||||
system_key: params.systemKey,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
where: {
|
|
||||||
id: params.id.toString(),
|
|
||||||
company_id: params.companyId.toString(),
|
|
||||||
},
|
|
||||||
paranoid: false,
|
|
||||||
transaction: params.transaction,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return Result.ok();
|
|
||||||
} catch (error: unknown) {
|
|
||||||
return Result.fail(translateSequelizeError(error));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async lockByCompanyId(
|
public async lockByCompanyId(
|
||||||
companyId: UniqueID,
|
companyId: UniqueID,
|
||||||
transaction?: Transaction
|
transaction?: Transaction
|
||||||
|
|||||||
@ -1,7 +0,0 @@
|
|||||||
import { z } from "zod/v4";
|
|
||||||
|
|
||||||
export const BootstrapSystemPaymentMethodsRequestSchema = z.object({});
|
|
||||||
|
|
||||||
export type BootstrapSystemPaymentMethodsRequestDTO = z.infer<
|
|
||||||
typeof BootstrapSystemPaymentMethodsRequestSchema
|
|
||||||
>;
|
|
||||||
@ -1,5 +1,4 @@
|
|||||||
export * from "./create-payment-method.request.dto";
|
export * from "./create-payment-method.request.dto";
|
||||||
export * from "./bootstrap-system-payment-methods.request.dto";
|
|
||||||
export * from "./delete-payment-method-by-id.request.dto";
|
export * from "./delete-payment-method-by-id.request.dto";
|
||||||
export * from "./get-payment-method-by-id.request.dto";
|
export * from "./get-payment-method-by-id.request.dto";
|
||||||
export * from "./list-payment-methods.request.dto";
|
export * from "./list-payment-methods.request.dto";
|
||||||
|
|||||||
@ -1,11 +0,0 @@
|
|||||||
import { z } from "zod/v4";
|
|
||||||
|
|
||||||
import { PaymentMethodDetailSchema } from "../shared";
|
|
||||||
|
|
||||||
export const BootstrapSystemPaymentMethodsResponseSchema = z.object({
|
|
||||||
items: z.array(PaymentMethodDetailSchema),
|
|
||||||
});
|
|
||||||
|
|
||||||
export type BootstrapSystemPaymentMethodsResponseDTO = z.infer<
|
|
||||||
typeof BootstrapSystemPaymentMethodsResponseSchema
|
|
||||||
>;
|
|
||||||
@ -1,5 +1,4 @@
|
|||||||
export * from "./create-payment-method.response.dto";
|
export * from "./create-payment-method.response.dto";
|
||||||
export * from "./bootstrap-system-payment-methods.response.dto";
|
|
||||||
export * from "./disable-payment-method-by-id.response.dto";
|
export * from "./disable-payment-method-by-id.response.dto";
|
||||||
export * from "./get-payment-method-by-id.response.dto";
|
export * from "./get-payment-method-by-id.response.dto";
|
||||||
export * from "./list-payment-methods.response.dto";
|
export * from "./list-payment-methods.response.dto";
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user