import { DataTypes, InferAttributes, InferCreationAttributes, Model, NonAttribute, Sequelize, } from "sequelize"; import { CustomerInvoiceItemCreationAttributes, CustomerInvoiceItemModel, } from "./customer-invoice-item.model"; export type CustomerInvoiceCreationAttributes = InferCreationAttributes< CustomerInvoiceModel, { omit: "items" } > & { items?: CustomerInvoiceItemCreationAttributes[]; }; export class CustomerInvoiceModel extends Model< InferAttributes, InferCreationAttributes > { declare id: string; declare company_id: string; declare status: string; declare series: string; declare invoice_number: string; declare invoice_date: string; declare operation_date: string; declare language_code: string; declare currency_code: string; declare notes: string; // Subtotal declare subtotal_amount_value: number; declare subtotal_amount_scale: number; // Discount percentage declare discount_percentage_value: number; declare discount_percentage_scale: number; // Discount amount declare discount_amount_value: number; declare discount_amount_scale: number; // Taxable amount (base imponible) declare taxable_amount_value: number; declare taxable_amount_scale: number; // Total tax amount / taxes total declare tax_amount_value: number; declare tax_amount_scale: number; // Total declare total_amount_value: number; declare total_amount_scale: number; // Relaciones declare items: NonAttribute; //declare customer: NonAttribute; static associate(database: Sequelize) { const { CustomerInvoiceModel, CustomerInvoiceItemModel } = database.models; CustomerInvoiceModel.hasMany(CustomerInvoiceItemModel, { as: "items", foreignKey: "invoice_id", sourceKey: "id", onDelete: "CASCADE", constraints: true, }); } static hooks(database: Sequelize) { // Soft-cascade manual: al borrar una factura, marcamos items como borrados (paranoid). /*CustomerInvoiceModel.addHook("afterDestroy", async (invoice, options) => { if (!invoice?.id) return; await CustomerInvoiceItemModel.destroy({ where: { invoice_id: invoice.id }, individualHooks: true, transaction: options.transaction, }); });*/ } } export default (database: Sequelize) => { CustomerInvoiceModel.init( { id: { type: new DataTypes.UUID(), primaryKey: true, }, company_id: { type: DataTypes.UUID, allowNull: false, }, status: { type: new DataTypes.STRING(), allowNull: false, defaultValue: "draft", }, series: { type: new DataTypes.STRING(), allowNull: true, defaultValue: null, }, invoice_number: { type: new DataTypes.STRING(), allowNull: true, defaultValue: null, }, invoice_date: { type: new DataTypes.DATEONLY(), allowNull: true, defaultValue: null, }, operation_date: { type: new DataTypes.DATEONLY(), allowNull: true, defaultValue: null, }, language_code: { type: DataTypes.STRING(2), allowNull: false, defaultValue: "es", }, currency_code: { type: new DataTypes.STRING(3), allowNull: false, }, notes: { type: new DataTypes.TEXT(), allowNull: true, defaultValue: null, }, subtotal_amount_value: { type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes allowNull: false, defaultValue: 0, }, subtotal_amount_scale: { type: new DataTypes.SMALLINT(), allowNull: false, defaultValue: 2, }, discount_percentage_value: { type: new DataTypes.SMALLINT(), allowNull: true, defaultValue: null, }, discount_percentage_scale: { type: new DataTypes.SMALLINT(), allowNull: false, defaultValue: 2, }, discount_amount_value: { type: new DataTypes.BIGINT(), allowNull: true, defaultValue: null, }, discount_amount_scale: { type: new DataTypes.SMALLINT(), allowNull: false, defaultValue: 2, }, taxable_amount_value: { type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes allowNull: true, defaultValue: null, }, taxable_amount_scale: { type: new DataTypes.SMALLINT(), allowNull: false, defaultValue: 2, }, tax_amount_value: { type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes allowNull: true, defaultValue: null, }, tax_amount_scale: { type: new DataTypes.SMALLINT(), allowNull: false, defaultValue: 2, }, total_amount_value: { type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes allowNull: true, defaultValue: null, }, total_amount_scale: { type: new DataTypes.SMALLINT(), allowNull: false, defaultValue: 2, }, }, { sequelize: database, tableName: "customer_invoices", underscored: true, paranoid: true, // softs deletes timestamps: true, createdAt: "created_at", updatedAt: "updated_at", deletedAt: "deleted_at", indexes: [ { name: "company_idx", fields: ["company_id"], unique: false }, { name: "idx_company_idx", fields: ["id", "company_id"], unique: true }, { unique: true, fields: ["invoice_number"] }, ], whereMergeStrategy: "and", // <- cómo tratar el merge de un scope defaultScope: {}, scopes: {}, } ); return CustomerInvoiceModel; };