.
This commit is contained in:
parent
5a9e7261f9
commit
42987d688f
@ -18,10 +18,10 @@ export class EmailAddress extends ValueObject<EmailAddressProps> {
|
|||||||
|
|
||||||
static createNullable(value?: string): Result<Maybe<EmailAddress>, Error> {
|
static createNullable(value?: string): Result<Maybe<EmailAddress>, Error> {
|
||||||
if (!value || value.trim() === "") {
|
if (!value || value.trim() === "") {
|
||||||
return Result.ok(Maybe.None<EmailAddress>());
|
return Result.ok(Maybe.none<EmailAddress>());
|
||||||
}
|
}
|
||||||
|
|
||||||
return EmailAddress.create(value!).map((value) => Maybe.Some(value));
|
return EmailAddress.create(value!).map((value) => Maybe.some(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static validate(value: string) {
|
private static validate(value: string) {
|
||||||
|
|||||||
@ -28,10 +28,10 @@ export class Name extends ValueObject<INameProps> {
|
|||||||
|
|
||||||
static createNullable(value?: string): Result<Maybe<Name>, Error> {
|
static createNullable(value?: string): Result<Maybe<Name>, Error> {
|
||||||
if (!value || value.trim() === "") {
|
if (!value || value.trim() === "") {
|
||||||
return Result.ok(Maybe.None<Name>());
|
return Result.ok(Maybe.none<Name>());
|
||||||
}
|
}
|
||||||
|
|
||||||
return Name.create(value!).map((value) => Maybe.Some(value));
|
return Name.create(value!).map((value) => Maybe.some(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
static generateAcronym(name: string): string {
|
static generateAcronym(name: string): string {
|
||||||
|
|||||||
@ -24,7 +24,7 @@ describe("PhoneNumber", () => {
|
|||||||
test("debe devolver None para valores nulos o vacíos", () => {
|
test("debe devolver None para valores nulos o vacíos", () => {
|
||||||
const result = PhoneNumber.createNullable(nullablePhone);
|
const result = PhoneNumber.createNullable(nullablePhone);
|
||||||
expect(result.isSuccess).toBe(true);
|
expect(result.isSuccess).toBe(true);
|
||||||
expect(result.data).toEqual(Maybe.None());
|
expect(result.data).toEqual(Maybe.none());
|
||||||
});
|
});
|
||||||
|
|
||||||
test("debe devolver Some con un número de teléfono válido", () => {
|
test("debe devolver Some con un número de teléfono válido", () => {
|
||||||
|
|||||||
@ -20,10 +20,10 @@ export class PhoneNumber extends ValueObject<PhoneNumberProps> {
|
|||||||
|
|
||||||
static createNullable(value?: string): Result<Maybe<PhoneNumber>, Error> {
|
static createNullable(value?: string): Result<Maybe<PhoneNumber>, Error> {
|
||||||
if (!value || value.trim() === "") {
|
if (!value || value.trim() === "") {
|
||||||
return Result.ok(Maybe.None<PhoneNumber>());
|
return Result.ok(Maybe.none<PhoneNumber>());
|
||||||
}
|
}
|
||||||
|
|
||||||
return PhoneNumber.create(value!).map((value) => Maybe.Some(value));
|
return PhoneNumber.create(value!).map((value) => Maybe.some(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
static validate(value: string) {
|
static validate(value: string) {
|
||||||
|
|||||||
@ -24,7 +24,7 @@ describe("PostalAddress Value Object", () => {
|
|||||||
expect(result.error?.message).toBe("Invalid postal code format");
|
expect(result.error?.message).toBe("Invalid postal code format");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("✅ `createNullable` debería devolver Maybe.None si los valores son nulos o vacíos", () => {
|
test("✅ `createNullable` debería devolver Maybe.none si los valores son nulos o vacíos", () => {
|
||||||
expect(PostalAddress.createNullable().data.isSome()).toBe(false);
|
expect(PostalAddress.createNullable().data.isSome()).toBe(false);
|
||||||
expect(
|
expect(
|
||||||
PostalAddress.createNullable({
|
PostalAddress.createNullable({
|
||||||
@ -37,7 +37,7 @@ describe("PostalAddress Value Object", () => {
|
|||||||
).toBe(false);
|
).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("✅ `createNullable` debería devolver Maybe.Some si los valores son válidos", () => {
|
test("✅ `createNullable` debería devolver Maybe.some si los valores son válidos", () => {
|
||||||
const result = PostalAddress.createNullable(validAddress);
|
const result = PostalAddress.createNullable(validAddress);
|
||||||
|
|
||||||
expect(result.isSuccess).toBe(true);
|
expect(result.isSuccess).toBe(true);
|
||||||
|
|||||||
@ -18,28 +18,23 @@ const provinceSchema = z.string().min(2).max(50);
|
|||||||
const citySchema = z.string().min(2).max(50);
|
const citySchema = z.string().min(2).max(50);
|
||||||
|
|
||||||
const streetSchema = z.string().min(2).max(255);
|
const streetSchema = z.string().min(2).max(255);
|
||||||
|
const street2Schema = z.string().optional();
|
||||||
|
|
||||||
interface IPostalAddressProps {
|
interface IPostalAddressProps {
|
||||||
street: string;
|
street: string;
|
||||||
|
street2?: string;
|
||||||
city: string;
|
city: string;
|
||||||
postalCode: string;
|
postalCode: string;
|
||||||
state: string;
|
state: string;
|
||||||
country: string;
|
country: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPostalAddressPrimitives extends IPostalAddressProps {
|
|
||||||
street: string;
|
|
||||||
city: string;
|
|
||||||
postal_code: string;
|
|
||||||
state: string;
|
|
||||||
country: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class PostalAddress extends ValueObject<IPostalAddressProps> {
|
export class PostalAddress extends ValueObject<IPostalAddressProps> {
|
||||||
protected static validate(values: IPostalAddressProps) {
|
protected static validate(values: IPostalAddressProps) {
|
||||||
return z
|
return z
|
||||||
.object({
|
.object({
|
||||||
street: streetSchema,
|
street: streetSchema,
|
||||||
|
street2: street2Schema,
|
||||||
city: citySchema,
|
city: citySchema,
|
||||||
postalCode: postalCodeSchema,
|
postalCode: postalCodeSchema,
|
||||||
state: provinceSchema,
|
state: provinceSchema,
|
||||||
@ -54,21 +49,25 @@ export class PostalAddress extends ValueObject<IPostalAddressProps> {
|
|||||||
if (!valueIsValid.success) {
|
if (!valueIsValid.success) {
|
||||||
return Result.fail(new Error(valueIsValid.error.errors[0].message));
|
return Result.fail(new Error(valueIsValid.error.errors[0].message));
|
||||||
}
|
}
|
||||||
return Result.ok(new PostalAddress(valueIsValid.data!));
|
return Result.ok(new PostalAddress(values));
|
||||||
}
|
}
|
||||||
|
|
||||||
static createNullable(values?: IPostalAddressProps): Result<Maybe<PostalAddress>, Error> {
|
static createNullable(values?: IPostalAddressProps): Result<Maybe<PostalAddress>, Error> {
|
||||||
if (!values || Object.values(values).every((value) => value.trim() === "")) {
|
if (!values || Object.values(values).every((value) => value.trim() === "")) {
|
||||||
return Result.ok(Maybe.None<PostalAddress>());
|
return Result.ok(Maybe.none<PostalAddress>());
|
||||||
}
|
}
|
||||||
|
|
||||||
return PostalAddress.create(values!).map((value) => Maybe.Some(value));
|
return PostalAddress.create(values!).map((value) => Maybe.some(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
get street(): string {
|
get street(): string {
|
||||||
return this.props.street;
|
return this.props.street;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get street2(): Maybe<string> {
|
||||||
|
return Maybe.fromNullable(this.props.street2);
|
||||||
|
}
|
||||||
|
|
||||||
get city(): string {
|
get city(): string {
|
||||||
return this.props.city;
|
return this.props.city;
|
||||||
}
|
}
|
||||||
@ -90,6 +89,6 @@ export class PostalAddress extends ValueObject<IPostalAddressProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
return `${this.props.street}, ${this.props.city}, ${this.props.postalCode}, ${this.props.state}, ${this.props.country}`;
|
return `${this.props.street}, ${this.props.street2}, ${this.props.city}, ${this.props.postalCode}, ${this.props.state}, ${this.props.country}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,10 +33,10 @@ export class Slug extends ValueObject<SlugProps> {
|
|||||||
|
|
||||||
static createNullable(value?: string): Result<Maybe<Slug>, Error> {
|
static createNullable(value?: string): Result<Maybe<Slug>, Error> {
|
||||||
if (!value || value.trim() === "") {
|
if (!value || value.trim() === "") {
|
||||||
return Result.ok(Maybe.None<Slug>());
|
return Result.ok(Maybe.none<Slug>());
|
||||||
}
|
}
|
||||||
|
|
||||||
return Slug.create(value!).map((value: Slug) => Maybe.Some(value));
|
return Slug.create(value!).map((value: Slug) => Maybe.some(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
getValue(): string {
|
getValue(): string {
|
||||||
|
|||||||
@ -35,10 +35,10 @@ export class TINNumber extends ValueObject<TINNumberProps> {
|
|||||||
|
|
||||||
static createNullable(value?: string): Result<Maybe<TINNumber>, Error> {
|
static createNullable(value?: string): Result<Maybe<TINNumber>, Error> {
|
||||||
if (!value || value.trim() === "") {
|
if (!value || value.trim() === "") {
|
||||||
return Result.ok(Maybe.None<TINNumber>());
|
return Result.ok(Maybe.none<TINNumber>());
|
||||||
}
|
}
|
||||||
|
|
||||||
return TINNumber.create(value!).map((value) => Maybe.Some(value));
|
return TINNumber.create(value!).map((value) => Maybe.some(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
getValue(): string {
|
getValue(): string {
|
||||||
|
|||||||
@ -2,19 +2,19 @@ import { Maybe } from "./maybe";
|
|||||||
|
|
||||||
describe("Maybe", () => {
|
describe("Maybe", () => {
|
||||||
test("debe contener un valor cuando se usa Some", () => {
|
test("debe contener un valor cuando se usa Some", () => {
|
||||||
const maybeNumber = Maybe.Some(42);
|
const maybeNumber = Maybe.some(42);
|
||||||
expect(maybeNumber.isSome()).toBe(true);
|
expect(maybeNumber.isSome()).toBe(true);
|
||||||
expect(maybeNumber.getOrUndefined()).toBe(42);
|
expect(maybeNumber.getOrUndefined()).toBe(42);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("debe estar vacío cuando se usa None", () => {
|
test("debe estar vacío cuando se usa None", () => {
|
||||||
const maybeEmpty = Maybe.None<number>();
|
const maybeEmpty = Maybe.none<number>();
|
||||||
expect(maybeEmpty.isSome()).toBe(false);
|
expect(maybeEmpty.isSome()).toBe(false);
|
||||||
expect(maybeEmpty.getOrUndefined()).toBeUndefined();
|
expect(maybeEmpty.getOrUndefined()).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("map debe transformar el valor si existe", () => {
|
test("map debe transformar el valor si existe", () => {
|
||||||
const maybeNumber = Maybe.Some(10);
|
const maybeNumber = Maybe.some(10);
|
||||||
const maybeDoubled = maybeNumber.map((n) => n * 2);
|
const maybeDoubled = maybeNumber.map((n) => n * 2);
|
||||||
|
|
||||||
expect(maybeDoubled.isSome()).toBe(true);
|
expect(maybeDoubled.isSome()).toBe(true);
|
||||||
@ -22,7 +22,7 @@ describe("Maybe", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("map debe retornar None si el valor no existe", () => {
|
test("map debe retornar None si el valor no existe", () => {
|
||||||
const maybeEmpty = Maybe.None<number>();
|
const maybeEmpty = Maybe.none<number>();
|
||||||
const maybeTransformed = maybeEmpty.map((n) => n * 2);
|
const maybeTransformed = maybeEmpty.map((n) => n * 2);
|
||||||
|
|
||||||
expect(maybeTransformed.isSome()).toBe(false);
|
expect(maybeTransformed.isSome()).toBe(false);
|
||||||
|
|||||||
@ -1,22 +1,26 @@
|
|||||||
/**
|
/**
|
||||||
* Uso:
|
* Uso:
|
||||||
*
|
*
|
||||||
* const maybeNumber = Maybe.Some(10);
|
* const maybeNumber = Maybe.some(10);
|
||||||
* const doubled = maybeNumber.map(n => n * 2);
|
* const doubled = maybeNumber.map(n => n * 2);
|
||||||
* console.log(doubled.getValue()); // 20
|
* console.log(doubled.getValue()); // 20
|
||||||
|
|
||||||
* const noValue = Maybe.None<number>();
|
* const noValue = Maybe.none<number>();
|
||||||
* console.log(noValue.isSome()); // false
|
* console.log(noValue.isSome()); // false
|
||||||
**/
|
**/
|
||||||
|
|
||||||
export class Maybe<T> {
|
export class Maybe<T> {
|
||||||
private constructor(private readonly value?: T) {}
|
private constructor(private readonly value?: T) {}
|
||||||
|
|
||||||
static Some<T>(value: T): Maybe<T> {
|
static fromNullable<T>(value?: T): Maybe<T> {
|
||||||
|
return value === undefined || value === null ? Maybe.none() : Maybe.some(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static some<T>(value: T): Maybe<T> {
|
||||||
return new Maybe<T>(value);
|
return new Maybe<T>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static None<T>(): Maybe<T> {
|
static none<T>(): Maybe<T> {
|
||||||
return new Maybe<T>();
|
return new Maybe<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,6 +41,6 @@ export class Maybe<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
map<U>(fn: (value: T) => U): Maybe<U> {
|
map<U>(fn: (value: T) => U): Maybe<U> {
|
||||||
return this.isSome() ? Maybe.Some(fn(this.value as T)) : Maybe.None();
|
return this.isSome() ? Maybe.some(fn(this.value as T)) : Maybe.none();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,19 +46,19 @@ export class AccountMapper
|
|||||||
{
|
{
|
||||||
isFreelancer: source.is_freelancer,
|
isFreelancer: source.is_freelancer,
|
||||||
name: source.name,
|
name: source.name,
|
||||||
tradeName: source.trade_name ? Maybe.Some(source.trade_name) : Maybe.None(),
|
tradeName: source.trade_name ? Maybe.some(source.trade_name) : Maybe.none(),
|
||||||
tin: tinOrError.data,
|
tin: tinOrError.data,
|
||||||
address: postalAddressOrError.data,
|
address: postalAddressOrError.data,
|
||||||
email: emailOrError.data,
|
email: emailOrError.data,
|
||||||
phone: phoneOrError.data,
|
phone: phoneOrError.data,
|
||||||
fax: faxOrError.data,
|
fax: faxOrError.data,
|
||||||
website: source.website ? Maybe.Some(source.website) : Maybe.None(),
|
website: source.website ? Maybe.some(source.website) : Maybe.none(),
|
||||||
legalRecord: source.legal_record,
|
legalRecord: source.legal_record,
|
||||||
defaultTax: source.default_tax,
|
defaultTax: source.default_tax,
|
||||||
status: source.status,
|
status: source.status,
|
||||||
langCode: source.lang_code,
|
langCode: source.lang_code,
|
||||||
currencyCode: source.currency_code,
|
currencyCode: source.currency_code,
|
||||||
logo: source.logo ? Maybe.Some(source.logo) : Maybe.None(),
|
logo: source.logo ? Maybe.some(source.logo) : Maybe.none(),
|
||||||
},
|
},
|
||||||
idOrError.data
|
idOrError.data
|
||||||
);
|
);
|
||||||
|
|||||||
@ -47,13 +47,13 @@ export class ContactMapper
|
|||||||
isFreelancer: source.is_freelancer,
|
isFreelancer: source.is_freelancer,
|
||||||
reference: source.reference,
|
reference: source.reference,
|
||||||
name: source.name,
|
name: source.name,
|
||||||
tradeName: source.trade_name ? Maybe.Some(source.trade_name) : Maybe.None(),
|
tradeName: source.trade_name ? Maybe.some(source.trade_name) : Maybe.none(),
|
||||||
tin: tinOrError.data,
|
tin: tinOrError.data,
|
||||||
address: postalAddressOrError.data,
|
address: postalAddressOrError.data,
|
||||||
email: emailOrError.data,
|
email: emailOrError.data,
|
||||||
phone: phoneOrError.data,
|
phone: phoneOrError.data,
|
||||||
fax: faxOrError.data,
|
fax: faxOrError.data,
|
||||||
website: source.website ? Maybe.Some(source.website) : Maybe.None(),
|
website: source.website ? Maybe.some(source.website) : Maybe.none(),
|
||||||
legalRecord: source.legal_record,
|
legalRecord: source.legal_record,
|
||||||
defaultTax: source.default_tax,
|
defaultTax: source.default_tax,
|
||||||
status: source.status,
|
status: source.status,
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
import { AggregateRoot, UniqueID, UtcDate } from "@common/domain";
|
import { AggregateRoot, UniqueID, UtcDate } from "@common/domain";
|
||||||
import { Result } from "@common/helpers";
|
import { Result } from "@common/helpers";
|
||||||
import { CustomerInvoiceItem } from "../../entities";
|
import { Customer, CustomerInvoiceItem } from "../entities";
|
||||||
import { InvoiceStatus } from "../../value-objetcs";
|
import { InvoiceStatus } from "../value-objetcs";
|
||||||
import { Customer } from "../customer/customer";
|
|
||||||
|
|
||||||
export interface ICustomerInvoiceProps {
|
export interface ICustomerInvoiceProps {
|
||||||
status: InvoiceStatus;
|
status: InvoiceStatus;
|
||||||
issueDate: UtcDate;
|
issueDate: UtcDate;
|
||||||
invoiceNumber: string;
|
invoiceNumber: string;
|
||||||
invoiceType: string;
|
invoiceType: string;
|
||||||
|
invoiceCustomerReference: string;
|
||||||
|
|
||||||
customer: Customer;
|
customer: Customer;
|
||||||
items: CustomerInvoiceItem[];
|
items: CustomerInvoiceItem[];
|
||||||
@ -20,6 +20,7 @@ export interface ICustomerInvoice {
|
|||||||
issueDate: UtcDate;
|
issueDate: UtcDate;
|
||||||
invoiceNumber: string;
|
invoiceNumber: string;
|
||||||
invoiceType: string;
|
invoiceType: string;
|
||||||
|
invoiceCustomerReference: string;
|
||||||
|
|
||||||
customer: Customer;
|
customer: Customer;
|
||||||
items: CustomerInvoiceItem[];
|
items: CustomerInvoiceItem[];
|
||||||
@ -62,6 +63,10 @@ export class CustomerInvoice
|
|||||||
return this.props.invoiceType;
|
return this.props.invoiceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get invoiceCustomerReference(): string {
|
||||||
|
return this.props.invoiceCustomerReference;
|
||||||
|
}
|
||||||
|
|
||||||
get customer(): Customer {
|
get customer(): Customer {
|
||||||
return this.props.customer;
|
return this.props.customer;
|
||||||
}
|
}
|
||||||
@ -1 +0,0 @@
|
|||||||
export * from "./customer-invoice";
|
|
||||||
@ -1,130 +0,0 @@
|
|||||||
import {
|
|
||||||
AggregateRoot,
|
|
||||||
EmailAddress,
|
|
||||||
PhoneNumber,
|
|
||||||
PostalAddress,
|
|
||||||
TINNumber,
|
|
||||||
UniqueID,
|
|
||||||
} from "@common/domain";
|
|
||||||
import { Maybe, Result } from "@common/helpers";
|
|
||||||
|
|
||||||
export interface ICustomerProps {
|
|
||||||
reference: string;
|
|
||||||
isFreelancer: boolean;
|
|
||||||
name: string;
|
|
||||||
tin: TINNumber;
|
|
||||||
address: PostalAddress;
|
|
||||||
email: EmailAddress;
|
|
||||||
phone: PhoneNumber;
|
|
||||||
legalRecord: string;
|
|
||||||
defaultTax: number;
|
|
||||||
status: string;
|
|
||||||
langCode: string;
|
|
||||||
currencyCode: string;
|
|
||||||
|
|
||||||
tradeName: Maybe<string>;
|
|
||||||
website: Maybe<string>;
|
|
||||||
fax: Maybe<PhoneNumber>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ICustomer {
|
|
||||||
id: UniqueID;
|
|
||||||
reference: string;
|
|
||||||
name: string;
|
|
||||||
tin: TINNumber;
|
|
||||||
address: PostalAddress;
|
|
||||||
email: EmailAddress;
|
|
||||||
phone: PhoneNumber;
|
|
||||||
legalRecord: string;
|
|
||||||
defaultTax: number;
|
|
||||||
langCode: string;
|
|
||||||
currencyCode: string;
|
|
||||||
|
|
||||||
tradeName: Maybe<string>;
|
|
||||||
fax: Maybe<PhoneNumber>;
|
|
||||||
website: Maybe<string>;
|
|
||||||
|
|
||||||
isCustomer: boolean;
|
|
||||||
isFreelancer: boolean;
|
|
||||||
isActive: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Customer extends AggregateRoot<ICustomerProps> implements ICustomer {
|
|
||||||
static create(props: ICustomerProps, id?: UniqueID): Result<Customer, Error> {
|
|
||||||
const customer = new Customer(props, id);
|
|
||||||
|
|
||||||
// Reglas de negocio / validaciones
|
|
||||||
// ...
|
|
||||||
// ...
|
|
||||||
|
|
||||||
// 🔹 Disparar evento de dominio "CustomerAuthenticatedEvent"
|
|
||||||
//const { customer } = props;
|
|
||||||
//user.addDomainEvent(new CustomerAuthenticatedEvent(id, customer.toString()));
|
|
||||||
|
|
||||||
return Result.ok(customer);
|
|
||||||
}
|
|
||||||
|
|
||||||
get reference() {
|
|
||||||
return this.props.reference;
|
|
||||||
}
|
|
||||||
|
|
||||||
get name() {
|
|
||||||
return this.props.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
get tradeName() {
|
|
||||||
return this.props.tradeName;
|
|
||||||
}
|
|
||||||
|
|
||||||
get tin(): TINNumber {
|
|
||||||
return this.props.tin;
|
|
||||||
}
|
|
||||||
|
|
||||||
get address(): PostalAddress {
|
|
||||||
return this.props.address;
|
|
||||||
}
|
|
||||||
|
|
||||||
get email(): EmailAddress {
|
|
||||||
return this.props.email;
|
|
||||||
}
|
|
||||||
|
|
||||||
get phone(): PhoneNumber {
|
|
||||||
return this.props.phone;
|
|
||||||
}
|
|
||||||
|
|
||||||
get fax(): Maybe<PhoneNumber> {
|
|
||||||
return this.props.fax;
|
|
||||||
}
|
|
||||||
|
|
||||||
get website() {
|
|
||||||
return this.props.website;
|
|
||||||
}
|
|
||||||
|
|
||||||
get legalRecord() {
|
|
||||||
return this.props.legalRecord;
|
|
||||||
}
|
|
||||||
|
|
||||||
get defaultTax() {
|
|
||||||
return this.props.defaultTax;
|
|
||||||
}
|
|
||||||
|
|
||||||
get langCode() {
|
|
||||||
return this.props.langCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
get currencyCode() {
|
|
||||||
return this.props.currencyCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
get isCustomer(): boolean {
|
|
||||||
return !this.props.isFreelancer;
|
|
||||||
}
|
|
||||||
|
|
||||||
get isFreelancer(): boolean {
|
|
||||||
return this.props.isFreelancer;
|
|
||||||
}
|
|
||||||
|
|
||||||
get isActive(): boolean {
|
|
||||||
return this.props.status === "active";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
export * from "./customer";
|
|
||||||
@ -1,2 +1 @@
|
|||||||
export * from "./customer";
|
|
||||||
export * from "./customer-invoice";
|
export * from "./customer-invoice";
|
||||||
|
|||||||
@ -57,28 +57,28 @@ export class CustomerInvoiceItem
|
|||||||
|
|
||||||
calculateSubtotal(): Maybe<MoneyValue> {
|
calculateSubtotal(): Maybe<MoneyValue> {
|
||||||
if (this.quantity.isNone() || this.unitPrice.isNone()) {
|
if (this.quantity.isNone() || this.unitPrice.isNone()) {
|
||||||
return Maybe.None();
|
return Maybe.none();
|
||||||
}
|
}
|
||||||
|
|
||||||
const _quantity = this.quantity.getOrUndefined()!;
|
const _quantity = this.quantity.getOrUndefined()!;
|
||||||
const _unitPrice = this.unitPrice.getOrUndefined()!;
|
const _unitPrice = this.unitPrice.getOrUndefined()!;
|
||||||
const _subtotal = _unitPrice.multiply(_quantity);
|
const _subtotal = _unitPrice.multiply(_quantity);
|
||||||
|
|
||||||
return Maybe.Some(_subtotal);
|
return Maybe.some(_subtotal);
|
||||||
}
|
}
|
||||||
|
|
||||||
calculateTotal(): Maybe<MoneyValue> {
|
calculateTotal(): Maybe<MoneyValue> {
|
||||||
const subtotal = this.calculateSubtotal();
|
const subtotal = this.calculateSubtotal();
|
||||||
|
|
||||||
if (subtotal.isNone()) {
|
if (subtotal.isNone()) {
|
||||||
return Maybe.None();
|
return Maybe.none();
|
||||||
}
|
}
|
||||||
|
|
||||||
const _subtotal = subtotal.getOrUndefined()!;
|
const _subtotal = subtotal.getOrUndefined()!;
|
||||||
const _discount = this.discount.getOrUndefined()!;
|
const _discount = this.discount.getOrUndefined()!;
|
||||||
const _total = _subtotal.subtract(_subtotal.percentage(_discount));
|
const _total = _subtotal.subtract(_subtotal.percentage(_discount));
|
||||||
|
|
||||||
return Maybe.Some(_total);
|
return Maybe.some(_total);
|
||||||
}
|
}
|
||||||
|
|
||||||
get description(): Maybe<string> {
|
get description(): Maybe<string> {
|
||||||
|
|||||||
@ -0,0 +1,44 @@
|
|||||||
|
import { AggregateRoot, PostalAddress, TINNumber, UniqueID } from "@common/domain";
|
||||||
|
import { Result } from "@common/helpers";
|
||||||
|
|
||||||
|
export interface ICustomerProps {
|
||||||
|
name: string;
|
||||||
|
tin: TINNumber;
|
||||||
|
address: PostalAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICustomer {
|
||||||
|
id: UniqueID;
|
||||||
|
|
||||||
|
name: string;
|
||||||
|
tin: TINNumber;
|
||||||
|
address: PostalAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Customer extends AggregateRoot<ICustomerProps> implements ICustomer {
|
||||||
|
static create(props: ICustomerProps, id?: UniqueID): Result<Customer, Error> {
|
||||||
|
const customer = new Customer(props, id);
|
||||||
|
|
||||||
|
// Reglas de negocio / validaciones
|
||||||
|
// ...
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// 🔹 Disparar evento de dominio "CustomerAuthenticatedEvent"
|
||||||
|
//const { customer } = props;
|
||||||
|
//user.addDomainEvent(new CustomerAuthenticatedEvent(id, customer.toString()));
|
||||||
|
|
||||||
|
return Result.ok(customer);
|
||||||
|
}
|
||||||
|
|
||||||
|
get name() {
|
||||||
|
return this.props.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
get tin(): TINNumber {
|
||||||
|
return this.props.tin;
|
||||||
|
}
|
||||||
|
|
||||||
|
get address(): PostalAddress {
|
||||||
|
return this.props.address;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
export * from "./customer";
|
||||||
export * from "./customer-invoice-item";
|
export * from "./customer-invoice-item";
|
||||||
export * from "./tax";
|
export * from "./tax";
|
||||||
export * from "./tax-collection";
|
export * from "./tax-collection";
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
export * from "./aggregates";
|
export * from "./aggregates";
|
||||||
|
export * from "./entities";
|
||||||
export * from "./repositories";
|
export * from "./repositories";
|
||||||
export * from "./services";
|
export * from "./services";
|
||||||
|
|||||||
@ -1,9 +0,0 @@
|
|||||||
import { EmailAddress, UniqueID } from "@common/domain";
|
|
||||||
import { Collection, Result } from "@common/helpers";
|
|
||||||
import { Customer } from "../aggregates";
|
|
||||||
|
|
||||||
export interface ICustomerRepository {
|
|
||||||
findAll(transaction?: any): Promise<Result<Collection<Customer>, Error>>;
|
|
||||||
findById(id: UniqueID, transaction?: any): Promise<Result<Customer, Error>>;
|
|
||||||
findByEmail(email: EmailAddress, transaction?: any): Promise<Result<Customer, Error>>;
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
import { UniqueID } from "@common/domain";
|
|
||||||
import { Collection, Result } from "@common/helpers";
|
|
||||||
import { Customer } from "../aggregates";
|
|
||||||
|
|
||||||
export interface ICustomerService {
|
|
||||||
findCustomer(transaction?: any): Promise<Result<Collection<Customer>, Error>>;
|
|
||||||
findCustomerById(customerId: UniqueID, transaction?: any): Promise<Result<Customer>>;
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
import { UniqueID } from "@common/domain";
|
|
||||||
import { Collection, Result } from "@common/helpers";
|
|
||||||
import { Customer } from "../aggregates";
|
|
||||||
import { ICustomerRepository } from "../repositories";
|
|
||||||
import { ICustomerService } from "./customer-service.interface";
|
|
||||||
|
|
||||||
export class CustomerService implements ICustomerService {
|
|
||||||
constructor(private readonly customerRepository: ICustomerRepository) {}
|
|
||||||
|
|
||||||
async findCustomer(transaction?: any): Promise<Result<Collection<Customer>, Error>> {
|
|
||||||
const customersOrError = await this.customerRepository.findAll(transaction);
|
|
||||||
if (customersOrError.isFailure) {
|
|
||||||
return Result.fail(customersOrError.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Solo devolver usuarios activos
|
|
||||||
const activeCustomers = customersOrError.data.filter((customer) => customer.isActive);
|
|
||||||
return Result.ok(new Collection(activeCustomers));
|
|
||||||
}
|
|
||||||
|
|
||||||
async findCustomerById(customerId: UniqueID, transaction?: any): Promise<Result<Customer>> {
|
|
||||||
return await this.customerRepository.findById(customerId, transaction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,11 +1,11 @@
|
|||||||
import { UniqueID, UtcDate } from "@common/domain";
|
import { PostalAddress, TINNumber, UniqueID, UtcDate } from "@common/domain";
|
||||||
import { Result } from "@common/helpers";
|
import { Result } from "@common/helpers";
|
||||||
import {
|
import {
|
||||||
ISequelizeMapper,
|
ISequelizeMapper,
|
||||||
MapperParamsType,
|
MapperParamsType,
|
||||||
SequelizeMapper,
|
SequelizeMapper,
|
||||||
} from "@common/infrastructure/sequelize/sequelize-mapper";
|
} from "@common/infrastructure/sequelize/sequelize-mapper";
|
||||||
import { CustomerInvoice } from "@contexts/customer-billing/domain";
|
import { Customer, CustomerInvoice } from "@contexts/customer-billing/domain";
|
||||||
import { InvoiceStatus } from "@contexts/customer-billing/domain/value-objetcs";
|
import { InvoiceStatus } from "@contexts/customer-billing/domain/value-objetcs";
|
||||||
import {
|
import {
|
||||||
CustomerInvoiceCreationAttributes,
|
CustomerInvoiceCreationAttributes,
|
||||||
@ -31,67 +31,51 @@ export class CustomerInvoiceMapper
|
|||||||
const statusOrError = InvoiceStatus.create(source.status);
|
const statusOrError = InvoiceStatus.create(source.status);
|
||||||
const issueDateOrError = UtcDate.create(source.issue_date);
|
const issueDateOrError = UtcDate.create(source.issue_date);
|
||||||
|
|
||||||
const result = Result.combine([idOrError, statusOrError]);
|
const result = Result.combine([idOrError, statusOrError, issueDateOrError]);
|
||||||
|
|
||||||
if (result.isFailure) {
|
if (result.isFailure) {
|
||||||
return Result.fail(result.error);
|
return Result.fail(result.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Customer
|
||||||
|
const customerIdOrError = UniqueID.create(source.customer_id);
|
||||||
|
const tinOrError = TINNumber.create(source.customer_tin);
|
||||||
|
const postalAddressOrError = PostalAddress.create({
|
||||||
|
street: source.customer_street,
|
||||||
|
street2: source.customer_street2,
|
||||||
|
city: source.customer_city,
|
||||||
|
state: source.customer_state,
|
||||||
|
postalCode: source.customer_postal_code,
|
||||||
|
country: source.customer_country,
|
||||||
|
});
|
||||||
|
|
||||||
|
const check2 = Result.combine([idOrError, tinOrError, postalAddressOrError]);
|
||||||
|
|
||||||
|
if (check2.isFailure) {
|
||||||
|
return Result.fail(check2.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const customerOrError = Customer.create(
|
||||||
|
{
|
||||||
|
name: source.customer_name,
|
||||||
|
tin: tinOrError.data,
|
||||||
|
address: postalAddressOrError.data,
|
||||||
|
},
|
||||||
|
customerIdOrError.data
|
||||||
|
);
|
||||||
|
|
||||||
return CustomerInvoice.create(
|
return CustomerInvoice.create(
|
||||||
{
|
{
|
||||||
status: statusOrError.data,
|
status: statusOrError.data,
|
||||||
issueDate: issueDateOrError.data,
|
issueDate: issueDateOrError.data,
|
||||||
invoiceNumber: source.invoice_number,
|
invoiceNumber: source.invoice_number,
|
||||||
invoiceType: source.invoice_type,
|
invoiceType: source.invoice_type,
|
||||||
|
invoiceCustomerReference: source.invoice_customer_reference,
|
||||||
|
customer: customerOrError.data,
|
||||||
|
items: [],
|
||||||
},
|
},
|
||||||
idOrError.data
|
idOrError.data
|
||||||
);
|
);
|
||||||
|
|
||||||
/*const tinOrError = TINNumber.create(source.tin);
|
|
||||||
const emailOrError = EmailAddress.create(source.email);
|
|
||||||
const phoneOrError = PhoneNumber.create(source.phone);
|
|
||||||
const faxOrError = PhoneNumber.createNullable(source.fax);
|
|
||||||
const postalAddressOrError = PostalAddress.create({
|
|
||||||
street: source.street,
|
|
||||||
city: source.city,
|
|
||||||
state: source.state,
|
|
||||||
postalCode: source.postal_code,
|
|
||||||
country: source.country,
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = Result.combine([
|
|
||||||
idOrError,
|
|
||||||
tinOrError,
|
|
||||||
emailOrError,
|
|
||||||
phoneOrError,
|
|
||||||
faxOrError,
|
|
||||||
postalAddressOrError,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (result.isFailure) {
|
|
||||||
return Result.fail(result.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Customer.create(
|
|
||||||
{
|
|
||||||
isFreelancer: source.is_freelancer,
|
|
||||||
reference: source.reference,
|
|
||||||
name: source.name,
|
|
||||||
tradeName: source.trade_name ? Maybe.Some(source.trade_name) : Maybe.None(),
|
|
||||||
tin: tinOrError.data,
|
|
||||||
address: postalAddressOrError.data,
|
|
||||||
email: emailOrError.data,
|
|
||||||
phone: phoneOrError.data,
|
|
||||||
fax: faxOrError.data,
|
|
||||||
website: source.website ? Maybe.Some(source.website) : Maybe.None(),
|
|
||||||
legalRecord: source.legal_record,
|
|
||||||
defaultTax: source.default_tax,
|
|
||||||
status: source.status,
|
|
||||||
langCode: source.lang_code,
|
|
||||||
currencyCode: source.currency_code,
|
|
||||||
},
|
|
||||||
idOrError.data
|
|
||||||
);*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public mapToPersistence(
|
public mapToPersistence(
|
||||||
@ -101,32 +85,25 @@ export class CustomerInvoiceMapper
|
|||||||
return Result.ok({
|
return Result.ok({
|
||||||
id: source.id.toString(),
|
id: source.id.toString(),
|
||||||
status: source.status.toString(),
|
status: source.status.toString(),
|
||||||
|
|
||||||
|
issue_date: source.issueDate.toDateString(),
|
||||||
|
invoice_number: source.invoiceNumber,
|
||||||
|
invoice_type: source.invoiceType,
|
||||||
|
invoice_customer_reference: source.invoiceCustomerReference,
|
||||||
|
|
||||||
|
lang_code: "es",
|
||||||
|
currency_code: "EUR",
|
||||||
|
|
||||||
|
customer_id: source.customer.id.toString(),
|
||||||
|
customer_name: source.customer.name,
|
||||||
|
customer_tin: source.customer.tin.toString(),
|
||||||
|
customer_street: source.customer.address.street,
|
||||||
|
customer_street2: source.customer.address.street2.getOrUndefined(),
|
||||||
|
customer_city: source.customer.address.city,
|
||||||
|
customer_postal_code: source.customer.address.postalCode,
|
||||||
|
customer_state: source.customer.address.state,
|
||||||
|
customer_country: source.customer.address.country,
|
||||||
});
|
});
|
||||||
/*return Result.ok({
|
|
||||||
id: source.id.toString(),
|
|
||||||
reference: source.reference,
|
|
||||||
is_freelancer: source.isFreelancer,
|
|
||||||
name: source.name,
|
|
||||||
trade_name: source.tradeName.isSome() ? source.tradeName.getValue() : undefined,
|
|
||||||
tin: source.tin.toString(),
|
|
||||||
|
|
||||||
street: source.address.street,
|
|
||||||
city: source.address.city,
|
|
||||||
state: source.address.state,
|
|
||||||
postal_code: source.address.postalCode,
|
|
||||||
country: source.address.country,
|
|
||||||
|
|
||||||
email: source.email.toString(),
|
|
||||||
phone: source.phone.toString(),
|
|
||||||
fax: source.fax.isSome() ? source.fax.getValue()?.toString() : undefined,
|
|
||||||
website: source.website.isSome() ? source.website.getValue() : undefined,
|
|
||||||
|
|
||||||
legal_record: source.legalRecord,
|
|
||||||
default_tax: source.defaultTax,
|
|
||||||
status: source.isActive ? "active" : "inactive",
|
|
||||||
lang_code: source.langCode,
|
|
||||||
currency_code: source.currencyCode,
|
|
||||||
});*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,100 +0,0 @@
|
|||||||
import { EmailAddress, PhoneNumber, PostalAddress, TINNumber, UniqueID } from "@common/domain";
|
|
||||||
import { Maybe, Result } from "@common/helpers";
|
|
||||||
import {
|
|
||||||
ISequelizeMapper,
|
|
||||||
MapperParamsType,
|
|
||||||
SequelizeMapper,
|
|
||||||
} from "@common/infrastructure/sequelize/sequelize-mapper";
|
|
||||||
import { Customer } from "@contexts/customer-billing/domain";
|
|
||||||
import { CustomerCreationAttributes, CustomerModel } from "../sequelize/customer.model";
|
|
||||||
|
|
||||||
export interface ICustomerMapper
|
|
||||||
extends ISequelizeMapper<CustomerModel, CustomerCreationAttributes, Customer> {}
|
|
||||||
|
|
||||||
export class CustomerMapper
|
|
||||||
extends SequelizeMapper<CustomerModel, CustomerCreationAttributes, Customer>
|
|
||||||
implements ICustomerMapper
|
|
||||||
{
|
|
||||||
public mapToDomain(source: CustomerModel, params?: MapperParamsType): Result<Customer, Error> {
|
|
||||||
const idOrError = UniqueID.create(source.id);
|
|
||||||
const tinOrError = TINNumber.create(source.tin);
|
|
||||||
const emailOrError = EmailAddress.create(source.email);
|
|
||||||
const phoneOrError = PhoneNumber.create(source.phone);
|
|
||||||
const faxOrError = PhoneNumber.createNullable(source.fax);
|
|
||||||
const postalAddressOrError = PostalAddress.create({
|
|
||||||
street: source.street,
|
|
||||||
city: source.city,
|
|
||||||
state: source.state,
|
|
||||||
postalCode: source.postal_code,
|
|
||||||
country: source.country,
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = Result.combine([
|
|
||||||
idOrError,
|
|
||||||
tinOrError,
|
|
||||||
emailOrError,
|
|
||||||
phoneOrError,
|
|
||||||
faxOrError,
|
|
||||||
postalAddressOrError,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (result.isFailure) {
|
|
||||||
return Result.fail(result.error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Customer.create(
|
|
||||||
{
|
|
||||||
isFreelancer: source.is_freelancer,
|
|
||||||
reference: source.reference,
|
|
||||||
name: source.name,
|
|
||||||
tradeName: source.trade_name ? Maybe.Some(source.trade_name) : Maybe.None(),
|
|
||||||
tin: tinOrError.data,
|
|
||||||
address: postalAddressOrError.data,
|
|
||||||
email: emailOrError.data,
|
|
||||||
phone: phoneOrError.data,
|
|
||||||
fax: faxOrError.data,
|
|
||||||
website: source.website ? Maybe.Some(source.website) : Maybe.None(),
|
|
||||||
legalRecord: source.legal_record,
|
|
||||||
defaultTax: source.default_tax,
|
|
||||||
status: source.status,
|
|
||||||
langCode: source.lang_code,
|
|
||||||
currencyCode: source.currency_code,
|
|
||||||
},
|
|
||||||
idOrError.data
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public mapToPersistence(
|
|
||||||
source: Customer,
|
|
||||||
params?: MapperParamsType
|
|
||||||
): Result<CustomerCreationAttributes, Error> {
|
|
||||||
return Result.ok({
|
|
||||||
id: source.id.toString(),
|
|
||||||
reference: source.reference,
|
|
||||||
is_freelancer: source.isFreelancer,
|
|
||||||
name: source.name,
|
|
||||||
trade_name: source.tradeName.getOrUndefined(),
|
|
||||||
tin: source.tin.toString(),
|
|
||||||
|
|
||||||
street: source.address.street,
|
|
||||||
city: source.address.city,
|
|
||||||
state: source.address.state,
|
|
||||||
postal_code: source.address.postalCode,
|
|
||||||
country: source.address.country,
|
|
||||||
|
|
||||||
email: source.email.toString(),
|
|
||||||
phone: source.phone.toString(),
|
|
||||||
fax: source.fax.isSome() ? source.fax.getOrUndefined()?.toString() : undefined,
|
|
||||||
website: source.website.getOrUndefined(),
|
|
||||||
|
|
||||||
legal_record: source.legalRecord,
|
|
||||||
default_tax: source.defaultTax,
|
|
||||||
status: source.isActive ? "active" : "inactive",
|
|
||||||
lang_code: source.langCode,
|
|
||||||
currency_code: source.currencyCode,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const customerMapper: CustomerMapper = new CustomerMapper();
|
|
||||||
export { customerMapper };
|
|
||||||
@ -1 +1 @@
|
|||||||
export * from "./customer.mapper";
|
export * from "./customer-invoice.mapper";
|
||||||
|
|||||||
@ -23,21 +23,21 @@ export class CustomerInvoiceItemModel extends Model<
|
|||||||
|
|
||||||
CustomerInvoiceItemModel.belongsTo(CustomerInvoiceModel, {
|
CustomerInvoiceItemModel.belongsTo(CustomerInvoiceModel, {
|
||||||
as: "invoice",
|
as: "invoice",
|
||||||
foreignKey: "invoice_id",
|
foreignKey: "id",
|
||||||
onDelete: "CASCADE",
|
onDelete: "CASCADE",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
declare invoice_id: string;
|
declare customer_invoice_id: string;
|
||||||
declare item_id: string;
|
declare item_id: string;
|
||||||
declare id_article: CreationOptional<number | null>;
|
declare id_article: CreationOptional<number>;
|
||||||
declare position: number;
|
declare position: number;
|
||||||
declare description: CreationOptional<string | null>;
|
declare description: CreationOptional<string>;
|
||||||
declare quantity: CreationOptional<number | null>;
|
declare quantity: CreationOptional<number>;
|
||||||
declare unit_price: CreationOptional<number | null>;
|
declare unit_price: CreationOptional<number>;
|
||||||
declare subtotal_price: CreationOptional<number | null>;
|
declare subtotal_price: CreationOptional<number>;
|
||||||
declare discount: CreationOptional<number | null>;
|
declare discount: CreationOptional<number>;
|
||||||
declare total_price: CreationOptional<number | null>;
|
declare total_price: CreationOptional<number>;
|
||||||
|
|
||||||
declare invoice: NonAttribute<CustomerInvoiceModel>;
|
declare invoice: NonAttribute<CustomerInvoiceModel>;
|
||||||
}
|
}
|
||||||
@ -49,7 +49,7 @@ export default (sequelize: Sequelize) => {
|
|||||||
type: new DataTypes.UUID(),
|
type: new DataTypes.UUID(),
|
||||||
primaryKey: true,
|
primaryKey: true,
|
||||||
},
|
},
|
||||||
invoice_id: {
|
customer_invoice_id: {
|
||||||
type: new DataTypes.UUID(),
|
type: new DataTypes.UUID(),
|
||||||
primaryKey: true,
|
primaryKey: true,
|
||||||
},
|
},
|
||||||
@ -89,7 +89,7 @@ export default (sequelize: Sequelize) => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
sequelize,
|
sequelize,
|
||||||
tableName: "invoice_items",
|
tableName: "customer_invoice_items",
|
||||||
timestamps: false,
|
timestamps: false,
|
||||||
|
|
||||||
indexes: [],
|
indexes: [],
|
||||||
|
|||||||
@ -8,19 +8,19 @@ import {
|
|||||||
Sequelize,
|
Sequelize,
|
||||||
} from "sequelize";
|
} from "sequelize";
|
||||||
import { CustomerInvoiceItemModel } from "./customer-invoice-item.model";
|
import { CustomerInvoiceItemModel } from "./customer-invoice-item.model";
|
||||||
import { CustomerModel } from "./customer.model";
|
|
||||||
|
|
||||||
export type CustomerInvoiceCreationAttributes = InferCreationAttributes<
|
export type CustomerInvoiceCreationAttributes = InferCreationAttributes<
|
||||||
CustomerInvoiceModel,
|
CustomerInvoiceModel,
|
||||||
{ omit: "items" | "customer" }
|
{ omit: "items" }
|
||||||
> & {
|
> & {
|
||||||
|
// creo que no es necesario
|
||||||
//items: CustomerInvoiceItemCreationAttributes[];
|
//items: CustomerInvoiceItemCreationAttributes[];
|
||||||
customer_id: string;
|
//customer_id: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class CustomerInvoiceModel extends Model<
|
export class CustomerInvoiceModel extends Model<
|
||||||
InferAttributes<CustomerInvoiceModel, { omit: "items" | "customer" }>,
|
InferAttributes<CustomerInvoiceModel, { omit: "items" }>,
|
||||||
InferCreationAttributes<CustomerInvoiceModel, { omit: "items" | "customer" }>
|
InferCreationAttributes<CustomerInvoiceModel, { omit: "items" }>
|
||||||
> {
|
> {
|
||||||
// To avoid table creation
|
// To avoid table creation
|
||||||
/*static async sync(): Promise<any> {
|
/*static async sync(): Promise<any> {
|
||||||
@ -32,15 +32,9 @@ export class CustomerInvoiceModel extends Model<
|
|||||||
|
|
||||||
CustomerInvoiceModel.hasMany(CustomerInvoiceItemModel, {
|
CustomerInvoiceModel.hasMany(CustomerInvoiceItemModel, {
|
||||||
as: "items",
|
as: "items",
|
||||||
foreignKey: "quote_id",
|
foreignKey: "customer_invoice_id",
|
||||||
onDelete: "CASCADE",
|
onDelete: "CASCADE",
|
||||||
});
|
});
|
||||||
|
|
||||||
CustomerInvoiceModel.belongsTo(CustomerModel, {
|
|
||||||
foreignKey: "dealer_id",
|
|
||||||
as: "dealer",
|
|
||||||
onDelete: "RESTRICT",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare id: string;
|
declare id: string;
|
||||||
@ -49,6 +43,7 @@ export class CustomerInvoiceModel extends Model<
|
|||||||
declare issue_date: string;
|
declare issue_date: string;
|
||||||
declare invoice_number: string;
|
declare invoice_number: string;
|
||||||
declare invoice_type: string;
|
declare invoice_type: string;
|
||||||
|
declare invoice_customer_reference?: CreationOptional<string>;
|
||||||
|
|
||||||
declare lang_code: string;
|
declare lang_code: string;
|
||||||
declare currency_code: string;
|
declare currency_code: string;
|
||||||
@ -57,34 +52,32 @@ export class CustomerInvoiceModel extends Model<
|
|||||||
declare customer_tin: string;
|
declare customer_tin: string;
|
||||||
declare customer_name: string;
|
declare customer_name: string;
|
||||||
|
|
||||||
declare customer_reference: CreationOptional<string>;
|
|
||||||
|
|
||||||
declare customer_street: string;
|
declare customer_street: string;
|
||||||
|
declare customer_street2?: CreationOptional<string>;
|
||||||
declare customer_city: string;
|
declare customer_city: string;
|
||||||
declare customer_state: string;
|
declare customer_state: string;
|
||||||
declare customer_postal_code: string;
|
declare customer_postal_code: string;
|
||||||
declare customer_country: string;
|
declare customer_country: string;
|
||||||
|
|
||||||
declare subtotal_price: CreationOptional<number | null>;
|
declare subtotal_price?: CreationOptional<number>;
|
||||||
|
|
||||||
declare discount: CreationOptional<number | null>;
|
declare discount?: CreationOptional<number>;
|
||||||
declare discount_price: CreationOptional<number | null>;
|
declare discount_price?: CreationOptional<number>;
|
||||||
|
|
||||||
declare before_tax_price: CreationOptional<number | null>;
|
declare before_tax_price?: CreationOptional<number>;
|
||||||
|
|
||||||
declare tax: CreationOptional<number | null>;
|
declare tax?: CreationOptional<number>;
|
||||||
declare tax_price: CreationOptional<number | null>;
|
declare tax_price?: CreationOptional<number>;
|
||||||
|
|
||||||
declare total_price: CreationOptional<number | null>;
|
declare total_price?: CreationOptional<number>;
|
||||||
|
|
||||||
declare notes: CreationOptional<string>;
|
declare notes?: CreationOptional<string>;
|
||||||
|
|
||||||
declare items: NonAttribute<CustomerInvoiceItemModel[]>;
|
declare items: NonAttribute<CustomerInvoiceItemModel[]>;
|
||||||
declare customer: NonAttribute<CustomerModel>;
|
|
||||||
|
|
||||||
declare integrity_hash: CreationOptional<string>;
|
declare integrity_hash?: CreationOptional<string>;
|
||||||
declare previous_invoice_id: CreationOptional<string>;
|
declare previous_invoice_id?: CreationOptional<string>;
|
||||||
declare signed_at: CreationOptional<string>;
|
declare signed_at?: CreationOptional<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default (sequelize: Sequelize) => {
|
export default (sequelize: Sequelize) => {
|
||||||
@ -110,6 +103,10 @@ export default (sequelize: Sequelize) => {
|
|||||||
allowNull: false,
|
allowNull: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
invoice_customer_reference: {
|
||||||
|
type: new DataTypes.STRING(),
|
||||||
|
},
|
||||||
|
|
||||||
invoice_type: {
|
invoice_type: {
|
||||||
type: new DataTypes.STRING(),
|
type: new DataTypes.STRING(),
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
@ -129,7 +126,6 @@ export default (sequelize: Sequelize) => {
|
|||||||
|
|
||||||
customer_id: {
|
customer_id: {
|
||||||
type: new DataTypes.UUID(),
|
type: new DataTypes.UUID(),
|
||||||
primaryKey: true,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
customer_name: {
|
customer_name: {
|
||||||
@ -142,14 +138,16 @@ export default (sequelize: Sequelize) => {
|
|||||||
allowNull: false,
|
allowNull: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
customer_reference: {
|
|
||||||
type: new DataTypes.STRING(),
|
|
||||||
},
|
|
||||||
|
|
||||||
customer_street: {
|
customer_street: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
customer_street2: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: true,
|
||||||
|
},
|
||||||
|
|
||||||
customer_city: {
|
customer_city: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
@ -204,11 +202,12 @@ export default (sequelize: Sequelize) => {
|
|||||||
|
|
||||||
notes: {
|
notes: {
|
||||||
type: DataTypes.TEXT,
|
type: DataTypes.TEXT,
|
||||||
|
allowNull: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
integrity_hash: {
|
integrity_hash: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
allowNull: false,
|
allowNull: true,
|
||||||
comment: "Hash criptográfico para asegurar integridad",
|
comment: "Hash criptográfico para asegurar integridad",
|
||||||
},
|
},
|
||||||
previous_invoice_id: {
|
previous_invoice_id: {
|
||||||
@ -218,7 +217,7 @@ export default (sequelize: Sequelize) => {
|
|||||||
},
|
},
|
||||||
signed_at: {
|
signed_at: {
|
||||||
type: DataTypes.DATE,
|
type: DataTypes.DATE,
|
||||||
allowNull: false,
|
allowNull: true,
|
||||||
comment: "Fecha en que la factura fue firmada digitalmente",
|
comment: "Fecha en que la factura fue firmada digitalmente",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -235,7 +234,7 @@ export default (sequelize: Sequelize) => {
|
|||||||
|
|
||||||
indexes: [
|
indexes: [
|
||||||
{ name: "status_idx", fields: ["status"] },
|
{ name: "status_idx", fields: ["status"] },
|
||||||
{ name: "reference_idx", fields: ["reference"] },
|
{ name: "invoice_number_idx", fields: ["invoice_number"] },
|
||||||
{ name: "deleted_at_idx", fields: ["deleted_at"] },
|
{ name: "deleted_at_idx", fields: ["deleted_at"] },
|
||||||
{ name: "signed_at_idx", fields: ["signed_at"] },
|
{ name: "signed_at_idx", fields: ["signed_at"] },
|
||||||
],
|
],
|
||||||
|
|||||||
@ -1,23 +0,0 @@
|
|||||||
import { validateRequestDTO } from "@common/presentation";
|
|
||||||
import { checkTabContext } from "@contexts/auth/infraestructure";
|
|
||||||
import {
|
|
||||||
listCustomersController,
|
|
||||||
ListCustomersSchema,
|
|
||||||
} from "@contexts/customer-billing/presentation";
|
|
||||||
import { NextFunction, Request, Response, Router } from "express";
|
|
||||||
|
|
||||||
export const customersRouter = (appRouter: Router) => {
|
|
||||||
const routes: Router = Router({ mergeParams: true });
|
|
||||||
|
|
||||||
routes.get(
|
|
||||||
"/",
|
|
||||||
validateRequestDTO(ListCustomersSchema),
|
|
||||||
checkTabContext,
|
|
||||||
//checkUserIsAdmin,
|
|
||||||
(req: Request, res: Response, next: NextFunction) => {
|
|
||||||
listCustomersController().execute(req, res, next);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
appRouter.use("/customers", routes);
|
|
||||||
};
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
import { accountsRouter } from "./accounts.routes";
|
import { accountsRouter } from "./accounts.routes";
|
||||||
import { authRouter } from "./auth.routes";
|
import { authRouter } from "./auth.routes";
|
||||||
import { customersRouter } from "./customers.routes";
|
import { customerInvoicesRouter } from "./customer-invoices.routes";
|
||||||
import { usersRouter } from "./users.routes";
|
import { usersRouter } from "./users.routes";
|
||||||
|
|
||||||
export const v1Routes = () => {
|
export const v1Routes = () => {
|
||||||
@ -16,7 +16,7 @@ export const v1Routes = () => {
|
|||||||
accountsRouter(routes);
|
accountsRouter(routes);
|
||||||
|
|
||||||
// Sales
|
// Sales
|
||||||
customersRouter(routes);
|
customerInvoicesRouter(routes);
|
||||||
|
|
||||||
return routes;
|
return routes;
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user