Catálogo de régimen de IVA
This commit is contained in:
parent
402b8300b1
commit
cea1ab2766
@ -1,2 +1,3 @@
|
|||||||
export * from "./payment-methods";
|
export * from "./payment-methods";
|
||||||
export * from "./payment-terms";
|
export * from "./payment-terms";
|
||||||
|
export * from "./tax-regimes";
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
export * from "./payment-term-creator";
|
export * from "./payment-term-creator.service";
|
||||||
export * from "./payment-term-deleter";
|
export * from "./payment-term-deleter.service";
|
||||||
export * from "./payment-term-finder";
|
export * from "./payment-term-finder.service";
|
||||||
export * from "./payment-term-public-services";
|
export * from "./payment-term-public-services";
|
||||||
export * from "./payment-term-status-changer";
|
export * from "./payment-term-status-changer.service";
|
||||||
export * from "./payment-term-updater";
|
export * from "./payment-term-updater.service";
|
||||||
|
|||||||
@ -1,11 +1,27 @@
|
|||||||
import type { IPaymentTermFinder } from "./payment-term-finder";
|
import type { IPaymentTermCreator } from "./payment-term-creator.service";
|
||||||
|
import type { IPaymentTermDeleter } from "./payment-term-deleter.service";
|
||||||
|
import type { IPaymentTermFinder } from "./payment-term-finder.service";
|
||||||
|
import type { IPaymentTermStatusChanger } from "./payment-term-status-changer.service";
|
||||||
|
import type { IPaymentTermUpdater } from "./payment-term-updater.service";
|
||||||
|
|
||||||
export interface IPaymentTermPublicServices {
|
export interface IPaymentTermPublicServices {
|
||||||
finder: IPaymentTermFinder;
|
finder: IPaymentTermFinder;
|
||||||
|
creator: IPaymentTermCreator;
|
||||||
|
updater: IPaymentTermUpdater;
|
||||||
|
deleter: IPaymentTermDeleter;
|
||||||
|
statusChanger: IPaymentTermStatusChanger;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const buildPaymentTermPublicServices = (
|
export const buildPaymentTermPublicServices = (
|
||||||
finder: IPaymentTermFinder
|
finder: IPaymentTermFinder,
|
||||||
|
creator: IPaymentTermCreator,
|
||||||
|
updater: IPaymentTermUpdater,
|
||||||
|
deleter: IPaymentTermDeleter,
|
||||||
|
statusChanger: IPaymentTermStatusChanger
|
||||||
): IPaymentTermPublicServices => ({
|
): IPaymentTermPublicServices => ({
|
||||||
finder,
|
finder,
|
||||||
|
creator,
|
||||||
|
updater,
|
||||||
|
deleter,
|
||||||
|
statusChanger,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { Result } from "@repo/rdx-utils";
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
import type { PaymentTerm } from "../../../domain";
|
import type { PaymentTerm } from "../../../domain";
|
||||||
import type { IPaymentTermRepository } from "../repositories/payment-term-repository.interface";
|
import type { IPaymentTermRepository } from "../repositories";
|
||||||
|
|
||||||
export type PaymentTermStatusChangeAction = "enable" | "disable";
|
export type PaymentTermStatusChangeAction = "enable" | "disable";
|
||||||
|
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
export * from "./tax-regime-input-mappers.di";
|
||||||
|
export * from "./tax-regime-services.di";
|
||||||
|
export * from "./tax-regime-snapshot-builders.di";
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
import {
|
||||||
|
CreateTaxRegimeInputMapper,
|
||||||
|
type ICreateTaxRegimeInputMapper,
|
||||||
|
UpdateTaxRegimeInputMapper,
|
||||||
|
} from "../mappers";
|
||||||
|
|
||||||
|
export interface ITaxRegimeInputMappers {
|
||||||
|
createInputMapper: ICreateTaxRegimeInputMapper;
|
||||||
|
updateInputMapper: UpdateTaxRegimeInputMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const buildTaxRegimeInputMappers = (): ITaxRegimeInputMappers => {
|
||||||
|
const createInputMapper = new CreateTaxRegimeInputMapper();
|
||||||
|
const updateInputMapper = new UpdateTaxRegimeInputMapper();
|
||||||
|
|
||||||
|
return {
|
||||||
|
createInputMapper,
|
||||||
|
updateInputMapper,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
import type { ITaxRegimeRepository } from "../repositories";
|
||||||
|
import {
|
||||||
|
type ITaxRegimeCreator,
|
||||||
|
type ITaxRegimeDeleter,
|
||||||
|
type ITaxRegimeFinder,
|
||||||
|
type ITaxRegimeStatusChanger,
|
||||||
|
type ITaxRegimeUpdater,
|
||||||
|
TaxRegimeCreator,
|
||||||
|
TaxRegimeDeleter,
|
||||||
|
TaxRegimeFinder,
|
||||||
|
TaxRegimeStatusChanger,
|
||||||
|
TaxRegimeUpdater,
|
||||||
|
} from "../services";
|
||||||
|
|
||||||
|
export function buildTaxRegimeFinder(params: {
|
||||||
|
repository: ITaxRegimeRepository;
|
||||||
|
}): ITaxRegimeFinder {
|
||||||
|
const { repository } = params;
|
||||||
|
|
||||||
|
return new TaxRegimeFinder(repository);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const buildTaxRegimeCreator = (params: {
|
||||||
|
repository: ITaxRegimeRepository;
|
||||||
|
}): ITaxRegimeCreator => {
|
||||||
|
const { repository } = params;
|
||||||
|
|
||||||
|
return new TaxRegimeCreator(repository);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const buildTaxRegimeDeleter = (params: {
|
||||||
|
repository: ITaxRegimeRepository;
|
||||||
|
}): ITaxRegimeDeleter => {
|
||||||
|
const { repository } = params;
|
||||||
|
|
||||||
|
return new TaxRegimeDeleter(repository);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const buildTaxRegimeStatusChanger = (params: {
|
||||||
|
repository: ITaxRegimeRepository;
|
||||||
|
}): ITaxRegimeStatusChanger => {
|
||||||
|
const { repository } = params;
|
||||||
|
|
||||||
|
return new TaxRegimeStatusChanger(repository);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const buildTaxRegimeUpdater = (params: {
|
||||||
|
repository: ITaxRegimeRepository;
|
||||||
|
}): ITaxRegimeUpdater => {
|
||||||
|
const { repository } = params;
|
||||||
|
|
||||||
|
return new TaxRegimeUpdater(repository);
|
||||||
|
};
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
import {
|
||||||
|
TaxRegimeFullSnapshotBuilder,
|
||||||
|
TaxRegimeSummarySnapshotBuilder,
|
||||||
|
} from "../snapshot-builders";
|
||||||
|
|
||||||
|
export function buildTaxRegimeSnapshotBuilders() {
|
||||||
|
const fullSnapshotBuilder = new TaxRegimeFullSnapshotBuilder();
|
||||||
|
const summarySnapshotBuilder = new TaxRegimeSummarySnapshotBuilder();
|
||||||
|
|
||||||
|
return {
|
||||||
|
full: fullSnapshotBuilder,
|
||||||
|
summary: summarySnapshotBuilder,
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
export * from "./mappers";
|
||||||
|
export * from "./models";
|
||||||
|
export * from "./repositories";
|
||||||
|
export * from "./services";
|
||||||
|
export * from "./snapshot-builders";
|
||||||
|
export * from "./use-cases";
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
import {
|
||||||
|
DomainError,
|
||||||
|
TextValue,
|
||||||
|
UniqueID,
|
||||||
|
ValidationErrorCollection,
|
||||||
|
type ValidationErrorDetail,
|
||||||
|
extractOrPushError,
|
||||||
|
} from "@repo/rdx-ddd";
|
||||||
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
|
import type { CreateTaxRegimeRequestDTO } from "../../../../common";
|
||||||
|
import { type ITaxRegimeCreateProps, TaxRegimeCode } from "../../../domain";
|
||||||
|
|
||||||
|
export interface ICreateTaxRegimeInputMapper {
|
||||||
|
map(
|
||||||
|
dto: CreateTaxRegimeRequestDTO,
|
||||||
|
params: { companyId: UniqueID }
|
||||||
|
): Result<{ id: UniqueID; props: ITaxRegimeCreateProps }, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CreateTaxRegimeInputMapper implements ICreateTaxRegimeInputMapper {
|
||||||
|
public map(
|
||||||
|
dto: CreateTaxRegimeRequestDTO,
|
||||||
|
params: { companyId: UniqueID }
|
||||||
|
): Result<{ id: UniqueID; props: ITaxRegimeCreateProps }, Error> {
|
||||||
|
const errors: ValidationErrorDetail[] = [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
const taxRegimeId = extractOrPushError(UniqueID.create(dto.id), "id", errors);
|
||||||
|
|
||||||
|
const code = extractOrPushError(TaxRegimeCode.create(dto.code), "code", errors);
|
||||||
|
|
||||||
|
const description = extractOrPushError(
|
||||||
|
TextValue.create(dto.description),
|
||||||
|
"description",
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
|
||||||
|
const isActive = extractOrPushError(Result.ok(dto.is_active), "is_active", errors);
|
||||||
|
|
||||||
|
this.throwIfValidationErrors(errors);
|
||||||
|
|
||||||
|
const props: ITaxRegimeCreateProps = {
|
||||||
|
companyId: params.companyId,
|
||||||
|
code: code!,
|
||||||
|
description: description!,
|
||||||
|
isActive: isActive ?? true,
|
||||||
|
isSystem: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
return Result.ok({ id: taxRegimeId!, props });
|
||||||
|
} catch (err: unknown) {
|
||||||
|
return Result.fail(new DomainError("Tax regime props mapping failed", { cause: err }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private throwIfValidationErrors(errors: ValidationErrorDetail[]): void {
|
||||||
|
if (errors.length > 0) {
|
||||||
|
throw new ValidationErrorCollection("Tax regime props mapping failed", errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./create-tax-regime-input.mapper";
|
||||||
|
export * from "./update-tax-regime-by-id-input.mapper";
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
import {
|
||||||
|
DomainError,
|
||||||
|
TextValue,
|
||||||
|
type UniqueID,
|
||||||
|
ValidationErrorCollection,
|
||||||
|
type ValidationErrorDetail,
|
||||||
|
extractOrPushError,
|
||||||
|
} from "@repo/rdx-ddd";
|
||||||
|
import { Result, isNullishOrEmpty, toPatchField } from "@repo/rdx-utils";
|
||||||
|
|
||||||
|
import type { UpdateTaxRegimeByIdRequestDTO } from "../../../../common";
|
||||||
|
import type { TaxRegimePatchProps } from "../../../domain";
|
||||||
|
|
||||||
|
export interface IUpdateTaxRegimeInputMapper {
|
||||||
|
map(
|
||||||
|
dto: UpdateTaxRegimeByIdRequestDTO,
|
||||||
|
_params: { companyId: UniqueID }
|
||||||
|
): Result<TaxRegimePatchProps>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UpdateTaxRegimeInputMapper implements IUpdateTaxRegimeInputMapper {
|
||||||
|
public map(
|
||||||
|
dto: UpdateTaxRegimeByIdRequestDTO,
|
||||||
|
_params: { companyId: UniqueID }
|
||||||
|
): Result<TaxRegimePatchProps> {
|
||||||
|
try {
|
||||||
|
const errors: ValidationErrorDetail[] = [];
|
||||||
|
const taxRegimePatchProps: TaxRegimePatchProps = {};
|
||||||
|
|
||||||
|
toPatchField(dto.description).ifSet((description) => {
|
||||||
|
if (isNullishOrEmpty(description)) {
|
||||||
|
errors.push({ path: "description", message: "Description cannot be empty" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
taxRegimePatchProps.description = extractOrPushError(
|
||||||
|
TextValue.create(description),
|
||||||
|
"description",
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
toPatchField(dto.is_active).ifSet((isActive) => {
|
||||||
|
taxRegimePatchProps.isActive = isActive;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.throwIfValidationErrors(errors);
|
||||||
|
|
||||||
|
return Result.ok(taxRegimePatchProps);
|
||||||
|
} catch (err: unknown) {
|
||||||
|
console.error(err);
|
||||||
|
return Result.fail(
|
||||||
|
new DomainError("Tax regime props mapping failed (update)", { cause: err })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private throwIfValidationErrors(errors: ValidationErrorDetail[]): void {
|
||||||
|
if (errors.length > 0) {
|
||||||
|
throw new ValidationErrorCollection("Tax regime props mapping failed", errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./tax-regime-detail.model";
|
||||||
|
export * from "./tax-regime-summary.model";
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
import type { TaxRegimeCode } from "@erp/catalogs/api/domain";
|
||||||
|
import type { TextValue, UniqueID } from "@repo/rdx-ddd";
|
||||||
|
|
||||||
|
export type TaxRegimeDetail = {
|
||||||
|
id: UniqueID;
|
||||||
|
companyId: UniqueID;
|
||||||
|
code: TaxRegimeCode;
|
||||||
|
description: TextValue;
|
||||||
|
is_active: boolean;
|
||||||
|
is_system: boolean;
|
||||||
|
};
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
import type { TaxRegimeCode } from "@erp/catalogs/api/domain";
|
||||||
|
import type { TextValue, UniqueID } from "@repo/rdx-ddd";
|
||||||
|
|
||||||
|
export type TaxRegimeSummary = {
|
||||||
|
id: UniqueID;
|
||||||
|
companyId: UniqueID;
|
||||||
|
code: TaxRegimeCode;
|
||||||
|
description: TextValue;
|
||||||
|
isActive: boolean;
|
||||||
|
isSystem: boolean;
|
||||||
|
};
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export * from "./tax-regime-repository.interface";
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
import type { Criteria } from "@repo/rdx-criteria/server";
|
||||||
|
import type { UniqueID } from "@repo/rdx-ddd";
|
||||||
|
import type { Collection, Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
|
import type { TaxRegime, TaxRegimeCode } from "../../../domain";
|
||||||
|
import type { TaxRegimeSummary } from "../models";
|
||||||
|
|
||||||
|
export interface ITaxRegimeRepository {
|
||||||
|
create(taxRegime: TaxRegime, transaction?: unknown): Promise<Result<void, Error>>;
|
||||||
|
update(taxRegime: TaxRegime, transaction?: unknown): Promise<Result<void, Error>>;
|
||||||
|
deleteByIdInCompany(
|
||||||
|
companyId: UniqueID,
|
||||||
|
id: UniqueID,
|
||||||
|
transaction: unknown
|
||||||
|
): Promise<Result<boolean, Error>>;
|
||||||
|
|
||||||
|
existsByIdInCompany(
|
||||||
|
companyId: UniqueID,
|
||||||
|
id: UniqueID,
|
||||||
|
transaction?: unknown
|
||||||
|
): Promise<Result<boolean, Error>>;
|
||||||
|
|
||||||
|
getByIdInCompany(
|
||||||
|
companyId: UniqueID,
|
||||||
|
id: UniqueID,
|
||||||
|
transaction?: unknown
|
||||||
|
): Promise<Result<TaxRegime, Error>>;
|
||||||
|
|
||||||
|
getByCodeInCompany(
|
||||||
|
companyId: UniqueID,
|
||||||
|
code: TaxRegimeCode,
|
||||||
|
transaction?: unknown
|
||||||
|
): Promise<Result<TaxRegime, Error>>;
|
||||||
|
|
||||||
|
findByCriteriaInCompany(
|
||||||
|
companyId: UniqueID,
|
||||||
|
criteria: Criteria,
|
||||||
|
transaction?: unknown
|
||||||
|
): Promise<Result<Collection<TaxRegimeSummary>, Error>>;
|
||||||
|
}
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
export * from "./tax-regime-creator.service";
|
||||||
|
export * from "./tax-regime-deleter.service";
|
||||||
|
export * from "./tax-regime-finder.service";
|
||||||
|
export * from "./tax-regime-public-services";
|
||||||
|
export * from "./tax-regime-status-changer.service";
|
||||||
|
export * from "./tax-regime-updater.service";
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
import type { UniqueID } from "@repo/rdx-ddd";
|
||||||
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
|
import { type ITaxRegimeCreateProps, TaxRegime } from "../../../domain";
|
||||||
|
import type { ITaxRegimeRepository } from "../repositories";
|
||||||
|
|
||||||
|
export interface ITaxRegimeCreatorParams {
|
||||||
|
companyId: UniqueID;
|
||||||
|
id: UniqueID;
|
||||||
|
props: ITaxRegimeCreateProps;
|
||||||
|
transaction: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ITaxRegimeCreator {
|
||||||
|
create(params: ITaxRegimeCreatorParams): Promise<Result<TaxRegime, Error>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TaxRegimeCreator implements ITaxRegimeCreator {
|
||||||
|
constructor(private readonly repository: ITaxRegimeRepository) {}
|
||||||
|
|
||||||
|
public async create(params: ITaxRegimeCreatorParams): Promise<Result<TaxRegime, Error>> {
|
||||||
|
const { companyId, id, props, transaction } = params;
|
||||||
|
|
||||||
|
// Create aggregate
|
||||||
|
const taxRegimeResult = TaxRegime.create({ ...props, companyId }, id);
|
||||||
|
|
||||||
|
if (taxRegimeResult.isFailure) {
|
||||||
|
return taxRegimeResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
const taxRegime = taxRegimeResult.data;
|
||||||
|
const saveResult = await this.repository.create(taxRegime, transaction);
|
||||||
|
if (saveResult.isFailure) {
|
||||||
|
return Result.fail(saveResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok(taxRegime);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
|
import { type TaxRegime, TaxRegimeCannotBeDeletedError } from "../../../domain";
|
||||||
|
import type { ITaxRegimeRepository } from "../repositories";
|
||||||
|
|
||||||
|
export interface ITaxRegimeDeleter {
|
||||||
|
delete(params: {
|
||||||
|
taxRegime: TaxRegime;
|
||||||
|
transaction?: unknown;
|
||||||
|
}): Promise<Result<TaxRegime, Error>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TaxRegimeDeleter implements ITaxRegimeDeleter {
|
||||||
|
public constructor(private readonly repository: ITaxRegimeRepository) {}
|
||||||
|
|
||||||
|
public async delete(params: {
|
||||||
|
taxRegime: TaxRegime;
|
||||||
|
transaction?: unknown;
|
||||||
|
}): Promise<Result<TaxRegime, Error>> {
|
||||||
|
const { taxRegime, transaction } = params;
|
||||||
|
|
||||||
|
if (taxRegime.isSystem) {
|
||||||
|
return Result.fail(new TaxRegimeCannotBeDeletedError("System tax regime cannot be deleted."));
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteResult = await this.repository.deleteByIdInCompany(
|
||||||
|
taxRegime.companyId,
|
||||||
|
taxRegime.id,
|
||||||
|
transaction
|
||||||
|
);
|
||||||
|
|
||||||
|
if (deleteResult.isFailure) {
|
||||||
|
return Result.fail(deleteResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok(taxRegime);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,69 @@
|
|||||||
|
import type { Criteria } from "@repo/rdx-criteria/server";
|
||||||
|
import type { UniqueID } from "@repo/rdx-ddd";
|
||||||
|
import type { Collection, Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
|
import type { TaxRegime, TaxRegimeCode } from "../../../domain";
|
||||||
|
import type { TaxRegimeSummary } from "../models";
|
||||||
|
import type { ITaxRegimeRepository } from "../repositories";
|
||||||
|
|
||||||
|
export interface ITaxRegimeFinder {
|
||||||
|
findTaxRegimeById(
|
||||||
|
companyId: UniqueID,
|
||||||
|
id: UniqueID,
|
||||||
|
transaction?: unknown
|
||||||
|
): Promise<Result<TaxRegime, Error>>;
|
||||||
|
|
||||||
|
findTaxRegimeByCode(
|
||||||
|
companyId: UniqueID,
|
||||||
|
code: TaxRegimeCode,
|
||||||
|
transaction?: unknown
|
||||||
|
): Promise<Result<TaxRegime, Error>>;
|
||||||
|
|
||||||
|
taxRegimeExists(
|
||||||
|
companyId: UniqueID,
|
||||||
|
id: UniqueID,
|
||||||
|
transaction?: unknown
|
||||||
|
): Promise<Result<boolean, Error>>;
|
||||||
|
|
||||||
|
findTaxRegimesByCriteria(
|
||||||
|
companyId: UniqueID,
|
||||||
|
criteria: Criteria,
|
||||||
|
transaction?: unknown
|
||||||
|
): Promise<Result<Collection<TaxRegimeSummary>, Error>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TaxRegimeFinder implements ITaxRegimeFinder {
|
||||||
|
constructor(private readonly repository: ITaxRegimeRepository) {}
|
||||||
|
|
||||||
|
async findTaxRegimeById(
|
||||||
|
companyId: UniqueID,
|
||||||
|
taxRegimeId: UniqueID,
|
||||||
|
transaction?: unknown
|
||||||
|
): Promise<Result<TaxRegime, Error>> {
|
||||||
|
return this.repository.getByIdInCompany(companyId, taxRegimeId, transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
async findTaxRegimeByCode(
|
||||||
|
companyId: UniqueID,
|
||||||
|
code: TaxRegimeCode,
|
||||||
|
transaction?: unknown
|
||||||
|
): Promise<Result<TaxRegime, Error>> {
|
||||||
|
return this.repository.getByCodeInCompany(companyId, code, transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
async taxRegimeExists(
|
||||||
|
companyId: UniqueID,
|
||||||
|
taxRegimeId: UniqueID,
|
||||||
|
transaction?: unknown
|
||||||
|
): Promise<Result<boolean, Error>> {
|
||||||
|
return this.repository.existsByIdInCompany(companyId, taxRegimeId, transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
async findTaxRegimesByCriteria(
|
||||||
|
companyId: UniqueID,
|
||||||
|
criteria: Criteria,
|
||||||
|
transaction?: unknown
|
||||||
|
): Promise<Result<Collection<TaxRegimeSummary>, Error>> {
|
||||||
|
return this.repository.findByCriteriaInCompany(companyId, criteria, transaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
import type { ITaxRegimeCreator } from "./tax-regime-creator.service";
|
||||||
|
import type { ITaxRegimeDeleter } from "./tax-regime-deleter.service";
|
||||||
|
import type { ITaxRegimeFinder } from "./tax-regime-finder.service";
|
||||||
|
import type { ITaxRegimeStatusChanger } from "./tax-regime-status-changer.service";
|
||||||
|
import type { ITaxRegimeUpdater } from "./tax-regime-updater.service";
|
||||||
|
|
||||||
|
export interface ITaxRegimePublicServices {
|
||||||
|
finder: ITaxRegimeFinder;
|
||||||
|
creator: ITaxRegimeCreator;
|
||||||
|
updater: ITaxRegimeUpdater;
|
||||||
|
deleter: ITaxRegimeDeleter;
|
||||||
|
statusChanger: ITaxRegimeStatusChanger;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const buildTaxRegimePublicServices = (
|
||||||
|
finder: ITaxRegimeFinder,
|
||||||
|
creator: ITaxRegimeCreator,
|
||||||
|
updater: ITaxRegimeUpdater,
|
||||||
|
deleter: ITaxRegimeDeleter,
|
||||||
|
statusChanger: ITaxRegimeStatusChanger
|
||||||
|
): ITaxRegimePublicServices => ({
|
||||||
|
finder,
|
||||||
|
creator,
|
||||||
|
updater,
|
||||||
|
deleter,
|
||||||
|
statusChanger,
|
||||||
|
});
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
import type { TaxRegime } from "@erp/catalogs/api/domain";
|
||||||
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
|
import type { ITaxRegimeRepository } from "../repositories";
|
||||||
|
|
||||||
|
export type TaxRegimeStatusChangeAction = "enable" | "disable";
|
||||||
|
|
||||||
|
export interface ITaxRegimeStatusChanger {
|
||||||
|
changeStatus(params: {
|
||||||
|
taxRegime: TaxRegime;
|
||||||
|
action: TaxRegimeStatusChangeAction;
|
||||||
|
transaction?: unknown;
|
||||||
|
}): Promise<Result<TaxRegime, Error>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TaxRegimeStatusChanger implements ITaxRegimeStatusChanger {
|
||||||
|
public constructor(private readonly repository: ITaxRegimeRepository) {}
|
||||||
|
|
||||||
|
public async changeStatus(params: {
|
||||||
|
taxRegime: TaxRegime;
|
||||||
|
action: TaxRegimeStatusChangeAction;
|
||||||
|
transaction?: unknown;
|
||||||
|
}): Promise<Result<TaxRegime, Error>> {
|
||||||
|
const { taxRegime, action, transaction } = params;
|
||||||
|
|
||||||
|
const statusResult = action === "enable" ? taxRegime.enable() : taxRegime.disable();
|
||||||
|
if (statusResult.isFailure) {
|
||||||
|
return Result.fail(statusResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!statusResult.data) {
|
||||||
|
return Result.ok(taxRegime);
|
||||||
|
}
|
||||||
|
|
||||||
|
const persistenceResult = await this.repository.update(taxRegime, transaction);
|
||||||
|
if (persistenceResult.isFailure) {
|
||||||
|
return Result.fail(persistenceResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok(taxRegime);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
import type { UniqueID } from "@repo/rdx-ddd";
|
||||||
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
|
import type { TaxRegime, TaxRegimePatchProps } from "../../../domain";
|
||||||
|
import type { ITaxRegimeRepository } from "../repositories";
|
||||||
|
|
||||||
|
export interface ITaxRegimeUpdater {
|
||||||
|
update(params: {
|
||||||
|
companyId: UniqueID;
|
||||||
|
id: UniqueID;
|
||||||
|
patchProps: TaxRegimePatchProps;
|
||||||
|
transaction?: unknown;
|
||||||
|
}): Promise<Result<TaxRegime, Error>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TaxRegimeUpdater implements ITaxRegimeUpdater {
|
||||||
|
constructor(private readonly repository: ITaxRegimeRepository) {}
|
||||||
|
|
||||||
|
public async update(params: {
|
||||||
|
companyId: UniqueID;
|
||||||
|
id: UniqueID;
|
||||||
|
patchProps: TaxRegimePatchProps;
|
||||||
|
transaction?: unknown;
|
||||||
|
}): Promise<Result<TaxRegime, Error>> {
|
||||||
|
const { companyId, id, patchProps, transaction } = params;
|
||||||
|
|
||||||
|
const existingResult = await this.repository.getByIdInCompany(companyId, id, transaction);
|
||||||
|
if (existingResult.isFailure) {
|
||||||
|
return Result.fail(existingResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const taxRegime = existingResult.data;
|
||||||
|
|
||||||
|
// Aplicar cambios en el agregado
|
||||||
|
const updateResult = taxRegime.update(patchProps);
|
||||||
|
if (updateResult.isFailure) {
|
||||||
|
return Result.fail(updateResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!updateResult.data) {
|
||||||
|
return Result.ok(taxRegime);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Persistir cambios
|
||||||
|
const saveResult = await this.repository.update(taxRegime, transaction);
|
||||||
|
if (saveResult.isFailure) {
|
||||||
|
return Result.fail(saveResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok(taxRegime);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
import type { GetTaxRegimeByIdResponseDTO } from "@erp/catalogs/common";
|
||||||
|
import type { ISnapshotBuilder } from "@erp/core/api";
|
||||||
|
|
||||||
|
import type { TaxRegime } from "../../../../domain";
|
||||||
|
|
||||||
|
export interface ITaxRegimeFullSnapshotBuilder
|
||||||
|
extends ISnapshotBuilder<TaxRegime, GetTaxRegimeByIdResponseDTO> {}
|
||||||
|
|
||||||
|
export class TaxRegimeFullSnapshotBuilder implements ITaxRegimeFullSnapshotBuilder {
|
||||||
|
public toOutput(taxRegime: TaxRegime): GetTaxRegimeByIdResponseDTO {
|
||||||
|
return {
|
||||||
|
id: taxRegime.code.toPrimitive(),
|
||||||
|
company_id: taxRegime.companyId.toPrimitive(),
|
||||||
|
code: taxRegime.code.toPrimitive(),
|
||||||
|
description: taxRegime.description.toPrimitive(),
|
||||||
|
is_active: taxRegime.isActive,
|
||||||
|
is_system: taxRegime.isSystem,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export * from "./full-tax-regime-snapshot.builder";
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./full";
|
||||||
|
export * from "./summary";
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export * from "./summary-tax-regime-snapshot.builder";
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
import type { ISnapshotBuilder } from "@erp/core/api";
|
||||||
|
|
||||||
|
import type { TaxRegimeSummaryDTO } from "../../../../../common";
|
||||||
|
import type { TaxRegimeSummary } from "../../models";
|
||||||
|
|
||||||
|
export interface ITaxRegimeSummarySnapshotBuilder
|
||||||
|
extends ISnapshotBuilder<TaxRegimeSummary, TaxRegimeSummaryDTO> {}
|
||||||
|
|
||||||
|
export class TaxRegimeSummarySnapshotBuilder implements ITaxRegimeSummarySnapshotBuilder {
|
||||||
|
public toOutput(taxRegime: TaxRegimeSummary): TaxRegimeSummaryDTO {
|
||||||
|
return {
|
||||||
|
id: taxRegime.id.toString(),
|
||||||
|
company_id: taxRegime.companyId.toString(),
|
||||||
|
code: taxRegime.code.toPrimitive(),
|
||||||
|
description: taxRegime.description.toPrimitive(),
|
||||||
|
is_active: taxRegime.isActive,
|
||||||
|
is_system: taxRegime.isSystem,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
import type { CreateTaxRegimeRequestDTO } 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 { ICreateTaxRegimeInputMapper } from "../mappers";
|
||||||
|
import type { ITaxRegimeCreator } from "../services";
|
||||||
|
import type { ITaxRegimeFullSnapshotBuilder } from "../snapshot-builders";
|
||||||
|
|
||||||
|
export type CreateTaxRegimeUseCaseInput = {
|
||||||
|
companyId: UniqueID;
|
||||||
|
dto: CreateTaxRegimeRequestDTO;
|
||||||
|
};
|
||||||
|
|
||||||
|
type CreateTaxRegimeUseCaseDeps = {
|
||||||
|
dtoMapper: ICreateTaxRegimeInputMapper;
|
||||||
|
creator: ITaxRegimeCreator;
|
||||||
|
fullSnapshotBuilder: ITaxRegimeFullSnapshotBuilder;
|
||||||
|
transactionManager: ITransactionManager;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class CreateTaxRegimeUseCase {
|
||||||
|
constructor(private readonly deps: CreateTaxRegimeUseCaseDeps) {}
|
||||||
|
|
||||||
|
public execute(params: CreateTaxRegimeUseCaseInput) {
|
||||||
|
const { dto, companyId } = params;
|
||||||
|
|
||||||
|
const mappedPropsResult = this.deps.dtoMapper.map(dto, { companyId });
|
||||||
|
if (mappedPropsResult.isFailure) {
|
||||||
|
return mappedPropsResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { props, id } = mappedPropsResult.data;
|
||||||
|
|
||||||
|
return this.deps.transactionManager.complete(async (transaction: unknown) => {
|
||||||
|
try {
|
||||||
|
const createResult = await this.deps.creator.create({
|
||||||
|
companyId,
|
||||||
|
id,
|
||||||
|
props,
|
||||||
|
transaction,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (createResult.isFailure) {
|
||||||
|
return createResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
const snapshot = this.deps.fullSnapshotBuilder.toOutput(createResult.data);
|
||||||
|
return Result.ok(snapshot);
|
||||||
|
} catch (error: unknown) {
|
||||||
|
return Result.fail(error as Error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
import type { ITransactionManager } from "@erp/core/api";
|
||||||
|
import { UniqueID } from "@repo/rdx-ddd";
|
||||||
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
|
import type { ITaxRegimeDeleter, ITaxRegimeFinder } from "../services";
|
||||||
|
import type { ITaxRegimeFullSnapshotBuilder } from "../snapshot-builders";
|
||||||
|
|
||||||
|
export type DeleteTaxRegimeByIdUseCaseInput = {
|
||||||
|
companyId: UniqueID;
|
||||||
|
tax_regime_id: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class DeleteTaxRegimeByIdUseCase {
|
||||||
|
constructor(
|
||||||
|
private readonly deps: {
|
||||||
|
finder: ITaxRegimeFinder;
|
||||||
|
deleter: ITaxRegimeDeleter;
|
||||||
|
fullSnapshotBuilder: ITaxRegimeFullSnapshotBuilder;
|
||||||
|
transactionManager: ITransactionManager;
|
||||||
|
}
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public execute(params: DeleteTaxRegimeByIdUseCaseInput) {
|
||||||
|
const { tax_regime_id, companyId } = params;
|
||||||
|
|
||||||
|
const idOrError = UniqueID.create(tax_regime_id);
|
||||||
|
if (idOrError.isFailure) return Result.fail(idOrError.error);
|
||||||
|
|
||||||
|
const taxRegimeId = idOrError.data;
|
||||||
|
|
||||||
|
return this.deps.transactionManager.complete(async (transaction: unknown) => {
|
||||||
|
try {
|
||||||
|
const findResult = await this.deps.finder.findTaxRegimeById(
|
||||||
|
companyId,
|
||||||
|
taxRegimeId,
|
||||||
|
transaction
|
||||||
|
);
|
||||||
|
if (findResult.isFailure) {
|
||||||
|
return Result.fail(findResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteResult = await this.deps.deleter.delete({
|
||||||
|
taxRegime: findResult.data,
|
||||||
|
transaction,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (deleteResult.isFailure) {
|
||||||
|
return Result.fail(deleteResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok(this.deps.fullSnapshotBuilder.toOutput(deleteResult.data));
|
||||||
|
} catch (error: unknown) {
|
||||||
|
return Result.fail(error as Error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
import type { ITransactionManager } from "@erp/core/api";
|
||||||
|
import { UniqueID } from "@repo/rdx-ddd";
|
||||||
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
|
import type { ITaxRegimeFinder, ITaxRegimeStatusChanger } from "../services";
|
||||||
|
import type { ITaxRegimeFullSnapshotBuilder } from "../snapshot-builders";
|
||||||
|
|
||||||
|
export type DisableTaxRegimeByIdUseCaseInput = {
|
||||||
|
companyId: UniqueID;
|
||||||
|
tax_regime_id: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class DisableTaxRegimeByIdUseCase {
|
||||||
|
constructor(
|
||||||
|
private readonly deps: {
|
||||||
|
finder: ITaxRegimeFinder;
|
||||||
|
changer: ITaxRegimeStatusChanger;
|
||||||
|
fullSnapshotBuilder: ITaxRegimeFullSnapshotBuilder;
|
||||||
|
transactionManager: ITransactionManager;
|
||||||
|
}
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public execute(params: DisableTaxRegimeByIdUseCaseInput) {
|
||||||
|
const { tax_regime_id, companyId } = params;
|
||||||
|
|
||||||
|
const idOrError = UniqueID.create(tax_regime_id);
|
||||||
|
if (idOrError.isFailure) return Result.fail(idOrError.error);
|
||||||
|
|
||||||
|
const taxRegimeId = idOrError.data;
|
||||||
|
|
||||||
|
return this.deps.transactionManager.complete(async (transaction: unknown) => {
|
||||||
|
try {
|
||||||
|
const findResult = await this.deps.finder.findTaxRegimeById(
|
||||||
|
companyId,
|
||||||
|
taxRegimeId,
|
||||||
|
transaction
|
||||||
|
);
|
||||||
|
if (findResult.isFailure) {
|
||||||
|
return Result.fail(findResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const disableResult = await this.deps.changer.changeStatus({
|
||||||
|
taxRegime: findResult.data,
|
||||||
|
action: "disable",
|
||||||
|
transaction,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (disableResult.isFailure) {
|
||||||
|
return Result.fail(disableResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok(this.deps.fullSnapshotBuilder.toOutput(disableResult.data));
|
||||||
|
} catch (error: unknown) {
|
||||||
|
return Result.fail(error as Error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
import type { ITransactionManager } from "@erp/core/api";
|
||||||
|
import { UniqueID } from "@repo/rdx-ddd";
|
||||||
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
|
import type { ITaxRegimeFinder, ITaxRegimeStatusChanger } from "../services";
|
||||||
|
import type { ITaxRegimeFullSnapshotBuilder } from "../snapshot-builders";
|
||||||
|
|
||||||
|
export type EnableTaxRegimeByIdUseCaseInput = {
|
||||||
|
companyId: UniqueID;
|
||||||
|
tax_regime_id: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class EnableTaxRegimeByIdUseCase {
|
||||||
|
constructor(
|
||||||
|
private readonly deps: {
|
||||||
|
finder: ITaxRegimeFinder;
|
||||||
|
changer: ITaxRegimeStatusChanger;
|
||||||
|
fullSnapshotBuilder: ITaxRegimeFullSnapshotBuilder;
|
||||||
|
transactionManager: ITransactionManager;
|
||||||
|
}
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public execute(params: EnableTaxRegimeByIdUseCaseInput) {
|
||||||
|
const { tax_regime_id, companyId } = params;
|
||||||
|
|
||||||
|
const idOrError = UniqueID.create(tax_regime_id);
|
||||||
|
if (idOrError.isFailure) return Result.fail(idOrError.error);
|
||||||
|
|
||||||
|
const taxRegimeId = idOrError.data;
|
||||||
|
|
||||||
|
return this.deps.transactionManager.complete(async (transaction: unknown) => {
|
||||||
|
try {
|
||||||
|
const findResult = await this.deps.finder.findTaxRegimeById(
|
||||||
|
companyId,
|
||||||
|
taxRegimeId,
|
||||||
|
transaction
|
||||||
|
);
|
||||||
|
if (findResult.isFailure) {
|
||||||
|
return Result.fail(findResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const enableResult = await this.deps.changer.changeStatus({
|
||||||
|
taxRegime: findResult.data,
|
||||||
|
action: "enable",
|
||||||
|
transaction,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (enableResult.isFailure) {
|
||||||
|
return Result.fail(enableResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok(this.deps.fullSnapshotBuilder.toOutput(enableResult.data));
|
||||||
|
} catch (error: unknown) {
|
||||||
|
return Result.fail(error as Error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
import type { ITransactionManager } from "@erp/core/api";
|
||||||
|
import { UniqueID } from "@repo/rdx-ddd";
|
||||||
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
|
import type { ITaxRegimeFinder } from "../services";
|
||||||
|
import type { ITaxRegimeFullSnapshotBuilder } from "../snapshot-builders";
|
||||||
|
|
||||||
|
export type GetTaxRegimeByIdUseCaseInput = {
|
||||||
|
companyId: UniqueID;
|
||||||
|
tax_regime_id: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class GetTaxRegimeByIdUseCase {
|
||||||
|
constructor(
|
||||||
|
private readonly finder: ITaxRegimeFinder,
|
||||||
|
private readonly fullSnapshotBuilder: ITaxRegimeFullSnapshotBuilder,
|
||||||
|
private readonly transactionManager: ITransactionManager
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public execute(params: GetTaxRegimeByIdUseCaseInput) {
|
||||||
|
const { tax_regime_id, companyId } = params;
|
||||||
|
|
||||||
|
const idOrError = UniqueID.create(tax_regime_id);
|
||||||
|
if (idOrError.isFailure) {
|
||||||
|
return Result.fail(idOrError.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const taxRegimeId = idOrError.data;
|
||||||
|
|
||||||
|
return this.transactionManager.complete(async (transaction: unknown) => {
|
||||||
|
try {
|
||||||
|
const result = await this.finder.findTaxRegimeById(companyId, taxRegimeId, transaction);
|
||||||
|
|
||||||
|
if (result.isFailure) {
|
||||||
|
return Result.fail(result.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok(this.fullSnapshotBuilder.toOutput(result.data));
|
||||||
|
} catch (error: unknown) {
|
||||||
|
return Result.fail(error as Error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
export * from "./create-tax-regime.use-case";
|
||||||
|
export * from "./delete-tax-regime-by-id.use-case";
|
||||||
|
export * from "./disable-tax-regime-by-id.use-case";
|
||||||
|
export * from "./enable-tax-regime-by-id.use-case";
|
||||||
|
export * from "./get-tax-regime-by-id.use-case";
|
||||||
|
export * from "./list-tax-regimes.use-case";
|
||||||
|
export * from "./update-tax-regime-by-id.use-case";
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
import type { ITransactionManager } from "@erp/core/api";
|
||||||
|
import type { Criteria } from "@repo/rdx-criteria/server";
|
||||||
|
import type { UniqueID } from "@repo/rdx-ddd";
|
||||||
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
|
import type { ITaxRegimeFinder } from "../services";
|
||||||
|
import type { ITaxRegimeSummarySnapshotBuilder } from "../snapshot-builders";
|
||||||
|
|
||||||
|
type ListTaxRegimesUseCaseInput = {
|
||||||
|
companyId: UniqueID;
|
||||||
|
criteria: Criteria;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class ListTaxRegimesUseCase {
|
||||||
|
constructor(
|
||||||
|
private readonly finder: ITaxRegimeFinder,
|
||||||
|
private readonly summarySnapshotBuilder: ITaxRegimeSummarySnapshotBuilder,
|
||||||
|
private readonly transactionManager: ITransactionManager
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public execute(params: ListTaxRegimesUseCaseInput) {
|
||||||
|
const { criteria, companyId } = params;
|
||||||
|
|
||||||
|
return this.transactionManager.complete(async (transaction: unknown) => {
|
||||||
|
try {
|
||||||
|
const result = await this.finder.findTaxRegimesByCriteria(companyId, criteria, transaction);
|
||||||
|
|
||||||
|
if (result.isFailure) {
|
||||||
|
return Result.fail(result.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const taxRegimes = result.data;
|
||||||
|
const totalItems = taxRegimes.total();
|
||||||
|
|
||||||
|
const items = taxRegimes.map((item) => this.summarySnapshotBuilder.toOutput(item));
|
||||||
|
|
||||||
|
const snapshot = {
|
||||||
|
page: criteria.pageNumber,
|
||||||
|
per_page: criteria.pageSize,
|
||||||
|
total_pages: Math.ceil(totalItems / criteria.pageSize),
|
||||||
|
total_items: totalItems,
|
||||||
|
items,
|
||||||
|
metadata: {
|
||||||
|
entity: "tax_regimes",
|
||||||
|
criteria: criteria.toJSON(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return Result.ok(snapshot);
|
||||||
|
} catch (error: unknown) {
|
||||||
|
return Result.fail(error as Error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
import type { UpdateTaxRegimeByIdRequestDTO } from "@erp/catalogs/common";
|
||||||
|
import type { ITransactionManager } from "@erp/core/api";
|
||||||
|
import { UniqueID } from "@repo/rdx-ddd";
|
||||||
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
|
import type { IUpdateTaxRegimeInputMapper } from "../mappers";
|
||||||
|
import type { ITaxRegimeFinder, ITaxRegimeUpdater } from "../services";
|
||||||
|
import type { ITaxRegimeFullSnapshotBuilder } from "../snapshot-builders";
|
||||||
|
|
||||||
|
export type UpdateTaxRegimeByIdUseCaseInput = {
|
||||||
|
companyId: UniqueID;
|
||||||
|
tax_regime_id: string;
|
||||||
|
dto: UpdateTaxRegimeByIdRequestDTO;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class UpdateTaxRegimeByIdUseCase {
|
||||||
|
constructor(
|
||||||
|
private readonly deps: {
|
||||||
|
updater: ITaxRegimeUpdater;
|
||||||
|
finder: ITaxRegimeFinder;
|
||||||
|
dtoMapper: IUpdateTaxRegimeInputMapper;
|
||||||
|
fullSnapshotBuilder: ITaxRegimeFullSnapshotBuilder;
|
||||||
|
transactionManager: ITransactionManager;
|
||||||
|
}
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public execute(params: UpdateTaxRegimeByIdUseCaseInput) {
|
||||||
|
const { companyId, tax_regime_id, dto } = params;
|
||||||
|
|
||||||
|
const idOrError = UniqueID.create(tax_regime_id);
|
||||||
|
if (idOrError.isFailure) {
|
||||||
|
return Result.fail(idOrError.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const taxRegimeId = idOrError.data;
|
||||||
|
|
||||||
|
const patchPropsResult = this.deps.dtoMapper.map(dto, { companyId });
|
||||||
|
if (patchPropsResult.isFailure) {
|
||||||
|
return patchPropsResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
const patchProps = patchPropsResult.data;
|
||||||
|
|
||||||
|
return this.deps.transactionManager.complete(async (transaction: unknown) => {
|
||||||
|
try {
|
||||||
|
const updateResult = await this.deps.updater.update({
|
||||||
|
companyId,
|
||||||
|
id: taxRegimeId,
|
||||||
|
patchProps,
|
||||||
|
transaction,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (updateResult.isFailure) {
|
||||||
|
return Result.fail(updateResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok(this.deps.fullSnapshotBuilder.toOutput(updateResult.data));
|
||||||
|
} catch (error: unknown) {
|
||||||
|
return Result.fail(error as Error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,2 +1,3 @@
|
|||||||
export * from "./payment-methods";
|
export * from "./payment-methods";
|
||||||
export * from "./payment-terms";
|
export * from "./payment-terms";
|
||||||
|
export * from "./tax-regimes";
|
||||||
|
|||||||
@ -154,7 +154,7 @@ export class PaymentTerm extends AggregateRoot<PaymentTermInternalProps> {
|
|||||||
return this._dueRules;
|
return this._dueRules;
|
||||||
}
|
}
|
||||||
|
|
||||||
public update(patchProps: PaymentTermPatchProps): Result<void, Error> {
|
public update(patchProps: PaymentTermPatchProps): Result<boolean, Error> {
|
||||||
if (this.isSystem) {
|
if (this.isSystem) {
|
||||||
return Result.fail(
|
return Result.fail(
|
||||||
new PaymentTermCannotBeUpdatedError("System payment terms cannot be updated.")
|
new PaymentTermCannotBeUpdatedError("System payment terms cannot be updated.")
|
||||||
@ -166,6 +166,7 @@ export class PaymentTerm extends AggregateRoot<PaymentTermInternalProps> {
|
|||||||
return Result.fail(validationResult.error);
|
return Result.fail(validationResult.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let hasChanges = false;
|
||||||
const { dueRules, ...otherProps } = patchProps;
|
const { dueRules, ...otherProps } = patchProps;
|
||||||
|
|
||||||
const candidateProps: PaymentTermInternalProps = {
|
const candidateProps: PaymentTermInternalProps = {
|
||||||
@ -175,6 +176,7 @@ export class PaymentTerm extends AggregateRoot<PaymentTermInternalProps> {
|
|||||||
|
|
||||||
// Aplicar cambios
|
// Aplicar cambios
|
||||||
Object.assign(this.props, candidateProps);
|
Object.assign(this.props, candidateProps);
|
||||||
|
hasChanges = true;
|
||||||
|
|
||||||
// Reemplazo de items (si se proporciona)
|
// Reemplazo de items (si se proporciona)
|
||||||
if (patchProps.dueRules !== undefined) {
|
if (patchProps.dueRules !== undefined) {
|
||||||
@ -184,7 +186,7 @@ export class PaymentTerm extends AggregateRoot<PaymentTermInternalProps> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.ok();
|
return Result.ok(hasChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
public disable(): Result<boolean, Error> {
|
public disable(): Result<boolean, Error> {
|
||||||
|
|||||||
66
modules/catalogs/src/api/domain/tax-regimes/errors.ts
Normal file
66
modules/catalogs/src/api/domain/tax-regimes/errors.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import { DomainError } from "@repo/rdx-ddd";
|
||||||
|
|
||||||
|
export class InvalidTaxRegimeIdError extends DomainError {
|
||||||
|
public readonly code = "TAX_REGIME_INVALID_ID" as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isInvalidTaxRegimeIdError = (e: unknown): e is InvalidTaxRegimeIdError =>
|
||||||
|
e instanceof InvalidTaxRegimeIdError;
|
||||||
|
|
||||||
|
export class InvalidTaxRegimeCodeError extends DomainError {
|
||||||
|
public readonly code = "TAX_REGIME_INVALID_CODE" as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isInvalidTaxRegimeCodeError = (e: unknown): e is InvalidTaxRegimeCodeError =>
|
||||||
|
e instanceof InvalidTaxRegimeCodeError;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
export class InvalidTaxRegimeDescriptionError extends DomainError {
|
||||||
|
public readonly code = "TAX_REGIME_DESCRIPTION" as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isInvalidTaxRegimeDescriptionError = (
|
||||||
|
e: unknown
|
||||||
|
): e is InvalidTaxRegimeDescriptionError => e instanceof InvalidTaxRegimeDescriptionError;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
export class TaxRegimeNotFoundError extends DomainError {
|
||||||
|
public readonly code = "TAX_REGIME_NOT_FOUND" as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isTaxRegimeNotFoundError = (e: unknown): e is TaxRegimeNotFoundError =>
|
||||||
|
e instanceof TaxRegimeNotFoundError;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
export class TaxRegimeCannotBeDeletedError extends DomainError {
|
||||||
|
public readonly code = "TAX_REGIME_CANNOT_BE_DELETED" as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isTaxRegimeCannotBeDeletedError = (e: unknown): e is TaxRegimeCannotBeDeletedError =>
|
||||||
|
e instanceof TaxRegimeCannotBeDeletedError;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
export class TaxRegimeCannotBeUpdatedError extends DomainError {
|
||||||
|
public readonly code = "TAX_REGIME_CANNOT_BE_UPDATED" as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isTaxRegimeCannotBeUpdatedError = (e: unknown): e is TaxRegimeCannotBeUpdatedError =>
|
||||||
|
e instanceof TaxRegimeCannotBeUpdatedError;
|
||||||
|
|
||||||
|
export class TaxRegimeCannotBeEnabledError extends DomainError {
|
||||||
|
public readonly code = "TAX_REGIME_CANNOT_BE_ENABLED" as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isTaxRegimeCannotBeEnabledError = (e: unknown): e is TaxRegimeCannotBeEnabledError =>
|
||||||
|
e instanceof TaxRegimeCannotBeEnabledError;
|
||||||
|
|
||||||
|
export class TaxRegimeCannotBeDisabledError extends DomainError {
|
||||||
|
public readonly code = "TAX_REGIME_CANNOT_BE_DISABLED" as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isTaxRegimeCannotBeDisabledError = (e: unknown): e is TaxRegimeCannotBeDisabledError =>
|
||||||
|
e instanceof TaxRegimeCannotBeDisabledError;
|
||||||
3
modules/catalogs/src/api/domain/tax-regimes/index.ts
Normal file
3
modules/catalogs/src/api/domain/tax-regimes/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from "./errors";
|
||||||
|
export * from "./tax-regime.aggregate";
|
||||||
|
export * from "./tax-regime-code";
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
|
import { InvalidTaxRegimeCodeError } from "./errors";
|
||||||
|
|
||||||
|
export class TaxRegimeCode {
|
||||||
|
private constructor(private readonly value: string) {}
|
||||||
|
|
||||||
|
public static create(code: string): Result<TaxRegimeCode, Error> {
|
||||||
|
const trimmed = code?.trim() ?? "";
|
||||||
|
if (trimmed.length === 0) {
|
||||||
|
return Result.fail(new InvalidTaxRegimeCodeError("Tax regime code cannot be empty"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok(new TaxRegimeCode(trimmed));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static fromPersistence(code: string): TaxRegimeCode {
|
||||||
|
return new TaxRegimeCode(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
public toString(): string {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public toPrimitive(): string {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,158 @@
|
|||||||
|
import { AggregateRoot, type TextValue, type UniqueID } from "@repo/rdx-ddd";
|
||||||
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
|
import { TaxRegimeCannotBeUpdatedError } from "./errors";
|
||||||
|
import type { TaxRegimeCode } from "./tax-regime-code";
|
||||||
|
|
||||||
|
export interface ITaxRegimeCreateProps {
|
||||||
|
companyId: UniqueID;
|
||||||
|
code: TaxRegimeCode;
|
||||||
|
description: TextValue;
|
||||||
|
isActive: boolean;
|
||||||
|
isSystem: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TaxRegimePatchProps = Partial<{
|
||||||
|
description: TextValue;
|
||||||
|
isActive: boolean;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export type TaxRegimeInternalProps = ITaxRegimeCreateProps;
|
||||||
|
|
||||||
|
export class TaxRegime extends AggregateRoot<TaxRegimeInternalProps> {
|
||||||
|
protected constructor(props: TaxRegimeInternalProps, id?: UniqueID) {
|
||||||
|
super(props, id); // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||||
|
}
|
||||||
|
|
||||||
|
public static create(props: ITaxRegimeCreateProps, id?: UniqueID): Result<TaxRegime, Error> {
|
||||||
|
const validationResult = TaxRegime.validateCreateProps(props);
|
||||||
|
|
||||||
|
if (validationResult.isFailure) {
|
||||||
|
return Result.fail(validationResult.error);
|
||||||
|
}
|
||||||
|
// Crear instancia
|
||||||
|
const taxRegime = new TaxRegime(props, id);
|
||||||
|
|
||||||
|
// Disparar eventos de dominio
|
||||||
|
// ...
|
||||||
|
// ...
|
||||||
|
|
||||||
|
return Result.ok(taxRegime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static rehydrate(props: TaxRegimeInternalProps, id: UniqueID): TaxRegime {
|
||||||
|
return new TaxRegime(props, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static validateCreateProps(props: ITaxRegimeCreateProps): Result<void, Error> {
|
||||||
|
if (!props.companyId) {
|
||||||
|
return Result.fail(new Error("Payment term company ID is required"));
|
||||||
|
}
|
||||||
|
if (!props.code) {
|
||||||
|
return Result.fail(new Error("Tax regime code is required"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static validatePatchProps(patchProps: TaxRegimePatchProps): Result<void, Error> {
|
||||||
|
if (Object.keys(patchProps).length === 0) {
|
||||||
|
return Result.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
public get companyId(): UniqueID {
|
||||||
|
return this.props.companyId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get code(): TaxRegimeCode {
|
||||||
|
return this.props.code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get description(): TextValue {
|
||||||
|
return this.props.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isActive(): boolean {
|
||||||
|
return this.props.isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isSystem(): boolean {
|
||||||
|
return this.props.isSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public update(patchProps: TaxRegimePatchProps): Result<boolean, Error> {
|
||||||
|
if (this.isSystem) {
|
||||||
|
return Result.fail(
|
||||||
|
new TaxRegimeCannotBeUpdatedError("System tax regimes cannot be updated.")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const validationResult = TaxRegime.validatePatchProps(patchProps);
|
||||||
|
if (validationResult.isFailure) {
|
||||||
|
return Result.fail(validationResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
let hasChanges = false;
|
||||||
|
|
||||||
|
if (patchProps.description !== undefined) {
|
||||||
|
if (!TaxRegime.sameDescription(this.props.description, patchProps.description)) {
|
||||||
|
this.props.description = patchProps.description;
|
||||||
|
hasChanges = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (patchProps.isActive !== undefined && this.props.isActive !== patchProps.isActive) {
|
||||||
|
this.props.isActive = patchProps.isActive;
|
||||||
|
hasChanges = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok(hasChanges);
|
||||||
|
}
|
||||||
|
|
||||||
|
public disable(): Result<boolean, Error> {
|
||||||
|
if (this.isSystem) {
|
||||||
|
return Result.fail(
|
||||||
|
new TaxRegimeCannotBeUpdatedError("System tax regimes cannot be disabled.")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.isActive) {
|
||||||
|
return Result.ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props.isActive = false;
|
||||||
|
|
||||||
|
return Result.ok(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enable(): Result<boolean, Error> {
|
||||||
|
if (this.isSystem) {
|
||||||
|
return Result.ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isActive) {
|
||||||
|
return Result.ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props.isActive = true;
|
||||||
|
|
||||||
|
return Result.ok(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public toJSON() {
|
||||||
|
return {
|
||||||
|
id: this.id.toPrimitive(),
|
||||||
|
code: this.code.toPrimitive(),
|
||||||
|
description: this.description.toPrimitive(),
|
||||||
|
is_active: this.isActive,
|
||||||
|
is_system: this.isSystem,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static sameDescription(current: TextValue, next: TextValue): boolean {
|
||||||
|
return current.toPrimitive() === next.toPrimitive();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,6 +5,8 @@ import {
|
|||||||
paymentMethodsRouter,
|
paymentMethodsRouter,
|
||||||
paymentTermModels,
|
paymentTermModels,
|
||||||
paymentTermsRouter,
|
paymentTermsRouter,
|
||||||
|
taxRegimeModels,
|
||||||
|
taxRegimesRouter,
|
||||||
} from "./infrastructure";
|
} from "./infrastructure";
|
||||||
import {
|
import {
|
||||||
buildCatalogsDependencies,
|
buildCatalogsDependencies,
|
||||||
@ -27,10 +29,11 @@ export const catalogsAPIModule: IModuleServer = {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
models: [...paymentMethodModels, ...paymentTermModels],
|
models: [...paymentMethodModels, ...paymentTermModels, ...taxRegimeModels],
|
||||||
services: {
|
services: {
|
||||||
paymentMethod: publicServices.paymentMethods,
|
paymentMethod: publicServices.paymentMethods,
|
||||||
paymentTerms: publicServices.paymentTerms,
|
paymentTerms: publicServices.paymentTerms,
|
||||||
|
taxRegimes: publicServices.taxRegimes,
|
||||||
},
|
},
|
||||||
internal,
|
internal,
|
||||||
};
|
};
|
||||||
@ -41,6 +44,7 @@ export const catalogsAPIModule: IModuleServer = {
|
|||||||
|
|
||||||
paymentMethodsRouter(params);
|
paymentMethodsRouter(params);
|
||||||
paymentTermsRouter(params);
|
paymentTermsRouter(params);
|
||||||
|
taxRegimesRouter(params);
|
||||||
|
|
||||||
logger.info("🚀 Catalogs module started", {
|
logger.info("🚀 Catalogs module started", {
|
||||||
label: this.name,
|
label: this.name,
|
||||||
|
|||||||
@ -10,16 +10,23 @@ import {
|
|||||||
buildPaymentTermsDependencies,
|
buildPaymentTermsDependencies,
|
||||||
buildPaymentTermsPublicServices,
|
buildPaymentTermsPublicServices,
|
||||||
} from "../payment-terms/di";
|
} from "../payment-terms/di";
|
||||||
|
import {
|
||||||
|
type TaxRegimesInternalDeps,
|
||||||
|
buildTaxRegimesDependencies,
|
||||||
|
buildTaxRegimesPublicServices,
|
||||||
|
} from "../tax-regimes/di";
|
||||||
|
|
||||||
export type CatalogsInternalDeps = {
|
export type CatalogsInternalDeps = {
|
||||||
paymentMethods: PaymentMethodsInternalDeps;
|
paymentMethods: PaymentMethodsInternalDeps;
|
||||||
paymentTerms: PaymentTermsInternalDeps;
|
paymentTerms: PaymentTermsInternalDeps;
|
||||||
|
taxRegimes: TaxRegimesInternalDeps;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const buildCatalogsDependencies = (params: ModuleParams): CatalogsInternalDeps => {
|
export const buildCatalogsDependencies = (params: ModuleParams): CatalogsInternalDeps => {
|
||||||
return {
|
return {
|
||||||
paymentMethods: buildPaymentMethodsDependencies(params),
|
paymentMethods: buildPaymentMethodsDependencies(params),
|
||||||
paymentTerms: buildPaymentTermsDependencies(params),
|
paymentTerms: buildPaymentTermsDependencies(params),
|
||||||
|
taxRegimes: buildTaxRegimesDependencies(params),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -27,5 +34,6 @@ export const buildCatalogsPublicServices = (params: SetupParams, deps: CatalogsI
|
|||||||
return {
|
return {
|
||||||
paymentMethods: buildPaymentMethodsPublicServices(params, deps.paymentMethods),
|
paymentMethods: buildPaymentMethodsPublicServices(params, deps.paymentMethods),
|
||||||
paymentTerms: buildPaymentTermsPublicServices(params, deps.paymentTerms),
|
paymentTerms: buildPaymentTermsPublicServices(params, deps.paymentTerms),
|
||||||
|
taxRegimes: buildTaxRegimesPublicServices(params, deps.taxRegimes),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,2 +1,3 @@
|
|||||||
export * from "./payment-methods";
|
export * from "./payment-methods";
|
||||||
export * from "./payment-terms";
|
export * from "./payment-terms";
|
||||||
|
export * from "./tax-regimes";
|
||||||
|
|||||||
@ -1,13 +1,11 @@
|
|||||||
import {
|
import {
|
||||||
SequelizePaymentMethodDomainMapper,
|
SequelizePaymentMethodDomainMapper,
|
||||||
SequelizePaymentMethodSummaryMapper,
|
SequelizePaymentMethodSummaryMapper,
|
||||||
} from "../persistence/index";
|
} from "../persistence";
|
||||||
|
|
||||||
export interface IPaymentMethodPersistenceMappers {
|
export interface IPaymentMethodPersistenceMappers {
|
||||||
domainMapper: SequelizePaymentMethodDomainMapper;
|
domainMapper: SequelizePaymentMethodDomainMapper;
|
||||||
listMapper: SequelizePaymentMethodSummaryMapper;
|
listMapper: SequelizePaymentMethodSummaryMapper;
|
||||||
|
|
||||||
//createMapper: CreatePaymentMethodRequestMapper;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const buildPaymentMethodPersistenceMappers = (): IPaymentMethodPersistenceMappers => {
|
export const buildPaymentMethodPersistenceMappers = (): IPaymentMethodPersistenceMappers => {
|
||||||
@ -15,13 +13,8 @@ export const buildPaymentMethodPersistenceMappers = (): IPaymentMethodPersistenc
|
|||||||
const domainMapper = new SequelizePaymentMethodDomainMapper();
|
const domainMapper = new SequelizePaymentMethodDomainMapper();
|
||||||
const listMapper = new SequelizePaymentMethodSummaryMapper();
|
const listMapper = new SequelizePaymentMethodSummaryMapper();
|
||||||
|
|
||||||
// Mappers el DTO a las props validadas (CustomerProps) y luego construir agregado
|
|
||||||
//const createMapper = new CreatePaymentMethodRequestMapper(catalogs);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
domainMapper,
|
domainMapper,
|
||||||
listMapper,
|
listMapper,
|
||||||
|
|
||||||
//createMapper,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -173,8 +173,6 @@ export class SequelizePaymentMethodRepository
|
|||||||
strictMode: true, // fuerza error si ORDER BY no permitido
|
strictMode: true, // fuerza error si ORDER BY no permitido
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(query?.where);
|
|
||||||
|
|
||||||
query.where = {
|
query.where = {
|
||||||
...query.where,
|
...query.where,
|
||||||
company_id: companyId.toString(),
|
company_id: companyId.toString(),
|
||||||
|
|||||||
@ -0,0 +1,3 @@
|
|||||||
|
export * from "./tax-regime-persistence-mappers.di";
|
||||||
|
export * from "./tax-regime-repositories.di";
|
||||||
|
export * from "./tax-regimes.di";
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
import { SequelizeTaxRegimeDomainMapper, SequelizeTaxRegimeSummaryMapper } from "../persistence";
|
||||||
|
|
||||||
|
export interface ITaxRegimePersistenceMappers {
|
||||||
|
domainMapper: SequelizeTaxRegimeDomainMapper;
|
||||||
|
listMapper: SequelizeTaxRegimeSummaryMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const buildTaxRegimePersistenceMappers = (): ITaxRegimePersistenceMappers => {
|
||||||
|
// Mappers para el repositorio
|
||||||
|
const domainMapper = new SequelizeTaxRegimeDomainMapper();
|
||||||
|
const listMapper = new SequelizeTaxRegimeSummaryMapper();
|
||||||
|
|
||||||
|
return {
|
||||||
|
domainMapper,
|
||||||
|
listMapper,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
import type { Sequelize } from "sequelize";
|
||||||
|
|
||||||
|
import { SequelizeTaxRegimeRepository } from "../persistence";
|
||||||
|
|
||||||
|
import type { ITaxRegimePersistenceMappers } from "./tax-regime-persistence-mappers.di";
|
||||||
|
|
||||||
|
export const buildTaxRegimeRepository = (params: {
|
||||||
|
database: Sequelize;
|
||||||
|
mappers: ITaxRegimePersistenceMappers;
|
||||||
|
}) => {
|
||||||
|
const { database, mappers } = params;
|
||||||
|
return new SequelizeTaxRegimeRepository(mappers.domainMapper, mappers.listMapper, database);
|
||||||
|
};
|
||||||
@ -0,0 +1,119 @@
|
|||||||
|
import type { ModuleParams, SetupParams } from "@erp/core/api";
|
||||||
|
import { buildTransactionManager } from "@erp/core/api";
|
||||||
|
import type { Sequelize } from "sequelize";
|
||||||
|
|
||||||
|
import type { ITaxRegimeRepository } from "../../../application/";
|
||||||
|
import { TaxRegimeFinder } from "../../../application/";
|
||||||
|
import {
|
||||||
|
CreateTaxRegimeUseCase,
|
||||||
|
DeleteTaxRegimeByIdUseCase,
|
||||||
|
DisableTaxRegimeByIdUseCase,
|
||||||
|
EnableTaxRegimeByIdUseCase,
|
||||||
|
GetTaxRegimeByIdUseCase,
|
||||||
|
ListTaxRegimesUseCase,
|
||||||
|
UpdateTaxRegimeByIdUseCase,
|
||||||
|
} from "../../../application/tax-regimes";
|
||||||
|
import {
|
||||||
|
buildTaxRegimeCreator,
|
||||||
|
buildTaxRegimeDeleter,
|
||||||
|
buildTaxRegimeFinder,
|
||||||
|
buildTaxRegimeInputMappers,
|
||||||
|
buildTaxRegimeSnapshotBuilders,
|
||||||
|
buildTaxRegimeStatusChanger,
|
||||||
|
buildTaxRegimeUpdater,
|
||||||
|
} from "../../../application/tax-regimes/di";
|
||||||
|
|
||||||
|
import { buildTaxRegimePersistenceMappers } from "./tax-regime-persistence-mappers.di";
|
||||||
|
import { buildTaxRegimeRepository } from "./tax-regime-repositories.di";
|
||||||
|
|
||||||
|
export type TaxRegimesInternalDeps = {
|
||||||
|
repository: ITaxRegimeRepository;
|
||||||
|
useCases: {
|
||||||
|
listTaxRegimes: () => ListTaxRegimesUseCase;
|
||||||
|
getTaxRegimeById: () => GetTaxRegimeByIdUseCase;
|
||||||
|
createTaxRegime: () => CreateTaxRegimeUseCase;
|
||||||
|
updateTaxRegimeById: () => UpdateTaxRegimeByIdUseCase;
|
||||||
|
deleteTaxRegimeById: () => DeleteTaxRegimeByIdUseCase;
|
||||||
|
disableTaxRegimeById: () => DisableTaxRegimeByIdUseCase;
|
||||||
|
enableTaxRegimeById: () => EnableTaxRegimeByIdUseCase;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const buildTaxRegimesDependencies = (params: ModuleParams): TaxRegimesInternalDeps => {
|
||||||
|
const { database } = params;
|
||||||
|
|
||||||
|
const transactionManager = buildTransactionManager(database as Sequelize);
|
||||||
|
const persistenceMappers = buildTaxRegimePersistenceMappers();
|
||||||
|
|
||||||
|
const repository = buildTaxRegimeRepository({ database, mappers: persistenceMappers });
|
||||||
|
|
||||||
|
const inputMappers = buildTaxRegimeInputMappers();
|
||||||
|
|
||||||
|
const finder = buildTaxRegimeFinder({ repository });
|
||||||
|
const creator = buildTaxRegimeCreator({ repository });
|
||||||
|
const updater = buildTaxRegimeUpdater({ repository });
|
||||||
|
const deleter = buildTaxRegimeDeleter({ repository });
|
||||||
|
const statusChanger = buildTaxRegimeStatusChanger({ repository });
|
||||||
|
|
||||||
|
const snapshotBuilders = buildTaxRegimeSnapshotBuilders();
|
||||||
|
return {
|
||||||
|
repository,
|
||||||
|
useCases: {
|
||||||
|
listTaxRegimes: () =>
|
||||||
|
new ListTaxRegimesUseCase(finder, snapshotBuilders.summary, transactionManager),
|
||||||
|
|
||||||
|
getTaxRegimeById: () =>
|
||||||
|
new GetTaxRegimeByIdUseCase(finder, snapshotBuilders.full, transactionManager),
|
||||||
|
|
||||||
|
createTaxRegime: () =>
|
||||||
|
new CreateTaxRegimeUseCase({
|
||||||
|
dtoMapper: inputMappers.createInputMapper,
|
||||||
|
creator,
|
||||||
|
fullSnapshotBuilder: snapshotBuilders.full,
|
||||||
|
transactionManager,
|
||||||
|
}),
|
||||||
|
|
||||||
|
updateTaxRegimeById: () =>
|
||||||
|
new UpdateTaxRegimeByIdUseCase({
|
||||||
|
updater,
|
||||||
|
finder,
|
||||||
|
dtoMapper: inputMappers.updateInputMapper,
|
||||||
|
fullSnapshotBuilder: snapshotBuilders.full,
|
||||||
|
transactionManager,
|
||||||
|
}),
|
||||||
|
|
||||||
|
deleteTaxRegimeById: () =>
|
||||||
|
new DeleteTaxRegimeByIdUseCase({
|
||||||
|
deleter,
|
||||||
|
finder,
|
||||||
|
fullSnapshotBuilder: snapshotBuilders.full,
|
||||||
|
transactionManager,
|
||||||
|
}),
|
||||||
|
|
||||||
|
disableTaxRegimeById: () =>
|
||||||
|
new DisableTaxRegimeByIdUseCase({
|
||||||
|
finder,
|
||||||
|
changer: statusChanger,
|
||||||
|
fullSnapshotBuilder: snapshotBuilders.full,
|
||||||
|
transactionManager,
|
||||||
|
}),
|
||||||
|
|
||||||
|
enableTaxRegimeById: () =>
|
||||||
|
new EnableTaxRegimeByIdUseCase({
|
||||||
|
finder,
|
||||||
|
changer: statusChanger,
|
||||||
|
fullSnapshotBuilder: snapshotBuilders.full,
|
||||||
|
transactionManager,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const buildTaxRegimesPublicServices = (
|
||||||
|
_params: SetupParams,
|
||||||
|
deps: TaxRegimesInternalDeps
|
||||||
|
): { finder: TaxRegimeFinder } => {
|
||||||
|
return {
|
||||||
|
finder: new TaxRegimeFinder(deps.repository),
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
import type { CreateTaxRegimeRequestDTO } from "@erp/catalogs/common";
|
||||||
|
import {
|
||||||
|
ExpressController,
|
||||||
|
forbidQueryFieldGuard,
|
||||||
|
requireAuthenticatedGuard,
|
||||||
|
requireCompanyContextGuard,
|
||||||
|
} from "@erp/core/api";
|
||||||
|
|
||||||
|
import type { CreateTaxRegimeUseCase } from "../../../../application/tax-regimes";
|
||||||
|
import { taxRegimesApiErrorMapper } from "../tax-regime-api-error-mapper";
|
||||||
|
|
||||||
|
export class CreateTaxRegimeController extends ExpressController {
|
||||||
|
constructor(private readonly useCase: CreateTaxRegimeUseCase) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.errorMapper = taxRegimesApiErrorMapper;
|
||||||
|
|
||||||
|
this.registerGuards(
|
||||||
|
requireAuthenticatedGuard(),
|
||||||
|
requireCompanyContextGuard(),
|
||||||
|
forbidQueryFieldGuard("companyId")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async executeImpl() {
|
||||||
|
const companyId = this.getTenantId();
|
||||||
|
if (!companyId) {
|
||||||
|
return this.forbiddenError("Tenant ID not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
const dto = this.req.body satisfies CreateTaxRegimeRequestDTO;
|
||||||
|
const result = await this.useCase.execute({ dto, companyId });
|
||||||
|
|
||||||
|
return result.match(
|
||||||
|
(data: unknown) => this.created(data),
|
||||||
|
(err: Error) => this.handleError(err)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
import {
|
||||||
|
ExpressController,
|
||||||
|
forbidQueryFieldGuard,
|
||||||
|
requireAuthenticatedGuard,
|
||||||
|
requireCompanyContextGuard,
|
||||||
|
} from "@erp/core/api";
|
||||||
|
|
||||||
|
import type { DeleteTaxRegimeByIdUseCase } from "../../../../application";
|
||||||
|
import { taxRegimesApiErrorMapper } from "../tax-regime-api-error-mapper";
|
||||||
|
|
||||||
|
export class DeleteTaxRegimeByIdController extends ExpressController {
|
||||||
|
constructor(private readonly useCase: DeleteTaxRegimeByIdUseCase) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.errorMapper = taxRegimesApiErrorMapper;
|
||||||
|
|
||||||
|
this.registerGuards(
|
||||||
|
requireAuthenticatedGuard(),
|
||||||
|
requireCompanyContextGuard(),
|
||||||
|
forbidQueryFieldGuard("companyId")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async executeImpl() {
|
||||||
|
const companyId = this.getTenantId();
|
||||||
|
if (!companyId) {
|
||||||
|
return this.forbiddenError("Tenant ID not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
const { tax_regime_id } = this.req.params;
|
||||||
|
const result = await this.useCase.execute({ tax_regime_id, companyId });
|
||||||
|
|
||||||
|
return result.match(
|
||||||
|
(data: unknown) => this.ok(data),
|
||||||
|
(err: Error) => this.handleError(err)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
import {
|
||||||
|
ExpressController,
|
||||||
|
forbidQueryFieldGuard,
|
||||||
|
requireAuthenticatedGuard,
|
||||||
|
requireCompanyContextGuard,
|
||||||
|
} from "@erp/core/api";
|
||||||
|
|
||||||
|
import type { DisableTaxRegimeByIdUseCase } from "../../../../application";
|
||||||
|
import { taxRegimesApiErrorMapper } from "../tax-regime-api-error-mapper";
|
||||||
|
|
||||||
|
export class DisableTaxRegimeByIdController extends ExpressController {
|
||||||
|
constructor(private readonly useCase: DisableTaxRegimeByIdUseCase) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.errorMapper = taxRegimesApiErrorMapper;
|
||||||
|
|
||||||
|
this.registerGuards(
|
||||||
|
requireAuthenticatedGuard(),
|
||||||
|
requireCompanyContextGuard(),
|
||||||
|
forbidQueryFieldGuard("companyId")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async executeImpl() {
|
||||||
|
const companyId = this.getTenantId();
|
||||||
|
if (!companyId) {
|
||||||
|
return this.forbiddenError("Tenant ID not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
const { tax_regime_id } = this.req.params;
|
||||||
|
const result = await this.useCase.execute({ tax_regime_id, companyId });
|
||||||
|
|
||||||
|
return result.match(
|
||||||
|
(data: unknown) => this.ok(data),
|
||||||
|
(err: Error) => this.handleError(err)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
import {
|
||||||
|
ExpressController,
|
||||||
|
forbidQueryFieldGuard,
|
||||||
|
requireAuthenticatedGuard,
|
||||||
|
requireCompanyContextGuard,
|
||||||
|
} from "@erp/core/api";
|
||||||
|
|
||||||
|
import type { EnableTaxRegimeByIdUseCase } from "../../../../application";
|
||||||
|
import { taxRegimesApiErrorMapper } from "../tax-regime-api-error-mapper";
|
||||||
|
|
||||||
|
export class EnableTaxRegimeByIdController extends ExpressController {
|
||||||
|
constructor(private readonly useCase: EnableTaxRegimeByIdUseCase) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.errorMapper = taxRegimesApiErrorMapper;
|
||||||
|
|
||||||
|
this.registerGuards(
|
||||||
|
requireAuthenticatedGuard(),
|
||||||
|
requireCompanyContextGuard(),
|
||||||
|
forbidQueryFieldGuard("companyId")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async executeImpl() {
|
||||||
|
const companyId = this.getTenantId();
|
||||||
|
if (!companyId) {
|
||||||
|
return this.forbiddenError("Tenant ID not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
const { tax_regime_id } = this.req.params;
|
||||||
|
const result = await this.useCase.execute({ tax_regime_id, companyId });
|
||||||
|
|
||||||
|
return result.match(
|
||||||
|
(data: unknown) => this.ok(data),
|
||||||
|
(err: Error) => this.handleError(err)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
import {
|
||||||
|
ExpressController,
|
||||||
|
forbidQueryFieldGuard,
|
||||||
|
requireAuthenticatedGuard,
|
||||||
|
requireCompanyContextGuard,
|
||||||
|
} from "@erp/core/api";
|
||||||
|
|
||||||
|
import type { GetTaxRegimeByIdUseCase } from "../../../../application";
|
||||||
|
import { taxRegimesApiErrorMapper } from "../tax-regime-api-error-mapper";
|
||||||
|
|
||||||
|
export class GetTaxRegimeByIdController extends ExpressController {
|
||||||
|
constructor(private readonly useCase: GetTaxRegimeByIdUseCase) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.errorMapper = taxRegimesApiErrorMapper;
|
||||||
|
|
||||||
|
this.registerGuards(
|
||||||
|
requireAuthenticatedGuard(),
|
||||||
|
requireCompanyContextGuard(),
|
||||||
|
forbidQueryFieldGuard("companyId")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async executeImpl() {
|
||||||
|
const companyId = this.getTenantId();
|
||||||
|
if (!companyId) {
|
||||||
|
return this.forbiddenError("Tenant ID not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
const { tax_regime_id } = this.req.params;
|
||||||
|
const result = await this.useCase.execute({ tax_regime_id, companyId });
|
||||||
|
|
||||||
|
return result.match(
|
||||||
|
(data: unknown) => this.ok(data),
|
||||||
|
(err: Error) => this.handleError(err)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
export * from "./create-tax-regime.controller";
|
||||||
|
export * from "./delete-tax-regime-by-id.controller";
|
||||||
|
export * from "./disable-tax-regime-by-id.controller";
|
||||||
|
export * from "./enable-tax-regime-by-id.controller";
|
||||||
|
export * from "./get-tax-regime-by-id.controller";
|
||||||
|
export * from "./list-tax-regimes.controller";
|
||||||
|
export * from "./update-tax-regime-by-id.controller";
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
import {
|
||||||
|
ExpressController,
|
||||||
|
forbidQueryFieldGuard,
|
||||||
|
requireAuthenticatedGuard,
|
||||||
|
requireCompanyContextGuard,
|
||||||
|
} from "@erp/core/api";
|
||||||
|
import { Criteria } from "@repo/rdx-criteria/server";
|
||||||
|
|
||||||
|
import type { ListTaxRegimesUseCase } from "../../../../application";
|
||||||
|
import { taxRegimesApiErrorMapper } from "../tax-regime-api-error-mapper";
|
||||||
|
|
||||||
|
export class ListTaxRegimesController extends ExpressController {
|
||||||
|
constructor(private readonly useCase: ListTaxRegimesUseCase) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.errorMapper = taxRegimesApiErrorMapper;
|
||||||
|
|
||||||
|
this.registerGuards(
|
||||||
|
requireAuthenticatedGuard(),
|
||||||
|
requireCompanyContextGuard(),
|
||||||
|
forbidQueryFieldGuard("companyId")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getCriteriaWithDefaultOrder() {
|
||||||
|
if (this.criteria.hasOrder()) {
|
||||||
|
return this.criteria;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { q: quicksearch, filters, pageSize, pageNumber } = this.criteria.toPrimitives();
|
||||||
|
return Criteria.fromPrimitives(filters, "code", "ASC", pageSize, pageNumber, quicksearch);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async executeImpl() {
|
||||||
|
const companyId = this.getTenantId();
|
||||||
|
if (!companyId) {
|
||||||
|
return this.forbiddenError("Tenant ID not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
const criteria = this.getCriteriaWithDefaultOrder();
|
||||||
|
const result = await this.useCase.execute({ criteria, companyId });
|
||||||
|
|
||||||
|
return result.match(
|
||||||
|
(data: any) =>
|
||||||
|
this.ok(data, {
|
||||||
|
"X-Total-Count": String(data.total_items),
|
||||||
|
"Pagination-Count": String(data.total_pages),
|
||||||
|
"Pagination-Page": String(data.page),
|
||||||
|
"Pagination-Limit": String(data.per_page),
|
||||||
|
}),
|
||||||
|
(err: Error) => this.handleError(err)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
import type { UpdateTaxRegimeByIdRequestDTO } from "@erp/catalogs/common";
|
||||||
|
import {
|
||||||
|
ExpressController,
|
||||||
|
forbidQueryFieldGuard,
|
||||||
|
requireAuthenticatedGuard,
|
||||||
|
requireCompanyContextGuard,
|
||||||
|
} from "@erp/core/api";
|
||||||
|
|
||||||
|
import type { UpdateTaxRegimeByIdUseCase } from "../../../../application";
|
||||||
|
import { taxRegimesApiErrorMapper } from "../tax-regime-api-error-mapper";
|
||||||
|
|
||||||
|
export class UpdateTaxRegimeByIdController extends ExpressController {
|
||||||
|
constructor(private readonly useCase: UpdateTaxRegimeByIdUseCase) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.errorMapper = taxRegimesApiErrorMapper;
|
||||||
|
|
||||||
|
this.registerGuards(
|
||||||
|
requireAuthenticatedGuard(),
|
||||||
|
requireCompanyContextGuard(),
|
||||||
|
forbidQueryFieldGuard("companyId")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async executeImpl() {
|
||||||
|
const companyId = this.getTenantId();
|
||||||
|
if (!companyId) {
|
||||||
|
return this.forbiddenError("Tenant ID not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
const { tax_regime_id } = this.req.params;
|
||||||
|
if (!tax_regime_id) {
|
||||||
|
return this.invalidInputError("Payment term ID missing");
|
||||||
|
}
|
||||||
|
|
||||||
|
const dto = this.req.body as UpdateTaxRegimeByIdRequestDTO;
|
||||||
|
const result = await this.useCase.execute({ tax_regime_id, companyId, dto });
|
||||||
|
|
||||||
|
return result.match(
|
||||||
|
(data: unknown) => this.ok(data),
|
||||||
|
(err: Error) => this.handleError(err)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./controllers";
|
||||||
|
export * from "./tax-regimes.routes";
|
||||||
@ -0,0 +1,107 @@
|
|||||||
|
import {
|
||||||
|
ApiErrorMapper,
|
||||||
|
ConflictApiError,
|
||||||
|
type ErrorToApiRule,
|
||||||
|
NotFoundApiError,
|
||||||
|
ValidationApiError,
|
||||||
|
} from "@erp/core/api";
|
||||||
|
|
||||||
|
import {
|
||||||
|
type InvalidTaxRegimeCodeError,
|
||||||
|
type InvalidTaxRegimeDescriptionError,
|
||||||
|
type InvalidTaxRegimeIdError,
|
||||||
|
type TaxRegimeCannotBeDeletedError,
|
||||||
|
type TaxRegimeCannotBeDisabledError,
|
||||||
|
type TaxRegimeCannotBeEnabledError,
|
||||||
|
type TaxRegimeCannotBeUpdatedError,
|
||||||
|
type TaxRegimeNotFoundError,
|
||||||
|
isInvalidTaxRegimeCodeError,
|
||||||
|
isInvalidTaxRegimeDescriptionError,
|
||||||
|
isInvalidTaxRegimeIdError,
|
||||||
|
isTaxRegimeCannotBeDeletedError,
|
||||||
|
isTaxRegimeCannotBeDisabledError,
|
||||||
|
isTaxRegimeCannotBeEnabledError,
|
||||||
|
isTaxRegimeCannotBeUpdatedError,
|
||||||
|
isTaxRegimeNotFoundError,
|
||||||
|
} from "../../../domain/tax-regimes";
|
||||||
|
|
||||||
|
const invalidTaxRegimeIdRule: ErrorToApiRule = {
|
||||||
|
priority: 120,
|
||||||
|
matches: isInvalidTaxRegimeIdError,
|
||||||
|
build: (error) =>
|
||||||
|
new ConflictApiError(
|
||||||
|
(error as InvalidTaxRegimeIdError).message ||
|
||||||
|
"Tax regime with the provided id already exists."
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
const invalidTaxRegimeCodeRule: ErrorToApiRule = {
|
||||||
|
priority: 120,
|
||||||
|
matches: isInvalidTaxRegimeCodeError,
|
||||||
|
build: (error) =>
|
||||||
|
new ValidationApiError(
|
||||||
|
(error as InvalidTaxRegimeCodeError).message || "Tax regime code is invalid."
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
const invalidTaxRegimeDescriptionRule: ErrorToApiRule = {
|
||||||
|
priority: 120,
|
||||||
|
matches: isInvalidTaxRegimeDescriptionError,
|
||||||
|
build: (error) =>
|
||||||
|
new ValidationApiError(
|
||||||
|
(error as InvalidTaxRegimeDescriptionError).message || "Tax regime description is invalid."
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
const taxRegimeNotFoundRule: ErrorToApiRule = {
|
||||||
|
priority: 120,
|
||||||
|
matches: isTaxRegimeNotFoundError,
|
||||||
|
build: (error) =>
|
||||||
|
new NotFoundApiError((error as TaxRegimeNotFoundError).message || "Tax regime not found."),
|
||||||
|
};
|
||||||
|
|
||||||
|
const taxRegimeCannotBeDeletedRule: ErrorToApiRule = {
|
||||||
|
priority: 120,
|
||||||
|
matches: isTaxRegimeCannotBeDeletedError,
|
||||||
|
build: (error) =>
|
||||||
|
new ValidationApiError(
|
||||||
|
(error as TaxRegimeCannotBeDeletedError).message || "Tax regime cannot be deleted."
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
const taxRegimeCannotBeDisabledRule: ErrorToApiRule = {
|
||||||
|
priority: 120,
|
||||||
|
matches: isTaxRegimeCannotBeDisabledError,
|
||||||
|
build: (error) =>
|
||||||
|
new ValidationApiError(
|
||||||
|
(error as TaxRegimeCannotBeDisabledError).message || "Tax regime cannot be disabled."
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
const taxRegimeCannotBeEnabledRule: ErrorToApiRule = {
|
||||||
|
priority: 120,
|
||||||
|
matches: isTaxRegimeCannotBeEnabledError,
|
||||||
|
build: (error) =>
|
||||||
|
new ValidationApiError(
|
||||||
|
(error as TaxRegimeCannotBeEnabledError).message || "Tax regime cannot be enabled."
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
const taxRegimeCannotBeUpdatedRule: ErrorToApiRule = {
|
||||||
|
priority: 120,
|
||||||
|
matches: isTaxRegimeCannotBeUpdatedError,
|
||||||
|
build: (error) =>
|
||||||
|
new ValidationApiError(
|
||||||
|
(error as TaxRegimeCannotBeUpdatedError).message || "Tax regime cannot be updated."
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const taxRegimesApiErrorMapper: ApiErrorMapper = ApiErrorMapper.default()
|
||||||
|
.register(invalidTaxRegimeIdRule)
|
||||||
|
.register(invalidTaxRegimeCodeRule)
|
||||||
|
.register(invalidTaxRegimeDescriptionRule)
|
||||||
|
.register(taxRegimeNotFoundRule)
|
||||||
|
.register(taxRegimeCannotBeDeletedRule)
|
||||||
|
.register(taxRegimeCannotBeDisabledRule)
|
||||||
|
.register(taxRegimeCannotBeEnabledRule)
|
||||||
|
.register(taxRegimeCannotBeUpdatedRule);
|
||||||
@ -0,0 +1,102 @@
|
|||||||
|
import { mockUser, requireAuthenticated, requireCompanyContext } from "@erp/auth/api";
|
||||||
|
import { type RequestWithAuth, type StartParams, validateRequest } from "@erp/core/api";
|
||||||
|
import type { NextFunction, Request, Response } from "express";
|
||||||
|
import { Router } from "express";
|
||||||
|
|
||||||
|
import {
|
||||||
|
CreateTaxRegimeRequestSchema,
|
||||||
|
DeleteTaxRegimeByIdRequestSchema,
|
||||||
|
GetTaxRegimeByIdRequestSchema,
|
||||||
|
ListTaxRegimesRequestSchema,
|
||||||
|
UpdateTaxRegimeByIdParamsRequestSchema,
|
||||||
|
UpdateTaxRegimeByIdRequestSchema,
|
||||||
|
} from "../../../../common";
|
||||||
|
import type { CatalogsInternalDeps } from "../../di";
|
||||||
|
|
||||||
|
import {
|
||||||
|
CreateTaxRegimeController,
|
||||||
|
DeleteTaxRegimeByIdController,
|
||||||
|
DisableTaxRegimeByIdController,
|
||||||
|
EnableTaxRegimeByIdController,
|
||||||
|
GetTaxRegimeByIdController,
|
||||||
|
ListTaxRegimesController,
|
||||||
|
UpdateTaxRegimeByIdController,
|
||||||
|
} from "./controllers";
|
||||||
|
|
||||||
|
export const taxRegimesRouter = (params: StartParams) => {
|
||||||
|
const { app, config, getInternal } = params;
|
||||||
|
const deps = getInternal<CatalogsInternalDeps>("catalogs").taxRegimes;
|
||||||
|
|
||||||
|
const router = Router({ mergeParams: true });
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === "development" || process.env.NODE_ENV === "production") {
|
||||||
|
router.use((req: Request, res: Response, next: NextFunction) =>
|
||||||
|
mockUser(req as RequestWithAuth, res, next)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
router.use([
|
||||||
|
(req: Request, res: Response, next: NextFunction) =>
|
||||||
|
requireAuthenticated()(req as RequestWithAuth, res, next),
|
||||||
|
(req: Request, res: Response, next: NextFunction) =>
|
||||||
|
requireCompanyContext()(req as RequestWithAuth, res, next),
|
||||||
|
]);
|
||||||
|
|
||||||
|
router.get("/", validateRequest(ListTaxRegimesRequestSchema, "query"), (req, res, next) => {
|
||||||
|
const controller = new ListTaxRegimesController(deps.useCases.listTaxRegimes());
|
||||||
|
return controller.execute(req, res, next);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/", validateRequest(CreateTaxRegimeRequestSchema, "body"), (req, res, next) => {
|
||||||
|
const controller = new CreateTaxRegimeController(deps.useCases.createTaxRegime());
|
||||||
|
return controller.execute(req, res, next);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get(
|
||||||
|
"/:tax_regime_id",
|
||||||
|
validateRequest(GetTaxRegimeByIdRequestSchema, "params"),
|
||||||
|
(req, res, next) => {
|
||||||
|
const controller = new GetTaxRegimeByIdController(deps.useCases.getTaxRegimeById());
|
||||||
|
return controller.execute(req, res, next);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
router.delete(
|
||||||
|
"/:tax_regime_id",
|
||||||
|
validateRequest(DeleteTaxRegimeByIdRequestSchema, "params"),
|
||||||
|
(req, res, next) => {
|
||||||
|
const controller = new DeleteTaxRegimeByIdController(deps.useCases.deleteTaxRegimeById());
|
||||||
|
return controller.execute(req, res, next);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
router.put(
|
||||||
|
"/:tax_regime_id",
|
||||||
|
validateRequest(UpdateTaxRegimeByIdParamsRequestSchema, "params"),
|
||||||
|
validateRequest(UpdateTaxRegimeByIdRequestSchema, "body"),
|
||||||
|
(req, res, next) => {
|
||||||
|
const controller = new UpdateTaxRegimeByIdController(deps.useCases.updateTaxRegimeById());
|
||||||
|
return controller.execute(req, res, next);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
router.patch(
|
||||||
|
"/:tax_regime_id/disable",
|
||||||
|
validateRequest(GetTaxRegimeByIdRequestSchema, "params"),
|
||||||
|
(req, res, next) => {
|
||||||
|
const controller = new DisableTaxRegimeByIdController(deps.useCases.disableTaxRegimeById());
|
||||||
|
return controller.execute(req, res, next);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
router.patch(
|
||||||
|
"/:tax_regime_id/enable",
|
||||||
|
validateRequest(GetTaxRegimeByIdRequestSchema, "params"),
|
||||||
|
(req, res, next) => {
|
||||||
|
const controller = new EnableTaxRegimeByIdController(deps.useCases.enableTaxRegimeById());
|
||||||
|
return controller.execute(req, res, next);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
app.use(`${config.server.apiBasePath}/catalogs/tax-regimes`, router);
|
||||||
|
};
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./express";
|
||||||
|
export * from "./persistence";
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export * from "./sequelize";
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
export * from "./mappers";
|
||||||
|
export * from "./models";
|
||||||
|
export * from "./repositories";
|
||||||
|
|
||||||
|
import taxRegimeModelInit from "./models/sequelize-tax-regime.model";
|
||||||
|
|
||||||
|
export const taxRegimeModels = [taxRegimeModelInit];
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./sequelize-tax-regime-domain.mapper";
|
||||||
|
export * from "./sequelize-tax-regime-summary.mapper";
|
||||||
@ -0,0 +1,79 @@
|
|||||||
|
import { type MapperParamsType, SequelizeDomainMapper } from "@erp/core/api";
|
||||||
|
import {
|
||||||
|
TextValue,
|
||||||
|
UniqueID,
|
||||||
|
ValidationErrorCollection,
|
||||||
|
type ValidationErrorDetail,
|
||||||
|
extractOrPushError,
|
||||||
|
} from "@repo/rdx-ddd";
|
||||||
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
|
import { TaxRegime, TaxRegimeCode } from "../../../../../domain";
|
||||||
|
import type { TaxRegimeCreationAttributes, TaxRegimeModel } from "../models";
|
||||||
|
|
||||||
|
export class SequelizeTaxRegimeDomainMapper extends SequelizeDomainMapper<
|
||||||
|
TaxRegimeModel,
|
||||||
|
TaxRegimeCreationAttributes,
|
||||||
|
TaxRegime
|
||||||
|
> {
|
||||||
|
public mapToDomain(source: TaxRegimeModel, _params?: MapperParamsType): Result<TaxRegime, Error> {
|
||||||
|
try {
|
||||||
|
const errors: ValidationErrorDetail[] = [];
|
||||||
|
|
||||||
|
const idResult = UniqueID.create(source.id, true);
|
||||||
|
if (idResult.isFailure) {
|
||||||
|
return Result.fail(idResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const companyId = extractOrPushError(
|
||||||
|
UniqueID.create(source.company_id),
|
||||||
|
"company_id",
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
|
||||||
|
const code = extractOrPushError(TaxRegimeCode.create(source.code), "code", errors);
|
||||||
|
|
||||||
|
const description = extractOrPushError(
|
||||||
|
TextValue.create(source.description),
|
||||||
|
"description",
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
|
||||||
|
// Si hubo errores de mapeo, devolvemos colección de validación
|
||||||
|
if (errors.length > 0) {
|
||||||
|
return Result.fail(
|
||||||
|
new ValidationErrorCollection("Payment method props mapping failed", errors)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const taxRegime = TaxRegime.rehydrate(
|
||||||
|
{
|
||||||
|
companyId: companyId!,
|
||||||
|
code: code!,
|
||||||
|
description: description!,
|
||||||
|
isActive: source.is_active,
|
||||||
|
isSystem: source.is_system,
|
||||||
|
},
|
||||||
|
idResult.data
|
||||||
|
);
|
||||||
|
|
||||||
|
return Result.ok(taxRegime);
|
||||||
|
} catch (error: unknown) {
|
||||||
|
return Result.fail(error as Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public mapToPersistence(
|
||||||
|
source: TaxRegime,
|
||||||
|
_params?: MapperParamsType
|
||||||
|
): Result<TaxRegimeCreationAttributes, Error> {
|
||||||
|
return Result.ok<TaxRegimeCreationAttributes>({
|
||||||
|
id: source.id.toPrimitive(),
|
||||||
|
company_id: source.companyId.toPrimitive(),
|
||||||
|
code: source.code.toPrimitive(),
|
||||||
|
description: source.description.toPrimitive(),
|
||||||
|
is_active: source.isActive,
|
||||||
|
is_system: source.isSystem,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
import { type MapperParamsType, SequelizeQueryMapper } from "@erp/core/api";
|
||||||
|
import {
|
||||||
|
TextValue,
|
||||||
|
UniqueID,
|
||||||
|
ValidationErrorCollection,
|
||||||
|
type ValidationErrorDetail,
|
||||||
|
extractOrPushError,
|
||||||
|
} from "@repo/rdx-ddd";
|
||||||
|
import { Result } from "@repo/rdx-utils";
|
||||||
|
|
||||||
|
import type { TaxRegimeSummary } from "../../../../../application";
|
||||||
|
import { TaxRegimeCode } from "../../../../../domain";
|
||||||
|
import type { TaxRegimeModel } from "../models";
|
||||||
|
|
||||||
|
export class SequelizeTaxRegimeSummaryMapper extends SequelizeQueryMapper<
|
||||||
|
TaxRegimeModel,
|
||||||
|
TaxRegimeSummary
|
||||||
|
> {
|
||||||
|
public mapToReadModel(
|
||||||
|
raw: TaxRegimeModel,
|
||||||
|
_params?: MapperParamsType
|
||||||
|
): Result<TaxRegimeSummary, Error> {
|
||||||
|
const errors: ValidationErrorDetail[] = [];
|
||||||
|
|
||||||
|
// 1) Valores escalares (atributos generales)
|
||||||
|
const companyId = extractOrPushError(UniqueID.create(raw.company_id), "company_id", errors);
|
||||||
|
const id = extractOrPushError(UniqueID.create(raw.id), "id", errors);
|
||||||
|
const code = extractOrPushError(TaxRegimeCode.create(raw.code), "code", errors);
|
||||||
|
const description = extractOrPushError(
|
||||||
|
TextValue.create(raw.description),
|
||||||
|
"description",
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
const isActive = raw.is_active;
|
||||||
|
const isSystem = raw.is_system;
|
||||||
|
|
||||||
|
// Si hubo errores de mapeo, devolvemos colección de validación
|
||||||
|
if (errors.length > 0) {
|
||||||
|
return Result.fail(
|
||||||
|
new ValidationErrorCollection("TaxRegime mapping failed [mapToDTO]", errors)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok<TaxRegimeSummary>({
|
||||||
|
id: id!,
|
||||||
|
companyId: companyId!,
|
||||||
|
code: code!,
|
||||||
|
description: description!,
|
||||||
|
isActive: isActive,
|
||||||
|
isSystem: isSystem,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export { type TaxRegimeCreationAttributes, TaxRegimeModel } from "./sequelize-tax-regime.model";
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
import {
|
||||||
|
type CreationOptional,
|
||||||
|
DataTypes,
|
||||||
|
type InferAttributes,
|
||||||
|
type InferCreationAttributes,
|
||||||
|
Model,
|
||||||
|
type Sequelize,
|
||||||
|
} from "sequelize";
|
||||||
|
|
||||||
|
export type TaxRegimeCreationAttributes = InferCreationAttributes<TaxRegimeModel, {}> & {};
|
||||||
|
|
||||||
|
export class TaxRegimeModel extends Model<
|
||||||
|
InferAttributes<TaxRegimeModel>,
|
||||||
|
InferCreationAttributes<TaxRegimeModel>
|
||||||
|
> {
|
||||||
|
declare id: string;
|
||||||
|
declare company_id: string;
|
||||||
|
declare code: string;
|
||||||
|
declare description: CreationOptional<string>;
|
||||||
|
declare is_active: boolean;
|
||||||
|
declare is_system: boolean;
|
||||||
|
|
||||||
|
static associate(_database: Sequelize) {}
|
||||||
|
|
||||||
|
static hooks(_database: Sequelize) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (database: Sequelize) => {
|
||||||
|
TaxRegimeModel.init(
|
||||||
|
{
|
||||||
|
id: {
|
||||||
|
type: DataTypes.UUID,
|
||||||
|
primaryKey: true,
|
||||||
|
},
|
||||||
|
company_id: {
|
||||||
|
type: DataTypes.UUID,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
code: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
unique: true,
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
is_active: {
|
||||||
|
type: DataTypes.BOOLEAN,
|
||||||
|
allowNull: false,
|
||||||
|
defaultValue: true,
|
||||||
|
},
|
||||||
|
is_system: {
|
||||||
|
type: DataTypes.BOOLEAN,
|
||||||
|
allowNull: false,
|
||||||
|
defaultValue: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sequelize: database,
|
||||||
|
modelName: "TaxRegimeModel",
|
||||||
|
tableName: "tax_regimes",
|
||||||
|
|
||||||
|
underscored: true,
|
||||||
|
paranoid: true, // softs deletes
|
||||||
|
timestamps: true,
|
||||||
|
|
||||||
|
createdAt: "created_at",
|
||||||
|
updatedAt: "updated_at",
|
||||||
|
deletedAt: "deleted_at",
|
||||||
|
|
||||||
|
indexes: [
|
||||||
|
{
|
||||||
|
name: "idx_tax_regimes_code",
|
||||||
|
fields: ["code", "deleted_at"],
|
||||||
|
unique: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
whereMergeStrategy: "and", // <- cómo tratar el merge de un scope
|
||||||
|
|
||||||
|
defaultScope: {},
|
||||||
|
|
||||||
|
scopes: {},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return TaxRegimeModel;
|
||||||
|
};
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export { SequelizeTaxRegimeRepository } from "./sequelize-tax-regime.repository";
|
||||||
@ -0,0 +1,253 @@
|
|||||||
|
import {
|
||||||
|
EntityNotFoundError,
|
||||||
|
InfrastructureRepositoryError,
|
||||||
|
SequelizeRepository,
|
||||||
|
translateSequelizeError,
|
||||||
|
} from "@erp/core/api";
|
||||||
|
import { type Criteria, CriteriaToSequelizeConverter } from "@repo/rdx-criteria/server";
|
||||||
|
import type { UniqueID } from "@repo/rdx-ddd";
|
||||||
|
import { type Collection, Result } from "@repo/rdx-utils";
|
||||||
|
import type { Sequelize, Transaction } from "sequelize";
|
||||||
|
|
||||||
|
import type { ITaxRegimeRepository, TaxRegimeSummary } from "../../../../../application";
|
||||||
|
import type { TaxRegime, TaxRegimeCode } from "../../../../../domain";
|
||||||
|
import type { SequelizeTaxRegimeDomainMapper, SequelizeTaxRegimeSummaryMapper } from "../mappers";
|
||||||
|
import { TaxRegimeModel } from "../models";
|
||||||
|
|
||||||
|
export class SequelizeTaxRegimeRepository
|
||||||
|
extends SequelizeRepository<TaxRegime>
|
||||||
|
implements ITaxRegimeRepository
|
||||||
|
{
|
||||||
|
constructor(
|
||||||
|
private readonly domainMapper: SequelizeTaxRegimeDomainMapper,
|
||||||
|
private readonly summaryMapper: SequelizeTaxRegimeSummaryMapper,
|
||||||
|
database: Sequelize
|
||||||
|
) {
|
||||||
|
super({ database });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Crea un nuevo método de pago
|
||||||
|
*
|
||||||
|
* @param taxRegime - El método de pago nuevo a guardar.
|
||||||
|
* @param transaction - Transacción activa para la operación.
|
||||||
|
* @returns Result<void, Error>
|
||||||
|
*/
|
||||||
|
async create(taxRegime: TaxRegime, transaction?: Transaction): Promise<Result<void, Error>> {
|
||||||
|
try {
|
||||||
|
const dtoResult = this.domainMapper.mapToPersistence(taxRegime);
|
||||||
|
if (dtoResult.isFailure) {
|
||||||
|
return Result.fail(dtoResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
await TaxRegimeModel.create(dtoResult.data, { transaction });
|
||||||
|
return Result.ok();
|
||||||
|
} catch (err: unknown) {
|
||||||
|
return Result.fail(translateSequelizeError(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actualiza un método de pago existente.
|
||||||
|
*
|
||||||
|
* @param taxRegime - El método de pago a actualizar.
|
||||||
|
* @param transaction - Transacción activa para la operación.
|
||||||
|
* @returns Result<void, Error>
|
||||||
|
*/
|
||||||
|
async update(taxRegime: TaxRegime, transaction?: Transaction): Promise<Result<void, Error>> {
|
||||||
|
try {
|
||||||
|
const dtoResult = this.domainMapper.mapToPersistence(taxRegime);
|
||||||
|
if (dtoResult.isFailure) {
|
||||||
|
return Result.fail(dtoResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { id, ...payload } = dtoResult.data;
|
||||||
|
const [affected] = await TaxRegimeModel.update(payload, {
|
||||||
|
where: { id },
|
||||||
|
transaction,
|
||||||
|
individualHooks: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (affected === 0) {
|
||||||
|
return Result.fail(
|
||||||
|
new InfrastructureRepositoryError("Concurrency conflict or payment method not found")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok();
|
||||||
|
} catch (err: unknown) {
|
||||||
|
return Result.fail(translateSequelizeError(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comprueba si existe un TaxRegime con un `id` dentro de una `company`.
|
||||||
|
*
|
||||||
|
* @param companyId - Identificador UUID de la empresa a la que pertenece el método de pago.
|
||||||
|
* @param id - Identificador UUID del método de pago.
|
||||||
|
* @param transaction - Transacción activa para la operación.
|
||||||
|
* @returns Result<boolean, Error>
|
||||||
|
*/
|
||||||
|
async existsByIdInCompany(
|
||||||
|
companyId: UniqueID,
|
||||||
|
id: UniqueID,
|
||||||
|
transaction?: Transaction
|
||||||
|
): Promise<Result<boolean, Error>> {
|
||||||
|
try {
|
||||||
|
const count = await TaxRegimeModel.count({
|
||||||
|
where: { id: id.toString(), company_id: companyId.toString() },
|
||||||
|
transaction,
|
||||||
|
});
|
||||||
|
return Result.ok(Boolean(count > 0));
|
||||||
|
} catch (error: unknown) {
|
||||||
|
return Result.fail(translateSequelizeError(error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recupera un método de pago por su ID y companyId.
|
||||||
|
*
|
||||||
|
* @param companyId - Identificador UUID de la empresa a la que pertenece el método de pago.
|
||||||
|
* @param id - Identificador UUID del método de pago.
|
||||||
|
* @param transaction - Transacción activa para la operación.
|
||||||
|
* @returns Result<TaxRegime, Error>
|
||||||
|
*/
|
||||||
|
|
||||||
|
async getByIdInCompany(
|
||||||
|
companyId: UniqueID,
|
||||||
|
id: UniqueID,
|
||||||
|
transaction?: Transaction
|
||||||
|
): Promise<Result<TaxRegime, Error>> {
|
||||||
|
try {
|
||||||
|
const row = await TaxRegimeModel.findOne({
|
||||||
|
where: {
|
||||||
|
id: id.toString(),
|
||||||
|
company_id: companyId.toString(),
|
||||||
|
},
|
||||||
|
transaction,
|
||||||
|
});
|
||||||
|
if (!row) {
|
||||||
|
return Result.fail(new EntityNotFoundError("TaxRegime", "id", id.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.domainMapper.mapToDomain(row);
|
||||||
|
} catch (err: unknown) {
|
||||||
|
return Result.fail(translateSequelizeError(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recupera un método de pago por su code y companyId.
|
||||||
|
*
|
||||||
|
* @param companyId - Identificador UUID de la empresa a la que pertenece el método de pago.
|
||||||
|
* @param code - Código del método de pago.
|
||||||
|
* @param transaction - Transacción activa para la operación.
|
||||||
|
* @returns Result<TaxRegime, Error>
|
||||||
|
*/
|
||||||
|
|
||||||
|
async getByCodeInCompany(
|
||||||
|
companyId: UniqueID,
|
||||||
|
code: TaxRegimeCode,
|
||||||
|
transaction?: Transaction
|
||||||
|
): Promise<Result<TaxRegime, Error>> {
|
||||||
|
try {
|
||||||
|
const row = await TaxRegimeModel.findOne({
|
||||||
|
where: {
|
||||||
|
code: code.toString(),
|
||||||
|
company_id: companyId.toString(),
|
||||||
|
},
|
||||||
|
transaction,
|
||||||
|
});
|
||||||
|
if (!row) {
|
||||||
|
return Result.fail(new EntityNotFoundError("TaxRegime", "code", code.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.domainMapper.mapToDomain(row);
|
||||||
|
} catch (err: unknown) {
|
||||||
|
return Result.fail(translateSequelizeError(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recupera múltiples customers dentro de una empresa según un criterio dinámico (búsqueda, paginación, etc.).
|
||||||
|
*
|
||||||
|
* @param companyId - Identificador UUID de la empresa a la que pertenece el cliente.
|
||||||
|
* @param criteria - Criterios de búsqueda.
|
||||||
|
* @param transaction - Transacción activa para la operación.
|
||||||
|
* @returns Result<Collection<CustomerListDTO>, Error>
|
||||||
|
*
|
||||||
|
* @see Criteria
|
||||||
|
*/
|
||||||
|
async findByCriteriaInCompany(
|
||||||
|
companyId: UniqueID,
|
||||||
|
criteria: Criteria,
|
||||||
|
transaction?: Transaction
|
||||||
|
): Promise<Result<Collection<TaxRegimeSummary>, Error>> {
|
||||||
|
try {
|
||||||
|
const criteriaConverter = new CriteriaToSequelizeConverter();
|
||||||
|
const query = criteriaConverter.convert(criteria, {
|
||||||
|
mappings: {
|
||||||
|
isActive: "is_active",
|
||||||
|
},
|
||||||
|
searchableFields: [],
|
||||||
|
sortableFields: ["code"],
|
||||||
|
enableFullText: true,
|
||||||
|
database: this.database,
|
||||||
|
strictMode: true, // fuerza error si ORDER BY no permitido
|
||||||
|
});
|
||||||
|
|
||||||
|
query.where = {
|
||||||
|
...query.where,
|
||||||
|
company_id: companyId.toString(),
|
||||||
|
deleted_at: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const [rows, count] = await Promise.all([
|
||||||
|
TaxRegimeModel.findAll({
|
||||||
|
...query,
|
||||||
|
transaction,
|
||||||
|
}),
|
||||||
|
TaxRegimeModel.count({
|
||||||
|
where: query.where,
|
||||||
|
distinct: true, // evita duplicados por LEFT JOIN
|
||||||
|
transaction,
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return this.summaryMapper.mapToReadModelCollection(rows, count);
|
||||||
|
} catch (err: unknown) {
|
||||||
|
return Result.fail(translateSequelizeError(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Elimina o marca como eliminado una forma de pago.
|
||||||
|
*
|
||||||
|
* @param companyId - Identificador UUID de la empresa a la que pertenece la forma de pago.
|
||||||
|
* @param id - UUID de la forma de pago a eliminar.
|
||||||
|
* @param transaction - Transacción activa para la operación.
|
||||||
|
* @returns Result<boolean, Error>
|
||||||
|
*/
|
||||||
|
async deleteByIdInCompany(
|
||||||
|
companyId: UniqueID,
|
||||||
|
id: UniqueID,
|
||||||
|
transaction: Transaction
|
||||||
|
): Promise<Result<boolean, Error>> {
|
||||||
|
try {
|
||||||
|
const deleted = await TaxRegimeModel.destroy({
|
||||||
|
where: { id: id.toString(), company_id: companyId.toString() },
|
||||||
|
transaction,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (deleted === 0) {
|
||||||
|
return Result.fail(new EntityNotFoundError("TaxRegime", "id", id.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok(true);
|
||||||
|
} catch (err: unknown) {
|
||||||
|
return Result.fail(translateSequelizeError(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,2 +1,3 @@
|
|||||||
export * from "./payment-methods";
|
export * from "./payment-methods";
|
||||||
export * from "./payment-terms";
|
export * from "./payment-terms";
|
||||||
|
export * from "./tax-regimes";
|
||||||
|
|||||||
3
modules/catalogs/src/common/dto/tax-regimes/index.ts
Normal file
3
modules/catalogs/src/common/dto/tax-regimes/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from "./request";
|
||||||
|
export * from "./response";
|
||||||
|
export * from "./shared";
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
|
export const CreateTaxRegimeRequestSchema = z.object({
|
||||||
|
id: z.uuid(),
|
||||||
|
code: z.string().regex(/^\d{2}$/),
|
||||||
|
description: z.string(),
|
||||||
|
is_active: z.boolean(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type CreateTaxRegimeRequestDTO = z.infer<typeof CreateTaxRegimeRequestSchema>;
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
|
export const DeleteTaxRegimeByIdRequestSchema = z.object({
|
||||||
|
tax_regime_id: z.uuid(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type DeleteTaxRegimeByIdRequestDTO = z.infer<typeof DeleteTaxRegimeByIdRequestSchema>;
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
|
export const DisableTaxRegimeByIdRequestSchema = z.object({
|
||||||
|
tax_regime_id: z.uuid(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type DisableTaxRegimeByIdRequestDTO = z.infer<typeof DisableTaxRegimeByIdRequestSchema>;
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
|
export const EnableTaxRegimeByIdRequestSchema = z.object({
|
||||||
|
tax_regime_id: z.uuid(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type EnableTaxRegimeByIdRequestDTO = z.infer<typeof EnableTaxRegimeByIdRequestSchema>;
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
|
export const GetTaxRegimeByIdRequestSchema = z.object({
|
||||||
|
tax_regime_id: z.uuid(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type GetTaxRegimeByIdRequestDTO = z.infer<typeof GetTaxRegimeByIdRequestSchema>;
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
export * from "./create-tax-regime.request.dto";
|
||||||
|
export * from "./delete-tax-regime-by-id.request.dto";
|
||||||
|
export * from "./disable-tax-regime-by-id.request.dto";
|
||||||
|
export * from "./enable-tax-regime-by-id.request.dto";
|
||||||
|
export * from "./get-tax-regime-by-id.request.dto";
|
||||||
|
export * from "./list-tax-regimes.request.dto";
|
||||||
|
export * from "./update-tax-regime-by-id.request.dto";
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
import { CriteriaSchema } from "@erp/core";
|
||||||
|
import type { z } from "zod/v4";
|
||||||
|
|
||||||
|
export const ListTaxRegimesRequestSchema = CriteriaSchema;
|
||||||
|
export type ListTaxRegimesRequestDTO = z.infer<typeof ListTaxRegimesRequestSchema>;
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
|
export const UpdateTaxRegimeByIdParamsRequestSchema = z.object({
|
||||||
|
tax_regime_id: z.uuid(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const UpdateTaxRegimeByIdRequestSchema = z.object({
|
||||||
|
description: z.string().optional(),
|
||||||
|
is_active: z.boolean().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type UpdateTaxRegimeByIdParamsRequestDTO = z.infer<
|
||||||
|
typeof UpdateTaxRegimeByIdParamsRequestSchema
|
||||||
|
>;
|
||||||
|
export type UpdateTaxRegimeByIdRequestDTO = z.infer<typeof UpdateTaxRegimeByIdRequestSchema>;
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
import type { z } from "zod/v4";
|
||||||
|
|
||||||
|
import { TaxRegimeDetailSchema } from "../shared";
|
||||||
|
|
||||||
|
export const CreateTaxRegimeResponseSchema = TaxRegimeDetailSchema;
|
||||||
|
export type CreateTaxRegimeResponseDTO = z.infer<typeof CreateTaxRegimeResponseSchema>;
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
import type { z } from "zod/v4";
|
||||||
|
|
||||||
|
import { TaxRegimeDetailSchema } from "../shared";
|
||||||
|
|
||||||
|
export const DisableTaxRegimeByIdResponseSchema = TaxRegimeDetailSchema;
|
||||||
|
export type DisableTaxRegimeByIdResponseDTO = z.infer<typeof DisableTaxRegimeByIdResponseSchema>;
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
import type { z } from "zod/v4";
|
||||||
|
|
||||||
|
import { TaxRegimeDetailSchema } from "../shared";
|
||||||
|
|
||||||
|
export const EnableTaxRegimeByIdResponseSchema = TaxRegimeDetailSchema;
|
||||||
|
export type EnableTaxRegimeByIdResponseDTO = z.infer<typeof EnableTaxRegimeByIdResponseSchema>;
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
import type { z } from "zod/v4";
|
||||||
|
|
||||||
|
import { TaxRegimeDetailSchema } from "../shared";
|
||||||
|
|
||||||
|
export const GetTaxRegimeByIdResponseSchema = TaxRegimeDetailSchema;
|
||||||
|
export type GetTaxRegimeByIdResponseDTO = z.infer<typeof GetTaxRegimeByIdResponseSchema>;
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
export * from "./create-tax-regime.response.dto";
|
||||||
|
export * from "./disable-tax-regime-by-id.response.dto";
|
||||||
|
export * from "./enable-tax-regime-by-id.response.dto";
|
||||||
|
export * from "./get-tax-regime-by-id.response.dto";
|
||||||
|
export * from "./list-tax-regimes.response.dto";
|
||||||
|
export * from "./update-tax-regime-by-id.response.dto";
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
import { createPaginatedListSchema } from "@erp/core";
|
||||||
|
import type { z } from "zod/v4";
|
||||||
|
|
||||||
|
import { TaxRegimeSummarySchema } from "../shared";
|
||||||
|
|
||||||
|
export const ListTaxRegimesResponseSchema = createPaginatedListSchema(TaxRegimeSummarySchema);
|
||||||
|
export type ListTaxRegimesResponseDTO = z.infer<typeof ListTaxRegimesResponseSchema>;
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
import type { z } from "zod/v4";
|
||||||
|
|
||||||
|
import { TaxRegimeDetailSchema } from "../shared";
|
||||||
|
|
||||||
|
export const UpdateTaxRegimeByIdResponseSchema = TaxRegimeDetailSchema;
|
||||||
|
export type UpdateTaxRegimeByIdResponseDTO = z.infer<typeof UpdateTaxRegimeByIdResponseSchema>;
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./tax-regime-detail.dto";
|
||||||
|
export * from "./tax-regime-summary.dto";
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
|
export const TaxRegimeDetailSchema = z.object({
|
||||||
|
id: z.uuid(),
|
||||||
|
company_id: z.uuid(),
|
||||||
|
code: z.string().regex(/^\d{2}$/),
|
||||||
|
description: z.string(),
|
||||||
|
is_active: z.boolean(),
|
||||||
|
is_system: z.boolean(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TaxRegimeDetailDTO = z.infer<typeof TaxRegimeDetailSchema>;
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
|
export const TaxRegimeSummarySchema = z.object({
|
||||||
|
id: z.uuid(),
|
||||||
|
company_id: z.uuid(),
|
||||||
|
code: z.string().regex(/^\d{2}$/),
|
||||||
|
description: z.string(),
|
||||||
|
is_active: z.boolean(),
|
||||||
|
is_system: z.boolean(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TaxRegimeSummaryDTO = z.infer<typeof TaxRegimeSummarySchema>;
|
||||||
Loading…
Reference in New Issue
Block a user