This commit is contained in:
David Arranz 2025-04-22 10:11:50 +02:00
parent b22845f8da
commit 8455ae43db
42 changed files with 228 additions and 1902 deletions

View File

@ -46,11 +46,13 @@ export function createApp(): Application {
next();
});
// Gestión global de errores
app.use(globalErrorHandler);
// Registrar rutas de la API
app.use("/api/v1", v1Routes());
// Gestión global de errores.
// Siempre al final de la cadena de middlewares
// y después de las rutas.
app.use(globalErrorHandler);
return app;
}

View File

@ -84,7 +84,7 @@ export class MoneyValue extends ValueObject<IMoneyValueProps> implements IMoneyV
/** Serializa el VO a una cadena del tipo "EUR:123400:2" */
toPersistence(): string {
return `${this.currency()}:${this.value.getAmount()}:${this.getScale()}`;
return `${this.currency}:${this.dinero.getAmount()}:${this.scale}`;
}
/** Reconstruye el VO desde la cadena persistida */
@ -92,8 +92,8 @@ export class MoneyValue extends ValueObject<IMoneyValueProps> implements IMoneyV
const [currencyCode, amountStr, scaleStr] = value.split(":");
const amount = parseInt(amountStr, 10);
const scale = parseInt(scaleStr, 10);
const currency = getCurrencyByCode(currencyCode);
return new MoneyValue(amount, scale, currency);
const currency = currencyCode;
return new MoneyValue({ amount, scale, currency_code: currency });
}
toPrimitive() {

View File

@ -2,7 +2,12 @@ import { logger } from "@common/infrastructure/logger";
import { NextFunction, Request, Response } from "express";
import { ApiError } from "../api-error";
export const globalErrorHandler = (error: any, req: Request, res: Response, next: NextFunction) => {
export const globalErrorHandler = async (
error: Error,
req: Request,
res: Response,
next: NextFunction
) => {
// Si ya se envió una respuesta, delegamos al siguiente error handler
if (res.headersSent) {
return next(error);

View File

@ -7,27 +7,32 @@ export const validateAndParseBody =
(schema: ZodSchema, options?: { sanitize?: boolean }) =>
(req: Request, res: Response, next: NextFunction) => {
const result = schema.safeParse(req.body);
if (!result.success) {
// Construye errores detallados
const validationErrors = result.error.errors.map((err) => ({
field: err.path.join("."),
message: err.message,
}));
try {
if (!result.success) {
// Construye errores detallados
const validationErrors = result.error.errors.map((err) => ({
field: err.path.join("."),
message: err.message,
}));
throw new ApiError({
status: httpStatus.BAD_REQUEST, //400
title: "Validation Error",
detail: "Algunos campos no cumplen con los criterios de validación.",
type: "https://example.com/probs/validation-error",
instance: req.originalUrl,
errors: validationErrors,
});
throw new ApiError({
status: httpStatus.BAD_REQUEST, //400
title: "Validation Error",
detail: "Algunos campos no cumplen con los criterios de validación.",
type: "https://example.com/probs/validation-error",
instance: req.originalUrl,
errors: validationErrors,
});
}
// Si pasa la validación, opcionalmente reescribe req.body
if (options?.sanitize ?? true) {
req.body = result.data;
}
next();
} catch (error: unknown) {
// Si ocurre un error, delega al manejador de errores global
next(error as ApiError);
}
// Si pasa la validación, opcionalmente reescribe req.body
if (options?.sanitize ?? true) {
req.body = result.data;
}
next();
};

View File

@ -28,7 +28,7 @@ export interface IInvoiceProps {
//paymentTerms: string;
customer?: InvoiceCustomer;
items?: Collection<InvoiceItem>;
items?: InvoiceItems;
}
export interface IInvoice {

View File

@ -1,4 +1,4 @@
import { MoneyValue, Percentage, Quantity, ValueObject } from "@common/domain";
import { DomainEntity, MoneyValue, Percentage, Quantity, UniqueID } from "@common/domain";
import { Result } from "@common/helpers";
import { InvoiceItemDescription } from "../../value-objects";
@ -6,12 +6,13 @@ export interface IInvoiceItemProps {
description: InvoiceItemDescription;
quantity: Quantity; // Cantidad de unidades
unitPrice: MoneyValue; // Precio unitario en la moneda de la factura
subtotalPrice?: MoneyValue; // Precio unitario * Cantidad
//subtotalPrice?: MoneyValue; // Precio unitario * Cantidad
discount: Percentage; // % descuento
totalPrice?: MoneyValue;
//totalPrice?: MoneyValue;
}
export interface IInvoiceItem {
id: UniqueID;
description: InvoiceItemDescription;
quantity: Quantity;
unitPrice: MoneyValue;
@ -20,12 +21,22 @@ export interface IInvoiceItem {
totalPrice: MoneyValue;
}
export class InvoiceItem extends ValueObject<IInvoiceItemProps> implements IInvoiceItem {
export class InvoiceItem extends DomainEntity<IInvoiceItemProps> implements IInvoiceItem {
private _subtotalPrice!: MoneyValue;
private _totalPrice!: MoneyValue;
public static create(props: IInvoiceItemProps): Result<InvoiceItem, Error> {
return Result.ok(new InvoiceItem(props));
public static create(props: IInvoiceItemProps, id?: UniqueID): Result<InvoiceItem, Error> {
const item = new InvoiceItem(props, id);
// Reglas de negocio / validaciones
// ...
// ...
// 🔹 Disparar evento de dominio "InvoiceItemCreatedEvent"
//const { invoice } = props;
//user.addDomainEvent(new InvoiceAuthenticatedEvent(id, invoice.toString()));
return Result.ok(item);
}
get description(): InvoiceItemDescription {

View File

@ -43,4 +43,8 @@ export class InvoiceItemDescription extends ValueObject<IInvoiceItemDescriptionP
toString(): string {
return this.getValue();
}
toPrimitive() {
return this.getValue();
}
}

View File

@ -1,53 +1,79 @@
import { ISequelizeMapper, SequelizeMapper } from "@/contexts/common/infrastructure";
import { Description, Quantity, UniqueID, UnitPrice } from "@shared/contexts";
import { Invoice } from "../../domain";
import { IInvoiceSimpleItemProps, InvoiceItem, InvoiceSimpleItem } from "../../domain/entities";
import { IInvoicingContext } from "../InvoicingContext";
import { InvoiceItem_Model, InvoiceModel, TCreationInvoiceItem_Model } from "../sequelize";
import { MoneyValue, Percentage, Quantity, UniqueID } from "@common/domain";
import { Result } from "@common/helpers";
import {
ISequelizeMapper,
MapperParamsType,
SequelizeMapper,
} from "@common/infrastructure/sequelize/sequelize-mapper";
import { Invoice, InvoiceItem, InvoiceItemDescription } from "@contexts/invoices/domain/";
import { InferCreationAttributes } from "sequelize";
import { InvoiceItemCreationAttributes, InvoiceItemModel, InvoiceModel } from "../sequelize";
export interface IInvoiceItemMapper
extends ISequelizeMapper<InvoiceItem_Model, TCreationInvoiceItem_Model, InvoiceItem> {}
extends ISequelizeMapper<InvoiceItemModel, InvoiceItemCreationAttributes, InvoiceItem> {}
export const createInvoiceItemMapper = (context: IInvoicingContext): IInvoiceItemMapper =>
new InvoiceItemMapper({ context });
class InvoiceItemMapper
extends SequelizeMapper<InvoiceItem_Model, TCreationInvoiceItem_Model, InvoiceItem>
export class InvoiceItemMapper
extends SequelizeMapper<InvoiceItemModel, InvoiceItemCreationAttributes, InvoiceItem>
implements IInvoiceItemMapper
{
protected toDomainMappingImpl(
source: InvoiceItem_Model,
params: { sourceParent: InvoiceModel }
): InvoiceItem {
const { sourceParent } = params;
const id = this.mapsValue(source, "item_id", UniqueID.create);
public mapToDomain(
source: InvoiceItemModel,
params?: MapperParamsType
): Result<InvoiceItem, Error> {
const { sourceParent } = params as { sourceParent: InvoiceModel };
const props: IInvoiceSimpleItemProps = {
description: this.mapsValue(source, "description", Description.create),
quantity: this.mapsValue(source, "quantity", Quantity.create),
unitPrice: this.mapsValue(source, "unit_price", (unit_price) =>
UnitPrice.create({
amount: unit_price,
currencyCode: sourceParent.invoice_currency,
precision: 4,
})
),
};
const idOrError = UniqueID.create(source.item_id);
const invoiceItemOrError = InvoiceSimpleItem.create(props, id);
const descriptionOrError = InvoiceItemDescription.create(source.description);
if (invoiceItemOrError.isFailure) {
throw invoiceItemOrError.error;
const quantityOrError = Quantity.create({
amount: source.quantity_amount,
scale: source.quantity_scale,
});
const unitPriceOrError = MoneyValue.create({
amount: source.unit_price_amount,
scale: source.unit_price_scale,
currency_code: sourceParent.invoice_currency,
});
const discountOrError = Percentage.create({
amount: source.discount_amount,
scale: source.discount_scale,
});
const result = Result.combine([
idOrError,
descriptionOrError,
quantityOrError,
unitPriceOrError,
discountOrError,
]);
if (result.isFailure) {
return Result.fail(result.error);
}
return invoiceItemOrError.object;
return InvoiceItem.create(
{
description: descriptionOrError.data,
quantity: quantityOrError.data,
unitPrice: unitPriceOrError.data,
discount: discountOrError.data,
},
idOrError.data
//sourceParent
);
}
protected toPersistenceMappingImpl(
public mapToPersistence(
source: InvoiceItem,
params: { index: number; sourceParent: Invoice }
): TCreationInvoiceItem_Model {
const { index, sourceParent } = params;
params?: MapperParamsType
): InferCreationAttributes<InvoiceItemModel, {}> {
const { index, sourceParent } = params as {
index: number;
sourceParent: Invoice;
};
const lineData = {
parent_id: undefined,
@ -57,10 +83,21 @@ class InvoiceItemMapper
item_id: source.id.toPrimitive(),
description: source.description.toPrimitive(),
quantity: source.quantity.toPrimitive(),
unit_price: source.unitPrice.toPrimitive(),
subtotal: source.calculateSubtotal().toPrimitive(),
total: source.calculateTotal().toPrimitive(),
quantity_amount: source.quantity.toPrimitive().amount,
quantity_scale: source.quantity.toPrimitive().scale,
unit_price_amount: source.unitPrice.toPrimitive().amount,
unit_price_scale: source.unitPrice.toPrimitive().scale,
subtotal_amount: source.subtotalPrice.toPrimitive().amount,
subtotal_scale: source.subtotalPrice.toPrimitive().scale,
discount_amount: source.discount.toPrimitive().amount,
discount_scale: source.discount.toPrimitive().scale,
total_amount: source.totalPrice.toPrimitive().amount,
total_scale: source.totalPrice.toPrimitive().scale,
};
return lineData;
}

View File

@ -7,6 +7,7 @@ import {
} from "@common/infrastructure/sequelize/sequelize-mapper";
import { Invoice, InvoiceNumber, InvoiceSerie, InvoiceStatus } from "@contexts/invoices/domain/";
import { InvoiceCreationAttributes, InvoiceModel } from "../sequelize";
import { InvoiceItemMapper } from "./invoice-item.mapper"; // Importar el mapper de items
export interface IInvoiceMapper
extends ISequelizeMapper<InvoiceModel, InvoiceCreationAttributes, Invoice> {}
@ -15,6 +16,13 @@ export class InvoiceMapper
extends SequelizeMapper<InvoiceModel, InvoiceCreationAttributes, Invoice>
implements IInvoiceMapper
{
private invoiceItemMapper: InvoiceItemMapper;
constructor() {
super();
this.invoiceItemMapper = new InvoiceItemMapper(); // Instanciar el mapper de items
}
public mapToDomain(source: InvoiceModel, params?: MapperParamsType): Result<Invoice, Error> {
const idOrError = UniqueID.create(source.id);
const statusOrError = InvoiceStatus.create(source.invoice_status);
@ -23,18 +31,6 @@ export class InvoiceMapper
const issueDateOrError = UtcDate.create(source.issue_date);
const operationDateOrError = UtcDate.create(source.operation_date);
/*const subtotalOrError = MoneyValue.create({
amount: source.subtotal,
scale: 2,
currency_code: source.invoice_currency,
});
const totalOrError = MoneyValue.create({
amount: source.total,
scale: 2,
currency_code: source.invoice_currency,
});*/
const result = Result.combine([
idOrError,
statusOrError,
@ -42,14 +38,22 @@ export class InvoiceMapper
invoiceNumberOrError,
issueDateOrError,
operationDateOrError,
//subtotalOrError,
//totalOrError,
]);
if (result.isFailure) {
return Result.fail(result.error);
}
// Mapear los items de la factura
const itemsOrErrors = this.invoiceItemMapper.mapArrayToDomain(source.items, {
sourceParent: source,
...params,
});
if (itemsOrErrors.isFailure) {
return Result.fail(itemsOrErrors.error);
}
const invoiceCurrency = source.invoice_currency || "EUR";
return Invoice.create(
@ -60,10 +64,7 @@ export class InvoiceMapper
issueDate: issueDateOrError.data,
operationDate: operationDateOrError.data,
invoiceCurrency,
//currency: source.invoice_currency,
//subtotal: subtotalOrError.data,
//total: totalOrError.data,
items: itemsOrErrors.data,
},
idOrError.data
);
@ -73,6 +74,8 @@ export class InvoiceMapper
const subtotal = source.calculateSubtotal();
const total = source.calculateTotal();
const items = this.invoiceItemMapper.mapCollectionToPersistence(source.items, params);
return {
id: source.id.toString(),
invoice_status: source.status.toPrimitive(),
@ -88,6 +91,8 @@ export class InvoiceMapper
total_amount: total.amount,
total_scale: total.scale,
items,
};
}
}

View File

@ -1,6 +1,7 @@
import { IInvoiceRepository } from "@contexts/invoices/domain";
import { invoiceRepository } from "./invoice.repository";
export * from "./invoice-item.model";
export * from "./invoice.model";
export * from "./invoice.repository";

View File

@ -4,47 +4,32 @@ import {
InferAttributes,
InferCreationAttributes,
Model,
NonAttribute,
Sequelize,
} from "sequelize";
import { InvoiceModel } from "./invoice.model";
export type TCreationInvoiceItem_Model = InferCreationAttributes<
InvoiceItem_Model,
{
/*omit: "invoice"*/
}
>;
export type InvoiceItemCreationAttributes = InferCreationAttributes<InvoiceItemModel, {}> & {};
export class InvoiceItem_Model extends Model<
InferAttributes<
InvoiceItem_Model,
{
/*omit: "invoice"*/
}
>,
InferCreationAttributes<
InvoiceItem_Model,
{
/*omit: "invoice"*/
}
>
export class InvoiceItemModel extends Model<
InferAttributes<InvoiceItemModel>,
InvoiceItemCreationAttributes
> {
static associate(connection: Sequelize) {
const { Invoice_Model, InvoiceItem_Model } = connection.models;
/*const { Invoice_Model, InvoiceItem_Model } = connection.models;
InvoiceItem_Model.belongsTo(Invoice_Model, {
as: "invoice",
foreignKey: "invoice_id",
onDelete: "CASCADE",
});
});*/
}
declare invoice_id: string;
declare item_id: string;
declare invoice_id: string;
declare parent_id: CreationOptional<string>;
declare position: number;
declare item_type: string;
declare description: CreationOptional<string>;
declare quantity_amount: CreationOptional<number>;
@ -56,14 +41,17 @@ export class InvoiceItem_Model extends Model<
declare subtotal_amount: CreationOptional<number>;
declare subtotal_scale: CreationOptional<number>;
declare discount_amount: CreationOptional<number>;
declare discount_scale: CreationOptional<number>;
declare total_amount: CreationOptional<number>;
declare total_scale: CreationOptional<number>;
declare invoice?: NonAttribute<InvoiceModel>;
//declare invoice?: NonAttribute<InvoiceModel>;
}
export default (sequelize: Sequelize) => {
InvoiceItem_Model.init(
InvoiceItemModel.init(
{
item_id: {
type: new DataTypes.UUID(),
@ -138,6 +126,17 @@ export default (sequelize: Sequelize) => {
defaultValue: null,
},
discount_amount: {
type: new DataTypes.SMALLINT(),
allowNull: true,
defaultValue: null,
},
discount_scale: {
type: new DataTypes.SMALLINT(),
allowNull: true,
defaultValue: null,
},
/*tax_amount: {
type: new DataTypes.BIGINT(),
allowNull: true,
@ -156,8 +155,12 @@ export default (sequelize: Sequelize) => {
{
sequelize,
tableName: "invoice_items",
defaultScope: {},
scopes: {},
}
);
return InvoiceItem_Model;
return InvoiceItemModel;
};

View File

@ -4,25 +4,24 @@ import {
InferAttributes,
InferCreationAttributes,
Model,
NonAttribute,
Sequelize,
} from "sequelize";
import { InvoiceItemCreationAttributes, InvoiceItemModel } from "./invoice-item.model";
export type InvoiceCreationAttributes = InferCreationAttributes<InvoiceModel, {}> & {};
export type InvoiceCreationAttributes = InferCreationAttributes<InvoiceModel, { omit: "items" }> & {
items?: InvoiceItemCreationAttributes[];
};
export class InvoiceModel extends Model<InferAttributes<InvoiceModel>, InvoiceCreationAttributes> {
static associate(connection: Sequelize) {
/*const { Invoice_Model, InvoiceItem_Model, InvoiceParticipant_Model } = connection.models;
const { InvoiceModel, InvoiceItemModel } = connection.models;
Invoice_Model.hasMany(InvoiceItem_Model, {
InvoiceModel.hasMany(InvoiceItemModel, {
as: "items",
foreignKey: "invoice_id",
onDelete: "CASCADE",
});
Invoice_Model.hasMany(InvoiceParticipant_Model, {
as: "customer",
foreignKey: "invoice_id",
onDelete: "CASCADE",
});*/
}
declare id: string;
@ -43,7 +42,8 @@ export class InvoiceModel extends Model<InferAttributes<InvoiceModel>, InvoiceCr
declare total_amount: CreationOptional<number>;
declare total_scale: CreationOptional<number>;
//declare items: NonAttribute<InvoiceItem_Model[]>;
// Relationships
declare items: NonAttribute<InvoiceItemModel[]>;
//declare customer: NonAttribute<InvoiceParticipant_Model[]>;
}

View File

@ -12,24 +12,30 @@ export const ICreateInvoiceRequestSchema = z.object({
const dateStr = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Invalid YYYY-MM-DD format");
return dateStr.safeParse(date).success;
}),
customerId: z.string().uuid(),
//customerId: z.string().uuid(),
lang_code: z.string().min(1),
currency_code: z.string().min(1),
items: z.array(
z.object({
//id: z.string().uuid(),
description: z.string().min(1),
unit_price: z.object({
amount: z.number().positive(),
scale: z.number().positive(),
}),
quantity: z.object({
amount: z.number().positive(),
scale: z.number().positive(),
}),
})
),
items: z
.array(
z.object({
//id: z.string().uuid(),
description: z.string().optional(),
unit_price: z
.object({
amount: z.number().positive(),
scale: z.number().positive(),
})
.optional(),
quantity: z
.object({
amount: z.number().positive(),
scale: z.number().positive(),
})
.optional(),
})
)
.optional(),
});
export const IUpdateInvoiceRequestSchema = z.object({});

View File

@ -50,7 +50,7 @@ const serverError = (error: NodeJS.ErrnoException) => {
}
// Dependiendo de la criticidad, podrías forzar el proceso a salir
// process.exit(1);
process.exit(1);
};
// Almacena en "connections" cada nueva conexión (descomentar si se quiere seguimiento)

View File

@ -1,8 +1,5 @@
import { Router } from "express";
import { accountsRouter } from "./accounts.routes";
import { authRouter } from "./auth.routes";
import { invoicesRouter } from "./invoices.routes";
import { usersRouter } from "./users.routes";
export const v1Routes = () => {
const routes = Router({ mergeParams: true });
@ -11,9 +8,9 @@ export const v1Routes = () => {
res.send("Hello world!");
});
authRouter(routes);
usersRouter(routes);
accountsRouter(routes);
//authRouter(routes);
//usersRouter(routes);
//accountsRouter(routes);
// Sales
invoicesRouter(routes);

View File

@ -1,63 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico para las líneas de detalle
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props);
// 🔹 Disparar evento de dominio "FacturaDraft"
factura.addDomainEvent(new FacturaDraft(factura.id, props.referencia));
return Result.ok(factura);
}
modify(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede modificar en estado 'draft'."));
}
// Lógica para modificar la factura
return Result.ok();
}
delete(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede eliminar en estado 'draft'."));
}
// Lógica para eliminar la factura
return Result.ok();
}
emit(): Result<void, Error> {
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.id, this.props.referencia));
return Result.ok();
}
send(): Result<void, Error> {
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.id, this.props.referencia));
return Result.ok();
}
reject(): Result<void, Error> {
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.id, this.props.referencia));
return Result.ok();
}
}

View File

@ -1,63 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico para las líneas de detalle
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props, props.id);
factura.addDomainEvent(new FacturaDraft(props.id));
return Result.ok(factura);
}
modify(props: Partial<IFacturaProps>): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede modificar en estado 'draft'."));
}
Object.assign(this.props, props);
}
emit(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede emitir en estado 'draft'."));
}
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.props.id));
}
send(): Result<void, Error> {
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.props.id));
}
reject(): Result<void, Error> {
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.props.id));
}
get referencia(): FacturaReference {
return this.props.referencia;
}
get estado(): FacturaStatus {
return this.props.estado;
}
get fecha(): UTCDate {
return this.props.fecha;
}
}

View File

@ -1,63 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico para las líneas de detalle
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props);
// Emitir evento de dominio "FacturaDraft"
factura.addDomainEvent(new FacturaDraft(factura.id, props.referencia));
return Result.ok(factura);
}
modify(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede modificar en estado 'draft'."));
}
// Lógica para modificar la factura
return Result.ok();
}
delete(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede eliminar en estado 'draft'."));
}
// Lógica para eliminar la factura
return Result.ok();
}
emit(): Result<void, Error> {
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.id));
return Result.ok();
}
send(): Result<void, Error> {
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.id));
return Result.ok();
}
reject(): Result<void, Error> {
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.id));
return Result.ok();
}
}

View File

@ -1,73 +0,0 @@
// filepath: /home/rodax/Documentos/uecko-erp/apps/server/src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico para las líneas de detalle
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props);
factura.addDomainEvent(new FacturaDraft(factura.id));
return Result.ok(factura);
}
emit(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo puede ser emitida en estado 'draft'."));
}
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.id));
return Result.ok();
}
send(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createEmitted()) {
return Result.fail(new Error("La factura solo puede ser enviada en estado 'emitted'."));
}
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.id));
return Result.ok();
}
reject(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo puede ser rechazada en estado 'draft'."));
}
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.id));
return Result.ok();
}
get referencia(): FacturaReference {
return this.props.referencia;
}
get estado(): FacturaStatus {
return this.props.estado;
}
get fecha(): UTCDate {
return this.props.fecha;
}
get lineasDetalle(): any[] {
return this.props.lineasDetalle;
}
get clienteOProveedor(): string {
return this.props.clienteOProveedor;
}
}

View File

@ -1,68 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico si es necesario
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props);
// Emitir evento de dominio "FacturaDraft"
factura.addDomainEvent(new FacturaDraft(props.id));
return Result.ok(factura);
}
modify(newProps: Partial<IFacturaProps>): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede modificar en estado 'draft'."));
}
Object.assign(this.props, newProps);
}
emit(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede emitir en estado 'draft'."));
}
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.props.id));
}
send(): Result<void, Error> {
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.props.id));
}
reject(): Result<void, Error> {
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.props.id));
}
get referencia(): FacturaReference {
return this.props.referencia;
}
get estado(): FacturaStatus {
return this.props.estado;
}
get fecha(): UTCDate {
return this.props.fecha;
}
}

View File

@ -1,60 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico si es necesario
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props);
// Emitir evento de dominio "FacturaDraft"
factura.addDomainEvent(new FacturaDraft(factura.id, props.referencia));
return Result.ok(factura);
}
modify(newProps: Partial<IFacturaProps>): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede modificar en estado 'draft'."));
}
Object.assign(this.props, newProps);
}
delete(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede eliminar en estado 'draft'."));
}
// Lógica para eliminar la factura
}
emit(): Result<void, Error> {
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.id, this.props.referencia));
}
send(): Result<void, Error> {
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.id, this.props.referencia));
}
reject(): Result<void, Error> {
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.id, this.props.referencia));
}
}

View File

@ -1,60 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico si es necesario
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props);
// Emitir evento de dominio "FacturaDraft"
factura.addDomainEvent(new FacturaDraft(factura.id));
return Result.ok(factura);
}
modify(newProps: Partial<IFacturaProps>): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede modificar en estado 'draft'."));
}
Object.assign(this.props, newProps);
}
delete(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede eliminar en estado 'draft'."));
}
// Lógica para eliminar la factura
}
emit(): Result<void, Error> {
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.id));
}
send(): Result<void, Error> {
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.id));
}
reject(): Result<void, Error> {
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.id));
}
}

View File

@ -1,69 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico para las líneas de detalle
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props, props.id);
factura.addDomainEvent(new FacturaDraft(props.id));
return Result.ok(factura);
}
emit(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede emitir en estado 'draft'."));
}
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.props.id));
return Result.ok();
}
send(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createEmitted()) {
return Result.fail(new Error("La factura solo se puede enviar en estado 'emitted'."));
}
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.props.id));
return Result.ok();
}
reject(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createEmitted()) {
return Result.fail(new Error("La factura solo se puede rechazar en estado 'emitted'."));
}
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.props.id));
return Result.ok();
}
get referencia(): FacturaReference {
return this.props.referencia;
}
get estado(): FacturaStatus {
return this.props.estado;
}
get fecha(): UTCDate {
return this.props.fecha;
}
get lineasDetalle(): any[] {
return this.props.lineasDetalle;
}
}

View File

@ -1,60 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico si es necesario
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props);
// Emitir evento de dominio "FacturaDraft"
factura.addDomainEvent(new FacturaDraft(factura.id));
return Result.ok(factura);
}
modify(newProps: Partial<IFacturaProps>): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede modificar en estado 'draft'."));
}
Object.assign(this.props, newProps);
}
delete(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede eliminar en estado 'draft'."));
}
// Lógica para eliminar la factura
}
emit(): Result<void, Error> {
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.id));
}
send(): Result<void, Error> {
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.id));
}
reject(): Result<void, Error> {
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.id));
}
}

View File

@ -1,60 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico si es necesario
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props);
// Emitir evento de dominio "FacturaDraft"
factura.addDomainEvent(new FacturaDraft(factura.id, props.referencia));
return Result.ok(factura);
}
modify(newProps: Partial<IFacturaProps>): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede modificar en estado 'draft'."));
}
Object.assign(this.props, newProps);
}
delete(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede eliminar en estado 'draft'."));
}
// Lógica para eliminar la factura
}
emit(): Result<void, Error> {
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.id, this.props.referencia));
}
send(): Result<void, Error> {
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.id, this.props.referencia));
}
reject(): Result<void, Error> {
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.id, this.props.referencia));
}
}

View File

@ -1,67 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico si es necesario
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props, props.id);
factura.addDomainEvent(new FacturaDraft(props.id, props.referencia));
return Result.ok(factura);
}
modify(newProps: Partial<IFacturaProps>): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede modificar en estado 'draft'."));
}
Object.assign(this.props, newProps);
return Result.ok(undefined);
}
emit(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede emitir en estado 'draft'."));
}
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.props.id, this.props.referencia));
return Result.ok(undefined);
}
send(): Result<void, Error> {
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.props.id, this.props.referencia));
return Result.ok(undefined);
}
reject(): Result<void, Error> {
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.props.id, this.props.referencia));
return Result.ok(undefined);
}
get referencia(): FacturaReference {
return this.props.referencia;
}
get estado(): FacturaStatus {
return this.props.estado;
}
get fecha(): UTCDate {
return this.props.fecha;
}
}

View File

@ -1,63 +0,0 @@
// filepath: /home/rodax/Documentos/uecko-erp/apps/server/src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico para las líneas de detalle
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props);
// Emitir evento de dominio "FacturaDraft"
factura.addDomainEvent(new FacturaDraft(factura.id, props.referencia));
return Result.ok(factura);
}
modify(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede modificar en estado 'draft'."));
}
// Lógica para modificar la factura
return Result.ok();
}
delete(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede eliminar en estado 'draft'."));
}
// Lógica para eliminar la factura
return Result.ok();
}
emit(): Result<void, Error> {
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.id));
return Result.ok();
}
send(): Result<void, Error> {
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.id));
return Result.ok();
}
reject(): Result<void, Error> {
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.id));
return Result.ok();
}
}

View File

@ -1,68 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico si es necesario
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props);
// Emitir evento de dominio "FacturaDraft"
factura.addDomainEvent(new FacturaDraft(factura.id, props.referencia));
return Result.ok(factura);
}
modify(newProps: Partial<IFacturaProps>): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede modificar en estado 'draft'."));
}
Object.assign(this.props, newProps);
}
emit(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede emitir en estado 'draft'."));
}
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.id, this.props.referencia));
}
send(): Result<void, Error> {
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.id, this.props.referencia));
}
reject(): Result<void, Error> {
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.id, this.props.referencia));
}
get referencia(): FacturaReference {
return this.props.referencia;
}
get estado(): FacturaStatus {
return this.props.estado;
}
get fecha(): UTCDate {
return this.props.fecha;
}
}

View File

@ -1,65 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Se puede definir una entidad específica para las líneas de detalle
clienteOProveedor: any; // Se puede definir una entidad específica para el cliente o proveedor
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props);
factura.addDomainEvent(new FacturaDraft(factura.id, props.referencia));
return Result.ok(factura);
}
emit(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.draft) {
return Result.fail(new Error("La factura solo puede ser emitida en estado 'draft'."));
}
this.props.estado = FacturaStatus.emitted();
this.addDomainEvent(new FacturaEmitted(this.id));
return Result.ok();
}
send(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.emitted) {
return Result.fail(new Error("La factura solo puede ser enviada en estado 'emitted'."));
}
this.props.estado = FacturaStatus.sent();
this.addDomainEvent(new FacturaSent(this.id));
return Result.ok();
}
reject(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.draft) {
return Result.fail(new Error("La factura solo puede ser rechazada en estado 'draft'."));
}
this.props.estado = FacturaStatus.rejected();
this.addDomainEvent(new FacturaRejected(this.id));
return Result.ok();
}
get referencia(): FacturaReference {
return this.props.referencia;
}
get estado(): FacturaStatus {
return this.props.estado;
}
get fecha(): UTCDate {
return this.props.fecha;
}
}

View File

@ -1,63 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico para las líneas de detalle
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props, props.id);
factura.addDomainEvent(new FacturaDraft(props.id));
return Result.ok(factura);
}
update(props: Partial<IFacturaProps>): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede modificar en estado 'draft'."));
}
Object.assign(this.props, props);
}
emit(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede emitir en estado 'draft'."));
}
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.props.id));
}
send(): Result<void, Error> {
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.props.id));
}
reject(): Result<void, Error> {
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.props.id));
}
get referencia(): FacturaReference {
return this.props.referencia;
}
get estado(): FacturaStatus {
return this.props.estado;
}
get fecha(): UTCDate {
return this.props.fecha;
}
}

View File

@ -1,66 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico si es necesario
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props, props.id);
factura.addDomainEvent(new FacturaDraft(props.id));
return Result.ok(factura);
}
update(props: Partial<IFacturaProps>): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede modificar en estado 'draft'."));
}
Object.assign(this.props, props);
}
emit(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede emitir en estado 'draft'."));
}
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.props.id));
return Result.ok();
}
send(): Result<void, Error> {
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.props.id));
return Result.ok();
}
reject(): Result<void, Error> {
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.props.id));
return Result.ok();
}
get referencia(): FacturaReference {
return this.props.referencia;
}
get estado(): FacturaStatus {
return this.props.estado;
}
get fecha(): UTCDate {
return this.props.fecha;
}
}

View File

@ -1,73 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico si es necesario
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props, props.id);
factura.addDomainEvent(new FacturaDraft(props.id));
return Result.ok(factura);
}
emit(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.draft) {
return Result.fail(new Error("La factura solo puede ser emitida en estado 'draft'."));
}
this.props.estado = FacturaStatus.emitted;
this.addDomainEvent(new FacturaEmitted(this.props.id));
return Result.ok();
}
send(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.emitted) {
return Result.fail(new Error("La factura solo puede ser enviada en estado 'emitted'."));
}
this.props.estado = FacturaStatus.sent;
this.addDomainEvent(new FacturaSent(this.props.id));
return Result.ok();
}
reject(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.draft) {
return Result.fail(new Error("La factura solo puede ser rechazada en estado 'draft'."));
}
this.props.estado = FacturaStatus.rejected;
this.addDomainEvent(new FacturaRejected(this.props.id));
return Result.ok();
}
get referencia(): FacturaReference {
return this.props.referencia;
}
get estado(): FacturaStatus {
return this.props.estado;
}
get fecha(): UTCDate {
return this.props.fecha;
}
get lineasDetalle(): any[] {
return this.props.lineasDetalle;
}
get clienteOProveedor(): string {
return this.props.clienteOProveedor;
}
}

View File

@ -1,63 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico para las líneas de detalle
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props, props.id);
factura.addDomainEvent(new FacturaDraft(props.id));
return Result.ok(factura);
}
modify(newProps: Partial<IFacturaProps>): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede modificar en estado 'draft'."));
}
Object.assign(this.props, newProps);
}
emit(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede emitir en estado 'draft'."));
}
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.props.id));
}
send(): Result<void, Error> {
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.props.id));
}
reject(): Result<void, Error> {
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.props.id));
}
get referencia(): FacturaReference {
return this.props.referencia;
}
get estado(): FacturaStatus {
return this.props.estado;
}
get fecha(): UTCDate {
return this.props.fecha;
}
}

View File

@ -1,60 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico para las líneas de detalle
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props, props.id);
factura.addDomainEvent(new FacturaDraft(props.id));
return Result.ok(factura);
}
modify(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede modificar en estado 'draft'."));
}
// Lógica para modificar la factura
return Result.ok();
}
delete(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede eliminar en estado 'draft'."));
}
// Lógica para eliminar la factura
return Result.ok();
}
emit(): Result<void, Error> {
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.props.id));
return Result.ok();
}
send(): Result<void, Error> {
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.props.id));
return Result.ok();
}
reject(): Result<void, Error> {
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.props.id));
return Result.ok();
}
}

View File

@ -1,60 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico si es necesario
clienteOProveedor: any; // Aquí puedes definir un tipo más específico si es necesario
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props);
factura.addDomainEvent(new FacturaDraft(factura.id, props.referencia));
return Result.ok(factura);
}
modify(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede modificar en estado 'draft'."));
}
// Lógica para modificar la factura
return Result.ok();
}
delete(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede eliminar en estado 'draft'."));
}
// Lógica para eliminar la factura
return Result.ok();
}
emit(): Result<void, Error> {
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.id));
return Result.ok();
}
send(): Result<void, Error> {
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.id));
return Result.ok();
}
reject(): Result<void, Error> {
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.id));
return Result.ok();
}
}

View File

@ -1,60 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico para las líneas de detalle
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props, props.id);
factura.addDomainEvent(new FacturaDraft(factura.id));
return Result.ok(factura);
}
update(props: Partial<IFacturaProps>): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede modificar en estado 'draft'."));
}
Object.assign(this.props, props);
}
emit(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede emitir en estado 'draft'."));
}
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.id));
return Result.ok();
}
send(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createEmitted()) {
return Result.fail(new Error("La factura solo se puede enviar si ha sido emitida."));
}
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.id));
return Result.ok();
}
reject(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede rechazar en estado 'draft'."));
}
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.id));
return Result.ok();
}
}

View File

@ -1,66 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico si es necesario
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props, props.id);
factura.addDomainEvent(new FacturaDraft(props.id));
return Result.ok(factura);
}
update(props: Partial<IFacturaProps>): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede modificar en estado 'draft'."));
}
Object.assign(this.props, props);
}
emit(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede emitir en estado 'draft'."));
}
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.props.id));
return Result.ok();
}
send(): Result<void, Error> {
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.props.id));
return Result.ok();
}
reject(): Result<void, Error> {
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.props.id));
return Result.ok();
}
get referencia(): FacturaReference {
return this.props.referencia;
}
get estado(): FacturaStatus {
return this.props.estado;
}
get fecha(): UTCDate {
return this.props.fecha;
}
}

View File

@ -1,73 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico si es necesario
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props, props.id);
factura.addDomainEvent(new FacturaDraft(factura.id));
return Result.ok(factura);
}
emit(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.draft) {
return Result.fail(new Error("La factura solo puede ser emitida en estado 'draft'."));
}
this.props.estado = FacturaStatus.emitted;
this.addDomainEvent(new FacturaEmitted(this.id));
return Result.ok();
}
send(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.emitted) {
return Result.fail(new Error("La factura solo puede ser enviada en estado 'emitted'."));
}
this.props.estado = FacturaStatus.sent;
this.addDomainEvent(new FacturaSent(this.id));
return Result.ok();
}
reject(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.draft) {
return Result.fail(new Error("La factura solo puede ser rechazada en estado 'draft'."));
}
this.props.estado = FacturaStatus.rejected;
this.addDomainEvent(new FacturaRejected(this.id));
return Result.ok();
}
get referencia(): FacturaReference {
return this.props.referencia;
}
get estado(): FacturaStatus {
return this.props.estado;
}
get fecha(): UTCDate {
return this.props.fecha;
}
get lineasDetalle(): any[] {
return this.props.lineasDetalle;
}
get clienteOProveedor(): string {
return this.props.clienteOProveedor;
}
}

View File

@ -1,66 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico si es necesario
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props, props.id);
factura.addDomainEvent(new FacturaDraft(props.id));
return Result.ok(factura);
}
modify(newProps: Partial<IFacturaProps>): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede modificar en estado 'draft'."));
}
Object.assign(this.props, newProps);
}
emit(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede emitir en estado 'draft'."));
}
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.props.id));
return Result.ok();
}
send(): Result<void, Error> {
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.props.id));
return Result.ok();
}
reject(): Result<void, Error> {
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.props.id));
return Result.ok();
}
get referencia(): FacturaReference {
return this.props.referencia;
}
get estado(): FacturaStatus {
return this.props.estado;
}
get fecha(): UTCDate {
return this.props.fecha;
}
}

View File

@ -1,65 +0,0 @@
// filepath: /home/rodax/Documentos/uecko-erp/apps/server/src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico para las líneas de detalle
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props);
// Emitir evento de dominio "FacturaDraft"
factura.addDomainEvent(new FacturaDraft(factura.id));
return Result.ok(factura);
}
modify(newProps: Partial<IFacturaProps>): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede modificar en estado 'draft'."));
}
Object.assign(this.props, newProps);
return Result.ok();
}
delete(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede eliminar en estado 'draft'."));
}
// Lógica para eliminar la factura
return Result.ok();
}
emit(): Result<void, Error> {
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.id));
return Result.ok();
}
send(): Result<void, Error> {
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.id));
return Result.ok();
}
reject(): Result<void, Error> {
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.id));
return Result.ok();
}
}

View File

@ -1,73 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico para las líneas de detalle
clienteOProveedor: string; // Puede ser un ID o un objeto más complejo
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props);
factura.addDomainEvent(new FacturaDraft(props.id));
return Result.ok(factura);
}
emit(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede emitir en estado 'draft'."));
}
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.props.id));
return Result.ok();
}
send(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createEmitted()) {
return Result.fail(new Error("La factura solo se puede enviar en estado 'emitted'."));
}
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.props.id));
return Result.ok();
}
reject(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede rechazar en estado 'draft'."));
}
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.props.id));
return Result.ok();
}
get referencia(): FacturaReference {
return this.props.referencia;
}
get estado(): FacturaStatus {
return this.props.estado;
}
get fecha(): UTCDate {
return this.props.fecha;
}
get lineasDetalle(): any[] {
return this.props.lineasDetalle;
}
get clienteOProveedor(): string {
return this.props.clienteOProveedor;
}
}

View File

@ -1,60 +0,0 @@
// filepath: src/contexts/billing/domain/aggregates/factura.ts
import { AggregateRoot, UniqueID, UTCDate } from "@common/domain";
import { Result } from "@common/helpers";
import { FacturaDraft } from "../events/factura-draft";
import { FacturaEmitted } from "../events/factura-emitted";
import { FacturaSent } from "../events/factura-sent";
import { FacturaRejected } from "../events/factura-rejected";
import { FacturaReference } from "../value-objects/factura-reference";
import { FacturaStatus } from "../value-objects/factura-status";
export interface IFacturaProps {
id: UniqueID;
referencia: FacturaReference;
lineasDetalle: any[]; // Aquí puedes definir un tipo más específico si es necesario
clienteOProveedor: any; // Aquí puedes definir un tipo más específico si es necesario
estado: FacturaStatus;
fecha: UTCDate;
}
export class Factura extends AggregateRoot<IFacturaProps> {
static create(props: IFacturaProps): Result<Factura, Error> {
const factura = new Factura(props, props.id);
factura.addDomainEvent(new FacturaDraft(factura.id, props.referencia));
return Result.ok(factura);
}
modify(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede modificar en estado 'draft'."));
}
// Lógica para modificar la factura
return Result.ok();
}
delete(): Result<void, Error> {
if (this.props.estado !== FacturaStatus.createDraft()) {
return Result.fail(new Error("La factura solo se puede eliminar en estado 'draft'."));
}
// Lógica para eliminar la factura
return Result.ok();
}
emit(): Result<void, Error> {
this.props.estado = FacturaStatus.createEmitted();
this.addDomainEvent(new FacturaEmitted(this.id));
return Result.ok();
}
send(): Result<void, Error> {
this.props.estado = FacturaStatus.createSent();
this.addDomainEvent(new FacturaSent(this.id));
return Result.ok();
}
reject(): Result<void, Error> {
this.props.estado = FacturaStatus.createRejected();
this.addDomainEvent(new FacturaRejected(this.id));
return Result.ok();
}
}