diff --git a/package-lock.json b/package-lock.json index 7bb0ce5..49057a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "@types/uuid": "^10.0.0", "dotenv": "^16.4.7", "express": "^5.1.0", - "fiscalapi": "^4.0.0", + "fiscalapi": "^4.0.360", "luxon": "^3.6.1", "swagger-jsdoc": "^6.2.8", "swagger-ui-express": "^5.0.1", @@ -735,11 +735,13 @@ } }, "node_modules/fiscalapi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fiscalapi/-/fiscalapi-4.0.0.tgz", - "integrity": "sha512-MN5CP2RrPMd+qAQq1uCJYO3RSiUna/eb4zfOPGkP57rlgsEoNbxLmdYua9MMBvyoEaeYDRqFIUdAlQtlx0PXHA==", + "version": "4.0.360", + "resolved": "https://registry.npmjs.org/fiscalapi/-/fiscalapi-4.0.360.tgz", + "integrity": "sha512-Wb1OwIqHa+hb31z2rE3j7/DY7iI5ye0fAGcBMlc9dLK1eSSf1EUZVRghheSaEZ2rSWGcH19SjudQGJRw/MjAmA==", + "license": "MPL-2.0", "dependencies": { "axios": "^1.8.4", + "form-data": "^4.0.4", "luxon": "^3.6.0" }, "engines": { @@ -766,13 +768,15 @@ } }, "node_modules/form-data": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", - "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { diff --git a/package.json b/package.json index d92d684..cf7eec9 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "@types/uuid": "^10.0.0", "dotenv": "^16.4.7", "express": "^5.1.0", - "fiscalapi": "^4.0.0", + "fiscalapi": "^4.0.360", "luxon": "^3.6.1", "swagger-jsdoc": "^6.2.8", "swagger-ui-express": "^5.0.1", diff --git a/src/controllers/invoiceController.ts b/src/controllers/invoiceController.ts index 41f281f..33e1aea 100644 --- a/src/controllers/invoiceController.ts +++ b/src/controllers/invoiceController.ts @@ -598,18 +598,8 @@ export const createPaymentComplementByValues = async (req: Request, res: Respons cfdiUseCode: "CP01", email: "someone@somewhere.com" }, - items: [ - { - itemCode: "84111506", - quantity: 1, - unitOfMeasurementCode: "ACT", - description: "Pago", - unitPrice: 0, - taxObjectCode: "01" - } - ], - payments: [ - { + complement: { + payment: { paymentDate: "2025-03-31T14:44:56", paymentFormCode: "28", currencyCode: "MXN", @@ -642,7 +632,7 @@ export const createPaymentComplementByValues = async (req: Request, res: Respons } ] } - ] + } }; const apiResponse = await fiscalapi.invoices.create(invoice); @@ -670,8 +660,8 @@ export const createPaymentComplementByReferences = async (req: Request, res: Res recipient: { id: "bef56254-0892-4558-95c3-f9c8729e4b0e" }, - payments: [ - { + complement: { + payment: { paymentDate: "2025-03-31T14:44:56", paymentFormCode: "28", currencyCode: "MXN", @@ -704,7 +694,7 @@ export const createPaymentComplementByReferences = async (req: Request, res: Res } ] } - ] + } }; const apiResponse = await fiscalapi.invoices.create(invoice); @@ -751,18 +741,8 @@ export const createPaymentUsdMxn = async (req: Request, res: Response): Promise< cfdiUseCode: "CP01", email: "someone@somewhere.com" }, - items: [ - { - itemCode: "84111506", - quantity: 1, - unitOfMeasurementCode: "ACT", - description: "Pago", - unitPrice: 0, - taxObjectCode: "01" - } - ], - payments: [ - { + complement: { + payment: { paymentDate: "2025-03-31T14:44:56", paymentFormCode: "28", currencyCode: "USD", @@ -808,7 +788,7 @@ export const createPaymentUsdMxn = async (req: Request, res: Response): Promise< } ] } - ] + } }; const apiResponse = await fiscalapi.invoices.create(invoice); @@ -855,18 +835,8 @@ export const createPaymentMxnUsd = async (req: Request, res: Response): Promise< cfdiUseCode: "CP01", email: "someone@somewhere.com" }, - items: [ - { - itemCode: "84111506", - quantity: 1, - unitOfMeasurementCode: "ACT", - description: "Pago", - unitPrice: 0, - taxObjectCode: "01" - } - ], - payments: [ - { + complement: { + payment: { paymentDate: "2025-03-31T14:44:56", paymentFormCode: "28", currencyCode: "MXN", @@ -912,7 +882,7 @@ export const createPaymentMxnUsd = async (req: Request, res: Response): Promise< } ] } - ] + } }; const apiResponse = await fiscalapi.invoices.create(invoice); @@ -959,18 +929,8 @@ export const createPaymentEurUsd = async (req: Request, res: Response): Promise< cfdiUseCode: "CP01", email: "someone@somewhere.com" }, - items: [ - { - itemCode: "84111506", - quantity: 1, - unitOfMeasurementCode: "ACT", - description: "Pago", - unitPrice: 0, - taxObjectCode: "01" - } - ], - payments: [ - { + complement: { + payment: { paymentDate: "2024-06-03T14:44:56", paymentFormCode: "28", currencyCode: "EUR", @@ -1016,7 +976,7 @@ export const createPaymentEurUsd = async (req: Request, res: Response): Promise< } ] } - ] + } }; const apiResponse = await fiscalapi.invoices.create(invoice); @@ -1026,6 +986,491 @@ export const createPaymentEurUsd = async (req: Request, res: Response): Promise< } }; +// Crear factura con complemento de nómina por valores +export const createPayrollComplementByValues = async (req: Request, res: Response): Promise => { + try { + const payrollInvoice: Invoice = { + versionCode: "4.0", + series: "F", + date: DateTime.now().toFormat("yyyy-MM-dd'T'HH:mm:ss"), + paymentMethodCode: "PUE", + currencyCode: "MXN", + typeCode: "N", + expeditionZipCode: "20000", + exportCode: "01", + issuer: { + tin: "FUNK671228PH6", + legalName: "KARLA FUENTE NOLASCO", + taxRegimeCode: "621", + employerData: { + employerRegistration: "B5510768108", + curp: "XEXX010101MNEXXXA8" + }, + taxCredentials: [ + { + base64File: base64Cert, + fileType: 0, + password: password + }, + { + base64File: base64Key, + fileType: 1, + password: password + } + ] + }, + recipient: { + tin: "FUNK671228PH6", + legalName: "KARLA FUENTE NOLASCO", + zipCode: "01160", + taxRegimeCode: "605", + cfdiUseCode: "CN01", + employeeData: { + curp: "XEXX010101MNEXXXA8", + socialSecurityNumber: "04078873454", + laborRelationStartDate: "2024-08-18", + seniority: "P54W", + satContractTypeId: "01", + satTaxRegimeTypeId: "02", + employeeNumber: "123456789", + department: "GenAI", + position: "Sr Software Engineer", + satJobRiskId: "1", + satPaymentPeriodicityId: "05", + satBankId: "012", + baseSalaryForContributions: 2828.50, + integratedDailySalary: 0.00, + satPayrollStateId: "JAL" + } + }, + complement: { + payroll: { + version: "1.2", + payrollTypeCode: "O", + paymentDate: "2025-08-30", + initialPaymentDate: "2025-07-31", + finalPaymentDate: "2025-08-30", + daysPaid: 30, + earnings: { + earnings: [ + { + earningTypeCode: "001", + code: "1003", + concept: "Sueldo Nominal", + taxedAmount: 95030.00, + exemptAmount: 0.00 + }, + { + earningTypeCode: "005", + code: "5913", + concept: "Fondo de Ahorro Aportación Patrón", + taxedAmount: 0.00, + exemptAmount: 4412.46 + }, + { + earningTypeCode: "038", + code: "1885", + concept: "Bono Ingles", + taxedAmount: 14254.50, + exemptAmount: 0.00 + }, + { + earningTypeCode: "029", + code: "1941", + concept: "Vales Despensa", + taxedAmount: 0.00, + exemptAmount: 3439.00 + }, + { + earningTypeCode: "038", + code: "1824", + concept: "Herramientas Teletrabajo (telecom y prop. electri)", + taxedAmount: 273.00, + exemptAmount: 0.00 + } + ], + otherPayments: [ + { + otherPaymentTypeCode: "002", + code: "5050", + concept: "Exceso de subsidio al empleo", + amount: 0.00, + subsidyCaused: 0.00 + } + ] + }, + deductions: [ + { + deductionTypeCode: "002", + code: "5003", + concept: "ISR Causado", + amount: 27645.52 + }, + { + deductionTypeCode: "004", + code: "5910", + concept: "Fondo de ahorro Empleado Inversión", + amount: 4412.46 + }, + { + deductionTypeCode: "004", + code: "5914", + concept: "Fondo de Ahorro Patrón Inversión", + amount: 4412.46 + }, + { + deductionTypeCode: "004", + code: "1966", + concept: "Contribución póliza exceso GMM", + amount: 519.91 + }, + { + deductionTypeCode: "004", + code: "1934", + concept: "Descuento Vales Despensa", + amount: 1.00 + }, + { + deductionTypeCode: "004", + code: "1942", + concept: "Vales Despensa Electrónico", + amount: 3439.00 + }, + { + deductionTypeCode: "001", + code: "1895", + concept: "IMSS", + amount: 2391.13 + } + ] + } + } + }; + + const apiResponse = await fiscalapi.invoices.create(payrollInvoice); + res.status(200).json(apiResponse); + } catch (error) { + res.status(500).json({ + succeeded: false, + message: 'Error al crear factura con complemento de nómina por valores', + error + }); + } +}; + +// Crear factura con complemento de impuestos locales por valores +export const createLocalTaxesComplementByValues = async (req: Request, res: Response): Promise => { + try { + const localTaxesInvoice: Invoice = { + versionCode: "4.0", + series: "F", + date: DateTime.now().toFormat("yyyy-MM-dd'T'HH:mm:ss"), + paymentFormCode: "01", + currencyCode: "MXN", + typeCode: "I", + expeditionZipCode: "42501", + paymentMethodCode: "PUE", + exchangeRate: 1, + exportCode: "01", + issuer: { + tin: "FUNK671228PH6", + legalName: "KARLA FUENTE NOLASCO", + taxRegimeCode: "621", + taxCredentials: [ + { + base64File: base64Cert, + fileType: 0, + password: password + }, + { + base64File: base64Key, + fileType: 1, + password: password + } + ] + }, + recipient: { + tin: "EKU9003173C9", + legalName: "ESCUELA KEMPER URGATE", + zipCode: "42501", + taxRegimeCode: "601", + cfdiUseCode: "G01", + email: "someone@somewhere.com" + }, + items: [ + { + itemCode: "01010101", + quantity: 9.5, + unitOfMeasurementCode: "E48", + description: "Invoicing software as a service", + unitPrice: 3587.75, + taxObjectCode: "02", + itemSku: "7506022301697", + discount: 255.85, + itemTaxes: [ + { + taxCode: "002", + taxTypeCode: "Tasa", + taxRate: "0.160000", + taxFlagCode: "T" + } + ] + }, + { + itemCode: "01010101", + quantity: 8, + unitOfMeasurementCode: "E48", + description: "Software Consultant", + unitPrice: 250.85, + taxObjectCode: "02", + itemSku: "7506022301698", + discount: 255.85, + itemTaxes: [ + { + taxCode: "002", + taxTypeCode: "Tasa", + taxRate: "0.160000", + taxFlagCode: "T" + } + ] + }, + { + itemCode: "01010101", + quantity: 6, + unitOfMeasurementCode: "E48", + description: "Computer software", + unitPrice: 1250.75, + taxObjectCode: "02", + itemSku: "7506022301699", + itemTaxes: [ + { + taxCode: "002", + taxTypeCode: "Tasa", + taxRate: "0.160000", + taxFlagCode: "T" + }, + { + taxCode: "002", + taxTypeCode: "Tasa", + taxRate: "0.106666", + taxFlagCode: "R" + } + ] + } + ], + complement: { + localTaxes: { + taxes: [ + { + taxName: "CEDULAR", + taxRate: "3.00", + taxAmount: "6.00", + taxFlagCode: "R" + }, + { + taxName: "ISH", + taxRate: "8.00", + taxAmount: "16.00", + taxFlagCode: "R" + } + ] + } + } + }; + + const apiResponse = await fiscalapi.invoices.create(localTaxesInvoice); + res.status(200).json(apiResponse); + } catch (error) { + res.status(500).json({ + succeeded: false, + message: 'Error al crear factura con complemento de impuestos locales por valores', + error + }); + } +}; + +// Crear complemento de nómina por referencias +export const createPayrollByReferences = async (req: Request, res: Response): Promise => { + try { + const payrollInvoice: Invoice = { + versionCode: "4.0", + series: "F", + date: DateTime.now().toFormat("yyyy-MM-dd'T'HH:mm:ss"), + paymentMethodCode: "PUE", + currencyCode: "MXN", + typeCode: "N", + expeditionZipCode: "20000", + exportCode: "01", + issuer: { + id: "0e82a655-5f0c-4e07-abab-8f322e4123ef" + }, + recipient: { + id: "da71df0c-f328-45ee-9bd9-3096ed02c164" + }, + complement: { + payroll: { + version: "1.2", + payrollTypeCode: "O", + paymentDate: "2025-08-30", + initialPaymentDate: "2025-07-31", + finalPaymentDate: "2025-08-30", + daysPaid: 30, + earnings: { + earnings: [ + { + earningTypeCode: "001", + code: "1003", + concept: "Sueldo Nominal", + taxedAmount: 95030.00, + exemptAmount: 0.00 + }, + { + earningTypeCode: "005", + code: "5913", + concept: "Fondo de Ahorro Aportación Patrón", + taxedAmount: 0.00, + exemptAmount: 4412.46 + }, + { + earningTypeCode: "038", + code: "1885", + concept: "Bono Ingles", + taxedAmount: 14254.50, + exemptAmount: 0.00 + }, + { + earningTypeCode: "029", + code: "1941", + concept: "Vales Despensa", + taxedAmount: 0.00, + exemptAmount: 3439.00 + }, + { + earningTypeCode: "038", + code: "1824", + concept: "Herramientas Teletrabajo (telecom y prop. electri)", + taxedAmount: 273.00, + exemptAmount: 0.00 + } + ], + otherPayments: [ + { + otherPaymentTypeCode: "002", + code: "5050", + concept: "Exceso de subsidio al empleo", + amount: 0.00, + subsidyCaused: 0.00 + } + ] + }, + deductions: [ + { + deductionTypeCode: "002", + code: "5003", + concept: "ISR Causado", + amount: 27645.52 + }, + { + deductionTypeCode: "004", + code: "5910", + concept: "Fondo de ahorro Empleado Inversión", + amount: 4412.46 + }, + { + deductionTypeCode: "004", + code: "5914", + concept: "Fondo de Ahorro Patrón Inversión", + amount: 4412.46 + }, + { + deductionTypeCode: "004", + code: "1966", + concept: "Contribución póliza exceso GMM", + amount: 519.91 + }, + { + deductionTypeCode: "004", + code: "1934", + concept: "Descuento Vales Despensa", + amount: 1.00 + }, + { + deductionTypeCode: "004", + code: "1942", + concept: "Vales Despensa Electrónico", + amount: 3439.00 + }, + { + deductionTypeCode: "001", + code: "1895", + concept: "IMSS", + amount: 2391.13 + } + ] + } + } + }; + + const apiResponse = await fiscalapi.invoices.create(payrollInvoice); + res.status(200).json(apiResponse); + } catch (error) { + res.status(500).json({ succeeded: false, message: 'Error al crear complemento de nómina por referencias', error }); + } +}; + +// Crear factura con complemento de impuestos locales por referencias +export const createLocalTaxesInvoiceByReference = async (req: Request, res: Response): Promise => { + try { + const localTaxesInvoice: Invoice = { + versionCode: "4.0", + series: "F", + date: DateTime.now().toFormat("yyyy-MM-dd'T'HH:mm:ss"), + paymentFormCode: "01", + currencyCode: "MXN", + typeCode: "I", + expeditionZipCode: "42501", + paymentMethodCode: "PUE", + exchangeRate: 1, + exportCode: "01", + issuer: { + id: "0e82a655-5f0c-4e07-abab-8f322e4123ef" + }, + recipient: { + id: "bd199ed8-02ef-47c0-919c-9479dd8ecae7" + }, + items: [ + { + id: "7f1c66f0-5d9b-4adc-821d-649d79abcbb5", + quantity: 1 + } + ], + complement: { + localTaxes: { + taxes: [ + { + taxName: "CEDULAR", + taxRate: "3.00", + taxAmount: "6.00", + taxFlagCode: "R" + }, + { + taxName: "ISH", + taxRate: "8.00", + taxAmount: "16.00", + taxFlagCode: "R" + } + ] + } + } + }; + + const apiResponse = await fiscalapi.invoices.create(localTaxesInvoice); + res.status(200).json(apiResponse); + } catch (error) { + res.status(500).json({ succeeded: false, message: 'Error al crear factura con complemento de impuestos locales por referencias', error }); + } +}; + // Cancelar una factura por valores export const cancelInvoiceByValues = async (req: Request, res: Response): Promise => { try { diff --git a/src/routes/invoiceRoutes.ts b/src/routes/invoiceRoutes.ts index facc104..98138f4 100644 --- a/src/routes/invoiceRoutes.ts +++ b/src/routes/invoiceRoutes.ts @@ -13,6 +13,10 @@ import { createPaymentUsdMxn, createPaymentMxnUsd, createPaymentEurUsd, + createPayrollComplementByValues, + createLocalTaxesComplementByValues, + createPayrollByReferences, + createLocalTaxesInvoiceByReference, cancelInvoiceByValues, cancelInvoiceById, getInvoiceStatusByValues, @@ -226,6 +230,401 @@ const router = Router(); * items: * $ref: '#/components/schemas/PaidInvoice' * + * LocalTax: + * type: object + * properties: + * taxName: + * type: string + * description: Nombre del impuesto local + * taxRate: + * type: number + * description: Tasa del impuesto local (2 decimales) + * taxAmount: + * type: number + * description: Monto del impuesto local (2 decimales) + * taxFlagCode: + * type: string + * description: Naturaleza del impuesto (T=Traslado, R=Retenido) + * + * LocalTaxesComplement: + * type: object + * properties: + * taxes: + * type: array + * items: + * $ref: '#/components/schemas/LocalTax' + * description: Lista de impuestos locales + * + * PaymentPaidInvoiceTax: + * type: object + * properties: + * taxCode: + * type: string + * description: Código del impuesto. Catálogo SAT c_Impuesto + * taxTypeCode: + * type: string + * description: Tipo de factor. Catálogo SAT c_TipoFactor + * taxRate: + * type: number + * description: Tasa del impuesto. Catálogo SAT c_TasaOCuota + * taxFlagCode: + * type: string + * description: Naturaleza del impuesto (T=Traslado, R=Retenido) + * required: + * - taxCode + * - taxTypeCode + * - taxRate + * - taxFlagCode + * + * PaymentPaidInvoice: + * type: object + * properties: + * uuid: + * type: string + * description: UUID de la factura pagada + * series: + * type: string + * description: Serie de la factura pagada + * number: + * type: string + * description: Folio de la factura pagada + * paymentAmount: + * type: number + * description: Monto pagado en la factura + * currencyCode: + * type: string + * description: Código de la moneda utilizada en la factura pagada + * partialityNumber: + * type: number + * description: Número de parcialidad + * subTotal: + * type: number + * description: Subtotal de la factura pagada + * previousBalance: + * type: number + * description: Saldo anterior de la factura pagada + * remainingBalance: + * type: number + * description: Saldo restante de la factura pagada + * taxObjectCode: + * type: string + * description: Código de obligaciones de impuesto aplicables + * equivalence: + * type: number + * description: Equivalencia de la moneda + * paidInvoiceTaxes: + * type: array + * items: + * $ref: '#/components/schemas/PaymentPaidInvoiceTax' + * required: + * - uuid + * - series + * - number + * - paymentAmount + * - currencyCode + * - partialityNumber + * - subTotal + * - previousBalance + * - remainingBalance + * - taxObjectCode + * + * PaymentComplement: + * type: object + * properties: + * paymentDate: + * type: string + * description: Fecha de pago (AAAA-MM-DDThh:mm:ss) + * paymentFormCode: + * type: string + * description: Código de la forma de pago. Catálogo SAT c_FormaPago + * currencyCode: + * type: string + * description: Código de la moneda utilizada en el pago. Default MXN + * exchangeRate: + * type: number + * description: Tipo de cambio + * amount: + * type: number + * description: Monto del pago + * operationNumber: + * type: string + * description: Número de operación asignado por el banco + * sourceBankTin: + * type: string + * description: RFC del banco origen + * sourceBankAccount: + * type: string + * description: Cuenta bancaria origen + * targetBankTin: + * type: string + * description: RFC del banco destino + * targetBankAccount: + * type: string + * description: Cuenta bancaria destino + * paidInvoices: + * type: array + * items: + * $ref: '#/components/schemas/PaymentPaidInvoice' + * required: + * - paymentDate + * - paymentFormCode + * - currencyCode + * - amount + * - paidInvoices + * + * PayrollOvertime: + * type: object + * properties: + * days: + * type: number + * description: Número de días con horas extra + * hoursTypeCode: + * type: string + * description: Código del tipo de horas (01=Dobles, 02=Triples) + * extraHours: + * type: number + * description: Número de horas extra trabajadas + * amountPaid: + * type: number + * description: Monto pagado por las horas extra + * required: + * - days + * - hoursTypeCode + * - extraHours + * - amountPaid + * + * PayrollStockOptions: + * type: object + * properties: + * marketPrice: + * type: number + * description: Precio de mercado de la acción + * grantPrice: + * type: number + * description: Precio de ejercicio de la acción + * required: + * - marketPrice + * - grantPrice + * + * PayrollEarning: + * type: object + * properties: + * earningTypeCode: + * type: string + * description: Código del tipo de percepción. Catálogo SAT c_TipoPercepcion + * code: + * type: string + * description: Clave de control interno de la percepción + * concept: + * type: string + * description: Concepto de la percepción + * taxedAmount: + * type: number + * description: Monto gravado de la percepción + * exemptAmount: + * type: number + * description: Monto exento de la percepción + * overtime: + * type: array + * items: + * $ref: '#/components/schemas/PayrollOvertime' + * stockOptions: + * $ref: '#/components/schemas/PayrollStockOptions' + * required: + * - earningTypeCode + * - code + * - concept + * - taxedAmount + * - exemptAmount + * + * PayrollBalanceCompensation: + * type: object + * properties: + * favorableBalance: + * type: number + * description: Saldo a favor + * year: + * type: number + * description: Año del saldo a favor + * remainingFavorableBalance: + * type: number + * description: Saldo a favor remanente + * required: + * - favorableBalance + * - year + * - remainingFavorableBalance + * + * PayrollOtherPayment: + * type: object + * properties: + * otherPaymentTypeCode: + * type: string + * description: Código del tipo de otro pago. Catálogo SAT c_TipoOtroPago + * code: + * type: string + * description: Clave de control interno del otro pago + * concept: + * type: string + * description: Concepto del otro pago + * amount: + * type: number + * description: Monto del otro pago + * subsidyCaused: + * type: number + * description: Subsidio causado (para tipo 002) + * balanceCompensation: + * $ref: '#/components/schemas/PayrollBalanceCompensation' + * required: + * - otherPaymentTypeCode + * - code + * - concept + * - amount + * + * PayrollRetirement: + * type: object + * properties: + * totalOneTime: + * type: number + * description: Total de pago único + * totalInstallments: + * type: number + * description: Total de parcialidades + * dailyAmount: + * type: number + * description: Monto diario + * accumulableIncome: + * type: number + * description: Ingreso acumulable + * nonAccumulableIncome: + * type: number + * description: Ingreso no acumulable + * + * PayrollSeverance: + * type: object + * properties: + * totalPaid: + * type: number + * description: Total pagado + * yearsOfService: + * type: number + * description: Años de servicio + * lastMonthlySalary: + * type: number + * description: Último sueldo mensual ordinario + * accumulableIncome: + * type: number + * description: Ingreso acumulable + * nonAccumulableIncome: + * type: number + * description: Ingreso no acumulable + * required: + * - totalPaid + * - yearsOfService + * - lastMonthlySalary + * - accumulableIncome + * - nonAccumulableIncome + * + * PayrollEarnings: + * type: object + * properties: + * earnings: + * type: array + * items: + * $ref: '#/components/schemas/PayrollEarning' + * otherPayments: + * type: array + * items: + * $ref: '#/components/schemas/PayrollOtherPayment' + * retirement: + * $ref: '#/components/schemas/PayrollRetirement' + * severance: + * $ref: '#/components/schemas/PayrollSeverance' + * + * PayrollDeduction: + * type: object + * properties: + * deductionTypeCode: + * type: string + * description: Código del tipo de deducción. Catálogo SAT c_TipoDeduccion + * code: + * type: string + * description: Clave de control interno de la deducción + * concept: + * type: string + * description: Concepto de la deducción + * amount: + * type: number + * description: Monto de la deducción + * required: + * - deductionTypeCode + * - code + * - concept + * - amount + * + * PayrollDisability: + * type: object + * properties: + * disabilityDays: + * type: number + * description: Número de días de incapacidad + * disabilityTypeCode: + * type: string + * description: Código del tipo de incapacidad. Catálogo SAT c_TipoIncapacidad + * monetaryAmount: + * type: number + * description: Monto monetario de la incapacidad + * required: + * - disabilityDays + * - disabilityTypeCode + * + * PayrollComplement: + * type: object + * properties: + * version: + * type: string + * description: Versión del complemento de nómina. Default 1.2 + * payrollTypeCode: + * type: string + * description: Código del tipo de nómina (O=Ordinaria, E=Extraordinaria) + * paymentDate: + * type: string + * description: Fecha de pago de la nómina + * initialPaymentDate: + * type: string + * description: Fecha inicial del periodo de pago + * finalPaymentDate: + * type: string + * description: Fecha final del periodo de pago + * daysPaid: + * type: number + * description: Número de días pagados + * earnings: + * $ref: '#/components/schemas/PayrollEarnings' + * deductions: + * type: array + * items: + * $ref: '#/components/schemas/PayrollDeduction' + * disabilities: + * type: array + * items: + * $ref: '#/components/schemas/PayrollDisability' + * required: + * - payrollTypeCode + * - paymentDate + * - initialPaymentDate + * - finalPaymentDate + * - daysPaid + * + * Complement: + * type: object + * properties: + * localTaxes: + * $ref: '#/components/schemas/LocalTaxesComplement' + * payment: + * $ref: '#/components/schemas/PaymentComplement' + * payroll: + * $ref: '#/components/schemas/PayrollComplement' + * * Invoice: * type: object * properties: @@ -273,8 +672,13 @@ const router = Router(); * $ref: '#/components/schemas/InvoiceItem' * payments: * type: array + * deprecated: true + * description: Lista de pagos relacionados a la factura (solo para CFDI 3.3, usar complementos de pago para CFDI 4.0) * items: * $ref: '#/components/schemas/Payment' + * complement: + * $ref: '#/components/schemas/Complement' + * description: Complementos de la factura (nómina, pago, impuestos locales) */ /** @@ -475,6 +879,62 @@ router.post('/create/payment-mxn-usd', createPaymentMxnUsd); */ router.post('/create/payment-eur-usd', createPaymentEurUsd); +/** + * @swagger + * /api/invoices/create/payroll/by-values: + * post: + * summary: Crear factura con complemento de nómina por valores + * tags: [Invoices] + * responses: + * 200: + * description: Factura con complemento de nómina creada exitosamente + * 500: + * description: Error al crear factura con complemento de nómina + */ +router.post('/create/payroll/by-values', createPayrollComplementByValues); + +/** + * @swagger + * /api/invoices/create/payroll/by-references: + * post: + * summary: Crear complemento de nómina por referencias + * tags: [Invoices] + * responses: + * 200: + * description: Complemento de nómina creado exitosamente + * 500: + * description: Error al crear complemento de nómina + */ +router.post('/create/payroll/by-references', createPayrollByReferences); + +/** + * @swagger + * /api/invoices/create/local-taxes/by-values: + * post: + * summary: Crear factura con complemento de impuestos locales por valores + * tags: [Invoices] + * responses: + * 200: + * description: Factura con complemento de impuestos locales creada exitosamente + * 500: + * description: Error al crear factura con complemento de impuestos locales + */ +router.post('/create/local-taxes/by-values', createLocalTaxesComplementByValues); + +/** + * @swagger + * /api/invoices/create/local-taxes/by-reference: + * post: + * summary: Crear factura con complemento de impuestos locales por referencias + * tags: [Invoices] + * responses: + * 200: + * description: Factura con complemento de impuestos locales creada exitosamente + * 500: + * description: Error al crear factura con complemento de impuestos locales + */ +router.post('/create/local-taxes/by-reference', createLocalTaxesInvoiceByReference); + /** * @swagger * /api/invoices/cancel/by-values: