From 0101e0a5d1bf5c37709568afce95d6389a7ee259 Mon Sep 17 00:00:00 2001 From: JesusMendoza Date: Mon, 26 Jan 2026 19:48:38 -0600 Subject: [PATCH 01/15] commonjs and esm support enhacements --- .claude/settings.local.json | 5 ++ .github/workflows/main.yml | 11 ++++- CLAUDE.md | 67 +++++++++++++++++++++++++++ package-lock.json | 6 ++- package.json | 12 ++--- scripts/fix-esm-imports.js | 92 +++++++++++++++++++++++++++++++++++++ src/index.ts | 7 ++- tsconfig.base.json | 22 +++++++++ tsconfig.cjs.json | 15 +++--- tsconfig.esm.json | 15 +++--- tsconfig.json | 30 ++---------- tsconfig.types.json | 10 ---- 12 files changed, 229 insertions(+), 63 deletions(-) create mode 100644 .claude/settings.local.json create mode 100644 CLAUDE.md create mode 100644 scripts/fix-esm-imports.js create mode 100644 tsconfig.base.json delete mode 100644 tsconfig.types.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..5473423 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,5 @@ +{ + "permissions": { + "defaultMode": "bypassPermissions" + } +} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 04f30a8..96ee8cf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -46,10 +46,19 @@ jobs: echo "ESM build missing" exit 1 fi - if [ ! -d "dist/types" ]; then + if [ ! -f "dist/cjs/index.d.ts" ]; then echo "TypeScript definitions missing" exit 1 fi + if [ ! -f "dist/cjs/package.json" ]; then + echo "CJS package.json missing" + exit 1 + fi + if [ ! -f "dist/esm/package.json" ]; then + echo "ESM package.json missing" + exit 1 + fi + echo "Build artifacts verified successfully" - name: Publish to NPM run: npm publish --access public diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..4266545 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,67 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +FiscalAPI SDK for Node.js - Official TypeScript SDK for Mexican electronic invoicing (CFDI 4.0) and fiscal services. Wraps the FiscalAPI REST API for invoice creation, payment complements, bulk XML downloads, and SAT catalog queries. + +## Build Commands + +```bash +npm run build # Full build: clean + esm + cjs + types +npm run build:esm # TypeScript to ES Modules (dist/esm) +npm run build:cjs # TypeScript to CommonJS (dist/cjs) +npm run build:types # TypeScript declaration files (dist/types) +npm run clean # Remove dist directory +npm test # Run Jest tests +npm run lint # ESLint on src/**/*.ts +npm run main # Run examples/main.ts with ts-node +``` + +## Architecture + +**Facade Pattern**: `FiscalapiClient` is the main entry point exposing all services: +- `invoices` - CFDI invoice creation, cancellation, PDF generation +- `products` - Product/service catalog management +- `persons` - Issuer/recipient (emisor/receptor) management +- `taxFiles` - CSD certificate upload +- `catalogs` - SAT catalog queries +- `downloadCatalogs`, `downloadRules`, `downloadRequests` - Bulk XML download + +**Directory Structure**: +- `src/abstractions/` - Service interfaces (I*Service) +- `src/services/` - Service implementations extending `BaseFiscalapiService` +- `src/models/` - Data models (Invoice, Person, Product, etc.) +- `src/common/` - Shared DTOs (ApiResponse, PagedList, FiscalapiSettings) +- `src/utils/` - Date formatting (Luxon), Base64 encoding, validation helpers + +**Key Patterns**: +- All services implement interfaces from `abstractions/` +- HTTP client injected via factory pattern +- Dual-package output: ESM + CommonJS + TypeScript declarations +- Date handling uses Luxon with `America/Mexico_City` timezone +- SAT date format: `yyyy-MM-ddTHH:mm:ss` + +## Configuration + +```typescript +const settings: FiscalapiSettings = { + apiUrl: "https://test.fiscalapi.com", // or https://live.fiscalapi.com + apiKey: "", + tenant: "", + apiVersion?: "v4", // default + timeZone?: "America/Mexico_City", // default + debug?: false +}; +const client = FiscalapiClient.create(settings); +``` + +## Two Operation Modes + +1. **By References**: Send only IDs of pre-configured entities in FiscalAPI dashboard +2. **By Values**: Send complete data in each request (no prior setup needed) + +## TypeScript Configuration + +Strict mode enabled with all checks: `noImplicitAny`, `strictNullChecks`, `noImplicitReturns`, `noUnusedParameters`. Target ES2018. diff --git a/package-lock.json b/package-lock.json index b3e6765..8786f6b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "fiscalapi", - "version": "4.0.141", + "version": "4.0.270", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "fiscalapi", - "version": "4.0.141", + "version": "4.0.270", "license": "MPL-2.0", "dependencies": { "axios": "^1.8.4", @@ -112,6 +112,7 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.14.tgz", "integrity": "sha512-Zs/Ollc1SJ8nKUAgc7ivOEdIBM8JAKgrqqUYi2J997JuKO7/tpQC+WCetQ1sypiKCQWHdvdg9wBNpUPEWZae7w==", "dev": true, + "peer": true, "dependencies": { "undici-types": "~6.20.0" } @@ -842,6 +843,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/package.json b/package.json index b231c18..f368227 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "SDK de Node.js para Fiscalapi", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", - "types": "dist/types/index.d.ts", + "types": "dist/cjs/index.d.ts", "files": [ "dist/", "README.md", @@ -14,10 +14,10 @@ ], "scripts": { "clean": "rimraf dist", - "build": "npm run clean && npm run build:esm && npm run build:cjs && npm run build:types", - "build:esm": "tsc -p tsconfig.esm.json", + "build": "npm run clean && npm run build:cjs && npm run build:esm && npm run build:package-json", + "build:esm": "tsc -p tsconfig.esm.json && node scripts/fix-esm-imports.js", "build:cjs": "tsc -p tsconfig.cjs.json", - "build:types": "tsc -p tsconfig.types.json", + "build:package-json": "node -e \"require('fs').writeFileSync('dist/cjs/package.json','{\\\"type\\\":\\\"commonjs\\\"}');require('fs').writeFileSync('dist/esm/package.json','{\\\"type\\\":\\\"module\\\"}')\"", "test": "jest", "lint": "eslint 'src/**/*.ts'", "prepare": "npm run build", @@ -38,9 +38,9 @@ }, "exports": { ".": { + "types": "./dist/cjs/index.d.ts", "import": "./dist/esm/index.js", - "require": "./dist/cjs/index.js", - "types": "./dist/types/index.d.ts" + "require": "./dist/cjs/index.js" } }, "repository": { diff --git a/scripts/fix-esm-imports.js b/scripts/fix-esm-imports.js new file mode 100644 index 0000000..c16b9f4 --- /dev/null +++ b/scripts/fix-esm-imports.js @@ -0,0 +1,92 @@ +/** + * Post-build script to add .js extensions to ESM imports/exports + * Required for Node.js native ESM support + */ +const fs = require('fs'); +const path = require('path'); + +const esmDir = path.join(__dirname, '..', 'dist', 'esm'); + +// Extensions that should NOT have .js added +const SKIP_EXTENSIONS = ['.js', '.mjs', '.cjs', '.json', '.node']; + +// Stats for logging +let stats = { + filesProcessed: 0, + importsFixed: 0 +}; + + +function hasSkipExtension(importPath) { + return SKIP_EXTENSIONS.some(ext => importPath.endsWith(ext)); +} + + +function processFile(filePath) { + if (!filePath.endsWith('.js')) return; + + let content = fs.readFileSync(filePath, 'utf8'); + let modified = false; + + + const staticImportRegex = /(from\s+['"])(\.\.?\/[^'"]+)(['"])/g; + + content = content.replace(staticImportRegex, (match, prefix, importPath, suffix) => { + if (hasSkipExtension(importPath)) { + return match; // Already has extension, skip + } + modified = true; + stats.importsFixed++; + return `${prefix}${importPath}.js${suffix}`; + }); + + + const dynamicImportRegex = /(import\s*\(\s*['"])(\.\.?\/[^'"]+)(['"]\s*\))/g; + + content = content.replace(dynamicImportRegex, (match, prefix, importPath, suffix) => { + if (hasSkipExtension(importPath)) { + return match; // Already has extension, skip + } + modified = true; + stats.importsFixed++; + return `${prefix}${importPath}.js${suffix}`; + }); + + if (modified) { + fs.writeFileSync(filePath, content); + stats.filesProcessed++; + } +} + +/** + * Recursively process all files in a directory + */ +function processDirectory(dir) { + if (!fs.existsSync(dir)) { + console.error(`Error: Directory not found: ${dir}`); + process.exit(1); + } + + const entries = fs.readdirSync(dir, { withFileTypes: true }); + + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + processDirectory(fullPath); + } else { + processFile(fullPath); + } + } +} + +// Main execution +console.log('Fixing ESM imports...'); +console.log(`Directory: ${esmDir}`); + +try { + processDirectory(esmDir); + console.log(`Done! Fixed ${stats.importsFixed} imports in ${stats.filesProcessed} files.`); +} catch (error) { + console.error('Error fixing ESM imports:', error.message); + process.exit(1); +} diff --git a/src/index.ts b/src/index.ts index a35c8d7..ef0b1ae 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,7 +3,7 @@ export { FiscalapiClient } from './services/fiscalapi-client'; export type { IFiscalapiClient } from './abstractions/fiscalapi-client.interface'; -export type { IFiscalapiService } from './abstractions/fiscalapi-service.interface'; +export type { IFiscalapiService, OperationOptions, RequestOptions } from './abstractions/fiscalapi-service.interface'; export type { IApiKeyService } from './abstractions/api-key-service.interface'; export type { ICatalogService } from './abstractions/catalog-service.interface'; export type { IInvoiceService } from './abstractions/invoice-service.interface'; @@ -11,6 +11,11 @@ export type { IPersonService } from './abstractions/person-service.interface'; export type { IProductService } from './abstractions/product-service.interface'; export type { ITaxFileService } from './abstractions/tax-file-service.interface'; export type { IDownloadCatalogService } from './abstractions/download-catalog.inteface'; +export type { IDownloadRequestService } from './abstractions/download-request.service.interface'; +export type { IDownloadRuleService } from './abstractions/download-rule.service.inteface'; + +// HTTP types +export type { HttpMethod } from './http/fiscalapi-http-client.interface'; // Models types export type { ApiKey } from './models/api-key'; diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 0000000..ab813ad --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ES2019", + "lib": ["ES2019"], + "moduleResolution": "node", + "rootDir": "./src", + "strict": true, + "noUnusedLocals": false, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "examples", "**/*.test.ts"] +} diff --git a/tsconfig.cjs.json b/tsconfig.cjs.json index 1d000e8..99d16d0 100644 --- a/tsconfig.cjs.json +++ b/tsconfig.cjs.json @@ -1,10 +1,7 @@ { - "extends": "./tsconfig.json", - "compilerOptions": { - "module": "CommonJS", - "moduleResolution": "node", - "outDir": "dist/cjs", - "declaration": false - }, - "include": ["src"] - } \ No newline at end of file + "extends": "./tsconfig.base.json", + "compilerOptions": { + "module": "CommonJS", + "outDir": "./dist/cjs" + } +} diff --git a/tsconfig.esm.json b/tsconfig.esm.json index 4ae7e8b..c3caec7 100644 --- a/tsconfig.esm.json +++ b/tsconfig.esm.json @@ -1,10 +1,7 @@ { - "extends": "./tsconfig.json", - "compilerOptions": { - "module": "ESNext", - "moduleResolution": "node", - "outDir": "dist/esm", - "declaration": false - }, - "include": ["src"] - } \ No newline at end of file + "extends": "./tsconfig.base.json", + "compilerOptions": { + "module": "ESNext", + "outDir": "./dist/esm" + } +} diff --git a/tsconfig.json b/tsconfig.json index 240f612..7fa0dfa 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,27 +1,7 @@ { + "extends": "./tsconfig.base.json", "compilerOptions": { - "target": "ES2018", - "module": "CommonJS", - "moduleResolution": "node", - "lib": ["ES2018", "DOM"], - "declaration": true, - "strict": true, - "noImplicitAny": true, - "strictNullChecks": true, - "noImplicitThis": true, - "alwaysStrict": true, - "noUnusedLocals": false, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": false, - "inlineSourceMap": true, - "inlineSources": true, - "experimentalDecorators": true, - "strictPropertyInitialization": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true - }, - "exclude": ["node_modules", "dist"] -} \ No newline at end of file + "module": "ESNext", + "outDir": "./dist" + } +} diff --git a/tsconfig.types.json b/tsconfig.types.json deleted file mode 100644 index 6980268..0000000 --- a/tsconfig.types.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "declaration": true, - "emitDeclarationOnly": true, - "moduleResolution": "node", - "outDir": "dist/types" - }, - "include": ["src"] - } \ No newline at end of file From e7c19773292015330784cd6b43a9e3d2a5452e68 Mon Sep 17 00:00:00 2001 From: JesusMendoza Date: Mon, 26 Jan 2026 21:27:06 -0600 Subject: [PATCH 02/15] servicio de timbres added --- .claude/settings.local.json | 6 + examples/ejemplo-timbres.ts | 39 + payroll-invoice-requrements.md | 2188 +++++++++++++++++ payroll-requirements.md | 820 ++++++ .../fiscalapi-client.interface.ts | 6 + src/abstractions/stamp-service.interface.ts | 22 + src/index.ts | 12 + src/models/stamp.ts | 79 + src/services/fiscalapi-client.ts | 16 +- src/services/stamp-service.ts | 51 + 10 files changed, 3235 insertions(+), 4 deletions(-) create mode 100644 examples/ejemplo-timbres.ts create mode 100644 payroll-invoice-requrements.md create mode 100644 payroll-requirements.md create mode 100644 src/abstractions/stamp-service.interface.ts create mode 100644 src/models/stamp.ts create mode 100644 src/services/stamp-service.ts diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 5473423..ad5811a 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -1,5 +1,11 @@ { "permissions": { + "allow": [ + "Bash(npm run build:*)", + "Bash(npm test)", + "Bash(npx ts-node:*)", + "Bash(findstr:*)" + ], "defaultMode": "bypassPermissions" } } diff --git a/examples/ejemplo-timbres.ts b/examples/ejemplo-timbres.ts new file mode 100644 index 0000000..d21f4e4 --- /dev/null +++ b/examples/ejemplo-timbres.ts @@ -0,0 +1,39 @@ +import { FiscalapiClient, FiscalapiSettings } from '../src/index'; + +async function main(): Promise { + const settings: FiscalapiSettings = { + apiUrl: 'https://test.fisalapi.com', + apiKey: '', + tenant: '', + }; + + const client = FiscalapiClient.create(settings); + + // 1. Listar transacciones de timbres + const list = await client.stamps.getList(1, 10); + console.log('Lista de transacciones:', list); + + // 2. Obtener transacción por ID + const transaction = await client.stamps.getById('77678d6d-94b1-4635-aa91-15cdd7423aab'); + console.log('Transacción por ID:', transaction); + + // 3. Transferir timbres + const transfer = await client.stamps.transferStamps({ + fromPersonId: '2e7b988f-3a2a-4f67-86e9-3f931dd48581', + toPersonId: '5fd9f48c-a6a2-474f-944b-88a01751d432', + amount: 1, + comments: 'Transferencia de prueba' + }); + console.log('Transferencia:', transfer); + + // 4. Retirar timbres + const withdraw = await client.stamps.withdrawStamps({ + fromPersonId: '5fd9f48c-a6a2-474f-944b-88a01751d432', + toPersonId: '2e7b988f-3a2a-4f67-86e9-3f931dd48581', + amount: 1, + comments: 'Retiro de prueba' + }); + console.log('Retiro:', withdraw); +} + +main(); diff --git a/payroll-invoice-requrements.md b/payroll-invoice-requrements.md new file mode 100644 index 0000000..f0d6a3e --- /dev/null +++ b/payroll-invoice-requrements.md @@ -0,0 +1,2188 @@ + + +# IDs de personas para los ejemplos +escuela_kemper_urgate_id = "2e7b988f-3a2a-4f67-86e9-3f931dd48581" +karla_fuente_nolasco_id = "109f4d94-63ea-4a21-ab15-20c8b87d8ee9" +organicos_navez_osorio_id = "f645e146-f80e-40fa-953f-fd1bd06d4e9f" +xochilt_casas_chavez_id = "e3b4edaa-e4d9-4794-9c5b-3dd5b7e372aa" +ingrid_xodar_jimenez_id = "9367249f-f0ee-43f4-b771-da2fff3f185f" +OSCAR_KALA_HAAK = "5fd9f48c-a6a2-474f-944b-88a01751d432" + + +apiUrl: http://localhost:5001 +productId: 69d0aec0-5dbb-4db0-a908-61fe5c8e7d75 +apikey: sk_development_b470ea83_3c0f_4209_b933_85223b960d91 +tenant: 102e5f13-e114-41dd-bea7-507fce177281 + + + +---- + + +You are a senior Node.js engineer specializing in TypeScript, module systems, and mexican payroll cdfi invoicing. Your task is to +add payroll invoice support to the existing code base following best practices. + + +# Important +-Make sure you follow the current project programing language, naming conventions and best practices for the current language and framework. +-Make sure you DO NOT ADD ACCIDENTAL COMPLEXITY, only add essential complexity. You can achieve this by reading the codebase thoroughly. DO NOT ASUME ANYTHING, BASE IT ON FACTS AND THE CURRENT STATE OF THE CODE. DO NOT DUPLICATE CODE. + +## Stamp resource +Implememt following changes as follows: + +Create a new service called StampService and add a new property 'stamps' on FiscalApiClient facade +the ultimage goal is add support for /api/v4/stamps resource. + + +### Models + +StampTransaction: + consecutive: int, + from_person: UserLookupDto, + to_person: UserLookupDto, + amount: int, + transaction_type: int, + transaction_status: int, + reference_id: str, + comments: str, + id: Optional[str] = None, + +StampTransactionParams + from_person_id: str, + to_person_id: str, + amount: int, + comments: str, + +### Service +class StampService: + + def transfer_stamps(self, request: StampTransactionParams) -> bool: + # lógica real aquí (HTTP, DB, lo que sea) + return True + + def withdraw_stamps(self, request: StampTransactionParams) -> bool: + # lógica real aquí + return True + + + +#Resource endpoints + +Listar movimientos + +## Request +curl --location 'http://localhost:5001/api/v4/stamps?pageNumber=1&pageSize=2' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--data '' + +### Response +{ + "data": { + "items": [ + { + "consecutive": 9, + "fromPerson": { + "tin": "FAP240304AU3", + "legalName": "FISCAL API", + "id": "1", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": "2025-11-02T13:12:47.205" + }, + "toPerson": { + "tin": "KAHO641101B39", + "legalName": "OSCAR KALA HAAK", + "id": "5fd9f48c-a6a2-474f-944b-88a01751d432", + "createdAt": "2025-01-07T15:15:00.305", + "updatedAt": "2025-11-03T19:19:48.455" + }, + "amount": 100, + "transactionType": 1, + "transactionStatus": 1, + "referenceId": "46aecf10-5e63-48e9-a101-bbb3cda10b38", + "comments": null, + "id": "77678d6d-94b1-4635-aa91-15cdd7423aab", + "createdAt": "2025-08-08T21:01:07.583", + "updatedAt": "2025-08-08T21:01:07.583" + }, + { + "consecutive": 11, + "fromPerson": { + "tin": "FAP240304AU3", + "legalName": "FISCAL API", + "id": "1", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": "2025-11-02T13:12:47.205" + }, + "toPerson": { + "tin": "KAHO641101B39", + "legalName": "OSCAR KALA HAAK", + "id": "5fd9f48c-a6a2-474f-944b-88a01751d432", + "createdAt": "2025-01-07T15:15:00.305", + "updatedAt": "2025-11-03T19:19:48.455" + }, + "amount": 500, + "transactionType": 1, + "transactionStatus": 1, + "referenceId": "7452186b-f890-4cad-90df-f478335ce117", + "comments": null, + "id": "e22e17d1-48c5-49a5-af71-a56cae4bdd95", + "createdAt": "2025-08-10T12:12:50.496", + "updatedAt": "2025-08-10T12:12:50.496" + } + ], + "pageNumber": 1, + "totalPages": 21, + "totalCount": 207, + "hasPreviousPage": false, + "hasNextPage": true + }, + "succeeded": true, + "message": "", + "details": "", + "httpStatusCode": 200 +} + + +--- +Obtener movimiento por ID + +### Request +curl --location 'http://localhost:5001/api/v4/stamps/77678d6d-94b1-4635-aa91-15cdd7423aab' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data '' + +### Response +{ + "data": { + "consecutive": 9, + "fromPerson": { + "tin": "FAP240304AU3", + "legalName": "FISCAL API", + "id": "1", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": "2025-11-02T13:12:47.205" + }, + "toPerson": { + "tin": "KAHO641101B39", + "legalName": "OSCAR KALA HAAK", + "id": "5fd9f48c-a6a2-474f-944b-88a01751d432", + "createdAt": "2025-01-07T15:15:00.305", + "updatedAt": "2025-11-03T19:19:48.455" + }, + "amount": 100, + "transactionType": 1, + "transactionStatus": 1, + "referenceId": "46aecf10-5e63-48e9-a101-bbb3cda10b38", + "comments": null, + "id": "77678d6d-94b1-4635-aa91-15cdd7423aab", + "createdAt": "2025-08-08T21:01:07.583", + "updatedAt": "2025-08-08T21:01:07.583" + }, + "succeeded": true, + "message": "", + "details": "", + "httpStatusCode": 200 +} + +--- +Transferir Timbres + +### Request +curl --location 'http://localhost:5001/api/v4/stamps' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'Content-Type: application/json' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data '{ + "fromPersonId": "1", + "toPersonId": "bef56254-0892-4558-95c3-f9c8729e4b0e", + "amount": 1, + "comments": "Compra 001" +}' + +### Response +{ + "data": true, + "succeeded": true, + "message": "", + "details": "", + "httpStatusCode": 200 +} + + +### Retirar Timbres +curl --location 'http://localhost:5001/api/v4/stamps' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'Content-Type: application/json' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data '{ + "fromPersonId": "1", + "toPersonId": "1a18f812-c623-448f-a222-9b7e4e3fd4b2", + "amount": 99, + "comments": "No se confirmó el pago..." +}' + +### Response +{ + "data": true, + "succeeded": true, + "message": "", + "details": "", + "httpStatusCode": 200 +} + +--- + +You are a senior Node.js engineer specializing in TypeScript, module systems, and mexican payroll cdfi invoicing. Your task is to +add payroll invoice support to the existing code base following best practices. + + +# Important +-Make sure you follow the current project programing language, naming conventions and best practices for the current language and framework. +-Make sure you DO NOT ADD ACCIDENTAL COMPLEXITY, only add essential complexity. You can achieve this by reading the codebase thoroughly. DO NOT ASUME ANYTHING, BASE IT ON FACTS AND THE CURRENT STATE OF THE CODE. DO NOT DUPLICATE CODE. + +## Employee/Employer sub-resources + +Implememt following changes as follows: + +interface IEmployeeFacade { + getById(id: string): Promise> + create(requestModel: CreateEmployeeRequest): Promise> + update(requestModel: UpdateEmployeeRequest): Promise> + delete(personId: string): Promise> +} + +interface IEmployerFacade { + getById(id: string): Promise> + create(requestModel: CreateEmployerRequest): Promise> + update(requestModel: UpdateEmployerRequest): Promise> + delete(personId: string): Promise> +} + +interface PersonService { + employee: IEmployeeFacade + employer: IEmployerFacade +} + +interface FiscalapiClient { + persons: PersonsFacade +} + + +### Obtener datos de empleador +curl --location 'http://localhost:5001/api/v4/people/bef56254-0892-4558-95c3-f9c8729e4b0e/employer' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' + +### Crear datos de empleador +curl --location 'http://localhost:5001/api/v4/people/bef56254-0892-4558-95c3-f9c8729e4b0e/employer' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'Content-Type: application/json' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data '{ + "personId": "bef56254-0892-4558-95c3-f9c8729e4b0e", + "employerRegistration": "B5510768108", + "originEmployerTin": "URE180429TM6", + "satFundSourceId": null, + "ownResourceAmount": null +} +' + +### Actualizar datos de empleador + +curl --location --request PUT 'http://localhost:5001/api/v4/people/bef56254-0892-4558-95c3-f9c8729e4b0e/employer' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'Content-Type: application/json' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data '{ + "personId": "bef56254-0892-4558-95c3-f9c8729e4b0e", + "employerRegistration": "A1230768108", + "originEmployerTin": "ARE180429TM6", + "satFundSourceId": null, + "ownResourceAmount": null +}' + +### Eliminar datos de empleador + +curl --location --request DELETE 'http://localhost:5001/api/v4/people/bef56254-0892-4558-95c3-f9c8729e4b0e/employer' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data '' + + +### Obtener datos de empleado +curl --location 'http://localhost:5001/api/v4/people/54fc14ae-c88f-4afc-996b-0574d63341e2/employee' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data '' + +### Crear datos de empleado +curl --location 'http://localhost:5001/api/v4/people/54fc14ae-c88f-4afc-996b-0574d63341e2/employee' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'Content-Type: application/json' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data ' +{ + "employerPersonId": "bef56254-0892-4558-95c3-f9c8729e4b0e", + "employeePersonId": "54fc14ae-c88f-4afc-996b-0574d63341e2", + "employeeNumber": "12345", + "satContractTypeId": "01", + "satTaxRegimeTypeId": "02", + "satPaymentPeriodicityId": "04", + "satPayrollStateId": "JAL", + "socialSecurityNumber": "123456789012345", + "laborRelationStartDate": "2023-01-15T00:00:00", + "satWorkdayTypeId": "01", + "satJobRiskId": "1", + "satBankId": "002", + "satUnionizedStatusId": "No", + "department": "Recursos Humanos", + "position": "Analista de Nóminas", + "seniority": "7Y3M1W", + "bankAccount": "12345678901234567890", + "baseSalaryForContributions": 490.22, + "integratedDailySalary": 146.47, + "subcontractorRfc": null, + "timePercentage": null +}' + +### Actualizar datos de empleado +curl --location --request PUT 'http://localhost:5001/api/v4/people/54fc14ae-c88f-4afc-996b-0574d63341e2/employee' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'Content-Type: application/json' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data ' +{ + "employerPersonId": "bef56254-0892-4558-95c3-f9c8729e4b0e", + "employeePersonId": "54fc14ae-c88f-4afc-996b-0574d63341e2", + "employeeNumber": "12345ABC", + "satContractTypeId": "02", + "satTaxRegimeTypeId": "02", + "satPaymentPeriodicityId": "02", + "satPayrollStateId": "AGU", + "socialSecurityNumber": "123456789012345", + "laborRelationStartDate": "2022-01-15T00:00:00", + "satWorkdayTypeId": "01", + "satJobRiskId": "2", + "satBankId": "012", + "satUnionizedStatusId": "Sí", + "department": "Sistemas", + "position": "Programador Jr.", + "seniority": "7Y3M1W", + "bankAccount": "12345678901234567890", + "baseSalaryForContributions": 290.22, + "integratedDailySalary": 46.47, + "subcontractorRfc": null, + "timePercentage": null +}' + +### Eliminar datos de empleado +curl --location --request DELETE 'http://localhost:5001/api/v4/people/54fc14ae-c88f-4afc-996b-0574d63341e2/employee' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'Content-Type: application/json' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data-raw '{ + "legalName": "MI EMPRESA DUMMY", + "email": "miempresa@domain.com", + "password": "UserPass123!" +}' + + + +--- +You are a senior Node.js engineer specializing in TypeScript, module systems, and mexican payroll cdfi invoicing. Your task is to +add payroll invoice support to the existing code base following best practices. + + +# Important +-Make sure you follow the current project programing language, naming conventions and best practices for the current language and framework. +-Make sure you DO NOT ADD ACCIDENTAL COMPLEXITY, only add essential complexity. You can achieve this by reading the codebase thoroughly. DO NOT ASUME ANYTHING, BASE IT ON FACTS AND THE CURRENT STATE OF THE CODE. DO NOT DUPLICATE CODE. + + +## Invoices resource + +Implememt following changes as follows: + +- Change invoice enpoint to the unified version for all methods +- Update the invoice request model to the unified version +- creare a new file named ejemplos-factura-nomina.ts con una funcion para cada caso de uso un comentario y +un una funcion principal para que invoque todas las funciones de los casos de uso. + +# ============================================================================ +# 1. NOMINA ORDINARIA (Facturación por valores) +# ============================================================================ +nominaOrdinariaByValues(){ + //implementation +} + +## Unified Invoice Endpoint and model + +curl http://localhost:5001/api/v4/invoices \ + --request POST \ + --header 'Content-Type: application/json' \ + --data '{ + "versionCode": null, + "paymentFormCode": null, + "paymentMethodCode": null, + "currencyCode": null, + "typeCode": null, + "expeditionZipCode": null, + "pacConfirmation": null, + "series": null, + "number": null, + "date": "", + "paymentConditions": null, + "exchangeRate": 1, + "exportCode": null, + "issuer": { + "id": null, + "tin": null, + "legalName": null, + "taxRegimeCode": null, + "employerData": { + "curp": null, + "employerRegistration": null, + "originEmployerTin": null, + "satFundSourceId": null, + "ownResourceAmount": null + }, + "taxCredentials": [ + { + "id": null, + "base64File": null, + "fileType": 1, + "password": null + } + ] + }, + "recipient": { + "id": null, + "tin": null, + "legalName": null, + "zipCode": null, + "taxRegimeCode": null, + "cfdiUseCode": null, + "email": null, + "foreignCountryCode": null, + "foreignTin": null, + "employeeData": { + "curp": null, + "socialSecurityNumber": null, + "laborRelationStartDate": null, + "seniority": null, + "satContractTypeId": null, + "satUnionizedStatusId": null, + "satWorkdayTypeId": null, + "satTaxRegimeTypeId": null, + "employeeNumber": null, + "department": null, + "...": "[Additional Properties Truncated]" + } + }, + "items": [ + { + "id": null, + "itemCode": null, + "itemSku": null, + "quantity": 1, + "unitOfMeasurementCode": null, + "description": null, + "unitPrice": 1, + "discount": 1, + "taxObjectCode": null, + "itemTaxes": [ + { + "taxCode": null, + "taxTypeCode": null, + "taxRate": 1, + "taxFlagCode": null + } + ], + "onBehalfOf": { + "tin": null, + "legalName": null, + "taxRegimeCode": null, + "zipCode": null + }, + "customsInfo": [ + { + "customsNumber": null + } + ], + "propertyInfo": [ + { + "number": null + } + ], + "parts": [ + { + "itemCode": null, + "itemSku": null, + "quantity": 1, + "unitOfMeasurementCode": null, + "description": null, + "unitPrice": 1, + "customsInfo": [ + { + "customsNumber": null + } + ] + } + ] + } + ], + "globalInformation": { + "periodicityCode": null, + "monthCode": null, + "year": 1 + }, + "relatedInvoices": [ + { + "relationshipTypeCode": null, + "uuid": null + } + ], + "complement": { + "localTaxes": { + "taxes": [ + { + "taxName": null, + "taxRate": 1, + "taxAmount": 1, + "taxFlagCode": null + } + ] + }, + "payment": { + "paymentDate": "", + "paymentFormCode": null, + "currencyCode": "", + "exchangeRate": 1, + "amount": 1, + "operationNumber": null, + "sourceBankTin": null, + "sourceBankAccount": null, + "targetBankTin": null, + "targetBankAccount": null, + "...": "[Additional Properties Truncated]" + }, + "payroll": { + "version": "", + "payrollTypeCode": null, + "paymentDate": "", + "initialPaymentDate": "", + "finalPaymentDate": "", + "daysPaid": 1, + "earnings": { + "earnings": [ + { + "earningTypeCode": "", + "code": "", + "concept": "", + "taxedAmount": 1, + "exemptAmount": 1, + "stockOptions": { + "marketPrice": "[Max Depth Exceeded]", + "grantPrice": "[Max Depth Exceeded]" + }, + "overtime": [ + { + "days": "[Max Depth Exceeded]", + "hoursTypeCode": "[Max Depth Exceeded]", + "extraHours": "[Max Depth Exceeded]", + "amountPaid": "[Max Depth Exceeded]" + } + ] + } + ], + "otherPayments": [ + { + "otherPaymentTypeCode": "", + "code": "", + "concept": "", + "amount": 1, + "subsidyCaused": null, + "balanceCompensation": { + "favorableBalance": "[Max Depth Exceeded]", + "year": "[Max Depth Exceeded]", + "remainingFavorableBalance": "[Max Depth Exceeded]" + } + } + ], + "retirement": { + "totalOneTime": 1, + "totalInstallments": 1, + "dailyAmount": 1, + "accumulableIncome": 1, + "nonAccumulableIncome": 1 + }, + "severance": { + "totalPaid": 1, + "yearsOfService": 1, + "lastMonthlySalary": 1, + "accumulableIncome": 1, + "nonAccumulableIncome": 1 + } + }, + "deductions": [ + { + "deductionTypeCode": "", + "code": "", + "concept": "", + "amount": 1 + } + ], + "disabilities": [ + { + "disabilityDays": 1, + "disabilityTypeCode": "", + "monetaryAmount": 1 + } + ] + }, + "lading": {} + }, + "metadata": null +}' + + +## Payroll use cases + +### Factura Nómina - Nómina Ordinaria +curl --location 'http://localhost:5001/api/v4/invoices' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'Content-Type: application/json' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data '{ + "versionCode": "4.0", + "series": "F", + "date": "2026-01-18T18:04:06", + "paymentMethodCode": "PUE", + "currencyCode": "MXN", + "typeCode": "N", + "expeditionZipCode": "20000", + "exportCode": "01", + "issuer": { + "tin": "EKU9003173C9", + "legalName": "ESCUELA KEMPER URGATE", + "taxRegimeCode": "601", + "employerData": { + "employerRegistration": "B5510768108" + }, + "taxCredentials": [ + { + "base64File": "base64cer...", + "fileType": 0, + "password": "12345678a" + }, + { + "base64File": "base64key...", + "fileType": 1, + "password": "12345678a" + } + ] + }, + "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 + } + ] + } + } +}' + + +### Factura Nómina - Nómina Asimilados +curl --location 'http://localhost:5001/api/v4/invoices' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'Content-Type: application/json' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data '{ + "versionCode": "4.0", + "series": "F", + "date": "2026-01-18T18:04:06", + "paymentMethodCode": "PUE", + "currencyCode": "MXN", + "typeCode": "N", + "expeditionZipCode": "06880", + "exportCode": "01", + "issuer": { + "tin": "EKU9003173C9", + "legalName": "ESCUELA KEMPER URGATE", + "taxRegimeCode": "601", + "employerData": { + "originEmployerTin": "EKU9003173C9" + }, + "taxCredentials": [ + { + "base64File": "base64cer...", + "fileType": 0, + "password": "12345678a" + }, + { + "base64File": "base64key...", + "fileType": 1, + "password": "12345678a" + } + ] + }, + "recipient": { + "tin": "CACX7605101P8", + "legalName": "XOCHILT CASAS CHAVEZ", + "zipCode": "36257", + "taxRegimeCode": "605", + "cfdiUseCode": "CN01", + "employeeData": { + "curp": "XEXX010101HNEXXXA4", + "satContractTypeId": "09", + "satUnionizedStatusId": "No", + "satTaxRegimeTypeId": "09", + "employeeNumber": "00002", + "department": "ADMINISTRACION", + "position": "DIRECTOR DE ADMINISTRACION", + "satPaymentPeriodicityId": "99", + "satBankId": "012", + "bankAccount": "1111111111", + "satPayrollStateId": "CMX" + } + }, + "complement": { + "payroll": { + "version": "1.2", + "payrollTypeCode": "E", + "paymentDate": "2023-06-02T00:00:00", + "initialPaymentDate": "2023-06-01T00:00:00", + "finalPaymentDate": "2023-06-02T00:00:00", + "daysPaid": 1, + "earnings": { + "earnings": [ + { + "earningTypeCode": "046", + "code": "010046", + "concept": "INGRESOS ASIMILADOS A SALARIOS", + "taxedAmount": 111197.73, + "exemptAmount": 0.00 + } + ], + "otherPayments": [] + }, + "deductions": [ + { + "deductionTypeCode": "002", + "code": "020002", + "concept": "ISR", + "amount": 36197.73 + } + ] + } + } +}' + + +### Factura Nómina - Nómina Con Bonos, Fondo Ahorro y Deducciones +curl --location 'http://localhost:5001/api/v4/invoices' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'Content-Type: application/json' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data '{ + "versionCode": "4.0", + "series": "F", + "date": "2026-01-18T18:04:06", + "paymentMethodCode": "PUE", + "currencyCode": "MXN", + "typeCode": "N", + "expeditionZipCode": "20000", + "exportCode": "01", + "issuer": { + "tin": "EKU9003173C9", + "legalName": "ESCUELA KEMPER URGATE", + "taxRegimeCode": "601", + "employerData": { + "employerRegistration": "Z0000001234" + }, + "taxCredentials": [ + { + "base64File": "base64cer...", + "fileType": 0, + "password": "12345678a" + }, + { + "base64File": "base64key...", + "fileType": 1, + "password": "12345678a" + } + ] + }, + "recipient": { + "tin": "XOJI740919U48", + "legalName": "INGRID XODAR JIMENEZ", + "zipCode": "76028", + "taxRegimeCode": "605", + "cfdiUseCode": "CN01", + "employeeData": { + "curp": "XEXX010101MNEXXXA8", + "socialSecurityNumber": "0000000000", + "laborRelationStartDate": "2022-03-02T00:00:00", + "seniority": "P66W", + "satContractTypeId": "01", + "satUnionizedStatusId": "No", + "satTaxRegimeTypeId": "02", + "employeeNumber": "111111", + "satJobRiskId": "4", + "satPaymentPeriodicityId": "02", + "integratedDailySalary": 180.96, + "satPayrollStateId": "GUA" + } + }, + "complement": { + "payroll": { + "version": "1.2", + "payrollTypeCode": "O", + "paymentDate": "2023-06-11T00:00:00", + "initialPaymentDate": "2023-06-05T00:00:00", + "finalPaymentDate": "2023-06-11T00:00:00", + "daysPaid": 7, + "earnings": { + "earnings": [ + { + "earningTypeCode": "001", + "code": "SP01", + "concept": "SUELDO", + "taxedAmount": 1210.30, + "exemptAmount": 0.00 + }, + { + "earningTypeCode": "010", + "code": "SP02", + "concept": "PREMIO PUNTUALIDAD", + "taxedAmount": 121.03, + "exemptAmount": 0.00 + }, + { + "earningTypeCode": "029", + "code": "SP03", + "concept": "MONEDERO ELECTRONICO", + "taxedAmount": 0.00, + "exemptAmount": 269.43 + }, + { + "earningTypeCode": "010", + "code": "SP04", + "concept": "PREMIO DE ASISTENCIA", + "taxedAmount": 121.03, + "exemptAmount": 0.00 + }, + { + "earningTypeCode": "005", + "code": "SP54", + "concept": "APORTACION FONDO AHORRO", + "taxedAmount": 0.00, + "exemptAmount": 121.03 + } + ], + "otherPayments": [ + { + "otherPaymentTypeCode": "002", + "code": "ISRSUB", + "concept": "Subsidio ISR para empleo", + "amount": 0.0, + "subsidyCaused": 0.0, + "balanceCompensation": { + "favorableBalance": 0.0, + "year": 2022, + "remainingFavorableBalance": 0.0 + } + } + ] + }, + "deductions": [ + { + "deductionTypeCode": "004", + "code": "ZA09", + "concept": "APORTACION FONDO AHORRO", + "amount": 121.03 + }, + { + "deductionTypeCode": "002", + "code": "ISR", + "concept": "ISR", + "amount": 36.57 + }, + { + "deductionTypeCode": "001", + "code": "IMSS", + "concept": "Cuota de Seguridad Social EE", + "amount": 30.08 + }, + { + "deductionTypeCode": "004", + "code": "ZA68", + "concept": "DEDUCCION FDO AHORRO PAT", + "amount": 121.03 + }, + { + "deductionTypeCode": "018", + "code": "ZA11", + "concept": "APORTACION CAJA AHORRO", + "amount": 300.00 + } + ] + } + } +}' + +### Factura Nómina - Nómina Con Horas Extra + +curl --location 'http://localhost:5001/api/v4/invoices' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'Content-Type: application/json' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data '{ + "versionCode": "4.0", + "series": "F", + "date": "2026-01-18T18:04:06", + "paymentMethodCode": "PUE", + "currencyCode": "MXN", + "typeCode": "N", + "expeditionZipCode": "20000", + "exportCode": "01", + "issuer": { + "tin": "EKU9003173C9", + "legalName": "ESCUELA KEMPER URGATE", + "taxRegimeCode": "601", + "employerData": { + "employerRegistration": "B5510768108", + "originEmployerTin": "URE180429TM6" + }, + "taxCredentials": [ + { + "base64File": "base64cer...", + "fileType": 0, + "password": "12345678a" + }, + { + "base64File": "base64key...", + "fileType": 1, + "password": "12345678a" + } + ] + }, + "recipient": { + "tin": "XOJI740919U48", + "legalName": "INGRID XODAR JIMENEZ", + "zipCode": "76028", + "taxRegimeCode": "605", + "cfdiUseCode": "CN01", + "employeeData": { + "curp": "XEXX010101HNEXXXA4", + "socialSecurityNumber": "000000", + "laborRelationStartDate": "2015-01-01", + "seniority": "P437W", + "satContractTypeId": "01", + "satWorkdayTypeId": "01", + "satTaxRegimeTypeId": "03", + "employeeNumber": "120", + "department": "Desarrollo", + "position": "Ingeniero de Software", + "satJobRiskId": "1", + "satPaymentPeriodicityId": "04", + "satBankId": "002", + "bankAccount": "1111111111", + "baseSalaryForContributions": 490.22, + "integratedDailySalary": 146.47, + "satPayrollStateId": "JAL" + } + }, + "complement": { + "payroll": { + "version": "1.2", + "payrollTypeCode": "O", + "paymentDate": "2023-05-24T00:00:00", + "initialPaymentDate": "2023-05-09T00:00:00", + "finalPaymentDate": "2023-05-24T00:00:00", + "daysPaid": 15, + "earnings": { + "earnings": [ + { + "earningTypeCode": "001", + "code": "00500", + "concept": "Sueldos, Salarios Rayas y Jornales", + "taxedAmount": 2808.8, + "exemptAmount": 2191.2 + }, + { + "earningTypeCode": "019", + "code": "00100", + "concept": "Horas Extra", + "taxedAmount": 50.00, + "exemptAmount": 50.00, + "overtime": [ + { + "days": 1, + "hoursTypeCode": "01", + "extraHours": 2, + "amountPaid": 100.00 + } + ] + } + ], + "otherPayments": [] + }, + "deductions": [ + { + "deductionTypeCode": "001", + "code": "00301", + "concept": "Seguridad Social", + "amount": 200 + }, + { + "deductionTypeCode": "002", + "code": "00302", + "concept": "ISR", + "amount": 100 + } + ] + } + } +}' + +### Factura Nómina - Nómina Con Incapacidades +curl --location 'http://localhost:5001/api/v4/invoices' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'Content-Type: application/json' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data '{ + "versionCode": "4.0", + "series": "F", + "date": "2026-01-18T18:04:06", + "paymentMethodCode": "PUE", + "currencyCode": "MXN", + "typeCode": "N", + "expeditionZipCode": "20000", + "exportCode": "01", + "issuer": { + "tin": "EKU9003173C9", + "legalName": "ESCUELA KEMPER URGATE", + "taxRegimeCode": "601", + "employerData": { + "employerRegistration": "B5510768108", + "originEmployerTin": "URE180429TM6" + }, + "taxCredentials": [ + { + "base64File": "base64cer...", + "fileType": 0, + "password": "12345678a" + }, + { + "base64File": "base64key...", + "fileType": 1, + "password": "12345678a" + } + ] + }, + "recipient": { + "tin": "XOJI740919U48", + "legalName": "INGRID XODAR JIMENEZ", + "zipCode": "76028", + "taxRegimeCode": "605", + "cfdiUseCode": "CN01", + "employeeData": { + "curp": "XEXX010101HNEXXXA4", + "socialSecurityNumber": "000000", + "laborRelationStartDate": "2015-01-01T00:00:00", + "seniority": "P437W", + "satContractTypeId": "01", + "satWorkdayTypeId": "01", + "satTaxRegimeTypeId": "03", + "employeeNumber": "120", + "department": "Desarrollo", + "position": "Ingeniero de Software", + "satJobRiskId": "1", + "satPaymentPeriodicityId": "04", + "satBankId": "002", + "bankAccount": "1111111111", + "baseSalaryForContributions": 490.22, + "integratedDailySalary": 146.47, + "satPayrollStateId": "JAL" + } + }, + "complement": { + "payroll": { + "version": "1.2", + "payrollTypeCode": "O", + "paymentDate": "2023-05-24T00:00:00", + "initialPaymentDate": "2023-05-09T00:00:00", + "finalPaymentDate": "2023-05-24T00:00:00", + "daysPaid": 15, + "earnings": { + "earnings": [ + { + "earningTypeCode": "001", + "code": "00500", + "concept": "Sueldos, Salarios Rayas y Jornales", + "taxedAmount": 2808.8, + "exemptAmount": 2191.2 + } + ] + }, + "deductions": [ + { + "deductionTypeCode": "001", + "code": "00301", + "concept": "Seguridad Social", + "amount": 200 + }, + { + "deductionTypeCode": "002", + "code": "00302", + "concept": "ISR", + "amount": 100 + } + ], + "disabilities": [ + { + "disabilityDays": 1, + "disabilityTypeCode": "01" + } + ] + } + } +}' + +### Factura Nómina - Nómina con SNCF + +curl --location 'http://localhost:5001/api/v4/invoices' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'Content-Type: application/json' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data '{ + "versionCode": "4.0", + "series": "F", + "date": "2026-01-18T18:04:06", + "paymentMethodCode": "PUE", + "currencyCode": "MXN", + "typeCode": "N", + "expeditionZipCode": "39074", + "exportCode": "01", + "issuer": { + "tin": "OÑO120726RX3", + "legalName": "ORGANICOS ÑAVEZ OSORIO", + "taxRegimeCode": "601", + "employerData": { + "employerRegistration": "27112029", + "satFundSourceId": "IP" + }, + "taxCredentials": [ + { + "base64File": "base64cer...", + "fileType": 0, + "password": "12345678a" + }, + { + "base64File": "base64key...", + "fileType": 1, + "password": "12345678a" + } + ] + }, + "recipient": { + "tin": "CACX7605101P8", + "legalName": "XOCHILT CASAS CHAVEZ", + "zipCode": "36257", + "taxRegimeCode": "605", + "cfdiUseCode": "CN01", + "employeeData": { + "curp": "XEXX010101HNEXXXA4", + "socialSecurityNumber": "80997742673", + "laborRelationStartDate": "2021-09-01", + "seniority": "P88W", + "satContractTypeId": "01", + "satTaxRegimeTypeId": "02", + "employeeNumber": "273", + "satJobRiskId": "1", + "satPaymentPeriodicityId": "04", + "integratedDailySalary": 221.48, + "satPayrollStateId": "GRO" + } + }, + "complement": { + "payroll": { + "version": "1.2", + "payrollTypeCode": "O", + "paymentDate": "2023-05-16T00:00:00", + "initialPaymentDate": "2023-05-01T00:00:00", + "finalPaymentDate": "2023-05-16T00:00:00", + "daysPaid": 15, + "earnings": { + "earnings": [ + { + "earningTypeCode": "001", + "code": "P001", + "concept": "Sueldos, Salarios Rayas y Jornales", + "taxedAmount": 3322.20, + "exemptAmount": 0.0 + }, + { + "earningTypeCode": "038", + "code": "P540", + "concept": "Compensacion", + "taxedAmount": 100.0, + "exemptAmount": 0.0 + }, + { + "earningTypeCode": "038", + "code": "P550", + "concept": "Compensación Garantizada Extraordinaria", + "taxedAmount": 2200.0, + "exemptAmount": 0.0 + }, + { + "earningTypeCode": "038", + "code": "P530", + "concept": "Servicio Extraordinario", + "taxedAmount": 200.0, + "exemptAmount": 0.0 + }, + { + "earningTypeCode": "001", + "code": "P506", + "concept": "Otras Prestaciones", + "taxedAmount": 1500.0, + "exemptAmount": 0.0 + }, + { + "earningTypeCode": "001", + "code": "P505", + "concept": "Remuneración al Desempeño Legislativo", + "taxedAmount": 17500.0, + "exemptAmount": 0.0 + } + ], + "otherPayments": [ + { + "otherPaymentTypeCode": "002", + "code": "o002", + "concept": "Subsidio para el empleo efectivamente entregado al trabajador", + "amount": 0.0, + "subsidyCaused": 0.0 + } + ] + }, + "deductions": [ + { + "deductionTypeCode": "002", + "code": "D002", + "concept": "ISR", + "amount": 4716.61 + }, + { + "deductionTypeCode": "004", + "code": "D525", + "concept": "Redondeo", + "amount": 0.81 + }, + { + "deductionTypeCode": "001", + "code": "D510", + "concept": "Cuota Trabajador ISSSTE", + "amount": 126.78 + } + ] + } + } +}' + +### Factura Nómina - Nómina Extraordinaria + +curl --location 'http://localhost:5001/api/v4/invoices' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'Content-Type: application/json' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data '{ + "versionCode": "4.0", + "series": "F", + "date": "2026-01-18T18:04:06", + "paymentMethodCode": "PUE", + "currencyCode": "MXN", + "typeCode": "N", + "expeditionZipCode": "20000", + "exportCode": "01", + "issuer": { + "tin": "EKU9003173C9", + "legalName": "ESCUELA KEMPER URGATE", + "taxRegimeCode": "601", + "employerData": { + "employerRegistration": "B5510768108", + "originEmployerTin": "URE180429TM6" + }, + "taxCredentials": [ + { + "base64File": "base64cer...", + "fileType": 0, + "password": "12345678a" + }, + { + "base64File": "base64key...", + "fileType": 1, + "password": "12345678a" + } + ] + }, + "recipient": { + "tin": "XOJI740919U48", + "legalName": "INGRID XODAR JIMENEZ", + "zipCode": "76028", + "taxRegimeCode": "605", + "cfdiUseCode": "CN01", + "employeeData": { + "curp": "XEXX010101HNEXXXA4", + "socialSecurityNumber": "000000", + "laborRelationStartDate": "2015-01-01", + "seniority": "P439W", + "satContractTypeId": "01", + "satWorkdayTypeId": "01", + "satTaxRegimeTypeId": "03", + "employeeNumber": "120", + "department": "Desarrollo", + "position": "Ingeniero de Software", + "satJobRiskId": "1", + "satPaymentPeriodicityId": "99", + "satBankId": "002", + "bankAccount": "1111111111", + "integratedDailySalary": 146.47, + "satPayrollStateId": "JAL" + } + }, + "complement": { + "payroll": { + "version": "1.2", + "payrollTypeCode": "E", + "paymentDate": "2023-06-04T00:00:00", + "initialPaymentDate": "2023-06-04T00:00:00", + "finalPaymentDate": "2023-06-04T00:00:00", + "daysPaid": 30, + "earnings": { + "earnings": [ + { + "earningTypeCode": "002", + "code": "00500", + "concept": "Gratificación Anual (Aguinaldo)", + "taxedAmount": 0.00, + "exemptAmount": 10000.00 + } + ], + "otherPayments": [] + }, + "deductions": [] + } + } +}' + +### Factura Nómina - Nómina Separación Indemnización + +curl --location 'http://localhost:5001/api/v4/invoices' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'Content-Type: application/json' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data '{ + "versionCode": "4.0", + "series": "F", + "date": "2026-01-18T18:04:06", + "paymentMethodCode": "PUE", + "currencyCode": "MXN", + "typeCode": "N", + "expeditionZipCode": "20000", + "exportCode": "01", + "issuer": { + "tin": "EKU9003173C9", + "legalName": "ESCUELA KEMPER URGATE", + "taxRegimeCode": "601", + "employerData": { + "employerRegistration": "B5510768108", + "originEmployerTin": "URE180429TM6" + }, + "taxCredentials": [ + { + "base64File": "base64cer...", + "fileType": 0, + "password": "12345678a" + }, + { + "base64File": "base64key...", + "fileType": 1, + "password": "12345678a" + } + ] + }, + "recipient": { + "tin": "XOJI740919U48", + "legalName": "INGRID XODAR JIMENEZ", + "zipCode": "76028", + "taxRegimeCode": "605", + "cfdiUseCode": "CN01", + "employeeData": { + "curp": "XEXX010101HNEXXXA4", + "socialSecurityNumber": "000000", + "laborRelationStartDate": "2015-01-01", + "seniority": "P439W", + "satContractTypeId": "01", + "satWorkdayTypeId": "01", + "satTaxRegimeTypeId": "03", + "employeeNumber": "120", + "department": "Desarrollo", + "position": "Ingeniero de Software", + "satJobRiskId": "1", + "satPaymentPeriodicityId": "99", + "satBankId": "002", + "bankAccount": "1111111111", + "integratedDailySalary": 146.47, + "satPayrollStateId": "JAL" + } + }, + "complement": { + "payroll": { + "version": "1.2", + "payrollTypeCode": "E", + "paymentDate": "2023-06-04T00:00:00", + "initialPaymentDate": "2023-05-05T00:00:00", + "finalPaymentDate": "2023-06-04T00:00:00", + "daysPaid": 30, + "earnings": { + "earnings": [ + { + "earningTypeCode": "023", + "code": "00500", + "concept": "Pagos por separación", + "taxedAmount": 0.00, + "exemptAmount": 10000.00 + }, + { + "earningTypeCode": "025", + "code": "00900", + "concept": "Indemnizaciones", + "taxedAmount": 0.00, + "exemptAmount": 500.00 + } + ], + "otherPayments": [], + "severance": { + "totalPaid": 10500.00, + "yearsOfService": 1, + "lastMonthlySalary": 10000.00, + "accumulableIncome": 10000.00, + "nonAccumulableIncome": 0.00 + } + }, + "deductions": [] + } + } +}' + + +### Factura Nómina - Nómina Jubilación Pensión Retiro +curl --location 'http://localhost:5001/api/v4/invoices' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'Content-Type: application/json' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data '{ + "versionCode": "4.0", + "series": "F", + "date": "2026-01-18T18:04:06", + "paymentMethodCode": "PUE", + "currencyCode": "MXN", + "typeCode": "N", + "expeditionZipCode": "20000", + "exportCode": "01", + "issuer": { + "tin": "EKU9003173C9", + "legalName": "ESCUELA KEMPER URGATE", + "taxRegimeCode": "601", + "employerData": { + "employerRegistration": "B5510768108", + "originEmployerTin": "URE180429TM6" + }, + "taxCredentials": [ + { + "base64File": "base64cer...", + "fileType": 0, + "password": "12345678a" + }, + { + "base64File": "base64key...", + "fileType": 1, + "password": "12345678a" + } + ] + }, + "recipient": { + "tin": "XOJI740919U48", + "legalName": "INGRID XODAR JIMENEZ", + "zipCode": "76028", + "taxRegimeCode": "605", + "cfdiUseCode": "CN01", + "employeeData": { + "curp": "XEXX010101HNEXXXA4", + "socialSecurityNumber": "000000", + "laborRelationStartDate": "2015-01-01", + "seniority": "P439W", + "satContractTypeId": "01", + "satWorkdayTypeId": "01", + "satTaxRegimeTypeId": "03", + "employeeNumber": "120", + "department": "Desarrollo", + "position": "Ingeniero de Software", + "satJobRiskId": "1", + "satPaymentPeriodicityId": "99", + "satBankId": "002", + "bankAccount": "1111111111", + "integratedDailySalary": 146.47, + "satPayrollStateId": "JAL" + } + }, + "complement": { + "payroll": { + "version": "1.2", + "payrollTypeCode": "E", + "paymentDate": "2023-05-05T00:00:00", + "initialPaymentDate": "2023-06-04T00:00:00", + "finalPaymentDate": "2023-06-04T00:00:00", + "daysPaid": 30, + "earnings": { + "earnings": [ + { + "earningTypeCode": "039", + "code": "00500", + "concept": "Jubilaciones, pensiones o haberes de retiro", + "taxedAmount": 0.00, + "exemptAmount": 10000.00 + } + ], + "retirement": { + "totalOneTime": 10000.00, + "accumulableIncome": 10000.00, + "nonAccumulableIncome": 0.00 + } + }, + "deductions": [] + } + } +}' + +### Factura Nómina - Nómina Sin Deducciones + +curl --location 'http://localhost:5001/api/v4/invoices' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'Content-Type: application/json' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data '{ + "versionCode": "4.0", + "series": "F", + "date": "2026-01-18T18:04:06", + "paymentMethodCode": "PUE", + "currencyCode": "MXN", + "typeCode": "N", + "expeditionZipCode": "20000", + "exportCode": "01", + "issuer": { + "tin": "EKU9003173C9", + "legalName": "ESCUELA KEMPER URGATE", + "taxRegimeCode": "601", + "employerData": { + "employerRegistration": "B5510768108", + "originEmployerTin": "URE180429TM6" + }, + "taxCredentials": [ + { + "base64File": "base64cer...", + "fileType": 0, + "password": "12345678a" + }, + { + "base64File": "base64key...", + "fileType": 1, + "password": "12345678a" + } + ] + }, + "recipient": { + "tin": "XOJI740919U48", + "legalName": "INGRID XODAR JIMENEZ", + "zipCode": "76028", + "taxRegimeCode": "605", + "cfdiUseCode": "CN01", + "employeeData": { + "curp": "XEXX010101HNEXXXA4", + "socialSecurityNumber": "000000", + "laborRelationStartDate": "2015-01-01", + "seniority": "P437W", + "satContractTypeId": "01", + "satWorkdayTypeId": "01", + "satTaxRegimeTypeId": "03", + "employeeNumber": "120", + "department": "Desarrollo", + "position": "Ingeniero de Software", + "satJobRiskId": "1", + "satPaymentPeriodicityId": "04", + "satBankId": "002", + "bankAccount": "1111111111", + "baseSalaryForContributions": 490.22, + "integratedDailySalary": 146.47, + "satPayrollStateId": "JAL" + } + }, + "complement": { + "payroll": { + "version": "1.2", + "payrollTypeCode": "O", + "paymentDate": "2023-05-24T00:00:00", + "initialPaymentDate": "2023-05-09T00:00:00", + "finalPaymentDate": "2023-05-24T00:00:00", + "daysPaid": 15, + "earnings": { + "earnings": [ + { + "earningTypeCode": "001", + "code": "00500", + "concept": "Sueldos, Salarios Rayas y Jornales", + "taxedAmount": 2808.8, + "exemptAmount": 2191.2 + } + ], + "otherPayments": [] + }, + "deductions": [] + } + } +}' + + +### Factura Nómina - Nómina Subsidio causado al empleo + +curl --location 'http://localhost:5001/api/v4/invoices' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'Content-Type: application/json' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data '{ + "versionCode": "4.0", + "series": "F", + "date": "2026-01-18T18:04:06", + "paymentMethodCode": "PUE", + "currencyCode": "MXN", + "typeCode": "N", + "expeditionZipCode": "20000", + "exportCode": "01", + "issuer": { + "tin": "EKU9003173C9", + "legalName": "ESCUELA KEMPER URGATE", + "taxRegimeCode": "601", + "employerData": { + "employerRegistration": "B5510768108", + "originEmployerTin": "URE180429TM6" + }, + "taxCredentials": [ + { + "base64File": "base64cer...", + "fileType": 0, + "password": "12345678a" + }, + { + "base64File": "base64key...", + "fileType": 1, + "password": "12345678a" + } + ] + }, + "recipient": { + "tin": "XOJI740919U48", + "legalName": "INGRID XODAR JIMENEZ", + "zipCode": "76028", + "taxRegimeCode": "605", + "cfdiUseCode": "CN01", + "employeeData": { + "curp": "XEXX010101HNEXXXA4", + "socialSecurityNumber": "000000", + "laborRelationStartDate": "2015-01-01T00:00:00", + "seniority": "P437W", + "satContractTypeId": "01", + "satWorkdayTypeId": "01", + "satTaxRegimeTypeId": "02", + "employeeNumber": "120", + "department": "Desarrollo", + "position": "Ingeniero de Software", + "satJobRiskId": "1", + "satPaymentPeriodicityId": "04", + "satBankId": "002", + "bankAccount": "1111111111", + "baseSalaryForContributions": 490.22, + "integratedDailySalary": 146.47, + "satPayrollStateId": "JAL" + } + }, + "complement": { + "payroll": { + "version": "1.2", + "payrollTypeCode": "O", + "paymentDate": "2023-05-24T00:00:00", + "initialPaymentDate": "2023-05-09T00:00:00", + "finalPaymentDate": "2023-05-24T00:00:00", + "daysPaid": 15, + "earnings": { + "earnings": [ + { + "earningTypeCode": "001", + "code": "00500", + "concept": "Sueldos, Salarios Rayas y Jornales", + "taxedAmount": 2808.8, + "exemptAmount": 2191.2 + } + ], + "otherPayments": [ + { + "otherPaymentTypeCode": "007", + "code": "0002", + "concept": "ISR ajustado por subsidio", + "amount": 145.80, + "subsidyCaused": 0.0 + } + ] + }, + "deductions": [ + { + "deductionTypeCode": "107", + "code": "D002", + "concept": "Ajuste al Subsidio Causado", + "amount": 160.35 + }, + { + "deductionTypeCode": "002", + "code": "D002", + "concept": "ISR", + "amount": 145.80 + } + ] + } + } +}' + +### Factura Nómina - Nómina Viáticos + +curl --location 'http://localhost:5001/api/v4/invoices' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'Content-Type: application/json' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data '{ + "versionCode": "4.0", + "series": "F", + "date": "2026-01-18T18:04:06", + "paymentMethodCode": "PUE", + "currencyCode": "MXN", + "typeCode": "N", + "expeditionZipCode": "20000", + "exportCode": "01", + "issuer": { + "tin": "EKU9003173C9", + "legalName": "ESCUELA KEMPER URGATE", + "taxRegimeCode": "601", + "employerData": { + "employerRegistration": "B5510768108", + "originEmployerTin": "URE180429TM6" + }, + "taxCredentials": [ + { + "base64File": "base64cer...", + "fileType": 0, + "password": "12345678a" + }, + { + "base64File": "base64key...", + "fileType": 1, + "password": "12345678a" + } + ] + }, + "recipient": { + "tin": "XOJI740919U48", + "legalName": "INGRID XODAR JIMENEZ", + "zipCode": "76028", + "taxRegimeCode": "605", + "cfdiUseCode": "CN01", + "employeeData": { + "curp": "XEXX010101HNEXXXA4", + "socialSecurityNumber": "000000", + "laborRelationStartDate": "2015-01-01T00:00:00", + "seniority": "P438W", + "satContractTypeId": "01", + "satWorkdayTypeId": "01", + "satTaxRegimeTypeId": "03", + "employeeNumber": "120", + "department": "Desarrollo", + "position": "Ingeniero de Software", + "satJobRiskId": "1", + "satPaymentPeriodicityId": "04", + "satBankId": "002", + "bankAccount": "1111111111", + "baseSalaryForContributions": 490.22, + "integratedDailySalary": 146.47, + "satPayrollStateId": "JAL" + } + }, + "complement": { + "payroll": { + "version": "1.2", + "payrollTypeCode": "O", + "paymentDate": "2023-09-26T00:00:00", + "initialPaymentDate": "2023-09-11T00:00:00", + "finalPaymentDate": "2023-09-26T00:00:00", + "daysPaid": 15, + "earnings": { + "earnings": [ + { + "earningTypeCode": "050", + "code": "050", + "concept": "Viaticos", + "taxedAmount": 0, + "exemptAmount": 3000 + } + ] + }, + "deductions": [ + { + "deductionTypeCode": "081", + "code": "081", + "concept": "Ajuste en viaticos entregados al trabajador", + "amount": 3000 + } + ] + } + } +}' + +### Factura Nómina - Nómina + +curl --location 'http://localhost:5001/api/v4/invoices' \ +--header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ +--header 'X-TIME-ZONE: America/Mexico_City' \ +--header 'Content-Type: application/json' \ +--header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ +--data '{ + "versionCode": "4.0", + "series": "F", + "date": "2026-01-18T18:04:06", + "paymentMethodCode": "PUE", + "currencyCode": "MXN", + "typeCode": "N", + "expeditionZipCode": "20000", + "exportCode": "01", + "issuer": { + "tin": "EKU9003173C9", + "legalName": "ESCUELA KEMPER URGATE", + "taxRegimeCode": "601", + "employerData": { + "employerRegistration": "B5510768108", + "originEmployerTin": "URE180429TM6" + }, + "taxCredentials": [ + { + "base64File": "base64cer...", + "fileType": 0, + "password": "12345678a" + }, + { + "base64File": "base64key...", + "fileType": 1, + "password": "12345678a" + } + ] + }, + "recipient": { + "tin": "XOJI740919U48", + "legalName": "INGRID XODAR JIMENEZ", + "zipCode": "76028", + "taxRegimeCode": "605", + "cfdiUseCode": "CN01", + "employeeData": { + "curp": "XEXX010101HNEXXXA4", + "socialSecurityNumber": "000000", + "laborRelationStartDate": "2015-01-01T00:00:00", + "seniority": "P437W", + "satContractTypeId": "01", + "satWorkdayTypeId": "01", + "satTaxRegimeTypeId": "03", + "employeeNumber": "120", + "department": "Desarrollo", + "position": "Ingeniero de Software", + "satJobRiskId": "1", + "satPaymentPeriodicityId": "04", + "satBankId": "002", + "bankAccount": "1111111111", + "baseSalaryForContributions": 490.22, + "integratedDailySalary": 146.47, + "satPayrollStateId": "JAL" + } + }, + "complement": { + "payroll": { + "version": "1.2", + "payrollTypeCode": "O", + "paymentDate": "2023-05-24T00:00:00", + "initialPaymentDate": "2023-05-09T00:00:00", + "finalPaymentDate": "2023-05-24T00:00:00", + "daysPaid": 15, + "earnings": { + "earnings": [ + { + "earningTypeCode": "001", + "code": "00500", + "concept": "Sueldos, Salarios Rayas y Jornales", + "taxedAmount": 2808.8, + "exemptAmount": 2191.2 + } + ], + "otherPayments": [] + }, + "deductions": [ + { + "deductionTypeCode": "001", + "code": "00301", + "concept": "Seguridad Social", + "amount": 200 + }, + { + "deductionTypeCode": "002", + "code": "00302", + "concept": "ISR", + "amount": 100 + } + ] + } + } +}' + + +### Response (for any use case) + +{ + "data": { + "versionCode": "4.0", + "series": "F", + "number": "EKU9003173C9-136", + "date": "2025-10-19T10:25:16.000", + "paymentFormCode": null, + "paymentConditions": null, + "subtotal": 117408.96, + "discount": 42821.48, + "currencyCode": "MXN", + "exchangeRate": 1, + "total": 74587.48, + "typeCode": "N", + "exportCode": "01", + "uuid": "a25e3739-a0ce-4c12-9ac0-283e035b9bf8", + "consecutive": 338, + "status": null, + "paymentMethodCode": "PUE", + "expeditionZipCode": "20000", + "issuer": { + "id": null, + "tin": "EKU9003173C9", + "legalName": "ESCUELA KEMPER URGATE", + "taxRegimeCode": "601" + }, + "recipient": { + "id": null, + "tin": "FUNK671228PH6", + "legalName": "KARLA FUENTE NOLASCO", + "zipCode": "01160", + "taxRegimeCode": "605", + "cfdiUseCode": "CN01", + "email": null + }, + "items": [ + { + "itemCode": "84111505", + "quantity": 1, + "unitOfMeasurementCode": "ACT", + "description": "Pago de nómina", + "unitPrice": 117408.96, + "taxObjectCode": "01", + "itemSku": null, + "unitOfMeasurement": null, + "discount": 42821.48, + "itemTaxes": [] + } + ], + "responses": [ + { + "invoiceId": "00c6f323-cf1d-4192-b3d0-eae33202a17a", + "invoiceUuid": "a25e3739-a0ce-4c12-9ac0-283e035b9bf8", + "invoiceCertificateNumber": "30001000000500003416", + "invoiceBase64Sello": "base64...", + "invoiceSignatureDate": "2025-10-20T12:56:42.000", + "invoiceBase64QrCode": "base64...", + "invoiceBase64": "base64...", + "satBase64Sello": "base64...", + "satBase64OriginalString": "base64...", + "satCertificateNumber": "30001000000500003456", + "id": "493f66c5-e366-485b-a3ce-1927e3d59710", + "createdAt": "2025-10-20T12:56:41.840", + "updatedAt": "2025-10-20T12:56:41.840" + } + ], + "metadata": { + "mode": "values" + }, + "id": "00c6f323-cf1d-4192-b3d0-eae33202a17a", + "createdAt": "2025-10-20T12:56:41.840", + "updatedAt": "2025-10-20T12:56:41.840" + }, + "succeeded": true, + "message": "", + "details": "", + "httpStatusCode": 200 +} + + + diff --git a/payroll-requirements.md b/payroll-requirements.md new file mode 100644 index 0000000..1f23733 --- /dev/null +++ b/payroll-requirements.md @@ -0,0 +1,820 @@ +# FiscalAPI SDK - Payroll (CFDI Nomina) Requirements + +This document describes the requirements for implementing payroll invoice (CFDI de Nomina) support in FiscalAPI SDKs. It is language-agnostic and focuses on the models, services, and functionality needed. + +--- + +## Table of Contents + +1. [Overview](#overview) +2. [New Models Required](#new-models-required) +3. [New Services Required](#new-services-required) + - [EmployeeService](#1-employeeservice) + - [EmployerService](#2-employerservice) + - [PeopleService Updates](#3-peopleservice-updates) + - [StampService](#4-stampservice) +4. [Person Model Updates](#person-model-updates) +5. [Invoice Model Updates](#invoice-model-updates) +6. [Two Operation Modes](#two-operation-modes) +7. [Payroll Types Reference](#payroll-types-reference) +8. [API Endpoints](#api-endpoints) +9. [Field Mappings (JSON Aliases)](#field-mappings-json-aliases) +10. [Example Implementations](#example-implementations) + +--- + +## Overview + +Payroll invoices (CFDI de Nomina) in Mexico require: +- **Employer data** attached to the issuer (company paying wages) +- **Employee data** attached to the recipient (worker receiving wages) +- **Payroll complement** containing earnings, deductions, and other payment details + +The SDK must support **13 different payroll types** and **two operation modes**: +1. **By Values** - All data sent inline with the invoice request +2. **By References** - Only person IDs sent; employee/employer data pre-configured via API + +--- + +## New Models Required + +### 1. EmployeeData + +Data model for storing employee information as a sub-resource of Person. + +| Field | JSON Alias | Type | Description | +|-------|------------|------|-------------| +| employer_person_id | employerPersonId | string | ID of the employer person | +| employee_person_id | employeePersonId | string | ID of the employee person | +| social_security_number | socialSecurityNumber | string | NSS (Numero de Seguridad Social) | +| labor_relation_start_date | laborRelationStartDate | datetime | Employment start date | +| seniority | seniority | string | ISO 8601 duration (e.g., "P54W" = 54 weeks) | +| sat_contract_type_id | satContractTypeId | string | SAT contract type code | +| sat_unionized_status_id | satUnionizedStatusId | string | Unionized status code | +| sat_tax_regime_type_id | satTaxRegimeTypeId | string | Tax regime type code | +| sat_workday_type_id | satWorkdayTypeId | string | Workday type code | +| sat_job_risk_id | satJobRiskId | string | Job risk level code | +| sat_payment_periodicity_id | satPaymentPeriodicityId | string | Payment frequency code | +| employee_number | employeeNumber | string | Internal employee number | +| sat_bank_id | satBankId | string | Bank code | +| sat_payroll_state_id | satPayrollStateId | string | State code for payroll | +| department | department | string | Department name | +| position | position | string | Job position/title | +| bank_account | bankAccount | string | Bank account number | +| base_salary_for_contributions | baseSalaryForContributions | decimal | Base salary for social security | +| integrated_daily_salary | integratedDailySalary | decimal | Integrated daily salary | +| subcontractor_rfc | subcontractorRfc | string | RFC of subcontractor (if applicable) | +| time_percentage | timePercentage | decimal | Time percentage (for partial employment) | + +### 2. EmployerData + +Data model for storing employer information as a sub-resource of Person. + +| Field | JSON Alias | Type | Description | +|-------|------------|------|-------------| +| person_id | personId | string | ID of the employer person | +| employer_registration | employerRegistration | string | Registro Patronal (IMSS) | +| origin_employer_tin | originEmployerTin | string | RFC of origin employer | +| sat_fund_source_id | satFundSourceId | string | Fund source code | +| own_resource_amount | ownResourceAmount | decimal | Own resource amount | + +### 3. InvoiceIssuerEmployerData + +Employer data embedded in invoice issuer (for "by values" mode). + +| Field | JSON Alias | Type | Description | +|-------|------------|------|-------------| +| curp | curp | string | CURP of employer representative | +| employer_registration | employerRegistration | string | Registro Patronal | +| origin_employer_tin | originEmployerTin | string | RFC of origin employer | +| sat_fund_source_id | satFundSourceId | string | Fund source code | +| own_resource_amount | ownResourceAmount | decimal | Own resource amount | + +### 4. InvoiceRecipientEmployeeData + +Employee data embedded in invoice recipient (for "by values" mode). + +| Field | JSON Alias | Type | Description | +|-------|------------|------|-------------| +| curp | curp | string | CURP of employee | +| social_security_number | socialSecurityNumber | string | NSS | +| labor_relation_start_date | laborRelationStartDate | string | Start date (ISO format) | +| seniority | seniority | string | ISO 8601 duration | +| sat_contract_type_id | satContractTypeId | string | Contract type | +| sat_unionized_status_id | satUnionizedStatusId | string | Unionized status | +| sat_workday_type_id | satWorkdayTypeId | string | Workday type | +| sat_tax_regime_type_id | satTaxRegimeTypeId | string | Tax regime type | +| employee_number | employeeNumber | string | Employee number | +| department | department | string | Department | +| position | position | string | Position | +| sat_job_risk_id | satJobRiskId | string | Job risk code | +| sat_payment_periodicity_id | satPaymentPeriodicityId | string | Payment periodicity | +| sat_bank_id | satBankId | string | Bank code | +| bank_account | bankAccount | string | Bank account | +| base_salary_for_contributions | baseSalaryForContributions | decimal | Base salary | +| integrated_daily_salary | integratedDailySalary | decimal | Integrated salary | +| sat_payroll_state_id | satPayrollStateId | string | Payroll state | + +### 5. Payroll Complement Models + +#### PayrollComplement (main container) + +| Field | JSON Alias | Type | Description | +|-------|------------|------|-------------| +| version | version | string | Always "1.2" | +| payroll_type_code | payrollTypeCode | string | "O" (ordinary) or "E" (extraordinary) | +| payment_date | paymentDate | string | Payment date (ISO format) | +| initial_payment_date | initialPaymentDate | string | Period start date | +| final_payment_date | finalPaymentDate | string | Period end date | +| days_paid | daysPaid | decimal | Days paid in period | +| earnings | earnings | PayrollEarningsComplement | Earnings container | +| deductions | deductions | PayrollDeduction[] | List of deductions | +| disabilities | disabilities | PayrollDisability[] | List of disabilities | + +#### PayrollEarningsComplement + +| Field | JSON Alias | Type | Description | +|-------|------------|------|-------------| +| earnings | earnings | PayrollEarning[] | List of earnings | +| other_payments | otherPayments | PayrollOtherPayment[] | Other payments (subsidies, etc.) | +| retirement | retirement | PayrollRetirement | Retirement/pension data | +| severance | severance | PayrollSeverance | Severance/indemnization data | + +#### PayrollEarning + +| Field | JSON Alias | Type | Description | +|-------|------------|------|-------------| +| earning_type_code | earningTypeCode | string | SAT earning type code | +| code | code | string | Internal code | +| concept | concept | string | Description | +| taxed_amount | taxedAmount | decimal | Taxable amount | +| exempt_amount | exemptAmount | decimal | Exempt amount | +| stock_options | stockOptions | PayrollStockOptions | Stock options (if applicable) | +| overtime | overtime | PayrollOvertime[] | Overtime hours | + +#### PayrollDeduction + +| Field | JSON Alias | Type | Description | +|-------|------------|------|-------------| +| deduction_type_code | deductionTypeCode | string | SAT deduction type code | +| code | code | string | Internal code | +| concept | concept | string | Description | +| amount | amount | decimal | Deduction amount | + +#### PayrollOtherPayment + +| Field | JSON Alias | Type | Description | +|-------|------------|------|-------------| +| other_payment_type_code | otherPaymentTypeCode | string | SAT other payment type code | +| code | code | string | Internal code | +| concept | concept | string | Description | +| amount | amount | decimal | Payment amount | +| subsidy_caused | subsidyCaused | decimal | Employment subsidy caused | +| balance_compensation | balanceCompensation | PayrollBalanceCompensation | Balance compensation | + +#### PayrollOvertime + +| Field | JSON Alias | Type | Description | +|-------|------------|------|-------------| +| days | days | int | Days with overtime | +| hours_type_code | hoursTypeCode | string | "01" (double) or "02" (triple) | +| extra_hours | extraHours | int | Number of extra hours | +| amount_paid | amountPaid | decimal | Amount paid | + +#### PayrollDisability + +| Field | JSON Alias | Type | Description | +|-------|------------|------|-------------| +| disability_days | disabilityDays | int | Days of disability | +| disability_type_code | disabilityTypeCode | string | SAT disability type code | +| monetary_amount | monetaryAmount | decimal | Monetary amount | + +#### PayrollRetirement + +| Field | JSON Alias | Type | Description | +|-------|------------|------|-------------| +| total_one_time | totalOneTime | decimal | One-time payment total | +| total_installments | totalInstallments | decimal | Installments total | +| daily_amount | dailyAmount | decimal | Daily amount | +| accumulable_income | accumulableIncome | decimal | Accumulable income | +| non_accumulable_income | nonAccumulableIncome | decimal | Non-accumulable income | + +#### PayrollSeverance + +| Field | JSON Alias | Type | Description | +|-------|------------|------|-------------| +| total_paid | totalPaid | decimal | Total paid | +| years_of_service | yearsOfService | int | Years of service | +| last_monthly_salary | lastMonthlySalary | decimal | Last monthly salary | +| accumulable_income | accumulableIncome | decimal | Accumulable income | +| non_accumulable_income | nonAccumulableIncome | decimal | Non-accumulable income | + +--- + +## New Services Required + +### 1. EmployeeService + +Sub-service of PeopleService for managing employee data. + +``` +Endpoint pattern: people/{personId}/employee +``` + +| Method | HTTP | Endpoint | Description | +|--------|------|----------|-------------| +| get_by_id(person_id) | GET | people/{personId}/employee | Get employee data | +| create(employee) | POST | people/{employeePersonId}/employee | Create employee data | +| update(employee) | PUT | people/{employeePersonId}/employee | Update employee data | +| delete(person_id) | DELETE | people/{personId}/employee | Delete employee data | + +### 2. EmployerService + +Sub-service of PeopleService for managing employer data. + +``` +Endpoint pattern: people/{personId}/employer +``` + +| Method | HTTP | Endpoint | Description | +|--------|------|----------|-------------| +| get_by_id(person_id) | GET | people/{personId}/employer | Get employer data | +| create(employer) | POST | people/{personId}/employer | Create employer data | +| update(employer) | PUT | people/{personId}/employer | Update employer data | +| delete(person_id) | DELETE | people/{personId}/employer | Delete employer data | + +### 3. PeopleService Updates + +Add employee and employer sub-services as properties: + +``` +client.people.employee -> EmployeeService +client.people.employer -> EmployerService +``` + +### 4. StampService + +Service for managing stamp transactions (timbres fiscales). Stamps are the digital fiscal tokens required to certify CFDI invoices. + +``` +Endpoint pattern: stamps +``` + +| Method | HTTP | Endpoint | Description | +|--------|------|----------|-------------| +| get_list(page_number, page_size) | GET | stamps?pageNumber={n}&pageSize={s} | List stamp transactions with pagination | +| get_by_id(transaction_id) | GET | stamps/{transactionId} | Get a stamp transaction by ID | +| transfer_stamps(request) | POST | stamps | Transfer stamps from one person to another | +| withdraw_stamps(request) | POST | stamps | Withdraw stamps (alias for transfer_stamps) | + +#### Stamp Models + +##### UserLookupDto + +Lookup DTO for user/person references in stamp transactions. + +| Field | JSON Alias | Type | Description | +|-------|------------|------|-------------| +| tin | tin | string | RFC of the user | +| legal_name | legalName | string | Legal name of the user | + +##### StampTransaction + +Represents a stamp transfer/withdrawal transaction. + +| Field | JSON Alias | Type | Description | +|-------|------------|------|-------------| +| consecutive | consecutive | int | Transaction consecutive number | +| from_person | fromPerson | UserLookupDto | Source person of the transfer | +| to_person | toPerson | UserLookupDto | Destination person of the transfer | +| amount | amount | int | Number of stamps transferred | +| transaction_type | transactionType | int | Type of transaction | +| transaction_status | transactionStatus | int | Status of the transaction | +| reference_id | referenceId | string | Transaction reference ID | +| comments | comments | string | Transaction comments | + +##### StampTransactionParams + +Request parameters for stamp transfer/withdraw operations. + +| Field | JSON Alias | Type | Required | Description | +|-------|------------|------|----------|-------------| +| from_person_id | fromPersonId | string | Yes | ID of the source person | +| to_person_id | toPersonId | string | Yes | ID of the destination person | +| amount | amount | int | Yes | Number of stamps to transfer | +| comments | comments | string | No | Transfer comments | + +#### Example: Transfer Stamps + +``` +// Transfer 100 stamps from master account to sub-account +params = StampTransactionParams( + from_person_id: "master-account-id", + to_person_id: "sub-account-id", + amount: 100, + comments: "Monthly stamp allocation" +) + +response = client.stamps.transfer_stamps(params) +``` + +#### Example: List Stamp Transactions + +``` +// Get paginated list of stamp transactions +response = client.stamps.get_list(page_number=1, page_size=10) + +for transaction in response.data.items: + print(f"Transfer: {transaction.amount} stamps from {transaction.from_person.legal_name}") +``` + +--- + +## Person Model Updates + +Add the following field to the Person model: + +| Field | JSON Alias | Type | Description | +|-------|------------|------|-------------| +| curp | curp | string | CURP (Clave Unica de Registro de Poblacion) | + +**Important**: For payroll invoices, the recipient (employee) must have: +- `curp` field populated +- `sat_tax_regime_id` = "605" (Sueldos y Salarios) +- `sat_cfdi_use_id` = "CN01" (Nomina) + +--- + +## Invoice Model Updates + +### InvoiceIssuer + +Add field: + +| Field | JSON Alias | Type | Description | +|-------|------------|------|-------------| +| employer_data | employerData | InvoiceIssuerEmployerData | Employer data for payroll | + +### InvoiceRecipient + +Add field: + +| Field | JSON Alias | Type | Description | +|-------|------------|------|-------------| +| employee_data | employeeData | InvoiceRecipientEmployeeData | Employee data for payroll | + +### InvoiceComplement + +Add field: + +| Field | JSON Alias | Type | Description | +|-------|------------|------|-------------| +| payroll | payroll | PayrollComplement | Payroll complement data | + +--- + +## Two Operation Modes + +### Mode 1: By Values + +All employee/employer data is sent inline with the invoice request. + +**Characteristics:** +- Self-contained request +- No prior setup required +- Larger payload size +- Employee data goes in `recipient.employee_data` +- Employer data goes in `issuer.employer_data` + +**Example structure:** +``` +Invoice { + issuer: { + tin: "EKU9003173C9", + legal_name: "ESCUELA KEMPER URGATE", + tax_regime_code: "601", + employer_data: { + employer_registration: "B5510768108", + origin_employer_tin: "URE180429TM6" + } + }, + recipient: { + tin: "XOJI740919U48", + legal_name: "INGRID XODAR JIMENEZ", + tax_regime_code: "605", + cfdi_use_code: "CN01", + employee_data: { + curp: "XOJI850618MJCDNG09", + social_security_number: "000000", + seniority: "P54W", + ... + } + }, + complement: { + payroll: { ... } + } +} +``` + +### Mode 2: By References + +Only person IDs are sent; employee/employer data must be pre-configured. + +**Characteristics:** +- Smaller payload +- Requires prior setup of employee/employer data via API +- Person must have CURP and tax regime configured +- Uses only `id` field in issuer/recipient + +**Setup steps:** +1. Update person with CURP and tax regime (605 for employee, appropriate for employer) +2. Create EmployeeData via `client.people.employee.create()` +3. Create EmployerData via `client.people.employer.create()` + +**Example structure:** +``` +Invoice { + issuer: { + id: "2e7b988f-3a2a-4f67-86e9-3f931dd48581" + }, + recipient: { + id: "9367249f-f0ee-43f4-b771-da2fff3f185f" + }, + complement: { + payroll: { ... } + } +} +``` + +--- + +## Payroll Types Reference + +### 13 Standard Payroll Types + +| # | Name | payroll_type_code | Key Characteristics | +|---|------|-------------------|---------------------| +| 1 | Ordinaria | O | Regular salary payment | +| 2 | Asimilados | O | Similar to salary (honorarios asimilados) | +| 3 | Bonos y Fondo de Ahorro | O | Bonuses and savings fund | +| 4 | Horas Extra | O | Overtime payment | +| 5 | Incapacidades | O | Disability/sick leave | +| 6 | SNCF | O | Federal government (SNCF) | +| 7 | Extraordinaria | E | Extraordinary payment | +| 8 | Separacion e Indemnizacion | E | Severance and indemnization | +| 9 | Jubilacion, Pension, Retiro | E | Retirement/pension | +| 10 | Sin Deducciones | O | Without deductions | +| 11 | Subsidio Causado | O | Employment subsidy adjustment | +| 12 | Viaticos | O | Travel expenses | +| 13 | Basica | O | Basic payroll | + +### Common Invoice Fields for All Payroll Types + +``` +version_code: "4.0" +payment_method_code: "PUE" +currency_code: "MXN" +type_code: "N" +expedition_zip_code: +export_code: "01" +``` + +### SAT Earning Type Codes (TipoPercepcion) + +| Code | Description | Common Use | +|------|-------------|------------| +| 001 | Sueldos, Salarios Rayas y Jornales | Regular salary | +| 002 | Gratificación Anual (Aguinaldo) | Christmas bonus | +| 003 | Participación de los Trabajadores en las Utilidades PTU | Profit sharing | +| 019 | Horas extra | Overtime | +| 022 | Prima vacacional | Vacation bonus | +| 023 | Pagos por separación | Severance pay | +| 025 | Indemnizaciones | Indemnization | +| 028 | Comisiones | Commissions | +| 029 | Vales de despensa | Food vouchers | +| 039 | Jubilaciones, pensiones o haberes de retiro | Retirement | +| 044 | Jubilaciones, pensiones o haberes de retiro parcial | Partial retirement | +| 045 | Ingresos en acciones | Stock income | +| 046 | Ingresos asimilados a salarios | Income similar to salary | +| 047 | Alimentación | Food | +| 050 | Viáticos | Travel expenses | + +### SAT Deduction Type Codes (TipoDeduccion) + +| Code | Description | Common Use | +|------|-------------|------------| +| 001 | Seguridad social | Social security | +| 002 | ISR | Income tax | +| 003 | Aportaciones a retiro | Retirement contributions | +| 004 | Otros | Other deductions | +| 006 | Descuento por incapacidad | Disability discount | +| 010 | Pensión alimenticia | Alimony | +| 020 | Fondo de ahorro | Savings fund | +| 081 | Ajuste en viáticos | Travel expense adjustment | +| 107 | Ajuste al Subsidio Causado | Subsidy adjustment | + +### SAT Other Payment Type Codes (TipoOtroPago) + +| Code | Description | +|------|-------------| +| 001 | Reintegro de ISR pagado en exceso | +| 002 | Subsidio para el empleo | +| 003 | Viáticos | +| 004 | Aplicación de saldo a favor por compensación anual | +| 007 | ISR ajustado por subsidio | + +--- + +## API Endpoints + +### Employee Endpoints + +``` +GET /api/{version}/people/{personId}/employee +POST /api/{version}/people/{personId}/employee +PUT /api/{version}/people/{personId}/employee +DELETE /api/{version}/people/{personId}/employee +``` + +### Employer Endpoints + +``` +GET /api/{version}/people/{personId}/employer +POST /api/{version}/people/{personId}/employer +PUT /api/{version}/people/{personId}/employer +DELETE /api/{version}/people/{personId}/employer +``` + +### Invoice Endpoints + +Payroll invoices use the standard invoice endpoint: + +``` +POST /api/{version}/invoices +``` + +With `type_code: "N"` for payroll invoices. + +### Stamp Endpoints + +``` +GET /api/{version}/stamps?pageNumber={n}&pageSize={s} +GET /api/{version}/stamps/{transactionId} +POST /api/{version}/stamps +``` + +--- + +## Field Mappings (JSON Aliases) + +All models must serialize using camelCase JSON aliases when communicating with the API. + +**Serialization rules:** +- Use camelCase for JSON property names +- Exclude null/None values from JSON +- Decimal values should serialize as strings +- Dates should serialize as ISO 8601 strings + +--- + +## Example Implementations + +### Example 1: Create Payroll Invoice (By Values) + +``` +// Pseudocode - adapt to target language + +invoice = Invoice( + version_code: "4.0", + series: "F", + date: "2026-01-25T10:00:00", + payment_method_code: "PUE", + currency_code: "MXN", + type_code: "N", + expedition_zip_code: "20000", + export_code: "01", + + issuer: InvoiceIssuer( + tin: "EKU9003173C9", + legal_name: "ESCUELA KEMPER URGATE", + tax_regime_code: "601", + employer_data: InvoiceIssuerEmployerData( + employer_registration: "B5510768108", + origin_employer_tin: "URE180429TM6" + ) + ), + + recipient: InvoiceRecipient( + tin: "XOJI740919U48", + legal_name: "INGRID XODAR JIMENEZ", + zip_code: "76028", + tax_regime_code: "605", + cfdi_use_code: "CN01", + employee_data: InvoiceRecipientEmployeeData( + curp: "XOJI850618MJCDNG09", + social_security_number: "000000", + labor_relation_start_date: "2015-01-01", + seniority: "P437W", + sat_contract_type_id: "01", + sat_workday_type_id: "01", + sat_tax_regime_type_id: "02", + employee_number: "120", + department: "Desarrollo", + position: "Ingeniero de Software", + sat_job_risk_id: "1", + sat_payment_periodicity_id: "04", + sat_bank_id: "002", + bank_account: "1111111111", + base_salary_for_contributions: 490.22, + integrated_daily_salary: 146.47, + sat_payroll_state_id: "JAL" + ) + ), + + complement: InvoiceComplement( + payroll: PayrollComplement( + version: "1.2", + payroll_type_code: "O", + payment_date: "2023-05-24", + initial_payment_date: "2023-05-09", + final_payment_date: "2023-05-24", + days_paid: 15, + earnings: PayrollEarningsComplement( + earnings: [ + PayrollEarning( + earning_type_code: "001", + code: "00500", + concept: "Sueldos, Salarios Rayas y Jornales", + taxed_amount: 2808.80, + exempt_amount: 2191.20 + ) + ] + ), + deductions: [ + PayrollDeduction( + deduction_type_code: "001", + code: "00301", + concept: "Seguridad Social", + amount: 200.00 + ), + PayrollDeduction( + deduction_type_code: "002", + code: "00302", + concept: "ISR", + amount: 100.00 + ) + ] + ) + ) +) + +response = client.invoices.create(invoice) +``` + +### Example 2: Setup for By References Mode + +``` +// Step 1: Update person with CURP and tax regime +employee_person = Person( + id: "9367249f-f0ee-43f4-b771-da2fff3f185f", + curp: "XOJI850618MJCDNG09", + sat_tax_regime_id: "605", + sat_cfdi_use_id: "CN01" +) +client.people.update(employee_person) + +// Step 2: Create employee data +employee_data = EmployeeData( + employer_person_id: "2e7b988f-3a2a-4f67-86e9-3f931dd48581", + employee_person_id: "9367249f-f0ee-43f4-b771-da2fff3f185f", + social_security_number: "000000", + labor_relation_start_date: datetime(2015, 1, 1), + seniority: "P437W", + sat_contract_type_id: "01", + sat_workday_type_id: "01", + sat_tax_regime_type_id: "02", + employee_number: "120", + department: "Desarrollo", + position: "Ingeniero de Software", + sat_job_risk_id: "1", + sat_payment_periodicity_id: "04", + sat_bank_id: "002", + bank_account: "1111111111", + integrated_daily_salary: 146.47, + sat_payroll_state_id: "JAL" +) +client.people.employee.create(employee_data) + +// Step 3: Create employer data +employer_data = EmployerData( + person_id: "2e7b988f-3a2a-4f67-86e9-3f931dd48581", + employer_registration: "B5510768108", + origin_employer_tin: "URE180429TM6" +) +client.people.employer.create(employer_data) +``` + +### Example 3: Create Payroll Invoice (By References) + +``` +invoice = Invoice( + version_code: "4.0", + series: "F", + date: "2026-01-25T10:00:00", + payment_method_code: "PUE", + currency_code: "MXN", + type_code: "N", + expedition_zip_code: "20000", + export_code: "01", + + // Only IDs - data comes from pre-configured employee/employer + issuer: InvoiceIssuer( + id: "2e7b988f-3a2a-4f67-86e9-3f931dd48581" + ), + recipient: InvoiceRecipient( + id: "9367249f-f0ee-43f4-b771-da2fff3f185f" + ), + + complement: InvoiceComplement( + payroll: PayrollComplement( + // Same payroll data as by-values mode + version: "1.2", + payroll_type_code: "O", + payment_date: "2023-05-24", + initial_payment_date: "2023-05-09", + final_payment_date: "2023-05-24", + days_paid: 15, + earnings: PayrollEarningsComplement( + earnings: [ + PayrollEarning( + earning_type_code: "001", + code: "00500", + concept: "Sueldos, Salarios Rayas y Jornales", + taxed_amount: 2808.80, + exempt_amount: 2191.20 + ) + ] + ), + deductions: [ + PayrollDeduction( + deduction_type_code: "001", + code: "00301", + concept: "Seguridad Social", + amount: 200.00 + ), + PayrollDeduction( + deduction_type_code: "002", + code: "00302", + concept: "ISR", + amount: 100.00 + ) + ] + ) + ) +) + +response = client.invoices.create(invoice) +``` + +--- + +## Implementation Checklist + +### Models +- [x] Add `curp` field to Person model +- [x] Create EmployeeData model +- [x] Create EmployerData model +- [x] Create InvoiceIssuerEmployerData model +- [x] Create InvoiceRecipientEmployeeData model +- [x] Create PayrollComplement and all sub-models +- [x] Add employer_data to InvoiceIssuer model +- [x] Add employee_data to InvoiceRecipient model +- [x] Add payroll to InvoiceComplement model +- [x] Create StampTransaction model +- [x] Create StampTransactionParams model +- [x] Create UserLookupDto model + +### Services +- [x] Create EmployeeService with CRUD operations +- [x] Create EmployerService with CRUD operations +- [x] Add employee and employer properties to PeopleService +- [x] Create StampService with get_list, get_by_id, transfer_stamps, withdraw_stamps + +### Examples & Testing +- [ ] Create examples for all 13 payroll types (by values) +- [ ] Create examples for all 13 payroll types (by references) +- [ ] Create setup data methods for by-references mode +- [ ] Create stamp service examples +- [ ] Test all payroll types successfully +- [ ] Test stamp transactions successfully + +--- + +## Notes + +1. **Seniority format**: Use ISO 8601 duration format (e.g., "P437W" for 437 weeks) +2. **Tax regime for employees**: Always "605" (Sueldos y Salarios) +3. **CFDI use for payroll**: Always "CN01" (Nomina) +4. **Invoice type**: Always "N" for payroll invoices +5. **Payment method**: Typically "PUE" (Pago en Una sola Exhibicion) +6. **Payroll complement version**: Always "1.2" diff --git a/src/abstractions/fiscalapi-client.interface.ts b/src/abstractions/fiscalapi-client.interface.ts index d696fdb..7f4cdee 100644 --- a/src/abstractions/fiscalapi-client.interface.ts +++ b/src/abstractions/fiscalapi-client.interface.ts @@ -6,6 +6,7 @@ import { IDownloadRuleService } from './download-rule.service.inteface'; import { IInvoiceService } from './invoice-service.interface'; import { IPersonService } from './person-service.interface'; import { IProductService } from './product-service.interface'; +import { IStampService } from './stamp-service.interface'; import { ITaxFileService } from './tax-file-service.interface'; /** @@ -56,4 +57,9 @@ export interface IFiscalapiClient { * Servicio de solicitudes de descarga masiva */ downloadRequests: IDownloadRequestService; + + /** + * Servicio de timbres fiscales + */ + stamps: IStampService; } \ No newline at end of file diff --git a/src/abstractions/stamp-service.interface.ts b/src/abstractions/stamp-service.interface.ts new file mode 100644 index 0000000..5908599 --- /dev/null +++ b/src/abstractions/stamp-service.interface.ts @@ -0,0 +1,22 @@ +import { ApiResponse } from '../common/api-response'; +import { StampTransaction, StampTransactionParams } from '../models/stamp'; +import { IFiscalapiService } from './fiscalapi-service.interface'; + +/** + * Interfaz para el servicio de timbres fiscales + */ +export interface IStampService extends IFiscalapiService { + /** + * Transfiere timbres de una persona a otra + * @param {StampTransactionParams} request - Parámetros de la transferencia + * @returns {Promise>} Resultado de la operación + */ + transferStamps(request: StampTransactionParams): Promise>; + + /** + * Retira timbres de una persona + * @param {StampTransactionParams} request - Parámetros del retiro + * @returns {Promise>} Resultado de la operación + */ + withdrawStamps(request: StampTransactionParams): Promise>; +} diff --git a/src/index.ts b/src/index.ts index ef0b1ae..584fb6b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,6 +13,7 @@ export type { ITaxFileService } from './abstractions/tax-file-service.interface' export type { IDownloadCatalogService } from './abstractions/download-catalog.inteface'; export type { IDownloadRequestService } from './abstractions/download-request.service.interface'; export type { IDownloadRuleService } from './abstractions/download-rule.service.inteface'; +export type { IStampService } from './abstractions/stamp-service.interface'; // HTTP types export type { HttpMethod } from './http/fiscalapi-http-client.interface'; @@ -62,6 +63,17 @@ export type { XmlComplement } from './models/download'; +export type { + StampTransaction, + StampTransactionParams, + UserLookupDto +} from './models/stamp'; + +export { + StampTransactionType, + StampTransactionStatus +} from './models/stamp'; + // Common types export type { FiscalapiSettings } from './common/fiscalapi-settings'; diff --git a/src/models/stamp.ts b/src/models/stamp.ts new file mode 100644 index 0000000..6c8ca32 --- /dev/null +++ b/src/models/stamp.ts @@ -0,0 +1,79 @@ +// src/models/stamp.ts +import { BaseDto } from '../common/base-dto'; + +/** + * Tipo de transacción de timbres + */ +export enum StampTransactionType { + Purchase = 1, + Transfer = 2, + Consumption = 3, + AutoInvoice = 4, + Rollback = 5, +} + +/** + * Estado de transacción de timbres + */ +export enum StampTransactionStatus { + Completed = 1, + Cancelled = 2, + RolledBack = 3, +} + +/** + * DTO para información resumida de persona en transacciones de timbres + */ +export interface UserLookupDto extends BaseDto { + /** RFC de la persona (Tax Identification Number) */ + tin?: string; + + /** Razón social de la persona */ + legalName?: string; +} + +/** + * Representa una transacción de timbres fiscales + */ +export interface StampTransaction extends BaseDto { + /** Número consecutivo de la transacción */ + consecutive?: number; + + /** Persona origen de la transferencia */ + fromPerson?: UserLookupDto; + + /** Persona destino de la transferencia */ + toPerson?: UserLookupDto; + + /** Cantidad de timbres en la transacción */ + amount?: number; + + /** Tipo de transacción */ + transactionType?: StampTransactionType; + + /** Estado de la transacción */ + transactionStatus?: StampTransactionStatus; + + /** ID de referencia de la transacción */ + referenceId?: string; + + /** Comentarios de la transacción */ + comments?: string; +} + +/** + * Parámetros para realizar una transferencia o retiro de timbres + */ +export interface StampTransactionParams { + /** ID de la persona origen */ + fromPersonId: string; + + /** ID de la persona destino */ + toPersonId: string; + + /** Cantidad de timbres a transferir */ + amount: number; + + /** Comentarios opcionales */ + comments?: string; +} diff --git a/src/services/fiscalapi-client.ts b/src/services/fiscalapi-client.ts index e661a8c..ec65c1a 100644 --- a/src/services/fiscalapi-client.ts +++ b/src/services/fiscalapi-client.ts @@ -8,19 +8,21 @@ import { IApiKeyService } from '../abstractions/api-key-service.interface'; import { ICatalogService } from '../abstractions/catalog-service.interface'; import { ITaxFileService } from '../abstractions/tax-file-service.interface'; import { IDownloadCatalogService } from '../abstractions/download-catalog.inteface'; +import { IDownloadRuleService } from '../abstractions/download-rule.service.inteface'; +import { IDownloadRequestService } from '../abstractions/download-request.service.interface'; +import { IStampService } from '../abstractions/stamp-service.interface'; import { FiscalapiSettings } from '../common/fiscalapi-settings'; import { FiscalapiHttpClientFactory } from '../http/fiscalapi-http-client-factory'; import { ApiKeyService } from './api-key-service'; import { CatalogService } from './catalog-service'; import { DownloadCatalogService } from './download-catalog.service'; +import { DownloadRuleService } from './download-rule.service'; +import { DownloadRequestService } from './download-request.service'; import { InvoiceService } from './invoice-service'; import { PersonService } from './person-service'; import { ProductService } from './product-service'; +import { StampService } from './stamp-service'; import { TaxFileService } from './tax-file-service'; -import { DownloadRuleService } from './download-rule.service'; -import { IDownloadRuleService } from '../abstractions/download-rule.service.inteface'; -import { DownloadRequestService } from './download-request.service'; -import { IDownloadRequestService } from '../abstractions/download-request.service.interface'; /** * Cliente principal para FiscalAPI @@ -71,6 +73,11 @@ export class FiscalapiClient implements IFiscalapiClient { */ readonly downloadRequests: IDownloadRequestService; + /** + * Servicio de timbres fiscales + */ + readonly stamps: IStampService; + /** * Crea una nueva instancia del cliente de FiscalAPI * @param {FiscalapiSettings} settings - Configuración @@ -91,6 +98,7 @@ export class FiscalapiClient implements IFiscalapiClient { this.downloadCatalogs = new DownloadCatalogService(httpClient, apiVersion); this.downloadRules = new DownloadRuleService(httpClient, apiVersion); this.downloadRequests = new DownloadRequestService(httpClient, apiVersion); + this.stamps = new StampService(httpClient, apiVersion); } /** diff --git a/src/services/stamp-service.ts b/src/services/stamp-service.ts new file mode 100644 index 0000000..f7d2ff7 --- /dev/null +++ b/src/services/stamp-service.ts @@ -0,0 +1,51 @@ +import { IFiscalapiHttpClient } from '../http/fiscalapi-http-client.interface'; +import { ApiResponse } from '../common/api-response'; +import { BaseFiscalapiService } from './base-fiscalapi-service'; +import { IStampService } from '../abstractions/stamp-service.interface'; +import { StampTransaction, StampTransactionParams } from '../models/stamp'; + +/** + * Implementación del servicio de timbres fiscales + */ +export class StampService extends BaseFiscalapiService implements IStampService { + /** + * Crea una nueva instancia del servicio de timbres + * @param {IFiscalapiHttpClient} httpClient - Cliente HTTP + * @param {string} apiVersion - Versión de la API + */ + constructor(httpClient: IFiscalapiHttpClient, apiVersion: string) { + super(httpClient, 'stamps', apiVersion); + } + + /** + * Transfiere timbres de una persona a otra + * @param {StampTransactionParams} request - Parámetros de la transferencia + * @returns {Promise>} Resultado de la operación + */ + async transferStamps(request: StampTransactionParams): Promise> { + if (!request) { + throw new Error('request cannot be null'); + } + + return await this.executeRequest({ + data: request, + method: 'POST', + }); + } + + /** + * Retira timbres de una persona + * @param {StampTransactionParams} request - Parámetros del retiro + * @returns {Promise>} Resultado de la operación + */ + async withdrawStamps(request: StampTransactionParams): Promise> { + if (!request) { + throw new Error('request cannot be null'); + } + + return await this.executeRequest({ + data: request, + method: 'POST', + }); + } +} From 67ed65772819bec125fdd8d1b84fbd273124f588 Mon Sep 17 00:00:00 2001 From: JesusMendoza Date: Mon, 26 Jan 2026 21:55:52 -0600 Subject: [PATCH 03/15] employee and employer data services added --- examples/ejemplo-timbres.ts | 1 + payroll-invoice-requrements.md | 297 +++++++++++++++++- .../employee-service.interface.ts | 12 + .../employer-service.interface.ts | 12 + src/abstractions/person-service.interface.ts | 9 +- src/index.ts | 4 + src/models/employee-data.ts | 61 ++++ src/models/employer-data.ts | 30 ++ src/models/invoice.ts | 2 +- src/services/employee-service.ts | 43 +++ src/services/employer-service.ts | 43 +++ src/services/person-service.ts | 11 +- 12 files changed, 508 insertions(+), 17 deletions(-) create mode 100644 src/abstractions/employee-service.interface.ts create mode 100644 src/abstractions/employer-service.interface.ts create mode 100644 src/models/employee-data.ts create mode 100644 src/models/employer-data.ts create mode 100644 src/services/employee-service.ts create mode 100644 src/services/employer-service.ts diff --git a/examples/ejemplo-timbres.ts b/examples/ejemplo-timbres.ts index d21f4e4..690970a 100644 --- a/examples/ejemplo-timbres.ts +++ b/examples/ejemplo-timbres.ts @@ -1,6 +1,7 @@ import { FiscalapiClient, FiscalapiSettings } from '../src/index'; async function main(): Promise { + const settings: FiscalapiSettings = { apiUrl: 'https://test.fisalapi.com', apiKey: '', diff --git a/payroll-invoice-requrements.md b/payroll-invoice-requrements.md index f0d6a3e..9f8b451 100644 --- a/payroll-invoice-requrements.md +++ b/payroll-invoice-requrements.md @@ -249,27 +249,27 @@ add payroll invoice support to the existing code base following best practices. Implememt following changes as follows: -interface IEmployeeFacade { - getById(id: string): Promise> - create(requestModel: CreateEmployeeRequest): Promise> - update(requestModel: UpdateEmployeeRequest): Promise> +interface IEmployeeService { + getById(id: string): Promise> + create(requestModel: CreateEmployeeRequest): Promise> + update(requestModel: UpdateEmployeeRequest): Promise> delete(personId: string): Promise> } -interface IEmployerFacade { - getById(id: string): Promise> - create(requestModel: CreateEmployerRequest): Promise> - update(requestModel: UpdateEmployerRequest): Promise> +interface IEmployerService { + getById(id: string): Promise> + create(requestModel: CreateEmployerRequest): Promise> + update(requestModel: UpdateEmployerRequest): Promise> delete(personId: string): Promise> } interface PersonService { - employee: IEmployeeFacade - employer: IEmployerFacade + employee: IEmployeeService + employer: IEmployerService } interface FiscalapiClient { - persons: PersonsFacade + persons: PersonsService } @@ -279,6 +279,30 @@ curl --location 'http://localhost:5001/api/v4/people/bef56254-0892-4558-95c3-f9c --header 'X-TIME-ZONE: America/Mexico_City' \ --header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' +response +{ + "data": { + "personId": "bef56254-0892-4558-95c3-f9c8729e4b0e", + "employerRegistration": "A1230768108", + "originEmployerTin": "ARE180429TM6", + "satFundSource": { + "id": "IP", + "description": "Ingresos propios.", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": null + }, + "ownResourceAmount": 1500, + "id": "23f0b555-68bc-48fd-bb90-deb36ed25ef6", + "createdAt": "2025-09-18T20:17:44.175", + "updatedAt": "2025-09-18T20:17:48.489" + }, + "succeeded": true, + "message": "", + "details": "", + "httpStatusCode": 200 +} + + ### Crear datos de empleador curl --location 'http://localhost:5001/api/v4/people/bef56254-0892-4558-95c3-f9c8729e4b0e/employer' \ --header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ @@ -294,6 +318,24 @@ curl --location 'http://localhost:5001/api/v4/people/bef56254-0892-4558-95c3-f9c } ' +Response +{ + "data": { + "personId": "bef56254-0892-4558-95c3-f9c8729e4b0e", + "employerRegistration": "B5510768108", + "originEmployerTin": "URE180429TM6", + "satFundSource": null, + "ownResourceAmount": null, + "id": "23f0b555-68bc-48fd-bb90-deb36ed25ef6", + "createdAt": "2025-09-18T20:17:44.175", + "updatedAt": "2025-09-18T20:17:44.175" + }, + "succeeded": true, + "message": "", + "details": "", + "httpStatusCode": 200 +} + ### Actualizar datos de empleador curl --location --request PUT 'http://localhost:5001/api/v4/people/bef56254-0892-4558-95c3-f9c8729e4b0e/employer' \ @@ -309,6 +351,24 @@ curl --location --request PUT 'http://localhost:5001/api/v4/people/bef56254-0892 "ownResourceAmount": null }' +Response +{ + "data": { + "personId": "bef56254-0892-4558-95c3-f9c8729e4b0e", + "employerRegistration": "A1230768108", + "originEmployerTin": "ARE180429TM6", + "satFundSource": null, + "ownResourceAmount": null, + "id": "23f0b555-68bc-48fd-bb90-deb36ed25ef6", + "createdAt": "2025-09-18T20:17:44.175", + "updatedAt": "2025-09-18T20:19:20.569" + }, + "succeeded": true, + "message": "", + "details": "", + "httpStatusCode": 200 +} + ### Eliminar datos de empleador curl --location --request DELETE 'http://localhost:5001/api/v4/people/bef56254-0892-4558-95c3-f9c8729e4b0e/employer' \ @@ -317,6 +377,15 @@ curl --location --request DELETE 'http://localhost:5001/api/v4/people/bef56254-0 --header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ --data '' +Response +{ + "data": true, + "succeeded": true, + "message": "", + "details": "", + "httpStatusCode": 200 +} + ### Obtener datos de empleado curl --location 'http://localhost:5001/api/v4/people/54fc14ae-c88f-4afc-996b-0574d63341e2/employee' \ @@ -325,6 +394,62 @@ curl --location 'http://localhost:5001/api/v4/people/54fc14ae-c88f-4afc-996b-057 --header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ --data '' +Response +{ + "data": { + "employerPersonId": "bef56254-0892-4558-95c3-f9c8729e4b0e", + "employeePersonId": "54fc14ae-c88f-4afc-996b-0574d63341e2", + "employeeNumber": "123456789", + "socialSecurityNumber": "0101010101", + "laborRelationStartDate": "2020-01-12T00:00:00.000", + "satContractType": { + "id": "01", + "description": "Contrato de trabajo por tiempo indeterminado", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": null + }, + "satTaxRegimeType": { + "id": "02", + "description": "Sueldos (Incluye ingresos art. 94 LISR)", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": null + }, + "satWorkdayType": null, + "satJobRisk": { + "id": "1", + "description": "Clase I", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": null + }, + "satPaymentPeriodicity": { + "id": "04", + "description": "Quincenal", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": null + }, + "satBank": null, + "satPayrollState": { + "id": "JAL", + "description": "Jalisco", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": null + }, + "satUnionizedStatus": null, + "department": null, + "position": null, + "seniority": "P1Y5M15D", + "bankAccount": null, + "baseSalaryForContributions": 520, + "integratedDailySalary": 186, + "subcontractorRfc": null, + "timePercentage": 0 + }, + "succeeded": true, + "message": "", + "details": "", + "httpStatusCode": 200 +} + ### Crear datos de empleado curl --location 'http://localhost:5001/api/v4/people/54fc14ae-c88f-4afc-996b-0574d63341e2/employee' \ --header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ @@ -356,6 +481,76 @@ curl --location 'http://localhost:5001/api/v4/people/54fc14ae-c88f-4afc-996b-057 "timePercentage": null }' +Response: +{ + "data": { + "employerPersonId": "bef56254-0892-4558-95c3-f9c8729e4b0e", + "employeePersonId": "54fc14ae-c88f-4afc-996b-0574d63341e2", + "employeeNumber": "12345", + "socialSecurityNumber": "123456789012345", + "laborRelationStartDate": "2023-01-15T00:00:00.000", + "satContractType": { + "id": "01", + "description": "Contrato de trabajo por tiempo indeterminado", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": null + }, + "satTaxRegimeType": { + "id": "02", + "description": "Sueldos (Incluye ingresos señalados en la fraccion I del articulo 94 de LISR)", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": null + }, + "satWorkdayType": { + "id": "01", + "description": "Diurna", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": null + }, + "satJobRisk": { + "id": "1", + "description": "Clase I", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": null + }, + "satPaymentPeriodicity": { + "id": "04", + "description": "Quincenal", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": null + }, + "satBank": { + "id": "002", + "description": "BANAMEX", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": null + }, + "satPayrollState": { + "id": "JAL", + "description": "Jalisco", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": null + }, + "satUnionizedStatus": { + "id": "No", + "description": "NO", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": null + }, + "department": "Recursos Humanos", + "position": "Analista de Nóminas", + "bankAccount": "12345678901234567890", + "baseSalaryForContributions": 490.22, + "integratedDailySalary": 146.47, + "subcontractorRfc": null, + "timePercentage": 0 + }, + "succeeded": true, + "message": "", + "details": "", + "httpStatusCode": 200 +} + ### Actualizar datos de empleado curl --location --request PUT 'http://localhost:5001/api/v4/people/54fc14ae-c88f-4afc-996b-0574d63341e2/employee' \ --header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ @@ -387,6 +582,77 @@ curl --location --request PUT 'http://localhost:5001/api/v4/people/54fc14ae-c88f "timePercentage": null }' +Response: +{ + "data": { + "employerPersonId": "bef56254-0892-4558-95c3-f9c8729e4b0e", + "employeePersonId": "54fc14ae-c88f-4afc-996b-0574d63341e2", + "employeeNumber": "12345ABC", + "socialSecurityNumber": "123456789012345", + "laborRelationStartDate": "2022-01-15T00:00:00.000", + "satContractType": { + "id": "02", + "description": "Contrato de trabajo para obra determinada", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": null + }, + "satTaxRegimeType": { + "id": "02", + "description": "Sueldos (Incluye ingresos señalados en la fraccion I del articulo 94 de LISR)", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": null + }, + "satWorkdayType": { + "id": "01", + "description": "Diurna", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": null + }, + "satJobRisk": { + "id": "2", + "description": "Clase II", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": null + }, + "satPaymentPeriodicity": { + "id": "02", + "description": "Semanal", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": null + }, + "satBank": { + "id": "012", + "description": "BBVA BANCOMER", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": null + }, + "satPayrollState": { + "id": "AGU", + "description": "Aguascalientes", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": null + }, + "satUnionizedStatus": { + "id": "Sí", + "description": "SI", + "createdAt": "2024-08-10T15:46:30.373", + "updatedAt": null + }, + "department": "Sistemas", + "position": "Programador Jr.", + "bankAccount": "12345678901234567890", + "baseSalaryForContributions": 290.22, + "integratedDailySalary": 46.47, + "subcontractorRfc": null, + "timePercentage": 0 + }, + "succeeded": true, + "message": "", + "details": "", + "httpStatusCode": 200 +} + + ### Eliminar datos de empleado curl --location --request DELETE 'http://localhost:5001/api/v4/people/54fc14ae-c88f-4afc-996b-0574d63341e2/employee' \ --header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ @@ -399,7 +665,14 @@ curl --location --request DELETE 'http://localhost:5001/api/v4/people/54fc14ae-c "password": "UserPass123!" }' - +Response: +{ + "data": true, + "succeeded": true, + "message": "", + "details": "", + "httpStatusCode": 200 +} --- You are a senior Node.js engineer specializing in TypeScript, module systems, and mexican payroll cdfi invoicing. Your task is to diff --git a/src/abstractions/employee-service.interface.ts b/src/abstractions/employee-service.interface.ts new file mode 100644 index 0000000..ec98bb1 --- /dev/null +++ b/src/abstractions/employee-service.interface.ts @@ -0,0 +1,12 @@ +import { ApiResponse } from '../common/api-response'; +import { EmployeeData, CreateEmployeeRequest, UpdateEmployeeRequest } from '../models/employee-data'; + +/** + * Interfaz del servicio de datos de empleado + */ +export interface IEmployeeService { + getById(id: string): Promise>; + create(requestModel: CreateEmployeeRequest): Promise>; + update(requestModel: UpdateEmployeeRequest): Promise>; + delete(personId: string): Promise>; +} diff --git a/src/abstractions/employer-service.interface.ts b/src/abstractions/employer-service.interface.ts new file mode 100644 index 0000000..3a9aeb3 --- /dev/null +++ b/src/abstractions/employer-service.interface.ts @@ -0,0 +1,12 @@ +import { ApiResponse } from '../common/api-response'; +import { EmployerData, CreateEmployerRequest, UpdateEmployerRequest } from '../models/employer-data'; + +/** + * Interfaz del servicio de datos de empleador + */ +export interface IEmployerService { + getById(id: string): Promise>; + create(requestModel: CreateEmployerRequest): Promise>; + update(requestModel: UpdateEmployerRequest): Promise>; + delete(personId: string): Promise>; +} diff --git a/src/abstractions/person-service.interface.ts b/src/abstractions/person-service.interface.ts index 4076fe1..ee73dea 100644 --- a/src/abstractions/person-service.interface.ts +++ b/src/abstractions/person-service.interface.ts @@ -1,10 +1,13 @@ - + import { IFiscalapiService } from './fiscalapi-service.interface'; +import { IEmployeeService } from './employee-service.interface'; +import { IEmployerService } from './employer-service.interface'; import { Person } from '../models/person'; /** * Interfaz del servicio de personas */ export interface IPersonService extends IFiscalapiService { - -} \ No newline at end of file + readonly employee: IEmployeeService; + readonly employer: IEmployerService; +} diff --git a/src/index.ts b/src/index.ts index 584fb6b..13752a0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,6 +14,8 @@ export type { IDownloadCatalogService } from './abstractions/download-catalog.in export type { IDownloadRequestService } from './abstractions/download-request.service.interface'; export type { IDownloadRuleService } from './abstractions/download-rule.service.inteface'; export type { IStampService } from './abstractions/stamp-service.interface'; +export type { IEmployeeService } from './abstractions/employee-service.interface'; +export type { IEmployerService } from './abstractions/employer-service.interface'; // HTTP types export type { HttpMethod } from './http/fiscalapi-http-client.interface'; @@ -21,6 +23,8 @@ export type { HttpMethod } from './http/fiscalapi-http-client.interface'; // Models types export type { ApiKey } from './models/api-key'; export type { Person } from './models/person'; +export type { EmployeeData, CreateEmployeeRequest, UpdateEmployeeRequest } from './models/employee-data'; +export type { EmployerData, CreateEmployerRequest, UpdateEmployerRequest } from './models/employer-data'; export type { Product, ProductTax } from './models/product'; export type { TaxFile } from './models/tax-file'; export type { diff --git a/src/models/employee-data.ts b/src/models/employee-data.ts new file mode 100644 index 0000000..c6cb2fb --- /dev/null +++ b/src/models/employee-data.ts @@ -0,0 +1,61 @@ +import { BaseDto } from '../common/base-dto'; +import { CatalogDto } from '../common/catalog-dto'; + +/** + * Datos de empleado (response model) + */ +export interface EmployeeData extends BaseDto { + employerPersonId?: string; + employeePersonId?: string; + employeeNumber?: string; + socialSecurityNumber?: string; + laborRelationStartDate?: string; + satContractType?: CatalogDto; + satTaxRegimeType?: CatalogDto; + satWorkdayType?: CatalogDto; + satJobRisk?: CatalogDto; + satPaymentPeriodicity?: CatalogDto; + satBank?: CatalogDto; + satPayrollState?: CatalogDto; + satUnionizedStatus?: CatalogDto; + department?: string; + position?: string; + seniority?: string; + bankAccount?: string; + baseSalaryForContributions?: number; + integratedDailySalary?: number; + subcontractorRfc?: string; + timePercentage?: number; +} + +/** + * Request para crear datos de empleado + */ +export interface CreateEmployeeRequest { + employerPersonId: string; + employeePersonId: string; + employeeNumber?: string; + satContractTypeId?: string; + satTaxRegimeTypeId?: string; + satPaymentPeriodicityId?: string; + satPayrollStateId?: string; + socialSecurityNumber?: string; + laborRelationStartDate?: string; + satWorkdayTypeId?: string; + satJobRiskId?: string; + satBankId?: string; + satUnionizedStatusId?: string; + department?: string; + position?: string; + seniority?: string; + bankAccount?: string; + baseSalaryForContributions?: number; + integratedDailySalary?: number; + subcontractorRfc?: string; + timePercentage?: number; +} + +/** + * Request para actualizar datos de empleado + */ +export interface UpdateEmployeeRequest extends CreateEmployeeRequest {} diff --git a/src/models/employer-data.ts b/src/models/employer-data.ts new file mode 100644 index 0000000..f4a8f8f --- /dev/null +++ b/src/models/employer-data.ts @@ -0,0 +1,30 @@ +import { BaseDto } from '../common/base-dto'; +import { CatalogDto } from '../common/catalog-dto'; + +/** + * Datos de empleador (response model) + * Extiende BaseDto porque la respuesta incluye id/createdAt/updatedAt + */ +export interface EmployerData extends BaseDto { + personId?: string; + employerRegistration?: string; + originEmployerTin?: string; + satFundSource?: CatalogDto; + ownResourceAmount?: number; +} + +/** + * Request para crear datos de empleador + */ +export interface CreateEmployerRequest { + personId: string; + employerRegistration?: string; + originEmployerTin?: string; + satFundSourceId?: string; + ownResourceAmount?: number; +} + +/** + * Request para actualizar datos de empleador + */ +export interface UpdateEmployerRequest extends CreateEmployerRequest {} diff --git a/src/models/invoice.ts b/src/models/invoice.ts index 458e320..878e466 100644 --- a/src/models/invoice.ts +++ b/src/models/invoice.ts @@ -8,7 +8,7 @@ import { BaseDto } from '../common/base-dto'; * Contiene toda la información de una factura, como datos del emisor, receptor, * productos/servicios, importes, método de pago, el tipo de factura, entre otros. */ -export interface Invoice { +export interface Invoice extends BaseDto { /** Código de la versión de la facura. Default: "4.0" */ versionCode?: string; diff --git a/src/services/employee-service.ts b/src/services/employee-service.ts new file mode 100644 index 0000000..b21e5a4 --- /dev/null +++ b/src/services/employee-service.ts @@ -0,0 +1,43 @@ +import { ApiResponse } from '../common/api-response'; +import { IFiscalapiHttpClient } from '../http/fiscalapi-http-client.interface'; +import { IEmployeeService } from '../abstractions/employee-service.interface'; +import { EmployeeData, CreateEmployeeRequest, UpdateEmployeeRequest } from '../models/employee-data'; + +/** + * Implementación del servicio de datos de empleado + */ +export class EmployeeService implements IEmployeeService { + private readonly httpClient: IFiscalapiHttpClient; + private readonly apiVersion: string; + + constructor(httpClient: IFiscalapiHttpClient, apiVersion: string) { + this.httpClient = httpClient; + this.apiVersion = apiVersion; + } + + private buildEndpoint(personId: string): string { + return `api/${this.apiVersion}/people/${personId}/employee`; + } + + async getById(id: string): Promise> { + return this.httpClient.getByIdAsync(this.buildEndpoint(id)); + } + + async create(requestModel: CreateEmployeeRequest): Promise> { + return this.httpClient.postAsync( + this.buildEndpoint(requestModel.employeePersonId), + requestModel + ); + } + + async update(requestModel: UpdateEmployeeRequest): Promise> { + return this.httpClient.putAsync( + this.buildEndpoint(requestModel.employeePersonId), + requestModel + ); + } + + async delete(personId: string): Promise> { + return this.httpClient.deleteAsync(this.buildEndpoint(personId)); + } +} diff --git a/src/services/employer-service.ts b/src/services/employer-service.ts new file mode 100644 index 0000000..28a57b3 --- /dev/null +++ b/src/services/employer-service.ts @@ -0,0 +1,43 @@ +import { ApiResponse } from '../common/api-response'; +import { IFiscalapiHttpClient } from '../http/fiscalapi-http-client.interface'; +import { IEmployerService } from '../abstractions/employer-service.interface'; +import { EmployerData, CreateEmployerRequest, UpdateEmployerRequest } from '../models/employer-data'; + +/** + * Implementación del servicio de datos de empleador + */ +export class EmployerService implements IEmployerService { + private readonly httpClient: IFiscalapiHttpClient; + private readonly apiVersion: string; + + constructor(httpClient: IFiscalapiHttpClient, apiVersion: string) { + this.httpClient = httpClient; + this.apiVersion = apiVersion; + } + + private buildEndpoint(personId: string): string { + return `api/${this.apiVersion}/people/${personId}/employer`; + } + + async getById(id: string): Promise> { + return this.httpClient.getByIdAsync(this.buildEndpoint(id)); + } + + async create(requestModel: CreateEmployerRequest): Promise> { + return this.httpClient.postAsync( + this.buildEndpoint(requestModel.personId), + requestModel + ); + } + + async update(requestModel: UpdateEmployerRequest): Promise> { + return this.httpClient.putAsync( + this.buildEndpoint(requestModel.personId), + requestModel + ); + } + + async delete(personId: string): Promise> { + return this.httpClient.deleteAsync(this.buildEndpoint(personId)); + } +} diff --git a/src/services/person-service.ts b/src/services/person-service.ts index d438075..c0ea37e 100644 --- a/src/services/person-service.ts +++ b/src/services/person-service.ts @@ -2,12 +2,19 @@ import { Person } from '../models/person'; import { IFiscalapiHttpClient } from '../http/fiscalapi-http-client.interface'; import { BaseFiscalapiService } from './base-fiscalapi-service'; -import { IPersonService } from '..'; +import { IPersonService } from '../abstractions/person-service.interface'; +import { IEmployeeService } from '../abstractions/employee-service.interface'; +import { IEmployerService } from '../abstractions/employer-service.interface'; +import { EmployeeService } from './employee-service'; +import { EmployerService } from './employer-service'; /** * Implementación del servicio de personas */ export class PersonService extends BaseFiscalapiService implements IPersonService { + readonly employee: IEmployeeService; + readonly employer: IEmployerService; + /** * Crea una nueva instancia del servicio de personas * @param {IFiscalapiHttpClient} httpClient - Cliente HTTP @@ -15,5 +22,7 @@ export class PersonService extends BaseFiscalapiService implements IPers */ constructor(httpClient: IFiscalapiHttpClient, apiVersion: string) { super(httpClient, 'people', apiVersion); + this.employee = new EmployeeService(httpClient, apiVersion); + this.employer = new EmployerService(httpClient, apiVersion); } } From 7ebb40ac72d5a62f981abf9369e3390a89df9114 Mon Sep 17 00:00:00 2001 From: JesusMendoza Date: Mon, 26 Jan 2026 22:08:22 -0600 Subject: [PATCH 04/15] employee and employer data samples added --- examples/ejemplo-datos-empleado-empleador.ts | 59 ++++++++++++++++++++ payroll-invoice-requrements.md | 2 +- 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 examples/ejemplo-datos-empleado-empleador.ts diff --git a/examples/ejemplo-datos-empleado-empleador.ts b/examples/ejemplo-datos-empleado-empleador.ts new file mode 100644 index 0000000..f253d45 --- /dev/null +++ b/examples/ejemplo-datos-empleado-empleador.ts @@ -0,0 +1,59 @@ +import { + FiscalapiClient, + FiscalapiSettings, + CreateEmployerRequest, + CreateEmployeeRequest +} from '../src'; + +async function main(): Promise { + + const settings: FiscalapiSettings = { + apiUrl: 'https://test.fisalapi.com', + apiKey: '', + tenant: '', + }; + + const client = FiscalapiClient.create(settings); + + const escuelaKemperUrgateId = ''; + const karlaFuenteNolascoId = ''; + + // Crear datos de empleador + const employerRequest: CreateEmployerRequest = { + personId: escuelaKemperUrgateId, + employerRegistration: 'B5510768108', + }; + const employerResult = await client.persons.employer.create(employerRequest); + console.log('Empleador:', JSON.stringify(employerResult, null, 2)); + + // Crear datos de empleado + const employeeRequest: CreateEmployeeRequest = { + employerPersonId: escuelaKemperUrgateId, + employeePersonId: karlaFuenteNolascoId, + employeeNumber: '123456789', + socialSecurityNumber: '04078873454', + laborRelationStartDate: '2024-08-18', + satContractTypeId: '01', + satTaxRegimeTypeId: '02', + satJobRiskId: '1', + satPaymentPeriodicityId: '05', + satBankId: '012', + satPayrollStateId: 'JAL', + department: 'GenAI', + position: 'Sr Software Engineer', + seniority: 'P54W', + baseSalaryForContributions: 2828.50, + integratedDailySalary: 0.00, + }; + const employeeResult = await client.persons.employee.create(employeeRequest); + console.log('Empleado:', JSON.stringify(employeeResult, null, 2)); + + // Consultar datos + const employer = await client.persons.employer.getById(escuelaKemperUrgateId); + console.log('Consulta empleador:', JSON.stringify(employer, null, 2)); + + const employee = await client.persons.employee.getById(karlaFuenteNolascoId); + console.log('Consulta empleado:', JSON.stringify(employee, null, 2)); +} + +main().catch(console.error); diff --git a/payroll-invoice-requrements.md b/payroll-invoice-requrements.md index 9f8b451..174b4c9 100644 --- a/payroll-invoice-requrements.md +++ b/payroll-invoice-requrements.md @@ -10,10 +10,10 @@ OSCAR_KALA_HAAK = "5fd9f48c-a6a2-474f-944b-88a01751d432" apiUrl: http://localhost:5001 -productId: 69d0aec0-5dbb-4db0-a908-61fe5c8e7d75 apikey: sk_development_b470ea83_3c0f_4209_b933_85223b960d91 tenant: 102e5f13-e114-41dd-bea7-507fce177281 +productId: 69d0aec0-5dbb-4db0-a908-61fe5c8e7d75 ---- From e361cdbd6dd590015e4ae6559dddf7dd3f27f20b Mon Sep 17 00:00:00 2001 From: JesusMendoza Date: Tue, 27 Jan 2026 12:23:12 -0600 Subject: [PATCH 05/15] 1. Fixed Filename Typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Renamed download-catalog.inteface.ts → download-catalog.interface.ts - Renamed download-rule.service.inteface.ts → download-rule.service.interface.ts - Updated all imports in 5 files to use the correct filenames 2. Fixed Code Style Inconsistencies in InvoiceService - Standardized object property spacing (path:endpoint → path: endpoint) - Fixed inconsistent indentation in getStatus() and create() methods 3. Fixed Method Naming Inconsistency in DownloadRequestService - Removed Async suffix from methods to match the pattern used in other services: - getXmlsAsync → getXmls - getMetadataItemsAsync → getMetadataItems - downloadPackageAsync → downloadPackage - downloadSatRequestAsync → downloadSatRequest - downloadSatResponseAsync → downloadSatResponse - searchAsync → searchByDate 4. Removed Dead Code - Deleted sdk-constants.ts which was unused and duplicated values from date-utils.ts 5. Fixed Security Issue - Fixed rejectUnauthorized: false in HTTP client factory to be conditional based on settings.debug 6. Fixed Minor Code Style Issues - Fixed var → const in download-rule.service.ts - Fixed inconsistent JSDoc comment indentation - Cleaned up extra blank lines and trailing whitespace - Fixed function indentation in date-utils.ts --- ...eface.ts => download-catalog.interface.ts} | 0 .../download-request.service.interface.ts | 26 +++++++------- ....ts => download-rule.service.interface.ts} | 0 .../fiscalapi-client.interface.ts | 4 +-- src/http/fiscalapi-http-client-factory.ts | 5 ++- src/index.ts | 4 +-- src/sdk-constants.ts | 25 ------------- src/services/download-catalog.service.ts | 7 +--- src/services/download-request.service.ts | 34 ++++++++---------- src/services/download-rule.service.ts | 10 +++--- src/services/fiscalapi-client.ts | 4 +-- src/services/invoice-service.ts | 36 +++++++++---------- src/utils/date-utils.ts | 6 ++-- 13 files changed, 61 insertions(+), 100 deletions(-) rename src/abstractions/{download-catalog.inteface.ts => download-catalog.interface.ts} (100%) rename src/abstractions/{download-rule.service.inteface.ts => download-rule.service.interface.ts} (100%) delete mode 100644 src/sdk-constants.ts diff --git a/src/abstractions/download-catalog.inteface.ts b/src/abstractions/download-catalog.interface.ts similarity index 100% rename from src/abstractions/download-catalog.inteface.ts rename to src/abstractions/download-catalog.interface.ts diff --git a/src/abstractions/download-request.service.interface.ts b/src/abstractions/download-request.service.interface.ts index 7a18266..d2d6f60 100644 --- a/src/abstractions/download-request.service.interface.ts +++ b/src/abstractions/download-request.service.interface.ts @@ -10,49 +10,49 @@ import { FileResponse } from '../common/file-response'; export interface IDownloadRequestService extends IFiscalapiService { /** * Lista los xmls descargados para un requestId. - * + * * @param requestId - ID de la solicitud * @returns Lista paginada de objetos Xml */ - getXmlsAsync(requestId: string): Promise>>; + getXmls(requestId: string): Promise>>; /** * Lista los meta-items descargados para un requestId. - * + * * @param requestId - ID de la solicitud * @returns Lista paginada de objetos MetadataItem */ - getMetadataItemsAsync(requestId: string): Promise>>; + getMetadataItems(requestId: string): Promise>>; /** - * Downloads la lista de paquetes (archivos .zip) de un requestId. - * + * Descarga la lista de paquetes (archivos .zip) de un requestId. + * * @param requestId - ID de la solicitud * @returns Lista de FileResponses */ - downloadPackageAsync(requestId: string): Promise>; + downloadPackage(requestId: string): Promise>; /** * Descarga el archivo crudo de solicitud SAT para un requestId. - * + * * @param requestId - ID de la solicitud * @returns Objeto de respuesta de archivo */ - downloadSatRequestAsync(requestId: string): Promise>; + downloadSatRequest(requestId: string): Promise>; /** * Descarga la respuesta SAT para un requestId. - * + * * @param requestId - ID de la solicitud * @returns Objeto de respuesta de archivo */ - downloadSatResponseAsync(requestId: string): Promise>; + downloadSatResponse(requestId: string): Promise>; /** * Busca solicitudes de descarga creadas en una fecha específica. - * + * * @param createdAt - Fecha de creación * @returns Lista de solicitudes de descarga */ - searchAsync(createdAt: Date): Promise>; + searchByDate(createdAt: Date): Promise>; } \ No newline at end of file diff --git a/src/abstractions/download-rule.service.inteface.ts b/src/abstractions/download-rule.service.interface.ts similarity index 100% rename from src/abstractions/download-rule.service.inteface.ts rename to src/abstractions/download-rule.service.interface.ts diff --git a/src/abstractions/fiscalapi-client.interface.ts b/src/abstractions/fiscalapi-client.interface.ts index 7f4cdee..76ea52b 100644 --- a/src/abstractions/fiscalapi-client.interface.ts +++ b/src/abstractions/fiscalapi-client.interface.ts @@ -1,8 +1,8 @@ import { IApiKeyService } from './api-key-service.interface'; import { ICatalogService } from './catalog-service.interface'; -import { IDownloadCatalogService } from './download-catalog.inteface'; +import { IDownloadCatalogService } from './download-catalog.interface'; import { IDownloadRequestService } from './download-request.service.interface'; -import { IDownloadRuleService } from './download-rule.service.inteface'; +import { IDownloadRuleService } from './download-rule.service.interface'; import { IInvoiceService } from './invoice-service.interface'; import { IPersonService } from './person-service.interface'; import { IProductService } from './product-service.interface'; diff --git a/src/http/fiscalapi-http-client-factory.ts b/src/http/fiscalapi-http-client-factory.ts index b5c8cf5..e568b11 100644 --- a/src/http/fiscalapi-http-client-factory.ts +++ b/src/http/fiscalapi-http-client-factory.ts @@ -46,10 +46,9 @@ export class FiscalapiHttpClientFactory { * @private */ private static createAxiosInstance(settings: FiscalapiSettings): AxiosInstance { - // Agente HTTPS que ignora la validación del certificado autofirmado si está en modo depuración + // Agente HTTPS que ignora la validación del certificado solo en modo debug const httpsAgent = new https.Agent({ - //rejectUnauthorized: !settings.debug - rejectUnauthorized: false, // Cambiado a true para producción + rejectUnauthorized: !settings.debug, }); // Crea y configura una nueva instancia de axios diff --git a/src/index.ts b/src/index.ts index 13752a0..d1d13cf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,9 +10,9 @@ export type { IInvoiceService } from './abstractions/invoice-service.interface'; export type { IPersonService } from './abstractions/person-service.interface'; export type { IProductService } from './abstractions/product-service.interface'; export type { ITaxFileService } from './abstractions/tax-file-service.interface'; -export type { IDownloadCatalogService } from './abstractions/download-catalog.inteface'; +export type { IDownloadCatalogService } from './abstractions/download-catalog.interface'; export type { IDownloadRequestService } from './abstractions/download-request.service.interface'; -export type { IDownloadRuleService } from './abstractions/download-rule.service.inteface'; +export type { IDownloadRuleService } from './abstractions/download-rule.service.interface'; export type { IStampService } from './abstractions/stamp-service.interface'; export type { IEmployeeService } from './abstractions/employee-service.interface'; export type { IEmployerService } from './abstractions/employer-service.interface'; diff --git a/src/sdk-constants.ts b/src/sdk-constants.ts deleted file mode 100644 index c8686f2..0000000 --- a/src/sdk-constants.ts +++ /dev/null @@ -1,25 +0,0 @@ - -/** - * Constantes utilizadas en todo el SDK - */ -export const SdkConstants = { - /** - * Formato de fecha SAT (para facturas mexicanas) - */ - SAT_DATE_FORMAT: 'yyyy-MM-ddTHH:mm:ss', - - /** - * Versión predeterminada de la API - */ - DEFAULT_API_VERSION: 'v4', - - /** - * Zona horaria predeterminada - */ - DEFAULT_TIME_ZONE: 'America/Mexico_City', - - /** - * Tiempo de espera HTTP predeterminado en milisegundos - */ - DEFAULT_HTTP_TIMEOUT: 30000 - }; \ No newline at end of file diff --git a/src/services/download-catalog.service.ts b/src/services/download-catalog.service.ts index 710cde8..a7d523a 100644 --- a/src/services/download-catalog.service.ts +++ b/src/services/download-catalog.service.ts @@ -1,9 +1,7 @@ - import { CatalogDto } from '../common/catalog-dto'; import { ApiResponse } from '../common/api-response'; import { IFiscalapiHttpClient } from '../http/fiscalapi-http-client.interface'; -import { IDownloadCatalogService } from '../abstractions/download-catalog.inteface'; - +import { IDownloadCatalogService } from '../abstractions/download-catalog.interface'; /** * Implementación del servicio de catálogos de descarga masiva @@ -18,7 +16,6 @@ export class DownloadCatalogService implements IDownloadCatalogService { this.apiVersion = apiVersion; this.baseEndpoint = `api/${apiVersion}/download-catalogs`; } - /** * Construye el endpoint completo para las peticiones @@ -46,6 +43,4 @@ export class DownloadCatalogService implements IDownloadCatalogService { const endpoint = this.buildEndpoint(catalogName); return this.httpClient.getAsync(endpoint); } - } - diff --git a/src/services/download-request.service.ts b/src/services/download-request.service.ts index ccd6bdc..45dc6e3 100644 --- a/src/services/download-request.service.ts +++ b/src/services/download-request.service.ts @@ -21,12 +21,11 @@ export class DownloadRequestService extends BaseFiscalapiService>> { - // GET /api/v4/download-requests//xmls + getXmls(requestId: string): Promise>> { const path = `${requestId}/xmls`; const endpoint = this.buildEndpoint(path); return this.httpClient.getAsync>(endpoint); @@ -34,25 +33,23 @@ export class DownloadRequestService extends BaseFiscalapiService>> { - // GET /api/v4/download-requests//meta-items + getMetadataItems(requestId: string): Promise>> { const path = `${requestId}/meta-items`; const endpoint = this.buildEndpoint(path); return this.httpClient.getAsync>(endpoint); } /** - * Downloads la lista de paquetes (archivos .zip) de un requestId. - * + * Descarga la lista de paquetes (archivos .zip) de un requestId. + * * @param requestId - ID de la solicitud * @returns Lista de FileResponses */ - downloadPackageAsync(requestId: string): Promise> { - // GET /api/v4/download-requests//package + downloadPackage(requestId: string): Promise> { const path = `${requestId}/package`; const endpoint = this.buildEndpoint(path); return this.httpClient.getAsync(endpoint); @@ -60,12 +57,11 @@ export class DownloadRequestService extends BaseFiscalapiService> { - // GET /api/v4/download-requests//raw-request + downloadSatRequest(requestId: string): Promise> { const path = `${requestId}/raw-request`; const endpoint = this.buildEndpoint(path); return this.httpClient.getAsync(endpoint); @@ -73,12 +69,11 @@ export class DownloadRequestService extends BaseFiscalapiService> { - // GET /api/v4/download-requests//raw-response + downloadSatResponse(requestId: string): Promise> { const path = `${requestId}/raw-response`; const endpoint = this.buildEndpoint(path); return this.httpClient.getAsync(endpoint); @@ -86,13 +81,12 @@ export class DownloadRequestService extends BaseFiscalapiService> { - // GET /api/v4/download-requests/search?createdAt=2025-08-21 - const formattedDate = createdAt.toISOString().split('T')[0]; // Format as YYYY-MM-DD + searchByDate(createdAt: Date): Promise> { + const formattedDate = createdAt.toISOString().split('T')[0]; const path = `search?createdAt=${formattedDate}`; const endpoint = this.buildEndpoint(path); return this.httpClient.getAsync(endpoint); diff --git a/src/services/download-rule.service.ts b/src/services/download-rule.service.ts index 865f6d8..4748761 100644 --- a/src/services/download-rule.service.ts +++ b/src/services/download-rule.service.ts @@ -1,7 +1,7 @@ import { DownloadRequest, DownloadRule } from '../models/download'; import { IFiscalapiHttpClient } from '../http/fiscalapi-http-client.interface'; import { BaseFiscalapiService } from './base-fiscalapi-service'; -import { IDownloadRuleService } from '../abstractions/download-rule.service.inteface'; +import { IDownloadRuleService } from '../abstractions/download-rule.service.interface'; import { ApiResponse } from '../common/api-response'; /** @@ -9,7 +9,7 @@ import { ApiResponse } from '../common/api-response'; */ export class DownloadRuleService extends BaseFiscalapiService implements IDownloadRuleService { /** -* Crea una nueva instancia del servicio de reglas de descarga masiva + * Crea una nueva instancia del servicio de reglas de descarga masiva * @param {IFiscalapiHttpClient} httpClient - Cliente HTTP * @param {string} apiVersion - Versión de la API */ @@ -23,9 +23,9 @@ export class DownloadRuleService extends BaseFiscalapiService impl * @returns solicitud de descarga masiva de prueba */ createTestRule(): Promise> { - // GET /api/v4/download-rules/test - var path = "test"; - var endpoint = this.buildEndpoint(path); + // POST /api/v4/download-rules/test + const path = 'test'; + const endpoint = this.buildEndpoint(path); return this.httpClient.postAsync(endpoint, {}); } } \ No newline at end of file diff --git a/src/services/fiscalapi-client.ts b/src/services/fiscalapi-client.ts index ec65c1a..2546a74 100644 --- a/src/services/fiscalapi-client.ts +++ b/src/services/fiscalapi-client.ts @@ -7,8 +7,8 @@ import { IPersonService } from '../abstractions/person-service.interface'; import { IApiKeyService } from '../abstractions/api-key-service.interface'; import { ICatalogService } from '../abstractions/catalog-service.interface'; import { ITaxFileService } from '../abstractions/tax-file-service.interface'; -import { IDownloadCatalogService } from '../abstractions/download-catalog.inteface'; -import { IDownloadRuleService } from '../abstractions/download-rule.service.inteface'; +import { IDownloadCatalogService } from '../abstractions/download-catalog.interface'; +import { IDownloadRuleService } from '../abstractions/download-rule.service.interface'; import { IDownloadRequestService } from '../abstractions/download-request.service.interface'; import { IStampService } from '../abstractions/stamp-service.interface'; import { FiscalapiSettings } from '../common/fiscalapi-settings'; diff --git a/src/services/invoice-service.ts b/src/services/invoice-service.ts index 87b97d9..3922ba8 100644 --- a/src/services/invoice-service.ts +++ b/src/services/invoice-service.ts @@ -54,11 +54,11 @@ export class InvoiceService extends BaseFiscalapiService implements IIn throw new Error(`Unsupported invoice type: ${requestModel.typeCode}`); } - return await this.executeRequest({ - path:endpoint, - data:requestModel, - method:'POST', - }); + return await this.executeRequest({ + path: endpoint, + data: requestModel, + method: 'POST', + }); } /** @@ -72,8 +72,8 @@ export class InvoiceService extends BaseFiscalapiService implements IIn } return await this.executeRequest({ - data:request, - method:'DELETE', + data: request, + method: 'DELETE', }); } @@ -87,9 +87,9 @@ export class InvoiceService extends BaseFiscalapiService implements IIn throw new Error('request cannot be null'); } return await this.executeRequest({ - path:'pdf', - data:request, - method:'POST', + path: 'pdf', + data: request, + method: 'POST', }); } @@ -118,9 +118,9 @@ export class InvoiceService extends BaseFiscalapiService implements IIn */ async send(request: SendInvoiceRequest): Promise> { return await this.executeRequest({ - path:'send', - data:request, - method:'POST', + path: 'send', + data: request, + method: 'POST', }); } @@ -130,10 +130,10 @@ export class InvoiceService extends BaseFiscalapiService implements IIn * @returns {Promise>} Respuesta con el estado de la factura */ async getStatus(request: InvoiceStatusRequest): Promise> { - return await this.executeRequest({ - path:'status', - data:request, - method:'POST', - }); + return await this.executeRequest({ + path: 'status', + data: request, + method: 'POST', + }); } } \ No newline at end of file diff --git a/src/utils/date-utils.ts b/src/utils/date-utils.ts index 040d7e7..022d22c 100644 --- a/src/utils/date-utils.ts +++ b/src/utils/date-utils.ts @@ -1,4 +1,3 @@ - import { DateTime } from 'luxon'; @@ -30,6 +29,5 @@ export function formatSatDate(date: Date | string | DateTime): string { * @returns {DateTime} Objeto DateTime */ export function parseSatDate(dateStr: string): DateTime { - return DateTime.fromFormat(dateStr, SAT_DATE_FORMAT); - } - \ No newline at end of file + return DateTime.fromFormat(dateStr, SAT_DATE_FORMAT); +} From 638494aa5bc7736346dd225c93cbeec87e196f80 Mon Sep 17 00:00:00 2001 From: JesusMendoza Date: Tue, 27 Jan 2026 13:59:35 -0600 Subject: [PATCH 06/15] =?UTF-8?q?ejemplos=20facturas=20de=20n=C3=B3mina=20?= =?UTF-8?q?por=20valores=20added?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/ejemplos-factura-nomina.ts | 1127 +++++++++++++++++++++++++++ payroll-invoice-requrements.md | 38 +- src/index.ts | 25 +- src/models/invoice.ts | 475 ++++++++++- src/services/invoice-service.ts | 34 - tsconfig.json | 7 + 6 files changed, 1661 insertions(+), 45 deletions(-) create mode 100644 examples/ejemplos-factura-nomina.ts diff --git a/examples/ejemplos-factura-nomina.ts b/examples/ejemplos-factura-nomina.ts new file mode 100644 index 0000000..e3771cb --- /dev/null +++ b/examples/ejemplos-factura-nomina.ts @@ -0,0 +1,1127 @@ +/** + * Ejemplos de facturas de nómina (CFDI Nómina) usando el SDK de FiscalAPI + * Todos los métodos usan el modo "ByValues" - los datos se pasan directamente en la petición HTTP + */ + +import { FiscalapiClient, FiscalapiSettings, Invoice } from '../src/index'; +import { inspect } from 'util'; + +// Configuración de la consola para mostrar objetos anidados +inspect.defaultOptions.depth = null; +inspect.defaultOptions.colors = true; + +// Configuración de FiscalAPI +const settings: FiscalapiSettings = { + // apiUrl: 'https://test.fiscalapi.com', + // apiKey: '', + // tenant: '', + +}; + +// Sellos SAT de prueba +const escuelaKemperUrgateBase64Cer = "MIIFsDCCA5igAwIBAgIUMzAwMDEwMDAwMDA1MDAwMDM0MTYwDQYJKoZIhvcNAQELBQAwggErMQ8wDQYDVQQDDAZBQyBVQVQxLjAsBgNVBAoMJVNFUlZJQ0lPIERFIEFETUlOSVNUUkFDSU9OIFRSSUJVVEFSSUExGjAYBgNVBAsMEVNBVC1JRVMgQXV0aG9yaXR5MSgwJgYJKoZIhvcNAQkBFhlvc2Nhci5tYXJ0aW5lekBzYXQuZ29iLm14MR0wGwYDVQQJDBQzcmEgY2VycmFkYSBkZSBjYWxpejEOMAwGA1UEEQwFMDYzNzAxCzAJBgNVBAYTAk1YMRkwFwYDVQQIDBBDSVVEQUQgREUgTUVYSUNPMREwDwYDVQQHDAhDT1lPQUNBTjERMA8GA1UELRMIMi41LjQuNDUxJTAjBgkqhkiG9w0BCQITFnJlc3BvbnNhYmxlOiBBQ0RNQS1TQVQwHhcNMjMwNTE4MTE0MzUxWhcNMjcwNTE4MTE0MzUxWjCB1zEnMCUGA1UEAxMeRVNDVUVMQSBLRU1QRVIgVVJHQVRFIFNBIERFIENWMScwJQYDVQQpEx5FU0NVRUxBIEtFTVBFUiBVUkdBVEUgU0EgREUgQ1YxJzAlBgNVBAoTHkVTQ1VFTEEgS0VNUEVSIFVSR0FURSBTQSBERSBDVjElMCMGA1UELRMcRUtVOTAwMzE3M0M5IC8gVkFEQTgwMDkyN0RKMzEeMBwGA1UEBRMVIC8gVkFEQTgwMDkyN0hTUlNSTDA1MRMwEQYDVQQLEwpTdWN1cnNhbCAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtmecO6n2GS0zL025gbHGQVxznPDICoXzR2uUngz4DqxVUC/w9cE6FxSiXm2ap8Gcjg7wmcZfm85EBaxCx/0J2u5CqnhzIoGCdhBPuhWQnIh5TLgj/X6uNquwZkKChbNe9aeFirU/JbyN7Egia9oKH9KZUsodiM/pWAH00PCtoKJ9OBcSHMq8Rqa3KKoBcfkg1ZrgueffwRLws9yOcRWLb02sDOPzGIm/jEFicVYt2Hw1qdRE5xmTZ7AGG0UHs+unkGjpCVeJ+BEBn0JPLWVvDKHZAQMj6s5Bku35+d/MyATkpOPsGT/VTnsouxekDfikJD1f7A1ZpJbqDpkJnss3vQIDAQABox0wGzAMBgNVHRMBAf8EAjAAMAsGA1UdDwQEAwIGwDANBgkqhkiG9w0BAQsFAAOCAgEAFaUgj5PqgvJigNMgtrdXZnbPfVBbukAbW4OGnUhNrA7SRAAfv2BSGk16PI0nBOr7qF2mItmBnjgEwk+DTv8Zr7w5qp7vleC6dIsZFNJoa6ZndrE/f7KO1CYruLXr5gwEkIyGfJ9NwyIagvHHMszzyHiSZIA850fWtbqtythpAliJ2jF35M5pNS+YTkRB+T6L/c6m00ymN3q9lT1rB03YywxrLreRSFZOSrbwWfg34EJbHfbFXpCSVYdJRfiVdvHnewN0r5fUlPtR9stQHyuqewzdkyb5jTTw02D2cUfL57vlPStBj7SEi3uOWvLrsiDnnCIxRMYJ2UA2ktDKHk+zWnsDmaeleSzonv2CHW42yXYPCvWi88oE1DJNYLNkIjua7MxAnkNZbScNw01A6zbLsZ3y8G6eEYnxSTRfwjd8EP4kdiHNJftm7Z4iRU7HOVh79/lRWB+gd171s3d/mI9kte3MRy6V8MMEMCAnMboGpaooYwgAmwclI2XZCczNWXfhaWe0ZS5PmytD/GDpXzkX0oEgY9K/uYo5V77NdZbGAjmyi8cE2B2ogvyaN2XfIInrZPgEffJ4AB7kFA2mwesdLOCh0BLD9itmCve3A1FGR4+stO2ANUoiI3w3Tv2yQSg4bjeDlJ08lXaaFCLW2peEXMXjQUk7fmpb5MNuOUTW6BE=" +const escuelaKemperUrgateBase64Key = "MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIAgEAAoIBAQACAggAMBQGCCqGSIb3DQMHBAgwggS/AgEAMASCBMh4EHl7aNSCaMDA1VlRoXCZ5UUmqErAbucoZQObOaLUEm+I+QZ7Y8Giupo+F1XWkLvAsdk/uZlJcTfKLJyJbJwsQYbSpLOCLataZ4O5MVnnmMbfG//NKJn9kSMvJQZhSwAwoGLYDm1ESGezrvZabgFJnoQv8Si1nAhVGTk9FkFBesxRzq07dmZYwFCnFSX4xt2fDHs1PMpQbeq83aL/PzLCce3kxbYSB5kQlzGtUYayiYXcu0cVRu228VwBLCD+2wTDDoCmRXtPesgrLKUR4WWWb5N2AqAU1mNDC+UEYsENAerOFXWnmwrcTAu5qyZ7GsBMTpipW4Dbou2yqQ0lpA/aB06n1kz1aL6mNqGPaJ+OqoFuc8Ugdhadd+MmjHfFzoI20SZ3b2geCsUMNCsAd6oXMsZdWm8lzjqCGWHFeol0ik/xHMQvuQkkeCsQ28PBxdnUgf7ZGer+TN+2ZLd2kvTBOk6pIVgy5yC6cZ+o1Tloql9hYGa6rT3xcMbXlW+9e5jM2MWXZliVW3ZhaPjptJFDbIfWxJPjz4QvKyJk0zok4muv13Iiwj2bCyefUTRz6psqI4cGaYm9JpscKO2RCJN8UluYGbbWmYQU+Int6LtZj/lv8p6xnVjWxYI+rBPdtkpfFYRp+MJiXjgPw5B6UGuoruv7+vHjOLHOotRo+RdjZt7NqL9dAJnl1Qb2jfW6+d7NYQSI/bAwxO0sk4taQIT6Gsu/8kfZOPC2xk9rphGqCSS/4q3Os0MMjA1bcJLyoWLp13pqhK6bmiiHw0BBXH4fbEp4xjSbpPx4tHXzbdn8oDsHKZkWh3pPC2J/nVl0k/yF1KDVowVtMDXE47k6TGVcBoqe8PDXCG9+vjRpzIidqNo5qebaUZu6riWMWzldz8x3Z/jLWXuDiM7/Yscn0Z2GIlfoeyz+GwP2eTdOw9EUedHjEQuJY32bq8LICimJ4Ht+zMJKUyhwVQyAER8byzQBwTYmYP5U0wdsyIFitphw+/IH8+v08Ia1iBLPQAeAvRfTTIFLCs8foyUrj5Zv2B/wTYIZy6ioUM+qADeXyo45uBLLqkN90Rf6kiTqDld78NxwsfyR5MxtJLVDFkmf2IMMJHTqSfhbi+7QJaC11OOUJTD0v9wo0X/oO5GvZhe0ZaGHnm9zqTopALuFEAxcaQlc4R81wjC4wrIrqWnbcl2dxiBtD73KW+wcC9ymsLf4I8BEmiN25lx/OUc1IHNyXZJYSFkEfaxCEZWKcnbiyf5sqFSSlEqZLc4lUPJFAoP6s1FHVcyO0odWqdadhRZLZC9RCzQgPlMRtji/OXy5phh7diOBZv5UYp5nb+MZ2NAB/eFXm2JLguxjvEstuvTDmZDUb6Uqv++RdhO5gvKf/AcwU38ifaHQ9uvRuDocYwVxZS2nr9rOwZ8nAh+P2o4e0tEXjxFKQGhxXYkn75H3hhfnFYjik/2qunHBBZfcdG148MaNP6DjX33M238T9Zw/GyGx00JMogr2pdP4JAErv9a5yt4YR41KGf8guSOUbOXVARw6+ybh7+meb7w4BeTlj3aZkv8tVGdfIt3lrwVnlbzhLjeQY6PplKp3/a5Kr5yM0T4wJoKQQ6v3vSNmrhpbuAtKxpMILe8CQoo=" +const organicosNavezOsorioBase64Cer = "MIIF1DCCA7ygAwIBAgIUMzAwMDEwMDAwMDA1MDAwMDM0MzkwDQYJKoZIhvcNAQELBQAwggErMQ8wDQYDVQQDDAZBQyBVQVQxLjAsBgNVBAoMJVNFUlZJQ0lPIERFIEFETUlOSVNUUkFDSU9OIFRSSUJVVEFSSUExGjAYBgNVBAsMEVNBVC1JRVMgQXV0aG9yaXR5MSgwJgYJKoZIhvcNAQkBFhlvc2Nhci5tYXJ0aW5lekBzYXQuZ29iLm14MR0wGwYDVQQJDBQzcmEgY2VycmFkYSBkZSBjYWxpejEOMAwGA1UEEQwFMDYzNzAxCzAJBgNVBAYTAk1YMRkwFwYDVQQIDBBDSVVEQUQgREUgTUVYSUNPMREwDwYDVQQHDAhDT1lPQUNBTjERMA8GA1UELRMIMi41LjQuNDUxJTAjBgkqhkiG9w0BCQITFnJlc3BvbnNhYmxlOiBBQ0RNQS1TQVQwHhcNMjMwNTE4MTI1NTE2WhcNMjcwNTE4MTI1NTE2WjCB+zEzMDEGA1UEAxQqT1JHQU5JQ09TINFBVkVaIE9TT1JJTyBTLkEgREUgQy5WIFNBIERFIENWMTMwMQYDVQQpFCpPUkdBTklDT1Mg0UFWRVogT1NPUklPIFMuQSBERSBDLlYgU0EgREUgQ1YxMzAxBgNVBAoUKk9SR0FOSUNPUyDRQVZFWiBPU09SSU8gUy5BIERFIEMuViBTQSBERSBDVjElMCMGA1UELRQcT9FPMTIwNzI2UlgzIC8gVkFEQTgwMDkyN0RKMzEeMBwGA1UEBRMVIC8gVkFEQTgwMDkyN0hTUlNSTDA1MRMwEQYDVQQLEwpTdWN1cnNhbCAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlAF4PoRqITQAEjFBzzfiT/NSN2yvb7Iv1ZMe4qD7tBxBxazRCx+GnimfpR+eaM744RlRDUj+hZfWcsOMn+q65UEIP+Xq5V1NbO1LZDse9uG1fLLSmptfKjyfvTtmBNYBjC3G6YmRv5qVw81CIS4aQOSMXKD+lrxjmRUhV9EAtXVoqGxvyDKeeX4caKuRz8mlrnR8/SMbnpobe5BNoXPrpDbEypemiJXe40pjsltY0RV3b0W0JtJQABUwZ9xn0lPYHY2q7IxYfohibv+o9ldXOXY6tivBZFfbGQSUp7CevC55+Y6uqh35Pi1o0nt/vBVgUOVPNM8d4TvGbXsE0G2J7QIDAQABox0wGzAMBgNVHRMBAf8EAjAAMAsGA1UdDwQEAwIGwDANBgkqhkiG9w0BAQsFAAOCAgEAFp52XykMXfFUtjQqA2zzLPrPIDSMEpkm1vWY0qfz2gC2TlVpbDCWH2vFHpP8D14OifXOmYkws2cvLyE0uBN6se4zXxVHBpTEq+93rvu/tjvMU6r7DISDwB0EX5kmKIFcOugET3/Eq1mxZ6mrI0K26RaEUz+HVyR0EQ2Ll5CLExDkPYV/am0gynhn6QPkxPNbcbm77PEIbH7zc+t7ZB5sgQ6LnubgnKNZDn8bNhkuM1jqFkh7h0owhlJrOvATgrDSLnrot8FoLFkrWQD4uA5udGRwXn5QWx0QM5ScNiSgSRilSFEyXn6rH/CJLO05Sx5OwJJTaxFbAyOXnoNdPMzbQAziaW78478nCNZVSrKWpjwWpScirtM2zcQ9fywd/a3CG66Ff29zasfhHJCp29TIjj1OURp6l1CKc16+UxjuVJ1z5Xh7v3s8S2gtmuYP1sUXPvAEYuVp9CFW87QVMtl3+nGlyJEzSAW/yaps9ua5RmyJK0Mjk1zyXjOJoIY75CIOMN8oqVAxmLJg5XftXJSekGpxybw9aq9qOJdmxVcZoAFaYg4MAdKViBoYxfWfEm4q/ihRz4asnzLp9NJWTXN1YH94rJrK7JSEq820flgr1kiL7z7n1rgWMvhJH9nHriG3yRkno/8OdLJxOSXd7MKZfZx0EWDX8toqWyE7zia8aPM=" +const organicosNavezOsorioBase64Key = "MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIAgEAAoIBAQACAggAMBQGCCqGSIb3DQMHBAgwggS8AgEAMASCBMh4EHl7aNSCaMDA1VlRoXCZ5UUmqErAbucRFLOMmsAaFFEdAecnfgJf0IlyJpvyNOGiSwXgY6uZtS0QJmmupWTlQATxbN4xeN7csx7yCMYxMiWXLyTbjVIWzzsFVKHbsxCudz6UDqMZ3aXEEPDDbPECXJC4FxqzuUgifN4QQuIvxfPbk23m3Vtqu9lr/xMrDNqLZ4RiqY2062kgQzGzekq8CSC97qBAbb8SFMgakFjeHN0JiTGaTpYCpGbu4d+i3ZrQ0mlYkxesdvCLqlCwVM0RTMJsNQ8vpBpRDzH372iOTLCO/gXtV8pEsxpUzG9LSUBo7xSMd1/lcfdyqVgnScgUm8/+toxk6uwZkUMWWvp7tqrMYQFYdR5CjiZjgAWrNorgMmawBqkJU6KQO/CpXVn99U1fANPfQoeyQMgLt35k0JKynG8MuWsgb4EG9Z6sRmOsCQQDDMKwhBjqcbEwN2dL4f1HyN8wklFCyYy6j1NTKU2AjRMXVu4+OlAp5jpjgv08RQxEkW/tNMSSBcpvOzNr64u0M692VA2fThR3UMQ/MZ2yVM6yY3GgIu2tJmg08lhmkoLpWZIMy7bZjj/AEbi7B3wSF4vDYZJcr/Djeezm3MMSghoiOIRSqtBjwf7ZjhA2ymdCsrzy7XSMVekT0y1S+ew1WhnzUNKQSucb6V2yRwNbm0EyeEuvVyHgiGEzCrzNbNHCfoFr69YCUi8itiDfiV7/p7LJzD8J/w85nmOkI/9p+aZ2EyaOdThqBmN4CtoDi5ixz/1EElLn7KVI4d/DZsZ4ZMu76kLAy94o0m6ORSbHX5hw12+P5DgGaLu/Dxd9cctRCkvcUdagiECuKGLJpxTJvEBQoZqUB8AJFgwKcNLl3Z5KAWL5hV0t1h8i3N4HllygqpfUSQMLWCtlGwdI4XGlGI5CmnjrL2Uj8sj9C0zSNqZVnAXFMV9f2ND9W6YJqfU89BQ6Y4QQRMGjXcVF7c78bn5r6zI+Qv2QKm3YiGCfuIa64B+PB/BdithpOuBPn5X5Zxc8ju/kYjJk7sau7VtKJseGOJ1bqOq99VzaxoHjzoJgthLHtni9WtGAnnQy7GMWGW4Un2yObHCxvQxx/rIZEaQiCGfRXOcZIZuXBe5xeHJFGrekDxu3YyumEnLWvsirDF3qhpUtxqvbkTuZw2xT3vTR+oWZpSEnYTd3k/09Eb0ovOPLkbhvcvCEeoI91EJvU+KI4Lm7ZsuTUSpECrHiS3uPOjboCigOWGayKzUHUICNrGK0zxgZXhhl6V7y9pImRl34ID/tZhr3veW4pQKgscv6sQjGJzaph2oCP7uZC6arGWcFpc2pgfBcobmOXYPWKskU3eWKClHBJnJ8MoOru+ObOb+izPhINHOmzP26TnKzFxdZiL+onxjadPYslcLtqlmOYpb/5hHgGOvitLhCLHCp0gYNB2uzj0sVxNs3k7k43KrlO5L6gp1KVaIw2a1yZzOCqDWWcePfKM3Mii9JdVyfHZLRRjFCQiOYo41AltHU+9IcaoT4J/j7pKw5tnlu2VaMlnN0dISpoq/ak0m4YjTd3XdRQeH9ktWmclkc65LdLKf9hIqjVqvOhQUJYkuT7OPgr+o7Z9BnClXMz1/CYWftwQE=" +const password = "12345678a" +const currentDate = '2026-01-27T10:04:06'; + + +// ============================================================================ +// 1. NOMINA ORDINARIA (Facturación por valores) +// ============================================================================ +async function nominaOrdinariaByValues(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Ordinaria ByValues ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + tin: 'EKU9003173C9', + legalName: 'ESCUELA KEMPER URGATE', + taxRegimeCode: '601', + employerData: { + employerRegistration: 'B5510768108' + }, + taxCredentials: [ + { base64File: escuelaKemperUrgateBase64Cer, fileType: 0, password }, + { base64File: escuelaKemperUrgateBase64Key, fileType: 1, 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 response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 2. NOMINA ASIMILADOS (Facturación por valores) +// ============================================================================ +async function nominaAsimiladosByValues(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Asimilados ByValues ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '06880', + exportCode: '01', + issuer: { + tin: 'EKU9003173C9', + legalName: 'ESCUELA KEMPER URGATE', + taxRegimeCode: '601', + employerData: { + originEmployerTin: 'EKU9003173C9' + }, + taxCredentials: [ + { base64File: escuelaKemperUrgateBase64Cer, fileType: 0, password }, + { base64File: escuelaKemperUrgateBase64Key, fileType: 1, password } + ] + }, + recipient: { + tin: 'CACX7605101P8', + legalName: 'XOCHILT CASAS CHAVEZ', + zipCode: '36257', + taxRegimeCode: '605', + cfdiUseCode: 'CN01', + employeeData: { + curp: 'XEXX010101HNEXXXA4', + satContractTypeId: '09', + satUnionizedStatusId: 'No', + satTaxRegimeTypeId: '09', + employeeNumber: '00002', + department: 'ADMINISTRACION', + position: 'DIRECTOR DE ADMINISTRACION', + satPaymentPeriodicityId: '99', + satBankId: '012', + bankAccount: '1111111111', + satPayrollStateId: 'CMX' + } + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'E', + paymentDate: '2023-06-02T00:00:00', + initialPaymentDate: '2023-06-01T00:00:00', + finalPaymentDate: '2023-06-02T00:00:00', + daysPaid: 1, + earnings: { + earnings: [ + { earningTypeCode: '046', code: '010046', concept: 'INGRESOS ASIMILADOS A SALARIOS', taxedAmount: 111197.73, exemptAmount: 0.00 } + ], + otherPayments: [] + }, + deductions: [ + { deductionTypeCode: '002', code: '020002', concept: 'ISR', amount: 36197.73 } + ] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 3. NOMINA CON BONOS Y FONDO DE AHORRO (Facturación por valores) +// ============================================================================ +async function nominaConBonosFondoAhorroByValues(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Con Bonos y Fondo de Ahorro ByValues ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + tin: 'EKU9003173C9', + legalName: 'ESCUELA KEMPER URGATE', + taxRegimeCode: '601', + employerData: { + employerRegistration: 'Z0000001234' + }, + taxCredentials: [ + { base64File: escuelaKemperUrgateBase64Cer, fileType: 0, password }, + { base64File: escuelaKemperUrgateBase64Key, fileType: 1, password } + ] + }, + recipient: { + tin: 'XOJI740919U48', + legalName: 'INGRID XODAR JIMENEZ', + zipCode: '76028', + taxRegimeCode: '605', + cfdiUseCode: 'CN01', + employeeData: { + curp: 'XEXX010101MNEXXXA8', + socialSecurityNumber: '0000000000', + laborRelationStartDate: '2022-03-02T00:00:00', + seniority: 'P66W', + satContractTypeId: '01', + satUnionizedStatusId: 'No', + satTaxRegimeTypeId: '02', + employeeNumber: '111111', + satJobRiskId: '4', + satPaymentPeriodicityId: '02', + integratedDailySalary: 180.96, + satPayrollStateId: 'GUA' + } + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'O', + paymentDate: '2023-06-11T00:00:00', + initialPaymentDate: '2023-06-05T00:00:00', + finalPaymentDate: '2023-06-11T00:00:00', + daysPaid: 7, + earnings: { + earnings: [ + { earningTypeCode: '001', code: 'SP01', concept: 'SUELDO', taxedAmount: 1210.30, exemptAmount: 0.00 }, + { earningTypeCode: '010', code: 'SP02', concept: 'PREMIO PUNTUALIDAD', taxedAmount: 121.03, exemptAmount: 0.00 }, + { earningTypeCode: '029', code: 'SP03', concept: 'MONEDERO ELECTRONICO', taxedAmount: 0.00, exemptAmount: 269.43 }, + { earningTypeCode: '010', code: 'SP04', concept: 'PREMIO DE ASISTENCIA', taxedAmount: 121.03, exemptAmount: 0.00 }, + { earningTypeCode: '005', code: 'SP54', concept: 'APORTACION FONDO AHORRO', taxedAmount: 0.00, exemptAmount: 121.03 } + ], + otherPayments: [ + { + otherPaymentTypeCode: '002', + code: 'ISRSUB', + concept: 'Subsidio ISR para empleo', + amount: 0.0, + subsidyCaused: 0.0, + balanceCompensation: { + favorableBalance: 0.0, + year: 2022, + remainingFavorableBalance: 0.0 + } + } + ] + }, + deductions: [ + { deductionTypeCode: '004', code: 'ZA09', concept: 'APORTACION FONDO AHORRO', amount: 121.03 }, + { deductionTypeCode: '002', code: 'ISR', concept: 'ISR', amount: 36.57 }, + { deductionTypeCode: '001', code: 'IMSS', concept: 'Cuota de Seguridad Social EE', amount: 30.08 }, + { deductionTypeCode: '004', code: 'ZA68', concept: 'DEDUCCION FDO AHORRO PAT', amount: 121.03 }, + { deductionTypeCode: '018', code: 'ZA11', concept: 'APORTACION CAJA AHORRO', amount: 300.00 } + ] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 4. NOMINA CON HORAS EXTRA (Facturación por valores) +// ============================================================================ +async function nominaConHorasExtraByValues(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Con Horas Extra ByValues ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + tin: 'EKU9003173C9', + legalName: 'ESCUELA KEMPER URGATE', + taxRegimeCode: '601', + employerData: { + employerRegistration: 'B5510768108', + originEmployerTin: 'URE180429TM6' + }, + taxCredentials: [ + { base64File: escuelaKemperUrgateBase64Cer, fileType: 0, password }, + { base64File: escuelaKemperUrgateBase64Key, fileType: 1, password } + ] + }, + recipient: { + tin: 'XOJI740919U48', + legalName: 'INGRID XODAR JIMENEZ', + zipCode: '76028', + taxRegimeCode: '605', + cfdiUseCode: 'CN01', + employeeData: { + curp: 'XEXX010101HNEXXXA4', + socialSecurityNumber: '000000', + laborRelationStartDate: '2015-01-01', + seniority: 'P437W', + satContractTypeId: '01', + satWorkdayTypeId: '01', + satTaxRegimeTypeId: '03', + employeeNumber: '120', + department: 'Desarrollo', + position: 'Ingeniero de Software', + satJobRiskId: '1', + satPaymentPeriodicityId: '04', + satBankId: '002', + bankAccount: '1111111111', + baseSalaryForContributions: 490.22, + integratedDailySalary: 146.47, + satPayrollStateId: 'JAL' + } + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'O', + paymentDate: '2023-05-24T00:00:00', + initialPaymentDate: '2023-05-09T00:00:00', + finalPaymentDate: '2023-05-24T00:00:00', + daysPaid: 15, + earnings: { + earnings: [ + { earningTypeCode: '001', code: '00500', concept: 'Sueldos, Salarios Rayas y Jornales', taxedAmount: 2808.8, exemptAmount: 2191.2 }, + { + earningTypeCode: '019', + code: '00100', + concept: 'Horas Extra', + taxedAmount: 50.00, + exemptAmount: 50.00, + overtime: [ + { days: 1, hoursTypeCode: '01', extraHours: 2, amountPaid: 100.00 } + ] + } + ], + otherPayments: [] + }, + deductions: [ + { deductionTypeCode: '001', code: '00301', concept: 'Seguridad Social', amount: 200 }, + { deductionTypeCode: '002', code: '00302', concept: 'ISR', amount: 100 } + ] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 5. NOMINA CON INCAPACIDADES (Facturación por valores) +// ============================================================================ +async function nominaConIncapacidadesByValues(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Con Incapacidades ByValues ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + tin: 'EKU9003173C9', + legalName: 'ESCUELA KEMPER URGATE', + taxRegimeCode: '601', + employerData: { + employerRegistration: 'B5510768108', + originEmployerTin: 'URE180429TM6' + }, + taxCredentials: [ + { base64File: escuelaKemperUrgateBase64Cer, fileType: 0, password }, + { base64File: escuelaKemperUrgateBase64Key, fileType: 1, password } + ] + }, + recipient: { + tin: 'XOJI740919U48', + legalName: 'INGRID XODAR JIMENEZ', + zipCode: '76028', + taxRegimeCode: '605', + cfdiUseCode: 'CN01', + employeeData: { + curp: 'XEXX010101HNEXXXA4', + socialSecurityNumber: '000000', + laborRelationStartDate: '2015-01-01T00:00:00', + seniority: 'P437W', + satContractTypeId: '01', + satWorkdayTypeId: '01', + satTaxRegimeTypeId: '03', + employeeNumber: '120', + department: 'Desarrollo', + position: 'Ingeniero de Software', + satJobRiskId: '1', + satPaymentPeriodicityId: '04', + satBankId: '002', + bankAccount: '1111111111', + baseSalaryForContributions: 490.22, + integratedDailySalary: 146.47, + satPayrollStateId: 'JAL' + } + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'O', + paymentDate: '2023-05-24T00:00:00', + initialPaymentDate: '2023-05-09T00:00:00', + finalPaymentDate: '2023-05-24T00:00:00', + daysPaid: 15, + earnings: { + earnings: [ + { earningTypeCode: '001', code: '00500', concept: 'Sueldos, Salarios Rayas y Jornales', taxedAmount: 2808.8, exemptAmount: 2191.2 } + ] + }, + deductions: [ + { deductionTypeCode: '001', code: '00301', concept: 'Seguridad Social', amount: 200 }, + { deductionTypeCode: '002', code: '00302', concept: 'ISR', amount: 100 } + ], + disabilities: [ + { disabilityDays: 1, disabilityTypeCode: '01' } + ] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 6. NOMINA CON SNCF (Facturación por valores) +// ============================================================================ +async function nominaConSNCFByValues(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Con SNCF ByValues ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '39074', + exportCode: '01', + issuer: { + tin: 'OÑO120726RX3', + legalName: 'ORGANICOS ÑAVEZ OSORIO', + taxRegimeCode: '601', + employerData: { + employerRegistration: '27112029', + satFundSourceId: 'IP' + }, + taxCredentials: [ + { base64File: organicosNavezOsorioBase64Cer, fileType: 0, password }, + { base64File: organicosNavezOsorioBase64Key, fileType: 1, password } + ] + }, + recipient: { + tin: 'CACX7605101P8', + legalName: 'XOCHILT CASAS CHAVEZ', + zipCode: '36257', + taxRegimeCode: '605', + cfdiUseCode: 'CN01', + employeeData: { + curp: 'XEXX010101HNEXXXA4', + socialSecurityNumber: '80997742673', + laborRelationStartDate: '2021-09-01', + seniority: 'P88W', + satContractTypeId: '01', + satTaxRegimeTypeId: '02', + employeeNumber: '273', + satJobRiskId: '1', + satPaymentPeriodicityId: '04', + integratedDailySalary: 221.48, + satPayrollStateId: 'GRO' + } + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'O', + paymentDate: '2023-05-16T00:00:00', + initialPaymentDate: '2023-05-01T00:00:00', + finalPaymentDate: '2023-05-16T00:00:00', + daysPaid: 15, + earnings: { + earnings: [ + { earningTypeCode: '001', code: 'P001', concept: 'Sueldos, Salarios Rayas y Jornales', taxedAmount: 3322.20, exemptAmount: 0.00 }, + { earningTypeCode: '038', code: 'P540', concept: 'Compensacion', taxedAmount: 100.00, exemptAmount: 0.00 }, + { earningTypeCode: '038', code: 'P550', concept: 'Compensación Garantizada Extraordinaria', taxedAmount: 2200.00, exemptAmount: 0.00 }, + { earningTypeCode: '038', code: 'P530', concept: 'Servicio Extraordinario', taxedAmount: 200.00, exemptAmount: 0.00 }, + { earningTypeCode: '001', code: 'P506', concept: 'Otras Prestaciones', taxedAmount: 1500.00, exemptAmount: 0.00 }, + { earningTypeCode: '001', code: 'P505', concept: 'Remuneración al Desempeño Legislativo', taxedAmount: 17500.00, exemptAmount: 0.00 } + ], + otherPayments: [ + { otherPaymentTypeCode: '002', code: 'o002', concept: 'Subsidio para el empleo efectivamente entregado al trabajador', amount: 0.00, subsidyCaused: 0.00 } + ] + }, + deductions: [ + { deductionTypeCode: '002', code: 'D002', concept: 'ISR', amount: 4716.61 }, + { deductionTypeCode: '004', code: 'D525', concept: 'Redondeo', amount: 0.81 }, + { deductionTypeCode: '001', code: 'D510', concept: 'Cuota Trabajador ISSSTE', amount: 126.78 } + ] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 7. NOMINA EXTRAORDINARIA - AGUINALDO (Facturación por valores) +// ============================================================================ +async function nominaExtraordinariaByValues(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Extraordinaria (Aguinaldo) ByValues ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + tin: 'EKU9003173C9', + legalName: 'ESCUELA KEMPER URGATE', + taxRegimeCode: '601', + employerData: { + employerRegistration: 'B5510768108', + originEmployerTin: 'URE180429TM6' + }, + taxCredentials: [ + { base64File: escuelaKemperUrgateBase64Cer, fileType: 0, password }, + { base64File: escuelaKemperUrgateBase64Key, fileType: 1, password } + ] + }, + recipient: { + tin: 'XOJI740919U48', + legalName: 'INGRID XODAR JIMENEZ', + zipCode: '76028', + taxRegimeCode: '605', + cfdiUseCode: 'CN01', + employeeData: { + curp: 'XEXX010101HNEXXXA4', + socialSecurityNumber: '000000', + laborRelationStartDate: '2015-01-01', + seniority: 'P439W', + satContractTypeId: '01', + satWorkdayTypeId: '01', + satTaxRegimeTypeId: '03', + employeeNumber: '120', + department: 'Desarrollo', + position: 'Ingeniero de Software', + satJobRiskId: '1', + satPaymentPeriodicityId: '99', + satBankId: '002', + bankAccount: '1111111111', + integratedDailySalary: 146.47, + satPayrollStateId: 'JAL' + } + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'E', + paymentDate: '2023-06-04T00:00:00', + initialPaymentDate: '2023-06-04T00:00:00', + finalPaymentDate: '2023-06-04T00:00:00', + daysPaid: 30, + earnings: { + earnings: [ + { earningTypeCode: '002', code: '00500', concept: 'Gratificación Anual (Aguinaldo)', taxedAmount: 0.00, exemptAmount: 10000.00 } + ], + otherPayments: [] + }, + deductions: [] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 8. NOMINA SEPARACION INDEMNIZACION (Facturación por valores) +// ============================================================================ +async function nominaSeparacionIndemnizacionByValues(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Separación Indemnización ByValues ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + tin: 'EKU9003173C9', + legalName: 'ESCUELA KEMPER URGATE', + taxRegimeCode: '601', + employerData: { + employerRegistration: 'B5510768108', + originEmployerTin: 'URE180429TM6' + }, + taxCredentials: [ + { base64File: escuelaKemperUrgateBase64Cer, fileType: 0, password }, + { base64File: escuelaKemperUrgateBase64Key, fileType: 1, password } + ] + }, + recipient: { + tin: 'XOJI740919U48', + legalName: 'INGRID XODAR JIMENEZ', + zipCode: '76028', + taxRegimeCode: '605', + cfdiUseCode: 'CN01', + employeeData: { + curp: 'XEXX010101HNEXXXA4', + socialSecurityNumber: '000000', + laborRelationStartDate: '2015-01-01', + seniority: 'P439W', + satContractTypeId: '01', + satWorkdayTypeId: '01', + satTaxRegimeTypeId: '03', + employeeNumber: '120', + department: 'Desarrollo', + position: 'Ingeniero de Software', + satJobRiskId: '1', + satPaymentPeriodicityId: '99', + satBankId: '002', + bankAccount: '1111111111', + integratedDailySalary: 146.47, + satPayrollStateId: 'JAL' + } + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'E', + paymentDate: '2023-06-04T00:00:00', + initialPaymentDate: '2023-05-05T00:00:00', + finalPaymentDate: '2023-06-04T00:00:00', + daysPaid: 30, + earnings: { + earnings: [ + { earningTypeCode: '023', code: '00500', concept: 'Pagos por separación', taxedAmount: 0.00, exemptAmount: 10000.00 }, + { earningTypeCode: '025', code: '00900', concept: 'Indemnizaciones', taxedAmount: 0.00, exemptAmount: 500.00 } + ], + otherPayments: [], + severance: { + totalPaid: 10500.00, + yearsOfService: 1, + lastMonthlySalary: 10000.00, + accumulableIncome: 10000.00, + nonAccumulableIncome: 0.00 + } + }, + deductions: [] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 9. NOMINA JUBILACION PENSION RETIRO (Facturación por valores) +// ============================================================================ +async function nominaJubilacionPensionRetiroByValues(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Jubilación Pensión Retiro ByValues ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + tin: 'EKU9003173C9', + legalName: 'ESCUELA KEMPER URGATE', + taxRegimeCode: '601', + employerData: { + employerRegistration: 'B5510768108', + originEmployerTin: 'URE180429TM6' + }, + taxCredentials: [ + { base64File: escuelaKemperUrgateBase64Cer, fileType: 0, password }, + { base64File: escuelaKemperUrgateBase64Key, fileType: 1, password } + ] + }, + recipient: { + tin: 'XOJI740919U48', + legalName: 'INGRID XODAR JIMENEZ', + zipCode: '76028', + taxRegimeCode: '605', + cfdiUseCode: 'CN01', + employeeData: { + curp: 'XEXX010101HNEXXXA4', + socialSecurityNumber: '000000', + laborRelationStartDate: '2015-01-01', + seniority: 'P439W', + satContractTypeId: '01', + satWorkdayTypeId: '01', + satTaxRegimeTypeId: '03', + employeeNumber: '120', + department: 'Desarrollo', + position: 'Ingeniero de Software', + satJobRiskId: '1', + satPaymentPeriodicityId: '99', + satBankId: '002', + bankAccount: '1111111111', + integratedDailySalary: 146.47, + satPayrollStateId: 'JAL' + } + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'E', + paymentDate: '2023-05-05T00:00:00', + initialPaymentDate: '2023-06-04T00:00:00', + finalPaymentDate: '2023-06-04T00:00:00', + daysPaid: 30, + earnings: { + earnings: [ + { earningTypeCode: '039', code: '00500', concept: 'Jubilaciones, pensiones o haberes de retiro', taxedAmount: 0.00, exemptAmount: 10000.00 } + ], + retirement: { + totalOneTime: 10000.00, + accumulableIncome: 10000.00, + nonAccumulableIncome: 0.00 + } + }, + deductions: [] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 10. NOMINA SIN DEDUCCIONES (Facturación por valores) +// ============================================================================ +async function nominaSinDeduccionesByValues(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Sin Deducciones ByValues ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + tin: 'EKU9003173C9', + legalName: 'ESCUELA KEMPER URGATE', + taxRegimeCode: '601', + employerData: { + employerRegistration: 'B5510768108', + originEmployerTin: 'URE180429TM6' + }, + taxCredentials: [ + { base64File: escuelaKemperUrgateBase64Cer, fileType: 0, password }, + { base64File: escuelaKemperUrgateBase64Key, fileType: 1, password } + ] + }, + recipient: { + tin: 'XOJI740919U48', + legalName: 'INGRID XODAR JIMENEZ', + zipCode: '76028', + taxRegimeCode: '605', + cfdiUseCode: 'CN01', + employeeData: { + curp: 'XEXX010101HNEXXXA4', + socialSecurityNumber: '000000', + laborRelationStartDate: '2015-01-01', + seniority: 'P437W', + satContractTypeId: '01', + satWorkdayTypeId: '01', + satTaxRegimeTypeId: '03', + employeeNumber: '120', + department: 'Desarrollo', + position: 'Ingeniero de Software', + satJobRiskId: '1', + satPaymentPeriodicityId: '04', + satBankId: '002', + bankAccount: '1111111111', + baseSalaryForContributions: 490.22, + integratedDailySalary: 146.47, + satPayrollStateId: 'JAL' + } + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'O', + paymentDate: '2023-05-24T00:00:00', + initialPaymentDate: '2023-05-09T00:00:00', + finalPaymentDate: '2023-05-24T00:00:00', + daysPaid: 15, + earnings: { + earnings: [ + { earningTypeCode: '001', code: '00500', concept: 'Sueldos, Salarios Rayas y Jornales', taxedAmount: 2808.8, exemptAmount: 2191.2 } + ], + otherPayments: [] + }, + deductions: [] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 11. NOMINA SUBSIDIO CAUSADO (Facturación por valores) +// ============================================================================ +async function nominaSubsidioCausadoByValues(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Subsidio Causado ByValues ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + tin: 'EKU9003173C9', + legalName: 'ESCUELA KEMPER URGATE', + taxRegimeCode: '601', + employerData: { + employerRegistration: 'B5510768108', + originEmployerTin: 'URE180429TM6' + }, + taxCredentials: [ + { base64File: escuelaKemperUrgateBase64Cer, fileType: 0, password }, + { base64File: escuelaKemperUrgateBase64Key, fileType: 1, password } + ] + }, + recipient: { + tin: 'XOJI740919U48', + legalName: 'INGRID XODAR JIMENEZ', + zipCode: '76028', + taxRegimeCode: '605', + cfdiUseCode: 'CN01', + employeeData: { + curp: 'XEXX010101HNEXXXA4', + socialSecurityNumber: '000000', + laborRelationStartDate: '2015-01-01T00:00:00', + seniority: 'P437W', + satContractTypeId: '01', + satWorkdayTypeId: '01', + satTaxRegimeTypeId: '02', + employeeNumber: '120', + department: 'Desarrollo', + position: 'Ingeniero de Software', + satJobRiskId: '1', + satPaymentPeriodicityId: '04', + satBankId: '002', + bankAccount: '1111111111', + baseSalaryForContributions: 490.22, + integratedDailySalary: 146.47, + satPayrollStateId: 'JAL' + } + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'O', + paymentDate: '2023-05-24T00:00:00', + initialPaymentDate: '2023-05-09T00:00:00', + finalPaymentDate: '2023-05-24T00:00:00', + daysPaid: 15, + earnings: { + earnings: [ + { earningTypeCode: '001', code: '00500', concept: 'Sueldos, Salarios Rayas y Jornales', taxedAmount: 2808.8, exemptAmount: 2191.2 } + ], + otherPayments: [ + { otherPaymentTypeCode: '007', code: '0002', concept: 'ISR ajustado por subsidio', amount: 145.80, subsidyCaused: 0.0 } + ] + }, + deductions: [ + { deductionTypeCode: '107', code: 'D002', concept: 'Ajuste al Subsidio Causado', amount: 160.35 }, + { deductionTypeCode: '002', code: 'D002', concept: 'ISR', amount: 145.80 } + ] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 12. NOMINA VIATICOS (Facturación por valores) +// ============================================================================ +async function nominaViaticosByValues(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Viáticos ByValues ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + tin: 'EKU9003173C9', + legalName: 'ESCUELA KEMPER URGATE', + taxRegimeCode: '601', + employerData: { + employerRegistration: 'B5510768108', + originEmployerTin: 'URE180429TM6' + }, + taxCredentials: [ + { base64File: escuelaKemperUrgateBase64Cer, fileType: 0, password }, + { base64File: escuelaKemperUrgateBase64Key, fileType: 1, password } + ] + }, + recipient: { + tin: 'XOJI740919U48', + legalName: 'INGRID XODAR JIMENEZ', + zipCode: '76028', + taxRegimeCode: '605', + cfdiUseCode: 'CN01', + employeeData: { + curp: 'XEXX010101HNEXXXA4', + socialSecurityNumber: '000000', + laborRelationStartDate: '2015-01-01T00:00:00', + seniority: 'P438W', + satContractTypeId: '01', + satWorkdayTypeId: '01', + satTaxRegimeTypeId: '03', + employeeNumber: '120', + department: 'Desarrollo', + position: 'Ingeniero de Software', + satJobRiskId: '1', + satPaymentPeriodicityId: '04', + satBankId: '002', + bankAccount: '1111111111', + baseSalaryForContributions: 490.22, + integratedDailySalary: 146.47, + satPayrollStateId: 'JAL' + } + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'O', + paymentDate: '2023-09-26T00:00:00', + initialPaymentDate: '2023-09-11T00:00:00', + finalPaymentDate: '2023-09-26T00:00:00', + daysPaid: 15, + earnings: { + earnings: [ + { earningTypeCode: '050', code: '050', concept: 'Viaticos', taxedAmount: 0, exemptAmount: 3000 } + ] + }, + deductions: [ + { deductionTypeCode: '081', code: '081', concept: 'Ajuste en viaticos entregados al trabajador', amount: 3000 } + ] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 13. NOMINA GENERAL (Facturación por valores) +// ============================================================================ +async function nominaGeneralByValues(client: FiscalapiClient): Promise { + console.log('\n=== Nómina General ByValues ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + tin: 'EKU9003173C9', + legalName: 'ESCUELA KEMPER URGATE', + taxRegimeCode: '601', + employerData: { + employerRegistration: 'B5510768108', + originEmployerTin: 'URE180429TM6' + }, + taxCredentials: [ + { base64File: escuelaKemperUrgateBase64Cer, fileType: 0, password }, + { base64File: escuelaKemperUrgateBase64Key, fileType: 1, password } + ] + }, + recipient: { + tin: 'XOJI740919U48', + legalName: 'INGRID XODAR JIMENEZ', + zipCode: '76028', + taxRegimeCode: '605', + cfdiUseCode: 'CN01', + employeeData: { + curp: 'XEXX010101HNEXXXA4', + socialSecurityNumber: '000000', + laborRelationStartDate: '2015-01-01T00:00:00', + seniority: 'P437W', + satContractTypeId: '01', + satWorkdayTypeId: '01', + satTaxRegimeTypeId: '03', + employeeNumber: '120', + department: 'Desarrollo', + position: 'Ingeniero de Software', + satJobRiskId: '1', + satPaymentPeriodicityId: '04', + satBankId: '002', + bankAccount: '1111111111', + baseSalaryForContributions: 490.22, + integratedDailySalary: 146.47, + satPayrollStateId: 'JAL' + } + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'O', + paymentDate: '2023-05-24T00:00:00', + initialPaymentDate: '2023-05-09T00:00:00', + finalPaymentDate: '2023-05-24T00:00:00', + daysPaid: 15, + earnings: { + earnings: [ + { earningTypeCode: '001', code: '00500', concept: 'Sueldos, Salarios Rayas y Jornales', taxedAmount: 2808.8, exemptAmount: 2191.2 } + ], + otherPayments: [] + }, + deductions: [ + { deductionTypeCode: '001', code: '00301', concept: 'Seguridad Social', amount: 200 }, + { deductionTypeCode: '002', code: '00302', concept: 'ISR', amount: 100 } + ] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// FUNCION PRINCIPAL +// ============================================================================ +async function main(): Promise { + console.log('=== Ejemplos de Factura Nómina FiscalAPI ===\n'); + + const client = FiscalapiClient.create(settings); + + try { + // Descomentar el caso de uso que se desea ejecutar + + // await nominaOrdinariaByValues(client); + // await nominaAsimiladosByValues(client); + // await nominaConBonosFondoAhorroByValues(client); + // await nominaConHorasExtraByValues(client); + // await nominaConIncapacidadesByValues(client); + await nominaConSNCFByValues(client); + // await nominaExtraordinariaByValues(client); + // await nominaSeparacionIndemnizacionByValues(client); + // await nominaJubilacionPensionRetiroByValues(client); + // await nominaSinDeduccionesByValues(client); + // await nominaSubsidioCausadoByValues(client); + // await nominaViaticosByValues(client); + await nominaGeneralByValues(client); + + console.log('\nEjecución completada.'); + } catch (error) { + console.error('Error:', error); + } +} + +// Ejecutar función principal +main(); diff --git a/payroll-invoice-requrements.md b/payroll-invoice-requrements.md index 174b4c9..2d90159 100644 --- a/payroll-invoice-requrements.md +++ b/payroll-invoice-requrements.md @@ -691,14 +691,38 @@ Implememt following changes as follows: - Change invoice enpoint to the unified version for all methods - Update the invoice request model to the unified version - creare a new file named ejemplos-factura-nomina.ts con una funcion para cada caso de uso un comentario y -un una funcion principal para que invoque todas las funciones de los casos de uso. +un una funcion principal para que invoque todas las funciones de los casos de uso, asegurate de agregar el sufijo 'ByValues' al nombre del metodo, todos estos metodos son por valores, signifca que todo los datos se pasan en la peticion http. + + // ============================================================================ + // 1. NOMINA ORDINARIA (Facturación por valores) + // ============================================================================ + nominaOrdinariaByValues(){ + //implementation + } + +- Use this names for the models and make sure the any complement is property modeled. becarefull with payment complement that alrredy exist, only need to be moved from invoice.payments?: InvoicePayment[]; to Complement.PaymentComplement: +Models names to use. +* Invoice +* Complement +* Complement.LocalTaxesComplement (Invoice.complement.localTaxes) +* Complement.LocalTaxesComplement.LocalTax +* Complement.PaymentComplement (Invoice.complement.payments) +* Complement.PaymentComplement.PaidInvoice +* Complement.PaymentComplement.PaidInvoice.PaidInvoiceTax +* Complement.PayrollComplement (Invoice.complement.payroll) +* Complement.PayrollComplement.Earnings +* Complement.PayrollComplement.Earnings.Earning +* Complement.PayrollComplement.Earnings.Earning.StockOptions +* Complement.PayrollComplement.Earnings.Earning.Overtime +* Complement.PayrollComplement.Earnings.OtherPayment +* Complement.PayrollComplement.Earnings.OtherPayment.BalanceCompensation +* Complement.PayrollComplement.Earnings.Retirement +* Complement.PayrollComplement.Earnings.Severance +* Complement.PayrollComplement.Deduction +* Complement.PayrollComplement.Disability +* Complement.LadingComplement (Invoice.Complement.landing) +- Make sure all existing models are updated or new models are acreated. -# ============================================================================ -# 1. NOMINA ORDINARIA (Facturación por valores) -# ============================================================================ -nominaOrdinariaByValues(){ - //implementation -} ## Unified Invoice Endpoint and model diff --git a/src/index.ts b/src/index.ts index d1d13cf..5847458 100644 --- a/src/index.ts +++ b/src/index.ts @@ -37,7 +37,7 @@ export type { GlobalInformation, RelatedInvoice, InvoiceResponse, - //Payments + // Payments (legacy) InvoicePayment, PaidInvoice, PaidInvoiceTax, @@ -47,7 +47,28 @@ export type { SendInvoiceRequest, InvoiceStatusRequest, InvoiceStatusResponse, - + // Inline data types for payroll (ByValues) + InvoiceIssuerEmployerData, + InvoiceRecipientEmployeeData, + // Complement types + Complement, + LocalTaxesComplement, + LocalTax, + PaymentComplement, + PaymentPaidInvoice, + PaymentPaidInvoiceTax, + PayrollComplement, + PayrollEarnings, + PayrollEarning, + PayrollStockOptions, + PayrollOvertime, + PayrollOtherPayment, + PayrollBalanceCompensation, + PayrollRetirement, + PayrollSeverance, + PayrollDeduction, + PayrollDisability, + LadingComplement, } from './models/invoice'; export type { diff --git a/src/models/invoice.ts b/src/models/invoice.ts index 878e466..d4f9d9c 100644 --- a/src/models/invoice.ts +++ b/src/models/invoice.ts @@ -1,8 +1,467 @@ import { DateTime } from 'luxon'; - + // src/models/invoice.ts import { BaseDto } from '../common/base-dto'; +// ============================================================================ +// Inline Data Types for Payroll (ByValues) +// ============================================================================ + +/** + * Datos del empleador para facturas de nómina (inline en issuer) + */ +export interface InvoiceIssuerEmployerData { + /** CURP del empleador */ + curp?: string; + + /** Registro patronal del empleador */ + employerRegistration?: string; + + /** RFC del empleador origen (para subcontratación) */ + originEmployerTin?: string; + + /** ID del origen de los recursos (catálogo SAT c_OrigenRecurso) */ + satFundSourceId?: string; + + /** Monto de recursos propios */ + ownResourceAmount?: number; +} + +/** + * Datos del empleado para facturas de nómina (inline en recipient) + */ +export interface InvoiceRecipientEmployeeData { + /** CURP del empleado */ + curp?: string; + + /** Número de seguridad social del empleado */ + socialSecurityNumber?: string; + + /** Fecha de inicio de la relación laboral */ + laborRelationStartDate?: string; + + /** Antigüedad del empleado en formato ISO 8601 duration (ej: P1Y5M15D) */ + seniority?: string; + + /** ID del tipo de contrato (catálogo SAT c_TipoContrato) */ + satContractTypeId?: string; + + /** ID del estatus de sindicalización (catálogo SAT c_TipoSindicalizado) */ + satUnionizedStatusId?: string; + + /** ID del tipo de jornada laboral (catálogo SAT c_TipoJornada) */ + satWorkdayTypeId?: string; + + /** ID del tipo de régimen fiscal del empleado (catálogo SAT c_TipoRegimen) */ + satTaxRegimeTypeId?: string; + + /** Número de empleado */ + employeeNumber?: string; + + /** Departamento del empleado */ + department?: string; + + /** Puesto del empleado */ + position?: string; + + /** ID del riesgo del puesto (catálogo SAT c_RiesgosPuesto) */ + satJobRiskId?: string; + + /** ID de la periodicidad de pago (catálogo SAT c_PeriodicidadPago) */ + satPaymentPeriodicityId?: string; + + /** ID del banco (catálogo SAT c_Banco) */ + satBankId?: string; + + /** Cuenta bancaria del empleado */ + bankAccount?: string; + + /** Salario base de cotización */ + baseSalaryForContributions?: number; + + /** Salario diario integrado */ + integratedDailySalary?: number; + + /** ID del estado donde se presta el servicio (catálogo SAT c_Estado) */ + satPayrollStateId?: string; +} + +// ============================================================================ +// Complement Types +// ============================================================================ + +/** + * Contenedor principal de complementos de factura + */ +export interface Complement { + /** Complemento de impuestos locales */ + localTaxes?: LocalTaxesComplement; + + /** Complemento de pago */ + payment?: PaymentComplement; + + /** Complemento de nómina */ + payroll?: PayrollComplement; + + /** Complemento de carta porte */ + lading?: LadingComplement; +} + +// ============================================================================ +// Local Taxes Complement +// ============================================================================ + +/** + * Complemento de impuestos locales + */ +export interface LocalTaxesComplement { + /** Lista de impuestos locales */ + taxes?: LocalTax[]; +} + +/** + * Impuesto local + */ +export interface LocalTax { + /** Nombre del impuesto local */ + taxName?: string; + + /** Tasa del impuesto local */ + taxRate?: number; + + /** Monto del impuesto local */ + taxAmount?: number; + + /** Código que indica la naturaleza del impuesto. "T": Traslado, "R": Retenido */ + taxFlagCode?: string; +} + +// ============================================================================ +// Payment Complement +// ============================================================================ + +/** + * Complemento de pago + */ +export interface PaymentComplement { + /** Fecha de pago. Se expresa en la forma AAAA-MM-DDThh:mm:ss */ + paymentDate: string; + + /** Código de la forma de pago del pago recibido. Catálogo del SAT c_FormaPago */ + paymentFormCode: string; + + /** Código de la moneda utilizada en el pago. Catálogo del SAT c_Moneda. Default: "MXN" */ + currencyCode: string; + + /** Tipo de cambio FIX conforme a la moneda registrada en la factura. Default: 1 */ + exchangeRate?: number | string; + + /** Monto del pago */ + amount: number | string; + + /** Número de operación asignado por el banco */ + operationNumber?: string; + + /** RFC del banco origen. (Rfc del banco emisor del pago) */ + sourceBankTin?: string; + + /** Cuenta bancaria origen. (Cuenta bancaria del banco emisor del pago) */ + sourceBankAccount?: string; + + /** RFC del banco destino. (Rfc del banco receptor del pago) */ + targetBankTin?: string; + + /** Cuenta bancaria destino (Cuenta bancaria del banco receptor del pago) */ + targetBankAccount?: string; + + /** Facturas pagadas con el pago recibido */ + paidInvoices: PaymentPaidInvoice[]; +} + +/** + * Factura pagada en el complemento de pago + */ +export interface PaymentPaidInvoice { + /** UUID de la factura pagada */ + uuid: string; + + /** Serie de la factura pagada */ + series: string; + + /** Folio de la factura pagada */ + number: string; + + /** Monto pagado en la factura */ + paymentAmount: number | string; + + /** Código de la moneda utilizada en la factura pagada. Default: "MXN" */ + currencyCode: string; + + /** Número de parcialidad */ + partialityNumber: number; + + /** Subtotal de la factura pagada */ + subTotal: number | string; + + /** Saldo anterior de la factura pagada */ + previousBalance: number | string; + + /** Saldo restante de la factura pagada */ + remainingBalance: number | string; + + /** Código de obligaciones de impuesto aplicables a la factura pagada */ + taxObjectCode: string; + + /** Equivalencia de la moneda. Default: 1 */ + equivalence?: number | string; + + /** Impuestos aplicables a la factura pagada */ + paidInvoiceTaxes?: PaymentPaidInvoiceTax[]; +} + +/** + * Impuesto de factura pagada en el complemento de pago + */ +export interface PaymentPaidInvoiceTax { + /** Código del impuesto. Catálogo del SAT c_Impuesto */ + taxCode: string; + + /** Tipo de factor. Catálogo del SAT c_TipoFactor */ + taxTypeCode: string; + + /** Tasa del impuesto. Catálogo del SAT c_TasaOCuota */ + taxRate: number | string; + + /** Código que indica la naturaleza del impuesto. "T": Impuesto Traslado, "R": Impuesto Retenido */ + taxFlagCode: string; +} + +// ============================================================================ +// Payroll Complement +// ============================================================================ + +/** + * Complemento de nómina + */ +export interface PayrollComplement { + /** Versión del complemento de nómina. Default: "1.2" */ + version?: string; + + /** Código del tipo de nómina. "O": Ordinaria, "E": Extraordinaria */ + payrollTypeCode: string; + + /** Fecha de pago de la nómina */ + paymentDate: string; + + /** Fecha inicial del periodo de pago */ + initialPaymentDate: string; + + /** Fecha final del periodo de pago */ + finalPaymentDate: string; + + /** Número de días pagados */ + daysPaid: number; + + /** Percepciones del empleado */ + earnings?: PayrollEarnings; + + /** Deducciones del empleado */ + deductions?: PayrollDeduction[]; + + /** Incapacidades del empleado */ + disabilities?: PayrollDisability[]; +} + +/** + * Contenedor de percepciones de nómina + */ +export interface PayrollEarnings { + /** Lista de percepciones */ + earnings?: PayrollEarning[]; + + /** Lista de otros pagos */ + otherPayments?: PayrollOtherPayment[]; + + /** Información de jubilación, pensión o retiro */ + retirement?: PayrollRetirement; + + /** Información de separación o indemnización */ + severance?: PayrollSeverance; +} + +/** + * Percepción de nómina + */ +export interface PayrollEarning { + /** Código del tipo de percepción. Catálogo SAT c_TipoPercepcion */ + earningTypeCode: string; + + /** Clave de control interno de la percepción */ + code: string; + + /** Concepto de la percepción */ + concept: string; + + /** Monto gravado de la percepción */ + taxedAmount: number; + + /** Monto exento de la percepción */ + exemptAmount: number; + + /** Horas extra trabajadas */ + overtime?: PayrollOvertime[]; + + /** Opciones de acciones */ + stockOptions?: PayrollStockOptions; +} + +/** + * Opciones de acciones en percepción + */ +export interface PayrollStockOptions { + /** Precio de mercado de la acción */ + marketPrice: number; + + /** Precio de ejercicio de la acción */ + grantPrice: number; +} + +/** + * Horas extra en percepción + */ +export interface PayrollOvertime { + /** Número de días con horas extra */ + days: number; + + /** Código del tipo de horas. "01": Dobles, "02": Triples */ + hoursTypeCode: string; + + /** Número de horas extra trabajadas */ + extraHours: number; + + /** Monto pagado por las horas extra */ + amountPaid: number; +} + +/** + * Otros pagos de nómina + */ +export interface PayrollOtherPayment { + /** Código del tipo de otro pago. Catálogo SAT c_TipoOtroPago */ + otherPaymentTypeCode: string; + + /** Clave de control interno del otro pago */ + code: string; + + /** Concepto del otro pago */ + concept: string; + + /** Monto del otro pago */ + amount: number; + + /** Subsidio causado (para tipo 002) */ + subsidyCaused?: number; + + /** Compensación de saldos a favor */ + balanceCompensation?: PayrollBalanceCompensation; +} + +/** + * Compensación de saldos a favor en otros pagos + */ +export interface PayrollBalanceCompensation { + /** Saldo a favor */ + favorableBalance: number; + + /** Año del saldo a favor */ + year: number; + + /** Saldo a favor remanente */ + remainingFavorableBalance: number; +} + +/** + * Información de jubilación, pensión o retiro + */ +export interface PayrollRetirement { + /** Total de pago único */ + totalOneTime?: number; + + /** Total de parcialidades */ + totalInstallments?: number; + + /** Monto diario */ + dailyAmount?: number; + + /** Ingreso acumulable */ + accumulableIncome?: number; + + /** Ingreso no acumulable */ + nonAccumulableIncome?: number; +} + +/** + * Información de separación o indemnización + */ +export interface PayrollSeverance { + /** Total pagado */ + totalPaid: number; + + /** Años de servicio */ + yearsOfService: number; + + /** Último sueldo mensual ordinario */ + lastMonthlySalary: number; + + /** Ingreso acumulable */ + accumulableIncome: number; + + /** Ingreso no acumulable */ + nonAccumulableIncome: number; +} + +/** + * Deducción de nómina + */ +export interface PayrollDeduction { + /** Código del tipo de deducción. Catálogo SAT c_TipoDeduccion */ + deductionTypeCode: string; + + /** Clave de control interno de la deducción */ + code: string; + + /** Concepto de la deducción */ + concept: string; + + /** Monto de la deducción */ + amount: number; +} + +/** + * Incapacidad de nómina + */ +export interface PayrollDisability { + /** Número de días de incapacidad */ + disabilityDays: number; + + /** Código del tipo de incapacidad. Catálogo SAT c_TipoIncapacidad */ + disabilityTypeCode: string; + + /** Monto monetario de la incapacidad */ + monetaryAmount?: number; +} + +// ============================================================================ +// Lading Complement (Carta Porte) +// ============================================================================ + +/** + * Complemento de carta porte (placeholder para futura implementación) + */ +export interface LadingComplement { + // Carta Porte complement - to be implemented +} + /** * Modelo factura * Contiene toda la información de una factura, como datos del emisor, receptor, @@ -72,9 +531,15 @@ export interface Invoice extends BaseDto { /** Facturas relacionadas */ relatedInvoices?: RelatedInvoice[]; - /** Pago o pagos recibidos para liquidar parcial o totalmente una factura de ingreso emitida previamente */ + /** + * Pago o pagos recibidos para liquidar parcial o totalmente una factura de ingreso emitida previamente + * @deprecated Use complement.payment instead + */ payments?: InvoicePayment[]; + /** Complementos de la factura (nómina, pago, impuestos locales, carta porte) */ + complement?: Complement; + /** Respuesta del SAT. Contiene la información del timbrado. (Sólo lectura) */ responses?: InvoiceResponse[]; } @@ -95,6 +560,9 @@ export interface InvoiceIssuer { /** Código del régimen fiscal del emisor. Catálogo del SAT c_RegimenFiscal */ taxRegimeCode?: string; + /** Datos del empleador para facturas de nómina (inline, modo ByValues) */ + employerData?: InvoiceIssuerEmployerData; + /** Sellos del emisor (archivos .cer y .key) */ taxCredentials?: TaxCredential[]; } @@ -137,6 +605,9 @@ export interface InvoiceRecipient { /** Correo electrónico del receptor. Para enviar la factura desde el dasborard */ email?: string; + + /** Datos del empleado para facturas de nómina (inline, modo ByValues) */ + employeeData?: InvoiceRecipientEmployeeData; } /** diff --git a/src/services/invoice-service.ts b/src/services/invoice-service.ts index 3922ba8..9006227 100644 --- a/src/services/invoice-service.ts +++ b/src/services/invoice-service.ts @@ -17,9 +17,6 @@ import { * Implementación del servicio de facturas */ export class InvoiceService extends BaseFiscalapiService implements IInvoiceService { - private readonly INCOME_ENDPOINT = 'income'; - private readonly CREDIT_NOTE_ENDPOINT = 'credit-note'; - private readonly PAYMENT_ENDPOINT = 'payment'; /** * Crea una nueva instancia del servicio de facturas @@ -30,37 +27,6 @@ export class InvoiceService extends BaseFiscalapiService implements IIn super(httpClient, 'invoices', apiVersion); } - /** - * @inheritdoc - */ - override async create(requestModel: Invoice): Promise> { - if (!requestModel) { - throw new Error('requestModel cannot be null'); - } - - let endpoint: string; - - switch (requestModel.typeCode) { - case 'I': - endpoint = this.INCOME_ENDPOINT; - break; - case 'E': - endpoint = this.CREDIT_NOTE_ENDPOINT; - break; - case 'P': - endpoint = this.PAYMENT_ENDPOINT; - break; - default: - throw new Error(`Unsupported invoice type: ${requestModel.typeCode}`); - } - - return await this.executeRequest({ - path: endpoint, - data: requestModel, - method: 'POST', - }); - } - /** * Cancela una factura * @param {CancelInvoiceRequest} request - Solicitud para cancelar factura diff --git a/tsconfig.json b/tsconfig.json index 7fa0dfa..165d94c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,5 +3,12 @@ "compilerOptions": { "module": "ESNext", "outDir": "./dist" + }, + "ts-node": { + "compilerOptions": { + "module": "CommonJS", + "rootDir": "." + }, + "include": ["src/**/*", "examples/**/*"] } } From 87dd8d3e52bbfa88fd8f678bf848431f62031439 Mon Sep 17 00:00:00 2001 From: JesusMendoza Date: Tue, 27 Jan 2026 14:21:10 -0600 Subject: [PATCH 07/15] =?UTF-8?q?ejemplos=20facturas=20de=20n=C3=B3mina=20?= =?UTF-8?q?updated?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/ejemplos-factura-nomina.ts | 5 +- payroll-invoice-requrements.md | 97 ++++ payroll-requirements.md | 820 ---------------------------- 3 files changed, 101 insertions(+), 821 deletions(-) delete mode 100644 payroll-requirements.md diff --git a/examples/ejemplos-factura-nomina.ts b/examples/ejemplos-factura-nomina.ts index e3771cb..724abdf 100644 --- a/examples/ejemplos-factura-nomina.ts +++ b/examples/ejemplos-factura-nomina.ts @@ -15,7 +15,10 @@ const settings: FiscalapiSettings = { // apiUrl: 'https://test.fiscalapi.com', // apiKey: '', // tenant: '', - + apiUrl: "http://localhost:5001", + apiKey: "sk_development_b470ea83_3c0f_4209_b933_85223b960d91", + tenant: "102e5f13-e114-41dd-bea7-507fce177281", + debug: true }; // Sellos SAT de prueba diff --git a/payroll-invoice-requrements.md b/payroll-invoice-requrements.md index 2d90159..a5c07a0 100644 --- a/payroll-invoice-requrements.md +++ b/payroll-invoice-requrements.md @@ -2483,3 +2483,100 @@ curl --location 'http://localhost:5001/api/v4/invoices' \ + + + +## Facturas de nomina por referencias. + +Analyze the existing **13 value-based payroll invoice examples** (where all data is sent via the request body) on @ejemplos-factura-nomina.ts file + +**Task:** +Recreate these 13 examples using a **reference-based approach**. In this approach, the Issuer (*Emisor*) and Receiver (*Receptor*) are referenced by their Object IDs rather than embedding their full details in the invoice payload. + +**Constants:** +Map the entities to the following UUIDs: + +```typescript +const escuelaKemperUrgateId = "2e7b988f-3a2a-4f67-86e9-3f931dd48581"; +const karlaFuenteNolascoId = "109f4d94-63ea-4a21-ab15-20c8b87d8ee9"; +const organicosNavezOsorioId = "f645e146-f80e-40fa-953f-fd1bd06d4e9f"; +const xochiltCasasChavezId = "e3b4edaa-e4d9-4794-9c5b-3dd5b7e372aa"; +const ingridXodarJimenezId = "9367249f-f0ee-43f4-b771-da2fff3f185f"; + +``` + +**Requirements:** +For each of the 13 use cases, you must generate **two distinct operations**: + +1. **Configuration (Setup):** Create the code to configure/save the Employee and Employer objects first. +* *Crucial:* You must extract the specific attributes (name, RFC, fiscal regime, etc.) from the original value-based example to populate these objects correctly. + + +2. **Invoice Generation (Execution):** Create the payroll invoice request using the IDs defined above (referencing the objects created in step 1). +* *Note:* The "Payroll Complement" data (amounts, perceptions, deductions) must remain identical to the original examples. + +3. Example + +// ============================================================================ +// 1. NOMINA ORDINARIA (Facturación por referencias) +// ============================================================================ +async function nominaOrdinariaByReferencesSetupData(client: FiscalapiClient): Promise { + // fiscalapiClient.persons.employer.delete() + // fiscalapiClient.persons.employer.create({...}) + // fiscalapiClient.persons.employee.delete() + // fiscalapiClient.persons.employee.create({...}) +} +async function nominaOrdinariaByReferences(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Ordinaria ByReferences ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + id: escuelaKemperUrgateId, //legalName: 'ESCUELA KEMPER URGATE', + }, + recipient: { + id: karlaFuenteNolascoId // legalName: 'KARLA FUENTE NOLASCO', + }, + 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 response = await client.invoices.create(invoice); + console.log('Response:', response); +} diff --git a/payroll-requirements.md b/payroll-requirements.md deleted file mode 100644 index 1f23733..0000000 --- a/payroll-requirements.md +++ /dev/null @@ -1,820 +0,0 @@ -# FiscalAPI SDK - Payroll (CFDI Nomina) Requirements - -This document describes the requirements for implementing payroll invoice (CFDI de Nomina) support in FiscalAPI SDKs. It is language-agnostic and focuses on the models, services, and functionality needed. - ---- - -## Table of Contents - -1. [Overview](#overview) -2. [New Models Required](#new-models-required) -3. [New Services Required](#new-services-required) - - [EmployeeService](#1-employeeservice) - - [EmployerService](#2-employerservice) - - [PeopleService Updates](#3-peopleservice-updates) - - [StampService](#4-stampservice) -4. [Person Model Updates](#person-model-updates) -5. [Invoice Model Updates](#invoice-model-updates) -6. [Two Operation Modes](#two-operation-modes) -7. [Payroll Types Reference](#payroll-types-reference) -8. [API Endpoints](#api-endpoints) -9. [Field Mappings (JSON Aliases)](#field-mappings-json-aliases) -10. [Example Implementations](#example-implementations) - ---- - -## Overview - -Payroll invoices (CFDI de Nomina) in Mexico require: -- **Employer data** attached to the issuer (company paying wages) -- **Employee data** attached to the recipient (worker receiving wages) -- **Payroll complement** containing earnings, deductions, and other payment details - -The SDK must support **13 different payroll types** and **two operation modes**: -1. **By Values** - All data sent inline with the invoice request -2. **By References** - Only person IDs sent; employee/employer data pre-configured via API - ---- - -## New Models Required - -### 1. EmployeeData - -Data model for storing employee information as a sub-resource of Person. - -| Field | JSON Alias | Type | Description | -|-------|------------|------|-------------| -| employer_person_id | employerPersonId | string | ID of the employer person | -| employee_person_id | employeePersonId | string | ID of the employee person | -| social_security_number | socialSecurityNumber | string | NSS (Numero de Seguridad Social) | -| labor_relation_start_date | laborRelationStartDate | datetime | Employment start date | -| seniority | seniority | string | ISO 8601 duration (e.g., "P54W" = 54 weeks) | -| sat_contract_type_id | satContractTypeId | string | SAT contract type code | -| sat_unionized_status_id | satUnionizedStatusId | string | Unionized status code | -| sat_tax_regime_type_id | satTaxRegimeTypeId | string | Tax regime type code | -| sat_workday_type_id | satWorkdayTypeId | string | Workday type code | -| sat_job_risk_id | satJobRiskId | string | Job risk level code | -| sat_payment_periodicity_id | satPaymentPeriodicityId | string | Payment frequency code | -| employee_number | employeeNumber | string | Internal employee number | -| sat_bank_id | satBankId | string | Bank code | -| sat_payroll_state_id | satPayrollStateId | string | State code for payroll | -| department | department | string | Department name | -| position | position | string | Job position/title | -| bank_account | bankAccount | string | Bank account number | -| base_salary_for_contributions | baseSalaryForContributions | decimal | Base salary for social security | -| integrated_daily_salary | integratedDailySalary | decimal | Integrated daily salary | -| subcontractor_rfc | subcontractorRfc | string | RFC of subcontractor (if applicable) | -| time_percentage | timePercentage | decimal | Time percentage (for partial employment) | - -### 2. EmployerData - -Data model for storing employer information as a sub-resource of Person. - -| Field | JSON Alias | Type | Description | -|-------|------------|------|-------------| -| person_id | personId | string | ID of the employer person | -| employer_registration | employerRegistration | string | Registro Patronal (IMSS) | -| origin_employer_tin | originEmployerTin | string | RFC of origin employer | -| sat_fund_source_id | satFundSourceId | string | Fund source code | -| own_resource_amount | ownResourceAmount | decimal | Own resource amount | - -### 3. InvoiceIssuerEmployerData - -Employer data embedded in invoice issuer (for "by values" mode). - -| Field | JSON Alias | Type | Description | -|-------|------------|------|-------------| -| curp | curp | string | CURP of employer representative | -| employer_registration | employerRegistration | string | Registro Patronal | -| origin_employer_tin | originEmployerTin | string | RFC of origin employer | -| sat_fund_source_id | satFundSourceId | string | Fund source code | -| own_resource_amount | ownResourceAmount | decimal | Own resource amount | - -### 4. InvoiceRecipientEmployeeData - -Employee data embedded in invoice recipient (for "by values" mode). - -| Field | JSON Alias | Type | Description | -|-------|------------|------|-------------| -| curp | curp | string | CURP of employee | -| social_security_number | socialSecurityNumber | string | NSS | -| labor_relation_start_date | laborRelationStartDate | string | Start date (ISO format) | -| seniority | seniority | string | ISO 8601 duration | -| sat_contract_type_id | satContractTypeId | string | Contract type | -| sat_unionized_status_id | satUnionizedStatusId | string | Unionized status | -| sat_workday_type_id | satWorkdayTypeId | string | Workday type | -| sat_tax_regime_type_id | satTaxRegimeTypeId | string | Tax regime type | -| employee_number | employeeNumber | string | Employee number | -| department | department | string | Department | -| position | position | string | Position | -| sat_job_risk_id | satJobRiskId | string | Job risk code | -| sat_payment_periodicity_id | satPaymentPeriodicityId | string | Payment periodicity | -| sat_bank_id | satBankId | string | Bank code | -| bank_account | bankAccount | string | Bank account | -| base_salary_for_contributions | baseSalaryForContributions | decimal | Base salary | -| integrated_daily_salary | integratedDailySalary | decimal | Integrated salary | -| sat_payroll_state_id | satPayrollStateId | string | Payroll state | - -### 5. Payroll Complement Models - -#### PayrollComplement (main container) - -| Field | JSON Alias | Type | Description | -|-------|------------|------|-------------| -| version | version | string | Always "1.2" | -| payroll_type_code | payrollTypeCode | string | "O" (ordinary) or "E" (extraordinary) | -| payment_date | paymentDate | string | Payment date (ISO format) | -| initial_payment_date | initialPaymentDate | string | Period start date | -| final_payment_date | finalPaymentDate | string | Period end date | -| days_paid | daysPaid | decimal | Days paid in period | -| earnings | earnings | PayrollEarningsComplement | Earnings container | -| deductions | deductions | PayrollDeduction[] | List of deductions | -| disabilities | disabilities | PayrollDisability[] | List of disabilities | - -#### PayrollEarningsComplement - -| Field | JSON Alias | Type | Description | -|-------|------------|------|-------------| -| earnings | earnings | PayrollEarning[] | List of earnings | -| other_payments | otherPayments | PayrollOtherPayment[] | Other payments (subsidies, etc.) | -| retirement | retirement | PayrollRetirement | Retirement/pension data | -| severance | severance | PayrollSeverance | Severance/indemnization data | - -#### PayrollEarning - -| Field | JSON Alias | Type | Description | -|-------|------------|------|-------------| -| earning_type_code | earningTypeCode | string | SAT earning type code | -| code | code | string | Internal code | -| concept | concept | string | Description | -| taxed_amount | taxedAmount | decimal | Taxable amount | -| exempt_amount | exemptAmount | decimal | Exempt amount | -| stock_options | stockOptions | PayrollStockOptions | Stock options (if applicable) | -| overtime | overtime | PayrollOvertime[] | Overtime hours | - -#### PayrollDeduction - -| Field | JSON Alias | Type | Description | -|-------|------------|------|-------------| -| deduction_type_code | deductionTypeCode | string | SAT deduction type code | -| code | code | string | Internal code | -| concept | concept | string | Description | -| amount | amount | decimal | Deduction amount | - -#### PayrollOtherPayment - -| Field | JSON Alias | Type | Description | -|-------|------------|------|-------------| -| other_payment_type_code | otherPaymentTypeCode | string | SAT other payment type code | -| code | code | string | Internal code | -| concept | concept | string | Description | -| amount | amount | decimal | Payment amount | -| subsidy_caused | subsidyCaused | decimal | Employment subsidy caused | -| balance_compensation | balanceCompensation | PayrollBalanceCompensation | Balance compensation | - -#### PayrollOvertime - -| Field | JSON Alias | Type | Description | -|-------|------------|------|-------------| -| days | days | int | Days with overtime | -| hours_type_code | hoursTypeCode | string | "01" (double) or "02" (triple) | -| extra_hours | extraHours | int | Number of extra hours | -| amount_paid | amountPaid | decimal | Amount paid | - -#### PayrollDisability - -| Field | JSON Alias | Type | Description | -|-------|------------|------|-------------| -| disability_days | disabilityDays | int | Days of disability | -| disability_type_code | disabilityTypeCode | string | SAT disability type code | -| monetary_amount | monetaryAmount | decimal | Monetary amount | - -#### PayrollRetirement - -| Field | JSON Alias | Type | Description | -|-------|------------|------|-------------| -| total_one_time | totalOneTime | decimal | One-time payment total | -| total_installments | totalInstallments | decimal | Installments total | -| daily_amount | dailyAmount | decimal | Daily amount | -| accumulable_income | accumulableIncome | decimal | Accumulable income | -| non_accumulable_income | nonAccumulableIncome | decimal | Non-accumulable income | - -#### PayrollSeverance - -| Field | JSON Alias | Type | Description | -|-------|------------|------|-------------| -| total_paid | totalPaid | decimal | Total paid | -| years_of_service | yearsOfService | int | Years of service | -| last_monthly_salary | lastMonthlySalary | decimal | Last monthly salary | -| accumulable_income | accumulableIncome | decimal | Accumulable income | -| non_accumulable_income | nonAccumulableIncome | decimal | Non-accumulable income | - ---- - -## New Services Required - -### 1. EmployeeService - -Sub-service of PeopleService for managing employee data. - -``` -Endpoint pattern: people/{personId}/employee -``` - -| Method | HTTP | Endpoint | Description | -|--------|------|----------|-------------| -| get_by_id(person_id) | GET | people/{personId}/employee | Get employee data | -| create(employee) | POST | people/{employeePersonId}/employee | Create employee data | -| update(employee) | PUT | people/{employeePersonId}/employee | Update employee data | -| delete(person_id) | DELETE | people/{personId}/employee | Delete employee data | - -### 2. EmployerService - -Sub-service of PeopleService for managing employer data. - -``` -Endpoint pattern: people/{personId}/employer -``` - -| Method | HTTP | Endpoint | Description | -|--------|------|----------|-------------| -| get_by_id(person_id) | GET | people/{personId}/employer | Get employer data | -| create(employer) | POST | people/{personId}/employer | Create employer data | -| update(employer) | PUT | people/{personId}/employer | Update employer data | -| delete(person_id) | DELETE | people/{personId}/employer | Delete employer data | - -### 3. PeopleService Updates - -Add employee and employer sub-services as properties: - -``` -client.people.employee -> EmployeeService -client.people.employer -> EmployerService -``` - -### 4. StampService - -Service for managing stamp transactions (timbres fiscales). Stamps are the digital fiscal tokens required to certify CFDI invoices. - -``` -Endpoint pattern: stamps -``` - -| Method | HTTP | Endpoint | Description | -|--------|------|----------|-------------| -| get_list(page_number, page_size) | GET | stamps?pageNumber={n}&pageSize={s} | List stamp transactions with pagination | -| get_by_id(transaction_id) | GET | stamps/{transactionId} | Get a stamp transaction by ID | -| transfer_stamps(request) | POST | stamps | Transfer stamps from one person to another | -| withdraw_stamps(request) | POST | stamps | Withdraw stamps (alias for transfer_stamps) | - -#### Stamp Models - -##### UserLookupDto - -Lookup DTO for user/person references in stamp transactions. - -| Field | JSON Alias | Type | Description | -|-------|------------|------|-------------| -| tin | tin | string | RFC of the user | -| legal_name | legalName | string | Legal name of the user | - -##### StampTransaction - -Represents a stamp transfer/withdrawal transaction. - -| Field | JSON Alias | Type | Description | -|-------|------------|------|-------------| -| consecutive | consecutive | int | Transaction consecutive number | -| from_person | fromPerson | UserLookupDto | Source person of the transfer | -| to_person | toPerson | UserLookupDto | Destination person of the transfer | -| amount | amount | int | Number of stamps transferred | -| transaction_type | transactionType | int | Type of transaction | -| transaction_status | transactionStatus | int | Status of the transaction | -| reference_id | referenceId | string | Transaction reference ID | -| comments | comments | string | Transaction comments | - -##### StampTransactionParams - -Request parameters for stamp transfer/withdraw operations. - -| Field | JSON Alias | Type | Required | Description | -|-------|------------|------|----------|-------------| -| from_person_id | fromPersonId | string | Yes | ID of the source person | -| to_person_id | toPersonId | string | Yes | ID of the destination person | -| amount | amount | int | Yes | Number of stamps to transfer | -| comments | comments | string | No | Transfer comments | - -#### Example: Transfer Stamps - -``` -// Transfer 100 stamps from master account to sub-account -params = StampTransactionParams( - from_person_id: "master-account-id", - to_person_id: "sub-account-id", - amount: 100, - comments: "Monthly stamp allocation" -) - -response = client.stamps.transfer_stamps(params) -``` - -#### Example: List Stamp Transactions - -``` -// Get paginated list of stamp transactions -response = client.stamps.get_list(page_number=1, page_size=10) - -for transaction in response.data.items: - print(f"Transfer: {transaction.amount} stamps from {transaction.from_person.legal_name}") -``` - ---- - -## Person Model Updates - -Add the following field to the Person model: - -| Field | JSON Alias | Type | Description | -|-------|------------|------|-------------| -| curp | curp | string | CURP (Clave Unica de Registro de Poblacion) | - -**Important**: For payroll invoices, the recipient (employee) must have: -- `curp` field populated -- `sat_tax_regime_id` = "605" (Sueldos y Salarios) -- `sat_cfdi_use_id` = "CN01" (Nomina) - ---- - -## Invoice Model Updates - -### InvoiceIssuer - -Add field: - -| Field | JSON Alias | Type | Description | -|-------|------------|------|-------------| -| employer_data | employerData | InvoiceIssuerEmployerData | Employer data for payroll | - -### InvoiceRecipient - -Add field: - -| Field | JSON Alias | Type | Description | -|-------|------------|------|-------------| -| employee_data | employeeData | InvoiceRecipientEmployeeData | Employee data for payroll | - -### InvoiceComplement - -Add field: - -| Field | JSON Alias | Type | Description | -|-------|------------|------|-------------| -| payroll | payroll | PayrollComplement | Payroll complement data | - ---- - -## Two Operation Modes - -### Mode 1: By Values - -All employee/employer data is sent inline with the invoice request. - -**Characteristics:** -- Self-contained request -- No prior setup required -- Larger payload size -- Employee data goes in `recipient.employee_data` -- Employer data goes in `issuer.employer_data` - -**Example structure:** -``` -Invoice { - issuer: { - tin: "EKU9003173C9", - legal_name: "ESCUELA KEMPER URGATE", - tax_regime_code: "601", - employer_data: { - employer_registration: "B5510768108", - origin_employer_tin: "URE180429TM6" - } - }, - recipient: { - tin: "XOJI740919U48", - legal_name: "INGRID XODAR JIMENEZ", - tax_regime_code: "605", - cfdi_use_code: "CN01", - employee_data: { - curp: "XOJI850618MJCDNG09", - social_security_number: "000000", - seniority: "P54W", - ... - } - }, - complement: { - payroll: { ... } - } -} -``` - -### Mode 2: By References - -Only person IDs are sent; employee/employer data must be pre-configured. - -**Characteristics:** -- Smaller payload -- Requires prior setup of employee/employer data via API -- Person must have CURP and tax regime configured -- Uses only `id` field in issuer/recipient - -**Setup steps:** -1. Update person with CURP and tax regime (605 for employee, appropriate for employer) -2. Create EmployeeData via `client.people.employee.create()` -3. Create EmployerData via `client.people.employer.create()` - -**Example structure:** -``` -Invoice { - issuer: { - id: "2e7b988f-3a2a-4f67-86e9-3f931dd48581" - }, - recipient: { - id: "9367249f-f0ee-43f4-b771-da2fff3f185f" - }, - complement: { - payroll: { ... } - } -} -``` - ---- - -## Payroll Types Reference - -### 13 Standard Payroll Types - -| # | Name | payroll_type_code | Key Characteristics | -|---|------|-------------------|---------------------| -| 1 | Ordinaria | O | Regular salary payment | -| 2 | Asimilados | O | Similar to salary (honorarios asimilados) | -| 3 | Bonos y Fondo de Ahorro | O | Bonuses and savings fund | -| 4 | Horas Extra | O | Overtime payment | -| 5 | Incapacidades | O | Disability/sick leave | -| 6 | SNCF | O | Federal government (SNCF) | -| 7 | Extraordinaria | E | Extraordinary payment | -| 8 | Separacion e Indemnizacion | E | Severance and indemnization | -| 9 | Jubilacion, Pension, Retiro | E | Retirement/pension | -| 10 | Sin Deducciones | O | Without deductions | -| 11 | Subsidio Causado | O | Employment subsidy adjustment | -| 12 | Viaticos | O | Travel expenses | -| 13 | Basica | O | Basic payroll | - -### Common Invoice Fields for All Payroll Types - -``` -version_code: "4.0" -payment_method_code: "PUE" -currency_code: "MXN" -type_code: "N" -expedition_zip_code: -export_code: "01" -``` - -### SAT Earning Type Codes (TipoPercepcion) - -| Code | Description | Common Use | -|------|-------------|------------| -| 001 | Sueldos, Salarios Rayas y Jornales | Regular salary | -| 002 | Gratificación Anual (Aguinaldo) | Christmas bonus | -| 003 | Participación de los Trabajadores en las Utilidades PTU | Profit sharing | -| 019 | Horas extra | Overtime | -| 022 | Prima vacacional | Vacation bonus | -| 023 | Pagos por separación | Severance pay | -| 025 | Indemnizaciones | Indemnization | -| 028 | Comisiones | Commissions | -| 029 | Vales de despensa | Food vouchers | -| 039 | Jubilaciones, pensiones o haberes de retiro | Retirement | -| 044 | Jubilaciones, pensiones o haberes de retiro parcial | Partial retirement | -| 045 | Ingresos en acciones | Stock income | -| 046 | Ingresos asimilados a salarios | Income similar to salary | -| 047 | Alimentación | Food | -| 050 | Viáticos | Travel expenses | - -### SAT Deduction Type Codes (TipoDeduccion) - -| Code | Description | Common Use | -|------|-------------|------------| -| 001 | Seguridad social | Social security | -| 002 | ISR | Income tax | -| 003 | Aportaciones a retiro | Retirement contributions | -| 004 | Otros | Other deductions | -| 006 | Descuento por incapacidad | Disability discount | -| 010 | Pensión alimenticia | Alimony | -| 020 | Fondo de ahorro | Savings fund | -| 081 | Ajuste en viáticos | Travel expense adjustment | -| 107 | Ajuste al Subsidio Causado | Subsidy adjustment | - -### SAT Other Payment Type Codes (TipoOtroPago) - -| Code | Description | -|------|-------------| -| 001 | Reintegro de ISR pagado en exceso | -| 002 | Subsidio para el empleo | -| 003 | Viáticos | -| 004 | Aplicación de saldo a favor por compensación anual | -| 007 | ISR ajustado por subsidio | - ---- - -## API Endpoints - -### Employee Endpoints - -``` -GET /api/{version}/people/{personId}/employee -POST /api/{version}/people/{personId}/employee -PUT /api/{version}/people/{personId}/employee -DELETE /api/{version}/people/{personId}/employee -``` - -### Employer Endpoints - -``` -GET /api/{version}/people/{personId}/employer -POST /api/{version}/people/{personId}/employer -PUT /api/{version}/people/{personId}/employer -DELETE /api/{version}/people/{personId}/employer -``` - -### Invoice Endpoints - -Payroll invoices use the standard invoice endpoint: - -``` -POST /api/{version}/invoices -``` - -With `type_code: "N"` for payroll invoices. - -### Stamp Endpoints - -``` -GET /api/{version}/stamps?pageNumber={n}&pageSize={s} -GET /api/{version}/stamps/{transactionId} -POST /api/{version}/stamps -``` - ---- - -## Field Mappings (JSON Aliases) - -All models must serialize using camelCase JSON aliases when communicating with the API. - -**Serialization rules:** -- Use camelCase for JSON property names -- Exclude null/None values from JSON -- Decimal values should serialize as strings -- Dates should serialize as ISO 8601 strings - ---- - -## Example Implementations - -### Example 1: Create Payroll Invoice (By Values) - -``` -// Pseudocode - adapt to target language - -invoice = Invoice( - version_code: "4.0", - series: "F", - date: "2026-01-25T10:00:00", - payment_method_code: "PUE", - currency_code: "MXN", - type_code: "N", - expedition_zip_code: "20000", - export_code: "01", - - issuer: InvoiceIssuer( - tin: "EKU9003173C9", - legal_name: "ESCUELA KEMPER URGATE", - tax_regime_code: "601", - employer_data: InvoiceIssuerEmployerData( - employer_registration: "B5510768108", - origin_employer_tin: "URE180429TM6" - ) - ), - - recipient: InvoiceRecipient( - tin: "XOJI740919U48", - legal_name: "INGRID XODAR JIMENEZ", - zip_code: "76028", - tax_regime_code: "605", - cfdi_use_code: "CN01", - employee_data: InvoiceRecipientEmployeeData( - curp: "XOJI850618MJCDNG09", - social_security_number: "000000", - labor_relation_start_date: "2015-01-01", - seniority: "P437W", - sat_contract_type_id: "01", - sat_workday_type_id: "01", - sat_tax_regime_type_id: "02", - employee_number: "120", - department: "Desarrollo", - position: "Ingeniero de Software", - sat_job_risk_id: "1", - sat_payment_periodicity_id: "04", - sat_bank_id: "002", - bank_account: "1111111111", - base_salary_for_contributions: 490.22, - integrated_daily_salary: 146.47, - sat_payroll_state_id: "JAL" - ) - ), - - complement: InvoiceComplement( - payroll: PayrollComplement( - version: "1.2", - payroll_type_code: "O", - payment_date: "2023-05-24", - initial_payment_date: "2023-05-09", - final_payment_date: "2023-05-24", - days_paid: 15, - earnings: PayrollEarningsComplement( - earnings: [ - PayrollEarning( - earning_type_code: "001", - code: "00500", - concept: "Sueldos, Salarios Rayas y Jornales", - taxed_amount: 2808.80, - exempt_amount: 2191.20 - ) - ] - ), - deductions: [ - PayrollDeduction( - deduction_type_code: "001", - code: "00301", - concept: "Seguridad Social", - amount: 200.00 - ), - PayrollDeduction( - deduction_type_code: "002", - code: "00302", - concept: "ISR", - amount: 100.00 - ) - ] - ) - ) -) - -response = client.invoices.create(invoice) -``` - -### Example 2: Setup for By References Mode - -``` -// Step 1: Update person with CURP and tax regime -employee_person = Person( - id: "9367249f-f0ee-43f4-b771-da2fff3f185f", - curp: "XOJI850618MJCDNG09", - sat_tax_regime_id: "605", - sat_cfdi_use_id: "CN01" -) -client.people.update(employee_person) - -// Step 2: Create employee data -employee_data = EmployeeData( - employer_person_id: "2e7b988f-3a2a-4f67-86e9-3f931dd48581", - employee_person_id: "9367249f-f0ee-43f4-b771-da2fff3f185f", - social_security_number: "000000", - labor_relation_start_date: datetime(2015, 1, 1), - seniority: "P437W", - sat_contract_type_id: "01", - sat_workday_type_id: "01", - sat_tax_regime_type_id: "02", - employee_number: "120", - department: "Desarrollo", - position: "Ingeniero de Software", - sat_job_risk_id: "1", - sat_payment_periodicity_id: "04", - sat_bank_id: "002", - bank_account: "1111111111", - integrated_daily_salary: 146.47, - sat_payroll_state_id: "JAL" -) -client.people.employee.create(employee_data) - -// Step 3: Create employer data -employer_data = EmployerData( - person_id: "2e7b988f-3a2a-4f67-86e9-3f931dd48581", - employer_registration: "B5510768108", - origin_employer_tin: "URE180429TM6" -) -client.people.employer.create(employer_data) -``` - -### Example 3: Create Payroll Invoice (By References) - -``` -invoice = Invoice( - version_code: "4.0", - series: "F", - date: "2026-01-25T10:00:00", - payment_method_code: "PUE", - currency_code: "MXN", - type_code: "N", - expedition_zip_code: "20000", - export_code: "01", - - // Only IDs - data comes from pre-configured employee/employer - issuer: InvoiceIssuer( - id: "2e7b988f-3a2a-4f67-86e9-3f931dd48581" - ), - recipient: InvoiceRecipient( - id: "9367249f-f0ee-43f4-b771-da2fff3f185f" - ), - - complement: InvoiceComplement( - payroll: PayrollComplement( - // Same payroll data as by-values mode - version: "1.2", - payroll_type_code: "O", - payment_date: "2023-05-24", - initial_payment_date: "2023-05-09", - final_payment_date: "2023-05-24", - days_paid: 15, - earnings: PayrollEarningsComplement( - earnings: [ - PayrollEarning( - earning_type_code: "001", - code: "00500", - concept: "Sueldos, Salarios Rayas y Jornales", - taxed_amount: 2808.80, - exempt_amount: 2191.20 - ) - ] - ), - deductions: [ - PayrollDeduction( - deduction_type_code: "001", - code: "00301", - concept: "Seguridad Social", - amount: 200.00 - ), - PayrollDeduction( - deduction_type_code: "002", - code: "00302", - concept: "ISR", - amount: 100.00 - ) - ] - ) - ) -) - -response = client.invoices.create(invoice) -``` - ---- - -## Implementation Checklist - -### Models -- [x] Add `curp` field to Person model -- [x] Create EmployeeData model -- [x] Create EmployerData model -- [x] Create InvoiceIssuerEmployerData model -- [x] Create InvoiceRecipientEmployeeData model -- [x] Create PayrollComplement and all sub-models -- [x] Add employer_data to InvoiceIssuer model -- [x] Add employee_data to InvoiceRecipient model -- [x] Add payroll to InvoiceComplement model -- [x] Create StampTransaction model -- [x] Create StampTransactionParams model -- [x] Create UserLookupDto model - -### Services -- [x] Create EmployeeService with CRUD operations -- [x] Create EmployerService with CRUD operations -- [x] Add employee and employer properties to PeopleService -- [x] Create StampService with get_list, get_by_id, transfer_stamps, withdraw_stamps - -### Examples & Testing -- [ ] Create examples for all 13 payroll types (by values) -- [ ] Create examples for all 13 payroll types (by references) -- [ ] Create setup data methods for by-references mode -- [ ] Create stamp service examples -- [ ] Test all payroll types successfully -- [ ] Test stamp transactions successfully - ---- - -## Notes - -1. **Seniority format**: Use ISO 8601 duration format (e.g., "P437W" for 437 weeks) -2. **Tax regime for employees**: Always "605" (Sueldos y Salarios) -3. **CFDI use for payroll**: Always "CN01" (Nomina) -4. **Invoice type**: Always "N" for payroll invoices -5. **Payment method**: Typically "PUE" (Pago en Una sola Exhibicion) -6. **Payroll complement version**: Always "1.2" From 15415c9611e80272dfc31f9245dd90655b260096 Mon Sep 17 00:00:00 2001 From: JesusMendoza Date: Tue, 27 Jan 2026 14:45:23 -0600 Subject: [PATCH 08/15] =?UTF-8?q?ejemplos=20facturas=20de=20n=C3=B3mina=20?= =?UTF-8?q?por=20referencias=20added?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/ejemplo-datos-empleado-empleador.ts | 1 + examples/ejemplo-timbres.ts | 1 + .../ejemplos-factura-nomina-referencias.ts | 1279 +++++++++++++++++ ....ts => ejemplos-factura-nomina-valores.ts} | 9 +- payroll-invoice-requrements.md | 5 +- 5 files changed, 1288 insertions(+), 7 deletions(-) create mode 100644 examples/ejemplos-factura-nomina-referencias.ts rename examples/{ejemplos-factura-nomina.ts => ejemplos-factura-nomina-valores.ts} (99%) diff --git a/examples/ejemplo-datos-empleado-empleador.ts b/examples/ejemplo-datos-empleado-empleador.ts index f253d45..6e368e8 100644 --- a/examples/ejemplo-datos-empleado-empleador.ts +++ b/examples/ejemplo-datos-empleado-empleador.ts @@ -11,6 +11,7 @@ async function main(): Promise { apiUrl: 'https://test.fisalapi.com', apiKey: '', tenant: '', + debug: true }; const client = FiscalapiClient.create(settings); diff --git a/examples/ejemplo-timbres.ts b/examples/ejemplo-timbres.ts index 690970a..04844ad 100644 --- a/examples/ejemplo-timbres.ts +++ b/examples/ejemplo-timbres.ts @@ -6,6 +6,7 @@ async function main(): Promise { apiUrl: 'https://test.fisalapi.com', apiKey: '', tenant: '', + debug: true }; const client = FiscalapiClient.create(settings); diff --git a/examples/ejemplos-factura-nomina-referencias.ts b/examples/ejemplos-factura-nomina-referencias.ts new file mode 100644 index 0000000..15d4e27 --- /dev/null +++ b/examples/ejemplos-factura-nomina-referencias.ts @@ -0,0 +1,1279 @@ +/** + * Ejemplos de facturas de nómina (CFDI Nómina) usando el SDK de FiscalAPI + * Todos los métodos usan el modo "ByReferences" - se pasan solo IDs de entidades preconfiguradas + */ + +import { + FiscalapiClient, + FiscalapiSettings, + Invoice, + CreateEmployerRequest, + CreateEmployeeRequest +} from '../src/index'; +import { inspect } from 'util'; + +// Configuración de la consola para mostrar objetos anidados +inspect.defaultOptions.depth = null; +inspect.defaultOptions.colors = true; + +// Configuración de FiscalAPI +const settings: FiscalapiSettings = { + apiUrl: 'https://test.fisalapi.com', + apiKey: '', + tenant: '', + debug: true +}; + +// ============================================================================ +// UUID CONSTANTS - IDs de personas preconfiguradas en FiscalAPI +// ============================================================================ +const escuelaKemperUrgateId = "2e7b988f-3a2a-4f67-86e9-3f931dd48581"; +const karlaFuenteNolascoId = "109f4d94-63ea-4a21-ab15-20c8b87d8ee9"; +const organicosNavezOsorioId = "f645e146-f80e-40fa-953f-fd1bd06d4e9f"; +const xochiltCasasChavezId = "e3b4edaa-e4d9-4794-9c5b-3dd5b7e372aa"; +const ingridXodarJimenezId = "9367249f-f0ee-43f4-b771-da2fff3f185f"; + +// Fecha actual para las facturas +const currentDate = '2026-01-27T10:04:06'; + +// ============================================================================ +// 1. NOMINA ORDINARIA (Facturación por referencias) +// ============================================================================ +async function nominaOrdinariaByReferencesSetupData(client: FiscalapiClient): Promise { + console.log('\n=== Setup: Nómina Ordinaria ByReferences ===\n'); + + // Eliminar datos existentes (idempotente) + try { await client.persons.employer.delete(escuelaKemperUrgateId); } catch { /* ignore */ } + try { await client.persons.employee.delete(karlaFuenteNolascoId); } catch { /* ignore */ } + + // Crear datos de empleador + const employerRequest: CreateEmployerRequest = { + personId: escuelaKemperUrgateId, + employerRegistration: 'B5510768108' + }; + const employerResult = await client.persons.employer.create(employerRequest); + console.log('Empleador:', JSON.stringify(employerResult, null, 2)); + + // Crear datos de empleado + const employeeRequest: CreateEmployeeRequest = { + employerPersonId: escuelaKemperUrgateId, + employeePersonId: karlaFuenteNolascoId, + 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' + }; + const employeeResult = await client.persons.employee.create(employeeRequest); + console.log('Empleado:', JSON.stringify(employeeResult, null, 2)); +} + +async function nominaOrdinariaByReferences(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Ordinaria ByReferences ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + id: escuelaKemperUrgateId + }, + recipient: { + id: karlaFuenteNolascoId + }, + 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 response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 2. NOMINA ASIMILADOS (Facturación por referencias) +// ============================================================================ +async function nominaAsimiladosByReferencesSetupData(client: FiscalapiClient): Promise { + console.log('\n=== Setup: Nómina Asimilados ByReferences ===\n'); + + // Eliminar datos existentes (idempotente) + try { await client.persons.employer.delete(escuelaKemperUrgateId); } catch { /* ignore */ } + try { await client.persons.employee.delete(xochiltCasasChavezId); } catch { /* ignore */ } + + // Crear datos de empleador + const employerRequest: CreateEmployerRequest = { + personId: escuelaKemperUrgateId, + originEmployerTin: 'EKU9003173C9' + }; + const employerResult = await client.persons.employer.create(employerRequest); + console.log('Empleador:', JSON.stringify(employerResult, null, 2)); + + // Crear datos de empleado + const employeeRequest: CreateEmployeeRequest = { + employerPersonId: escuelaKemperUrgateId, + employeePersonId: xochiltCasasChavezId, + satContractTypeId: '09', + satUnionizedStatusId: 'No', + satTaxRegimeTypeId: '09', + employeeNumber: '00002', + department: 'ADMINISTRACION', + position: 'DIRECTOR DE ADMINISTRACION', + satPaymentPeriodicityId: '99', + satBankId: '012', + bankAccount: '1111111111', + satPayrollStateId: 'CMX' + }; + const employeeResult = await client.persons.employee.create(employeeRequest); + console.log('Empleado:', JSON.stringify(employeeResult, null, 2)); +} + +async function nominaAsimiladosByReferences(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Asimilados ByReferences ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '06880', + exportCode: '01', + issuer: { + id: escuelaKemperUrgateId + }, + recipient: { + id: xochiltCasasChavezId + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'E', + paymentDate: '2023-06-02T00:00:00', + initialPaymentDate: '2023-06-01T00:00:00', + finalPaymentDate: '2023-06-02T00:00:00', + daysPaid: 1, + earnings: { + earnings: [ + { earningTypeCode: '046', code: '010046', concept: 'INGRESOS ASIMILADOS A SALARIOS', taxedAmount: 111197.73, exemptAmount: 0.00 } + ], + otherPayments: [] + }, + deductions: [ + { deductionTypeCode: '002', code: '020002', concept: 'ISR', amount: 36197.73 } + ] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 3. NOMINA CON BONOS Y FONDO DE AHORRO (Facturación por referencias) +// ============================================================================ +async function nominaConBonosFondoAhorroByReferencesSetupData(client: FiscalapiClient): Promise { + console.log('\n=== Setup: Nómina Con Bonos y Fondo de Ahorro ByReferences ===\n'); + + // Eliminar datos existentes (idempotente) + try { await client.persons.employer.delete(escuelaKemperUrgateId); } catch { /* ignore */ } + try { await client.persons.employee.delete(ingridXodarJimenezId); } catch { /* ignore */ } + + // Crear datos de empleador + const employerRequest: CreateEmployerRequest = { + personId: escuelaKemperUrgateId, + employerRegistration: 'Z0000001234' + }; + const employerResult = await client.persons.employer.create(employerRequest); + console.log('Empleador:', JSON.stringify(employerResult, null, 2)); + + // Crear datos de empleado + const employeeRequest: CreateEmployeeRequest = { + employerPersonId: escuelaKemperUrgateId, + employeePersonId: ingridXodarJimenezId, + socialSecurityNumber: '0000000000', + laborRelationStartDate: '2022-03-02T00:00:00', + seniority: 'P66W', + satContractTypeId: '01', + satUnionizedStatusId: 'No', + satTaxRegimeTypeId: '02', + employeeNumber: '111111', + satJobRiskId: '4', + satPaymentPeriodicityId: '02', + integratedDailySalary: 180.96, + satPayrollStateId: 'GUA' + }; + const employeeResult = await client.persons.employee.create(employeeRequest); + console.log('Empleado:', JSON.stringify(employeeResult, null, 2)); +} + +async function nominaConBonosFondoAhorroByReferences(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Con Bonos y Fondo de Ahorro ByReferences ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + id: escuelaKemperUrgateId + }, + recipient: { + id: ingridXodarJimenezId + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'O', + paymentDate: '2023-06-11T00:00:00', + initialPaymentDate: '2023-06-05T00:00:00', + finalPaymentDate: '2023-06-11T00:00:00', + daysPaid: 7, + earnings: { + earnings: [ + { earningTypeCode: '001', code: 'SP01', concept: 'SUELDO', taxedAmount: 1210.30, exemptAmount: 0.00 }, + { earningTypeCode: '010', code: 'SP02', concept: 'PREMIO PUNTUALIDAD', taxedAmount: 121.03, exemptAmount: 0.00 }, + { earningTypeCode: '029', code: 'SP03', concept: 'MONEDERO ELECTRONICO', taxedAmount: 0.00, exemptAmount: 269.43 }, + { earningTypeCode: '010', code: 'SP04', concept: 'PREMIO DE ASISTENCIA', taxedAmount: 121.03, exemptAmount: 0.00 }, + { earningTypeCode: '005', code: 'SP54', concept: 'APORTACION FONDO AHORRO', taxedAmount: 0.00, exemptAmount: 121.03 } + ], + otherPayments: [ + { + otherPaymentTypeCode: '002', + code: 'ISRSUB', + concept: 'Subsidio ISR para empleo', + amount: 0.0, + subsidyCaused: 0.0, + balanceCompensation: { + favorableBalance: 0.0, + year: 2022, + remainingFavorableBalance: 0.0 + } + } + ] + }, + deductions: [ + { deductionTypeCode: '004', code: 'ZA09', concept: 'APORTACION FONDO AHORRO', amount: 121.03 }, + { deductionTypeCode: '002', code: 'ISR', concept: 'ISR', amount: 36.57 }, + { deductionTypeCode: '001', code: 'IMSS', concept: 'Cuota de Seguridad Social EE', amount: 30.08 }, + { deductionTypeCode: '004', code: 'ZA68', concept: 'DEDUCCION FDO AHORRO PAT', amount: 121.03 }, + { deductionTypeCode: '018', code: 'ZA11', concept: 'APORTACION CAJA AHORRO', amount: 300.00 } + ] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 4. NOMINA CON HORAS EXTRA (Facturación por referencias) +// ============================================================================ +async function nominaConHorasExtraByReferencesSetupData(client: FiscalapiClient): Promise { + console.log('\n=== Setup: Nómina Con Horas Extra ByReferences ===\n'); + + // Eliminar datos existentes (idempotente) + try { await client.persons.employer.delete(escuelaKemperUrgateId); } catch { /* ignore */ } + try { await client.persons.employee.delete(ingridXodarJimenezId); } catch { /* ignore */ } + + // Crear datos de empleador + const employerRequest: CreateEmployerRequest = { + personId: escuelaKemperUrgateId, + employerRegistration: 'B5510768108', + originEmployerTin: 'URE180429TM6' + }; + const employerResult = await client.persons.employer.create(employerRequest); + console.log('Empleador:', JSON.stringify(employerResult, null, 2)); + + // Crear datos de empleado + const employeeRequest: CreateEmployeeRequest = { + employerPersonId: escuelaKemperUrgateId, + employeePersonId: ingridXodarJimenezId, + socialSecurityNumber: '000000', + laborRelationStartDate: '2015-01-01', + seniority: 'P437W', + satContractTypeId: '01', + satWorkdayTypeId: '01', + satTaxRegimeTypeId: '03', + employeeNumber: '120', + department: 'Desarrollo', + position: 'Ingeniero de Software', + satJobRiskId: '1', + satPaymentPeriodicityId: '04', + satBankId: '002', + bankAccount: '1111111111', + baseSalaryForContributions: 490.22, + integratedDailySalary: 146.47, + satPayrollStateId: 'JAL' + }; + const employeeResult = await client.persons.employee.create(employeeRequest); + console.log('Empleado:', JSON.stringify(employeeResult, null, 2)); +} + +async function nominaConHorasExtraByReferences(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Con Horas Extra ByReferences ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + id: escuelaKemperUrgateId + }, + recipient: { + id: ingridXodarJimenezId + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'O', + paymentDate: '2023-05-24T00:00:00', + initialPaymentDate: '2023-05-09T00:00:00', + finalPaymentDate: '2023-05-24T00:00:00', + daysPaid: 15, + earnings: { + earnings: [ + { earningTypeCode: '001', code: '00500', concept: 'Sueldos, Salarios Rayas y Jornales', taxedAmount: 2808.8, exemptAmount: 2191.2 }, + { + earningTypeCode: '019', + code: '00100', + concept: 'Horas Extra', + taxedAmount: 50.00, + exemptAmount: 50.00, + overtime: [ + { days: 1, hoursTypeCode: '01', extraHours: 2, amountPaid: 100.00 } + ] + } + ], + otherPayments: [] + }, + deductions: [ + { deductionTypeCode: '001', code: '00301', concept: 'Seguridad Social', amount: 200 }, + { deductionTypeCode: '002', code: '00302', concept: 'ISR', amount: 100 } + ] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 5. NOMINA CON INCAPACIDADES (Facturación por referencias) +// ============================================================================ +async function nominaConIncapacidadesByReferencesSetupData(client: FiscalapiClient): Promise { + console.log('\n=== Setup: Nómina Con Incapacidades ByReferences ===\n'); + + // Eliminar datos existentes (idempotente) + try { await client.persons.employer.delete(escuelaKemperUrgateId); } catch { /* ignore */ } + try { await client.persons.employee.delete(ingridXodarJimenezId); } catch { /* ignore */ } + + // Crear datos de empleador + const employerRequest: CreateEmployerRequest = { + personId: escuelaKemperUrgateId, + employerRegistration: 'B5510768108', + originEmployerTin: 'URE180429TM6' + }; + const employerResult = await client.persons.employer.create(employerRequest); + console.log('Empleador:', JSON.stringify(employerResult, null, 2)); + + // Crear datos de empleado + const employeeRequest: CreateEmployeeRequest = { + employerPersonId: escuelaKemperUrgateId, + employeePersonId: ingridXodarJimenezId, + socialSecurityNumber: '000000', + laborRelationStartDate: '2015-01-01T00:00:00', + seniority: 'P437W', + satContractTypeId: '01', + satWorkdayTypeId: '01', + satTaxRegimeTypeId: '03', + employeeNumber: '120', + department: 'Desarrollo', + position: 'Ingeniero de Software', + satJobRiskId: '1', + satPaymentPeriodicityId: '04', + satBankId: '002', + bankAccount: '1111111111', + baseSalaryForContributions: 490.22, + integratedDailySalary: 146.47, + satPayrollStateId: 'JAL' + }; + const employeeResult = await client.persons.employee.create(employeeRequest); + console.log('Empleado:', JSON.stringify(employeeResult, null, 2)); +} + +async function nominaConIncapacidadesByReferences(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Con Incapacidades ByReferences ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + id: escuelaKemperUrgateId + }, + recipient: { + id: ingridXodarJimenezId + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'O', + paymentDate: '2023-05-24T00:00:00', + initialPaymentDate: '2023-05-09T00:00:00', + finalPaymentDate: '2023-05-24T00:00:00', + daysPaid: 15, + earnings: { + earnings: [ + { earningTypeCode: '001', code: '00500', concept: 'Sueldos, Salarios Rayas y Jornales', taxedAmount: 2808.8, exemptAmount: 2191.2 } + ] + }, + deductions: [ + { deductionTypeCode: '001', code: '00301', concept: 'Seguridad Social', amount: 200 }, + { deductionTypeCode: '002', code: '00302', concept: 'ISR', amount: 100 } + ], + disabilities: [ + { disabilityDays: 1, disabilityTypeCode: '01' } + ] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 6. NOMINA CON SNCF (Facturación por referencias) +// ============================================================================ +async function nominaConSNCFByReferencesSetupData(client: FiscalapiClient): Promise { + console.log('\n=== Setup: Nómina Con SNCF ByReferences ===\n'); + + // Eliminar datos existentes (idempotente) + try { await client.persons.employer.delete(organicosNavezOsorioId); } catch { /* ignore */ } + try { await client.persons.employee.delete(xochiltCasasChavezId); } catch { /* ignore */ } + + // Crear datos de empleador + const employerRequest: CreateEmployerRequest = { + personId: organicosNavezOsorioId, + employerRegistration: '27112029', + satFundSourceId: 'IP' + }; + const employerResult = await client.persons.employer.create(employerRequest); + console.log('Empleador:', JSON.stringify(employerResult, null, 2)); + + // Crear datos de empleado + const employeeRequest: CreateEmployeeRequest = { + employerPersonId: organicosNavezOsorioId, + employeePersonId: xochiltCasasChavezId, + socialSecurityNumber: '80997742673', + laborRelationStartDate: '2021-09-01', + seniority: 'P88W', + satContractTypeId: '01', + satTaxRegimeTypeId: '02', + employeeNumber: '273', + satJobRiskId: '1', + satPaymentPeriodicityId: '04', + integratedDailySalary: 221.48, + satPayrollStateId: 'GRO' + }; + const employeeResult = await client.persons.employee.create(employeeRequest); + console.log('Empleado:', JSON.stringify(employeeResult, null, 2)); +} + +async function nominaConSNCFByReferences(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Con SNCF ByReferences ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '39074', + exportCode: '01', + issuer: { + id: organicosNavezOsorioId + }, + recipient: { + id: xochiltCasasChavezId + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'O', + paymentDate: '2023-05-16T00:00:00', + initialPaymentDate: '2023-05-01T00:00:00', + finalPaymentDate: '2023-05-16T00:00:00', + daysPaid: 15, + earnings: { + earnings: [ + { earningTypeCode: '001', code: 'P001', concept: 'Sueldos, Salarios Rayas y Jornales', taxedAmount: 3322.20, exemptAmount: 0.00 }, + { earningTypeCode: '038', code: 'P540', concept: 'Compensacion', taxedAmount: 100.00, exemptAmount: 0.00 }, + { earningTypeCode: '038', code: 'P550', concept: 'Compensación Garantizada Extraordinaria', taxedAmount: 2200.00, exemptAmount: 0.00 }, + { earningTypeCode: '038', code: 'P530', concept: 'Servicio Extraordinario', taxedAmount: 200.00, exemptAmount: 0.00 }, + { earningTypeCode: '001', code: 'P506', concept: 'Otras Prestaciones', taxedAmount: 1500.00, exemptAmount: 0.00 }, + { earningTypeCode: '001', code: 'P505', concept: 'Remuneración al Desempeño Legislativo', taxedAmount: 17500.00, exemptAmount: 0.00 } + ], + otherPayments: [ + { otherPaymentTypeCode: '002', code: 'o002', concept: 'Subsidio para el empleo efectivamente entregado al trabajador', amount: 0.00, subsidyCaused: 0.00 } + ] + }, + deductions: [ + { deductionTypeCode: '002', code: 'D002', concept: 'ISR', amount: 4716.61 }, + { deductionTypeCode: '004', code: 'D525', concept: 'Redondeo', amount: 0.81 }, + { deductionTypeCode: '001', code: 'D510', concept: 'Cuota Trabajador ISSSTE', amount: 126.78 } + ] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 7. NOMINA EXTRAORDINARIA - AGUINALDO (Facturación por referencias) +// ============================================================================ +async function nominaExtraordinariaByReferencesSetupData(client: FiscalapiClient): Promise { + console.log('\n=== Setup: Nómina Extraordinaria (Aguinaldo) ByReferences ===\n'); + + // Eliminar datos existentes (idempotente) + try { await client.persons.employer.delete(escuelaKemperUrgateId); } catch { /* ignore */ } + try { await client.persons.employee.delete(ingridXodarJimenezId); } catch { /* ignore */ } + + // Crear datos de empleador + const employerRequest: CreateEmployerRequest = { + personId: escuelaKemperUrgateId, + employerRegistration: 'B5510768108', + originEmployerTin: 'URE180429TM6' + }; + const employerResult = await client.persons.employer.create(employerRequest); + console.log('Empleador:', JSON.stringify(employerResult, null, 2)); + + // Crear datos de empleado + const employeeRequest: CreateEmployeeRequest = { + employerPersonId: escuelaKemperUrgateId, + employeePersonId: ingridXodarJimenezId, + socialSecurityNumber: '000000', + laborRelationStartDate: '2015-01-01', + seniority: 'P439W', + satContractTypeId: '01', + satWorkdayTypeId: '01', + satTaxRegimeTypeId: '03', + employeeNumber: '120', + department: 'Desarrollo', + position: 'Ingeniero de Software', + satJobRiskId: '1', + satPaymentPeriodicityId: '99', + satBankId: '002', + bankAccount: '1111111111', + integratedDailySalary: 146.47, + satPayrollStateId: 'JAL' + }; + const employeeResult = await client.persons.employee.create(employeeRequest); + console.log('Empleado:', JSON.stringify(employeeResult, null, 2)); +} + +async function nominaExtraordinariaByReferences(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Extraordinaria (Aguinaldo) ByReferences ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + id: escuelaKemperUrgateId + }, + recipient: { + id: ingridXodarJimenezId + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'E', + paymentDate: '2023-06-04T00:00:00', + initialPaymentDate: '2023-06-04T00:00:00', + finalPaymentDate: '2023-06-04T00:00:00', + daysPaid: 30, + earnings: { + earnings: [ + { earningTypeCode: '002', code: '00500', concept: 'Gratificación Anual (Aguinaldo)', taxedAmount: 0.00, exemptAmount: 10000.00 } + ], + otherPayments: [] + }, + deductions: [] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 8. NOMINA SEPARACION INDEMNIZACION (Facturación por referencias) +// ============================================================================ +async function nominaSeparacionIndemnizacionByReferencesSetupData(client: FiscalapiClient): Promise { + console.log('\n=== Setup: Nómina Separación Indemnización ByReferences ===\n'); + + // Eliminar datos existentes (idempotente) + try { await client.persons.employer.delete(escuelaKemperUrgateId); } catch { /* ignore */ } + try { await client.persons.employee.delete(ingridXodarJimenezId); } catch { /* ignore */ } + + // Crear datos de empleador + const employerRequest: CreateEmployerRequest = { + personId: escuelaKemperUrgateId, + employerRegistration: 'B5510768108', + originEmployerTin: 'URE180429TM6' + }; + const employerResult = await client.persons.employer.create(employerRequest); + console.log('Empleador:', JSON.stringify(employerResult, null, 2)); + + // Crear datos de empleado + const employeeRequest: CreateEmployeeRequest = { + employerPersonId: escuelaKemperUrgateId, + employeePersonId: ingridXodarJimenezId, + socialSecurityNumber: '000000', + laborRelationStartDate: '2015-01-01', + seniority: 'P439W', + satContractTypeId: '01', + satWorkdayTypeId: '01', + satTaxRegimeTypeId: '03', + employeeNumber: '120', + department: 'Desarrollo', + position: 'Ingeniero de Software', + satJobRiskId: '1', + satPaymentPeriodicityId: '99', + satBankId: '002', + bankAccount: '1111111111', + integratedDailySalary: 146.47, + satPayrollStateId: 'JAL' + }; + const employeeResult = await client.persons.employee.create(employeeRequest); + console.log('Empleado:', JSON.stringify(employeeResult, null, 2)); +} + +async function nominaSeparacionIndemnizacionByReferences(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Separación Indemnización ByReferences ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + id: escuelaKemperUrgateId + }, + recipient: { + id: ingridXodarJimenezId + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'E', + paymentDate: '2023-06-04T00:00:00', + initialPaymentDate: '2023-05-05T00:00:00', + finalPaymentDate: '2023-06-04T00:00:00', + daysPaid: 30, + earnings: { + earnings: [ + { earningTypeCode: '023', code: '00500', concept: 'Pagos por separación', taxedAmount: 0.00, exemptAmount: 10000.00 }, + { earningTypeCode: '025', code: '00900', concept: 'Indemnizaciones', taxedAmount: 0.00, exemptAmount: 500.00 } + ], + otherPayments: [], + severance: { + totalPaid: 10500.00, + yearsOfService: 1, + lastMonthlySalary: 10000.00, + accumulableIncome: 10000.00, + nonAccumulableIncome: 0.00 + } + }, + deductions: [] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 9. NOMINA JUBILACION PENSION RETIRO (Facturación por referencias) +// ============================================================================ +async function nominaJubilacionPensionRetiroByReferencesSetupData(client: FiscalapiClient): Promise { + console.log('\n=== Setup: Nómina Jubilación Pensión Retiro ByReferences ===\n'); + + // Eliminar datos existentes (idempotente) + try { await client.persons.employer.delete(escuelaKemperUrgateId); } catch { /* ignore */ } + try { await client.persons.employee.delete(ingridXodarJimenezId); } catch { /* ignore */ } + + // Crear datos de empleador + const employerRequest: CreateEmployerRequest = { + personId: escuelaKemperUrgateId, + employerRegistration: 'B5510768108', + originEmployerTin: 'URE180429TM6' + }; + const employerResult = await client.persons.employer.create(employerRequest); + console.log('Empleador:', JSON.stringify(employerResult, null, 2)); + + // Crear datos de empleado + const employeeRequest: CreateEmployeeRequest = { + employerPersonId: escuelaKemperUrgateId, + employeePersonId: ingridXodarJimenezId, + socialSecurityNumber: '000000', + laborRelationStartDate: '2015-01-01', + seniority: 'P439W', + satContractTypeId: '01', + satWorkdayTypeId: '01', + satTaxRegimeTypeId: '03', + employeeNumber: '120', + department: 'Desarrollo', + position: 'Ingeniero de Software', + satJobRiskId: '1', + satPaymentPeriodicityId: '99', + satBankId: '002', + bankAccount: '1111111111', + integratedDailySalary: 146.47, + satPayrollStateId: 'JAL' + }; + const employeeResult = await client.persons.employee.create(employeeRequest); + console.log('Empleado:', JSON.stringify(employeeResult, null, 2)); +} + +async function nominaJubilacionPensionRetiroByReferences(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Jubilación Pensión Retiro ByReferences ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + id: escuelaKemperUrgateId + }, + recipient: { + id: ingridXodarJimenezId + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'E', + paymentDate: '2023-05-05T00:00:00', + initialPaymentDate: '2023-06-04T00:00:00', + finalPaymentDate: '2023-06-04T00:00:00', + daysPaid: 30, + earnings: { + earnings: [ + { earningTypeCode: '039', code: '00500', concept: 'Jubilaciones, pensiones o haberes de retiro', taxedAmount: 0.00, exemptAmount: 10000.00 } + ], + retirement: { + totalOneTime: 10000.00, + accumulableIncome: 10000.00, + nonAccumulableIncome: 0.00 + } + }, + deductions: [] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 10. NOMINA SIN DEDUCCIONES (Facturación por referencias) +// ============================================================================ +async function nominaSinDeduccionesByReferencesSetupData(client: FiscalapiClient): Promise { + console.log('\n=== Setup: Nómina Sin Deducciones ByReferences ===\n'); + + // Eliminar datos existentes (idempotente) + try { await client.persons.employer.delete(escuelaKemperUrgateId); } catch { /* ignore */ } + try { await client.persons.employee.delete(ingridXodarJimenezId); } catch { /* ignore */ } + + // Crear datos de empleador + const employerRequest: CreateEmployerRequest = { + personId: escuelaKemperUrgateId, + employerRegistration: 'B5510768108', + originEmployerTin: 'URE180429TM6' + }; + const employerResult = await client.persons.employer.create(employerRequest); + console.log('Empleador:', JSON.stringify(employerResult, null, 2)); + + // Crear datos de empleado + const employeeRequest: CreateEmployeeRequest = { + employerPersonId: escuelaKemperUrgateId, + employeePersonId: ingridXodarJimenezId, + socialSecurityNumber: '000000', + laborRelationStartDate: '2015-01-01', + seniority: 'P437W', + satContractTypeId: '01', + satWorkdayTypeId: '01', + satTaxRegimeTypeId: '03', + employeeNumber: '120', + department: 'Desarrollo', + position: 'Ingeniero de Software', + satJobRiskId: '1', + satPaymentPeriodicityId: '04', + satBankId: '002', + bankAccount: '1111111111', + baseSalaryForContributions: 490.22, + integratedDailySalary: 146.47, + satPayrollStateId: 'JAL' + }; + const employeeResult = await client.persons.employee.create(employeeRequest); + console.log('Empleado:', JSON.stringify(employeeResult, null, 2)); +} + +async function nominaSinDeduccionesByReferences(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Sin Deducciones ByReferences ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + id: escuelaKemperUrgateId + }, + recipient: { + id: ingridXodarJimenezId + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'O', + paymentDate: '2023-05-24T00:00:00', + initialPaymentDate: '2023-05-09T00:00:00', + finalPaymentDate: '2023-05-24T00:00:00', + daysPaid: 15, + earnings: { + earnings: [ + { earningTypeCode: '001', code: '00500', concept: 'Sueldos, Salarios Rayas y Jornales', taxedAmount: 2808.8, exemptAmount: 2191.2 } + ], + otherPayments: [] + }, + deductions: [] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 11. NOMINA SUBSIDIO CAUSADO (Facturación por referencias) +// ============================================================================ +async function nominaSubsidioCausadoByReferencesSetupData(client: FiscalapiClient): Promise { + console.log('\n=== Setup: Nómina Subsidio Causado ByReferences ===\n'); + + // Eliminar datos existentes (idempotente) + try { await client.persons.employer.delete(escuelaKemperUrgateId); } catch { /* ignore */ } + try { await client.persons.employee.delete(ingridXodarJimenezId); } catch { /* ignore */ } + + // Crear datos de empleador + const employerRequest: CreateEmployerRequest = { + personId: escuelaKemperUrgateId, + employerRegistration: 'B5510768108', + originEmployerTin: 'URE180429TM6' + }; + const employerResult = await client.persons.employer.create(employerRequest); + console.log('Empleador:', JSON.stringify(employerResult, null, 2)); + + // Crear datos de empleado + const employeeRequest: CreateEmployeeRequest = { + employerPersonId: escuelaKemperUrgateId, + employeePersonId: ingridXodarJimenezId, + socialSecurityNumber: '000000', + laborRelationStartDate: '2015-01-01T00:00:00', + seniority: 'P437W', + satContractTypeId: '01', + satWorkdayTypeId: '01', + satTaxRegimeTypeId: '02', + employeeNumber: '120', + department: 'Desarrollo', + position: 'Ingeniero de Software', + satJobRiskId: '1', + satPaymentPeriodicityId: '04', + satBankId: '002', + bankAccount: '1111111111', + baseSalaryForContributions: 490.22, + integratedDailySalary: 146.47, + satPayrollStateId: 'JAL' + }; + const employeeResult = await client.persons.employee.create(employeeRequest); + console.log('Empleado:', JSON.stringify(employeeResult, null, 2)); +} + +async function nominaSubsidioCausadoByReferences(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Subsidio Causado ByReferences ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + id: escuelaKemperUrgateId + }, + recipient: { + id: ingridXodarJimenezId + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'O', + paymentDate: '2023-05-24T00:00:00', + initialPaymentDate: '2023-05-09T00:00:00', + finalPaymentDate: '2023-05-24T00:00:00', + daysPaid: 15, + earnings: { + earnings: [ + { earningTypeCode: '001', code: '00500', concept: 'Sueldos, Salarios Rayas y Jornales', taxedAmount: 2808.8, exemptAmount: 2191.2 } + ], + otherPayments: [ + { otherPaymentTypeCode: '007', code: '0002', concept: 'ISR ajustado por subsidio', amount: 145.80, subsidyCaused: 0.0 } + ] + }, + deductions: [ + { deductionTypeCode: '107', code: 'D002', concept: 'Ajuste al Subsidio Causado', amount: 160.35 }, + { deductionTypeCode: '002', code: 'D002', concept: 'ISR', amount: 145.80 } + ] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 12. NOMINA VIATICOS (Facturación por referencias) +// ============================================================================ +async function nominaViaticosByReferencesSetupData(client: FiscalapiClient): Promise { + console.log('\n=== Setup: Nómina Viáticos ByReferences ===\n'); + + // Eliminar datos existentes (idempotente) + try { await client.persons.employer.delete(escuelaKemperUrgateId); } catch { /* ignore */ } + try { await client.persons.employee.delete(ingridXodarJimenezId); } catch { /* ignore */ } + + // Crear datos de empleador + const employerRequest: CreateEmployerRequest = { + personId: escuelaKemperUrgateId, + employerRegistration: 'B5510768108', + originEmployerTin: 'URE180429TM6' + }; + const employerResult = await client.persons.employer.create(employerRequest); + console.log('Empleador:', JSON.stringify(employerResult, null, 2)); + + // Crear datos de empleado + const employeeRequest: CreateEmployeeRequest = { + employerPersonId: escuelaKemperUrgateId, + employeePersonId: ingridXodarJimenezId, + socialSecurityNumber: '000000', + laborRelationStartDate: '2015-01-01T00:00:00', + seniority: 'P438W', + satContractTypeId: '01', + satWorkdayTypeId: '01', + satTaxRegimeTypeId: '03', + employeeNumber: '120', + department: 'Desarrollo', + position: 'Ingeniero de Software', + satJobRiskId: '1', + satPaymentPeriodicityId: '04', + satBankId: '002', + bankAccount: '1111111111', + baseSalaryForContributions: 490.22, + integratedDailySalary: 146.47, + satPayrollStateId: 'JAL' + }; + const employeeResult = await client.persons.employee.create(employeeRequest); + console.log('Empleado:', JSON.stringify(employeeResult, null, 2)); +} + +async function nominaViaticosByReferences(client: FiscalapiClient): Promise { + console.log('\n=== Nómina Viáticos ByReferences ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + id: escuelaKemperUrgateId + }, + recipient: { + id: ingridXodarJimenezId + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'O', + paymentDate: '2023-09-26T00:00:00', + initialPaymentDate: '2023-09-11T00:00:00', + finalPaymentDate: '2023-09-26T00:00:00', + daysPaid: 15, + earnings: { + earnings: [ + { earningTypeCode: '050', code: '050', concept: 'Viaticos', taxedAmount: 0, exemptAmount: 3000 } + ] + }, + deductions: [ + { deductionTypeCode: '081', code: '081', concept: 'Ajuste en viaticos entregados al trabajador', amount: 3000 } + ] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 13. NOMINA GENERAL (Facturación por referencias) +// ============================================================================ +async function nominaGeneralByReferencesSetupData(client: FiscalapiClient): Promise { + console.log('\n=== Setup: Nómina General ByReferences ===\n'); + + // Eliminar datos existentes (idempotente) + try { await client.persons.employer.delete(escuelaKemperUrgateId); } catch { /* ignore */ } + try { await client.persons.employee.delete(ingridXodarJimenezId); } catch { /* ignore */ } + + // Crear datos de empleador + const employerRequest: CreateEmployerRequest = { + personId: escuelaKemperUrgateId, + employerRegistration: 'B5510768108', + originEmployerTin: 'URE180429TM6' + }; + const employerResult = await client.persons.employer.create(employerRequest); + console.log('Empleador:', JSON.stringify(employerResult, null, 2)); + + // Crear datos de empleado + const employeeRequest: CreateEmployeeRequest = { + employerPersonId: escuelaKemperUrgateId, + employeePersonId: ingridXodarJimenezId, + socialSecurityNumber: '000000', + laborRelationStartDate: '2015-01-01T00:00:00', + seniority: 'P437W', + satContractTypeId: '01', + satWorkdayTypeId: '01', + satTaxRegimeTypeId: '03', + employeeNumber: '120', + department: 'Desarrollo', + position: 'Ingeniero de Software', + satJobRiskId: '1', + satPaymentPeriodicityId: '04', + satBankId: '002', + bankAccount: '1111111111', + baseSalaryForContributions: 490.22, + integratedDailySalary: 146.47, + satPayrollStateId: 'JAL' + }; + const employeeResult = await client.persons.employee.create(employeeRequest); + console.log('Empleado:', JSON.stringify(employeeResult, null, 2)); +} + +async function nominaGeneralByReferences(client: FiscalapiClient): Promise { + console.log('\n=== Nómina General ByReferences ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentMethodCode: 'PUE', + currencyCode: 'MXN', + typeCode: 'N', + expeditionZipCode: '20000', + exportCode: '01', + issuer: { + id: escuelaKemperUrgateId + }, + recipient: { + id: ingridXodarJimenezId + }, + complement: { + payroll: { + version: '1.2', + payrollTypeCode: 'O', + paymentDate: '2023-05-24T00:00:00', + initialPaymentDate: '2023-05-09T00:00:00', + finalPaymentDate: '2023-05-24T00:00:00', + daysPaid: 15, + earnings: { + earnings: [ + { earningTypeCode: '001', code: '00500', concept: 'Sueldos, Salarios Rayas y Jornales', taxedAmount: 2808.8, exemptAmount: 2191.2 } + ], + otherPayments: [] + }, + deductions: [ + { deductionTypeCode: '001', code: '00301', concept: 'Seguridad Social', amount: 200 }, + { deductionTypeCode: '002', code: '00302', concept: 'ISR', amount: 100 } + ] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// FUNCION PRINCIPAL +// ============================================================================ +async function main(): Promise { + console.log('=== Ejemplos de Factura Nómina FiscalAPI (Referencias) ===\n'); + + const client = FiscalapiClient.create(settings); + + try { + // Descomentar el caso de uso que se desea ejecutar + // IMPORTANTE: Ejecutar primero la función de setup, luego la de factura + + // 1. Nómina Ordinaria + // await nominaOrdinariaByReferencesSetupData(client); + // await nominaOrdinariaByReferences(client); + + // 2. Nómina Asimilados + // await nominaAsimiladosByReferencesSetupData(client); + // await nominaAsimiladosByReferences(client); + + // 3. Nómina Con Bonos y Fondo de Ahorro + // await nominaConBonosFondoAhorroByReferencesSetupData(client); + // await nominaConBonosFondoAhorroByReferences(client); + + // 4. Nómina Con Horas Extra + // await nominaConHorasExtraByReferencesSetupData(client); + // await nominaConHorasExtraByReferences(client); + + // 5. Nómina Con Incapacidades + // await nominaConIncapacidadesByReferencesSetupData(client); + // await nominaConIncapacidadesByReferences(client); + + // 6. Nómina Con SNCF + // await nominaConSNCFByReferencesSetupData(client); + // await nominaConSNCFByReferences(client); + + // 7. Nómina Extraordinaria (Aguinaldo) + // await nominaExtraordinariaByReferencesSetupData(client); + // await nominaExtraordinariaByReferences(client); + + // 8. Nómina Separación Indemnización + // await nominaSeparacionIndemnizacionByReferencesSetupData(client); + // await nominaSeparacionIndemnizacionByReferences(client); + + // 9. Nómina Jubilación Pensión Retiro + // await nominaJubilacionPensionRetiroByReferencesSetupData(client); + // await nominaJubilacionPensionRetiroByReferences(client); + + // 10. Nómina Sin Deducciones + // await nominaSinDeduccionesByReferencesSetupData(client); + // await nominaSinDeduccionesByReferences(client); + + // 11. Nómina Subsidio Causado + // await nominaSubsidioCausadoByReferencesSetupData(client); + // await nominaSubsidioCausadoByReferences(client); + + // 12. Nómina Viáticos + // await nominaViaticosByReferencesSetupData(client); + // await nominaViaticosByReferences(client); + + // 13. Nómina General + await nominaGeneralByReferencesSetupData(client); + await nominaGeneralByReferences(client); + + console.log('\nEjecución completada.'); + } catch (error) { + console.error('Error:', error); + } +} + +// Ejecutar función principal +main(); diff --git a/examples/ejemplos-factura-nomina.ts b/examples/ejemplos-factura-nomina-valores.ts similarity index 99% rename from examples/ejemplos-factura-nomina.ts rename to examples/ejemplos-factura-nomina-valores.ts index 724abdf..f53bbaf 100644 --- a/examples/ejemplos-factura-nomina.ts +++ b/examples/ejemplos-factura-nomina-valores.ts @@ -12,12 +12,9 @@ inspect.defaultOptions.colors = true; // Configuración de FiscalAPI const settings: FiscalapiSettings = { - // apiUrl: 'https://test.fiscalapi.com', - // apiKey: '', - // tenant: '', - apiUrl: "http://localhost:5001", - apiKey: "sk_development_b470ea83_3c0f_4209_b933_85223b960d91", - tenant: "102e5f13-e114-41dd-bea7-507fce177281", + apiUrl: 'https://test.fisalapi.com', + apiKey: '', + tenant: '', debug: true }; diff --git a/payroll-invoice-requrements.md b/payroll-invoice-requrements.md index a5c07a0..3b6048b 100644 --- a/payroll-invoice-requrements.md +++ b/payroll-invoice-requrements.md @@ -2515,7 +2515,10 @@ For each of the 13 use cases, you must generate **two distinct operations**: 2. **Invoice Generation (Execution):** Create the payroll invoice request using the IDs defined above (referencing the objects created in step 1). * *Note:* The "Payroll Complement" data (amounts, perceptions, deductions) must remain identical to the original examples. -3. Example +3. Add those samples to the main function to be executable uncommeting them as needed, follow the same patter that the by values version. + + +Example // ============================================================================ // 1. NOMINA ORDINARIA (Facturación por referencias) From 731428d18c85bf32f1b212935a0f762aa0457d5b Mon Sep 17 00:00:00 2001 From: JesusMendoza Date: Tue, 27 Jan 2026 14:56:06 -0600 Subject: [PATCH 09/15] readme updated --- README.md | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index c8f63e1..cf30065 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,15 @@ - **Soporte completo para CFDI 4.0** con todas las especificaciones oficiales - **Timbrado de facturas de ingreso** con validación automática - **Timbrado de notas de crédito** (facturas de egreso) -- **Timbrado de complementos de pago** en MXN, USD y EUR. +- **Timbrado de complementos de pago** en MXN, USD y EUR +- **Timbrado de facturas de nómina** (CFDI Nómina 1.2) - **Consulta del estatus de facturas** en el SAT en tiempo real -- **Cancelación de facturas** +- **Cancelación de facturas** - **Generación de archivos PDF** de las facturas con formato profesional - **Personalización de logos y colores** en los PDF generados - **Envío de facturas por correo electrónico** automatizado - **Descarga de archivos XML** con estructura completa -- **Almacenamiento y recuperación** de facturas por 5 años. +- **Almacenamiento y recuperación** de facturas por 5 años - Dos [modos de operación](https://docs.fiscalapi.com/modes-of-operation): **Por valores** o **Por referencias** ## 📥 Descarga Masiva @@ -32,11 +33,16 @@ - **Administración de personas** (emisores, receptores, clientes, usuarios, etc.) - **Gestión de certificados CSD y FIEL** (subir archivos .cer y .key a FiscalAPI) - **Configuración de datos fiscales** (RFC, domicilio fiscal, régimen fiscal) +- **Datos de empleado** (agrega/actualiza/elimina datos de empleado a una persona. CFDI Nómina) +- **Datos de empleador** (agrega/actualiza/elimina datos de empleador a una persona. CFDI Nómina) ## 🛍️ Gestión de Productos/Servicios - **Gestión de productos y servicios** con catálogo personalizable - **Administración de impuestos aplicables** (IVA, ISR, IEPS) +## 🎖️ Gestión de Timbres +- **Gestión de folios fiscales** Compra timbres a fiscalapi y transfiere/retira a las personas de tu organizacion segun tus reglas de negocio. + ## 📚 Consulta de Catálogos SAT - **Consulta en catálogos oficiales del SAT** actualizados - **Consulta en catálogos oficiales de Descarga masiva del SAT** actualizados @@ -381,16 +387,21 @@ try { } ``` +## 📂 Más Ejemplos + +- [Gestión de Timbres](examples/ejemplo-timbres.ts) - Transferencias y retiros de timbres +- [Datos Empleador/Empleado](examples/ejemplo-datos-empleado-empleador.ts) - Configuración para nómina +- [Facturas de Nómina (Por Valores)](examples/ejemplos-factura-nomina-valores.ts) - 13 ejemplos completos +- [Facturas de Nómina (Por Referencias)](examples/ejemplos-factura-nomina-referencias.ts) - 13 ejemplos completos + --- ## 📋 Operaciones Principales -- **Facturas (CFDI)** - Crear facturas de ingreso, notas de crédito, complementos de pago, cancelaciones, generación de PDF/XML. -- **Personas (Clientes/Emisores)** - Alta y administración de personas, gestión de certificados (CSD). -- **Productos y Servicios** - Administración de catálogos de productos, búsqueda en catálogos SAT. +- **Facturas (CFDI)** - Ingreso, egreso, pago, nómina, cancelaciones, PDF/XML +- **Personas** - Emisores, receptores, certificados CSD +- **Productos** - Catálogo de productos/servicios +- **Timbres** - Transferencias y retiros ## 🤝 Contribuir From 7f0c09029520be2c39960e4cdb58d2fdb3869f17 Mon Sep 17 00:00:00 2001 From: JesusMendoza Date: Tue, 27 Jan 2026 15:11:10 -0600 Subject: [PATCH 10/15] modules naming convention standarized added --- .../ejemplos-factura-nomina-referencias.ts | 8 ++- examples/ejemplos-factura-nomina-valores.ts | 14 ++--- ... => download-catalog-service.interface.ts} | 0 ... => download-request-service.interface.ts} | 0 ....ts => download-rule-service.interface.ts} | 0 .../fiscalapi-client.interface.ts | 6 +- .../tax-file-service.interface.ts | 6 +- src/http/fiscalapi-http-client.interface.ts | 8 --- src/http/fiscalapi-http-client.ts | 56 +++++++++++-------- src/index.ts | 6 +- ...service.ts => download-catalog-service.ts} | 2 +- ...service.ts => download-request-service.ts} | 2 +- ...le.service.ts => download-rule-service.ts} | 2 +- src/services/employee-service.ts | 2 +- src/services/employer-service.ts | 2 +- src/services/fiscalapi-client.ts | 14 ++--- 16 files changed, 64 insertions(+), 64 deletions(-) rename src/abstractions/{download-catalog.interface.ts => download-catalog-service.interface.ts} (100%) rename src/abstractions/{download-request.service.interface.ts => download-request-service.interface.ts} (100%) rename src/abstractions/{download-rule.service.interface.ts => download-rule-service.interface.ts} (100%) rename src/services/{download-catalog.service.ts => download-catalog-service.ts} (98%) rename src/services/{download-request.service.ts => download-request-service.ts} (99%) rename src/services/{download-rule.service.ts => download-rule-service.ts} (98%) diff --git a/examples/ejemplos-factura-nomina-referencias.ts b/examples/ejemplos-factura-nomina-referencias.ts index 15d4e27..27fcdec 100644 --- a/examples/ejemplos-factura-nomina-referencias.ts +++ b/examples/ejemplos-factura-nomina-referencias.ts @@ -18,10 +18,12 @@ inspect.defaultOptions.colors = true; // Configuración de FiscalAPI const settings: FiscalapiSettings = { - apiUrl: 'https://test.fisalapi.com', + apiUrl: 'https://test.fisalapi.com', apiKey: '', tenant: '', debug: true + + }; // ============================================================================ @@ -1218,8 +1220,8 @@ async function main(): Promise { // IMPORTANTE: Ejecutar primero la función de setup, luego la de factura // 1. Nómina Ordinaria - // await nominaOrdinariaByReferencesSetupData(client); - // await nominaOrdinariaByReferences(client); + await nominaOrdinariaByReferencesSetupData(client); + await nominaOrdinariaByReferences(client); // 2. Nómina Asimilados // await nominaAsimiladosByReferencesSetupData(client); diff --git a/examples/ejemplos-factura-nomina-valores.ts b/examples/ejemplos-factura-nomina-valores.ts index f53bbaf..69706a3 100644 --- a/examples/ejemplos-factura-nomina-valores.ts +++ b/examples/ejemplos-factura-nomina-valores.ts @@ -12,10 +12,10 @@ inspect.defaultOptions.colors = true; // Configuración de FiscalAPI const settings: FiscalapiSettings = { - apiUrl: 'https://test.fisalapi.com', - apiKey: '', - tenant: '', - debug: true + apiUrl: 'https://test.fisalapi.com', + apiKey: '', + tenant: '', + debug: true }; // Sellos SAT de prueba @@ -1103,19 +1103,19 @@ async function main(): Promise { try { // Descomentar el caso de uso que se desea ejecutar - // await nominaOrdinariaByValues(client); + await nominaOrdinariaByValues(client); // await nominaAsimiladosByValues(client); // await nominaConBonosFondoAhorroByValues(client); // await nominaConHorasExtraByValues(client); // await nominaConIncapacidadesByValues(client); - await nominaConSNCFByValues(client); + // await nominaConSNCFByValues(client); // await nominaExtraordinariaByValues(client); // await nominaSeparacionIndemnizacionByValues(client); // await nominaJubilacionPensionRetiroByValues(client); // await nominaSinDeduccionesByValues(client); // await nominaSubsidioCausadoByValues(client); // await nominaViaticosByValues(client); - await nominaGeneralByValues(client); + // await nominaGeneralByValues(client); console.log('\nEjecución completada.'); } catch (error) { diff --git a/src/abstractions/download-catalog.interface.ts b/src/abstractions/download-catalog-service.interface.ts similarity index 100% rename from src/abstractions/download-catalog.interface.ts rename to src/abstractions/download-catalog-service.interface.ts diff --git a/src/abstractions/download-request.service.interface.ts b/src/abstractions/download-request-service.interface.ts similarity index 100% rename from src/abstractions/download-request.service.interface.ts rename to src/abstractions/download-request-service.interface.ts diff --git a/src/abstractions/download-rule.service.interface.ts b/src/abstractions/download-rule-service.interface.ts similarity index 100% rename from src/abstractions/download-rule.service.interface.ts rename to src/abstractions/download-rule-service.interface.ts diff --git a/src/abstractions/fiscalapi-client.interface.ts b/src/abstractions/fiscalapi-client.interface.ts index 76ea52b..fada5e7 100644 --- a/src/abstractions/fiscalapi-client.interface.ts +++ b/src/abstractions/fiscalapi-client.interface.ts @@ -1,8 +1,8 @@ import { IApiKeyService } from './api-key-service.interface'; import { ICatalogService } from './catalog-service.interface'; -import { IDownloadCatalogService } from './download-catalog.interface'; -import { IDownloadRequestService } from './download-request.service.interface'; -import { IDownloadRuleService } from './download-rule.service.interface'; +import { IDownloadCatalogService } from './download-catalog-service.interface'; +import { IDownloadRequestService } from './download-request-service.interface'; +import { IDownloadRuleService } from './download-rule-service.interface'; import { IInvoiceService } from './invoice-service.interface'; import { IPersonService } from './person-service.interface'; import { IProductService } from './product-service.interface'; diff --git a/src/abstractions/tax-file-service.interface.ts b/src/abstractions/tax-file-service.interface.ts index 079139b..bf61851 100644 --- a/src/abstractions/tax-file-service.interface.ts +++ b/src/abstractions/tax-file-service.interface.ts @@ -1,4 +1,3 @@ - import { IFiscalapiService } from './fiscalapi-service.interface'; import { TaxFile } from '../models/tax-file'; import { ApiResponse } from '../common/api-response'; @@ -16,7 +15,7 @@ export interface ITaxFileService extends IFiscalapiService { * @param personId - Id de la persona propietaria de los certificados * @returns Promise que resuelve en una respuesta API con una lista de un par de certificados, pero sin contenido, solo sus Ids */ - getDefaultReferences(personId: string): Promise> + getDefaultReferences(personId: string): Promise>; /** * Obtiene el último par de certificados válidos y vigente de una persona. Es decir sus certificados por defecto @@ -24,7 +23,6 @@ export interface ITaxFileService extends IFiscalapiService { * @param personId - Id de la persona dueña de los certificados * @returns Promise que resuelve en una respuesta API con una lista de un par de certificados */ - getDefaultValues(personId: string): Promise> - + getDefaultValues(personId: string): Promise>; } diff --git a/src/http/fiscalapi-http-client.interface.ts b/src/http/fiscalapi-http-client.interface.ts index 71c7479..dadb896 100644 --- a/src/http/fiscalapi-http-client.interface.ts +++ b/src/http/fiscalapi-http-client.interface.ts @@ -33,14 +33,6 @@ export interface IFiscalapiHttpClient { */ getAsync(endpoint: string, config?: AxiosRequestConfig): Promise>; - /** - * Realiza una petición GET por ID a la API - * @param endpoint - Punto final de la API con ID - * @param config - Configuración adicional para la petición - * @returns Respuesta de la API - */ - getByIdAsync(endpoint: string, config?: AxiosRequestConfig): Promise>; - /** * Realiza una petición POST a la API * @param endpoint - Punto final de la API diff --git a/src/http/fiscalapi-http-client.ts b/src/http/fiscalapi-http-client.ts index 507a0ec..c5496e4 100644 --- a/src/http/fiscalapi-http-client.ts +++ b/src/http/fiscalapi-http-client.ts @@ -228,21 +228,42 @@ export class FiscalapiHttpClient implements IFiscalapiHttpClient { * @private */ private handleRequestError(error: unknown): ApiResponse { + // Verificar si es un error de Axios usando type guard + if (!(error instanceof Error)) { + return { + data: {} as T, + succeeded: false, + message: 'Error desconocido en la comunicación con el servidor', + details: String(error), + httpStatusCode: 500 + }; + } + + // Verificar si es un AxiosError (tiene la propiedad isAxiosError) + const isAxiosError = 'isAxiosError' in error && error.isAxiosError === true; + if (!isAxiosError) { + return { + data: {} as T, + succeeded: false, + message: error.message || 'Error en la comunicación con el servidor', + details: error.stack || '', + httpStatusCode: 500 + }; + } + const axiosError = error as AxiosError; - - // Extraer datos de respuesta const responseData = axiosError.response?.data; - + // Revisar si es un ProblemDetails según RFC 9457 if ( - responseData && - typeof responseData === 'object' && - 'type' in responseData && + responseData && + typeof responseData === 'object' && + 'type' in responseData && 'title' in responseData && 'status' in responseData ) { const problemDetails = responseData as ProblemDetails; - + return { data: {} as T, succeeded: false, @@ -251,17 +272,17 @@ export class FiscalapiHttpClient implements IFiscalapiHttpClient { httpStatusCode: axiosError.response?.status || 500 }; } - + // Revisar si es un ApiResponse para errores 400 if ( axiosError.response?.status === 400 && responseData && typeof responseData === 'object' && 'data' in responseData && - Array.isArray(responseData.data) + Array.isArray((responseData as { data: unknown }).data) ) { const apiResponse = responseData as ApiResponse; - + // Si hay errores de validación, extraer el primer mensaje if (apiResponse.data && apiResponse.data.length > 0) { const firstFailure = apiResponse.data[0]; @@ -274,8 +295,8 @@ export class FiscalapiHttpClient implements IFiscalapiHttpClient { }; } } - - // Respuesta de error genérica + + // Respuesta de error genérica para AxiosError return { data: {} as T, succeeded: false, @@ -296,17 +317,6 @@ export class FiscalapiHttpClient implements IFiscalapiHttpClient { return this.executeRequest('GET', endpoint, { config }); } - /** - * Realiza una petición GET por ID a la API - * @param {string} endpoint - Punto final de la API con ID - * @param {AxiosRequestConfig} [config] - Configuración adicional para la petición - * @returns {Promise>} Respuesta de la API - * @template T - Tipo de datos esperado en la respuesta - */ - async getByIdAsync(endpoint: string, config?: AxiosRequestConfig): Promise> { - return this.executeRequest('GET', endpoint, { config }); - } - /** * Realiza una petición POST a la API * @param {string} endpoint - Punto final de la API diff --git a/src/index.ts b/src/index.ts index 5847458..3588073 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,9 +10,9 @@ export type { IInvoiceService } from './abstractions/invoice-service.interface'; export type { IPersonService } from './abstractions/person-service.interface'; export type { IProductService } from './abstractions/product-service.interface'; export type { ITaxFileService } from './abstractions/tax-file-service.interface'; -export type { IDownloadCatalogService } from './abstractions/download-catalog.interface'; -export type { IDownloadRequestService } from './abstractions/download-request.service.interface'; -export type { IDownloadRuleService } from './abstractions/download-rule.service.interface'; +export type { IDownloadCatalogService } from './abstractions/download-catalog-service.interface'; +export type { IDownloadRequestService } from './abstractions/download-request-service.interface'; +export type { IDownloadRuleService } from './abstractions/download-rule-service.interface'; export type { IStampService } from './abstractions/stamp-service.interface'; export type { IEmployeeService } from './abstractions/employee-service.interface'; export type { IEmployerService } from './abstractions/employer-service.interface'; diff --git a/src/services/download-catalog.service.ts b/src/services/download-catalog-service.ts similarity index 98% rename from src/services/download-catalog.service.ts rename to src/services/download-catalog-service.ts index a7d523a..cc3148e 100644 --- a/src/services/download-catalog.service.ts +++ b/src/services/download-catalog-service.ts @@ -1,7 +1,7 @@ import { CatalogDto } from '../common/catalog-dto'; import { ApiResponse } from '../common/api-response'; import { IFiscalapiHttpClient } from '../http/fiscalapi-http-client.interface'; -import { IDownloadCatalogService } from '../abstractions/download-catalog.interface'; +import { IDownloadCatalogService } from '../abstractions/download-catalog-service.interface'; /** * Implementación del servicio de catálogos de descarga masiva diff --git a/src/services/download-request.service.ts b/src/services/download-request-service.ts similarity index 99% rename from src/services/download-request.service.ts rename to src/services/download-request-service.ts index 45dc6e3..9c3dec2 100644 --- a/src/services/download-request.service.ts +++ b/src/services/download-request-service.ts @@ -1,7 +1,7 @@ import { DownloadRequest, Xml, MetadataItem } from '../models/download'; import { IFiscalapiHttpClient } from '../http/fiscalapi-http-client.interface'; import { BaseFiscalapiService } from './base-fiscalapi-service'; -import { IDownloadRequestService } from '../abstractions/download-request.service.interface'; +import { IDownloadRequestService } from '../abstractions/download-request-service.interface'; import { ApiResponse } from '../common/api-response'; import { PagedList } from '../common/paged-list'; import { FileResponse } from '../common/file-response'; diff --git a/src/services/download-rule.service.ts b/src/services/download-rule-service.ts similarity index 98% rename from src/services/download-rule.service.ts rename to src/services/download-rule-service.ts index 4748761..db221ae 100644 --- a/src/services/download-rule.service.ts +++ b/src/services/download-rule-service.ts @@ -1,7 +1,7 @@ import { DownloadRequest, DownloadRule } from '../models/download'; import { IFiscalapiHttpClient } from '../http/fiscalapi-http-client.interface'; import { BaseFiscalapiService } from './base-fiscalapi-service'; -import { IDownloadRuleService } from '../abstractions/download-rule.service.interface'; +import { IDownloadRuleService } from '../abstractions/download-rule-service.interface'; import { ApiResponse } from '../common/api-response'; /** diff --git a/src/services/employee-service.ts b/src/services/employee-service.ts index b21e5a4..304445a 100644 --- a/src/services/employee-service.ts +++ b/src/services/employee-service.ts @@ -20,7 +20,7 @@ export class EmployeeService implements IEmployeeService { } async getById(id: string): Promise> { - return this.httpClient.getByIdAsync(this.buildEndpoint(id)); + return this.httpClient.getAsync(this.buildEndpoint(id)); } async create(requestModel: CreateEmployeeRequest): Promise> { diff --git a/src/services/employer-service.ts b/src/services/employer-service.ts index 28a57b3..acf5fa0 100644 --- a/src/services/employer-service.ts +++ b/src/services/employer-service.ts @@ -20,7 +20,7 @@ export class EmployerService implements IEmployerService { } async getById(id: string): Promise> { - return this.httpClient.getByIdAsync(this.buildEndpoint(id)); + return this.httpClient.getAsync(this.buildEndpoint(id)); } async create(requestModel: CreateEmployerRequest): Promise> { diff --git a/src/services/fiscalapi-client.ts b/src/services/fiscalapi-client.ts index 2546a74..e236178 100644 --- a/src/services/fiscalapi-client.ts +++ b/src/services/fiscalapi-client.ts @@ -1,5 +1,3 @@ - - import { IFiscalapiClient } from '../abstractions/fiscalapi-client.interface'; import { IInvoiceService } from '../abstractions/invoice-service.interface'; import { IProductService } from '../abstractions/product-service.interface'; @@ -7,17 +5,17 @@ import { IPersonService } from '../abstractions/person-service.interface'; import { IApiKeyService } from '../abstractions/api-key-service.interface'; import { ICatalogService } from '../abstractions/catalog-service.interface'; import { ITaxFileService } from '../abstractions/tax-file-service.interface'; -import { IDownloadCatalogService } from '../abstractions/download-catalog.interface'; -import { IDownloadRuleService } from '../abstractions/download-rule.service.interface'; -import { IDownloadRequestService } from '../abstractions/download-request.service.interface'; +import { IDownloadCatalogService } from '../abstractions/download-catalog-service.interface'; +import { IDownloadRuleService } from '../abstractions/download-rule-service.interface'; +import { IDownloadRequestService } from '../abstractions/download-request-service.interface'; import { IStampService } from '../abstractions/stamp-service.interface'; import { FiscalapiSettings } from '../common/fiscalapi-settings'; import { FiscalapiHttpClientFactory } from '../http/fiscalapi-http-client-factory'; import { ApiKeyService } from './api-key-service'; import { CatalogService } from './catalog-service'; -import { DownloadCatalogService } from './download-catalog.service'; -import { DownloadRuleService } from './download-rule.service'; -import { DownloadRequestService } from './download-request.service'; +import { DownloadCatalogService } from './download-catalog-service'; +import { DownloadRuleService } from './download-rule-service'; +import { DownloadRequestService } from './download-request-service'; import { InvoiceService } from './invoice-service'; import { PersonService } from './person-service'; import { ProductService } from './product-service'; From e0fbfb3492bad5076b51a484d45e5e5c8b5ac966 Mon Sep 17 00:00:00 2001 From: JesusMendoza Date: Tue, 27 Jan 2026 15:14:27 -0600 Subject: [PATCH 11/15] fix: upgrade dependencies to resolve security vulnerabilities - Add form-data ^4.0.4 to fix CVE-2025-7783 (predictable boundary) - Upgrade axios to 1.13.4 to fix DoS vulnerability - Upgrade glob, brace-expansion, diff to fix ReDOS vulnerabilities --- package-lock.json | 143 +++++++++++++++++++++++++++++----------------- package.json | 1 + 2 files changed, 92 insertions(+), 52 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8786f6b..336f31a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "MPL-2.0", "dependencies": { "axios": "^1.8.4", + "form-data": "^4.0.4", "luxon": "^3.6.0" }, "devDependencies": { @@ -35,11 +36,35 @@ "node": ">=12" } }, + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -142,10 +167,11 @@ } }, "node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -154,10 +180,11 @@ } }, "node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -177,30 +204,16 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/axios": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz", - "integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.4.tgz", + "integrity": "sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==", + "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", + "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -218,6 +231,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -229,7 +243,8 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/combined-stream": { "version": "1.0.8", @@ -271,10 +286,11 @@ } }, "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } @@ -296,13 +312,15 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/es-define-property": { "version": "1.0.1", @@ -381,13 +399,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": { @@ -438,14 +458,15 @@ } }, "node_modules/glob": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz", - "integrity": "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", + "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^4.0.1", - "minimatch": "^10.0.0", + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.1.1", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" @@ -512,6 +533,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -523,10 +545,11 @@ "dev": true }, "node_modules/jackspeak": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.0.tgz", - "integrity": "sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", + "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -588,12 +611,13 @@ } }, "node_modules/minimatch": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", - "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", + "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^2.0.1" + "@isaacs/brace-expansion": "^5.0.0" }, "engines": { "node": "20 || >=22" @@ -704,6 +728,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, + "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -722,6 +747,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -736,6 +762,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -744,13 +771,15 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -759,10 +788,11 @@ } }, "node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -779,6 +809,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -791,6 +822,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -884,6 +916,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -902,6 +935,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -919,6 +953,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -928,6 +963,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -942,13 +978,15 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -963,6 +1001,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, diff --git a/package.json b/package.json index f368227..d853dfe 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ }, "dependencies": { "axios": "^1.8.4", + "form-data": "^4.0.4", "luxon": "^3.6.0" }, "devDependencies": { From 2686dc92f61b552ca131f9e19969e034e2902a6d Mon Sep 17 00:00:00 2001 From: JesusMendoza Date: Tue, 27 Jan 2026 15:16:27 -0600 Subject: [PATCH 12/15] samples updated --- examples/ejemplos-factura-nomina-referencias.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/ejemplos-factura-nomina-referencias.ts b/examples/ejemplos-factura-nomina-referencias.ts index 27fcdec..b122735 100644 --- a/examples/ejemplos-factura-nomina-referencias.ts +++ b/examples/ejemplos-factura-nomina-referencias.ts @@ -22,8 +22,7 @@ const settings: FiscalapiSettings = { apiKey: '', tenant: '', debug: true - - + }; // ============================================================================ From 5ef6aa7427b30dba49c191266a062d807c7dffa2 Mon Sep 17 00:00:00 2001 From: JesusMendoza Date: Tue, 27 Jan 2026 16:22:03 -0600 Subject: [PATCH 13/15] ejemplos facturas con complemento de impuesos locales added --- ...s-factura-impuestos-locales-referencias.ts | 208 ++ ...mplos-factura-impuestos-locales-valores.ts | 243 ++ payroll-invoice-requrements.md | 2585 ----------------- src/models/invoice.ts | 8 +- 4 files changed, 455 insertions(+), 2589 deletions(-) create mode 100644 examples/ejemplos-factura-impuestos-locales-referencias.ts create mode 100644 examples/ejemplos-factura-impuestos-locales-valores.ts delete mode 100644 payroll-invoice-requrements.md diff --git a/examples/ejemplos-factura-impuestos-locales-referencias.ts b/examples/ejemplos-factura-impuestos-locales-referencias.ts new file mode 100644 index 0000000..163f570 --- /dev/null +++ b/examples/ejemplos-factura-impuestos-locales-referencias.ts @@ -0,0 +1,208 @@ +/** + * Ejemplos de facturas con impuestos locales (CFDI complemento Impuestos Locales) usando el SDK de FiscalAPI + * Todos los métodos usan el modo "ByReferences" - se envían IDs de entidades pre-configuradas en FiscalAPI + */ + +import { FiscalapiClient, FiscalapiSettings, Invoice, InvoiceItem, ItemTax } from '../src/index'; +import { inspect } from 'util'; + +// Configuración de la consola para mostrar objetos anidados +inspect.defaultOptions.depth = null; +inspect.defaultOptions.colors = true; + +// Configuración de FiscalAPI +const settings: FiscalapiSettings = { + // apiUrl: 'https://test.fiscalapi.com', + // apiKey: '', + // tenant: '', + apiUrl: "http://localhost:5001", + apiKey: "sk_development_b470ea83_3c0f_4209_b933_85223b960d91", + tenant: "102e5f13-e114-41dd-bea7-507fce177281", + debug: true +}; + +// IDs de personas pre-configuradas en FiscalAPI (modo ByReferences) +const currentDate = '2026-01-27T10:04:06'; +const escuelaKemperUrgateId = "2e7b988f-3a2a-4f67-86e9-3f931dd48581"; +const karlaFuenteNolascoId = "109f4d94-63ea-4a21-ab15-20c8b87d8ee9"; + +// Items comunes para las facturas de ingreso +const invoiceItems: InvoiceItem[] = [ + { + 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' } as ItemTax + ] + }, + { + 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' } as ItemTax + ] + }, + { + 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' } as ItemTax, + { taxCode: '002', taxTypeCode: 'Tasa', taxRate: '0.106666', taxFlagCode: 'R' } as ItemTax + ] + } +]; + +// ============================================================================ +// 1. FACTURA INGRESO - IMPUESTOS LOCALES CEDULAR + ISH (ByReferences) +// ============================================================================ +async function facturaImpuestosLocalesCedularIshByReferences(client: FiscalapiClient): Promise { + console.log('\n=== Factura Ingreso con Impuestos Locales CEDULAR + ISH (ByReferences) ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentFormCode: '01', + currencyCode: 'MXN', + typeCode: 'I', + expeditionZipCode: '42501', + paymentMethodCode: 'PUE', + exchangeRate: 1, + exportCode: '01', + issuer: { + id: escuelaKemperUrgateId + }, + recipient: { + id: karlaFuenteNolascoId + }, + items: invoiceItems, + complement: { + localTaxes: { + taxes: [ + { taxName: 'CEDULAR', taxRate: '3.00', taxAmount: '6.00', taxFlagCode: 'R' }, + { taxName: 'ISH', taxRate: '8.00', taxAmount: '16.00', taxFlagCode: 'R' } + ] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 2. FACTURA INGRESO - IMPUESTOS LOCALES CEDULAR (ByReferences) +// ============================================================================ +async function facturaImpuestosLocalesCedularByReferences(client: FiscalapiClient): Promise { + console.log('\n=== Factura Ingreso con Impuestos Locales CEDULAR (ByReferences) ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentFormCode: '01', + currencyCode: 'MXN', + typeCode: 'I', + expeditionZipCode: '42501', + paymentMethodCode: 'PUE', + exchangeRate: 1, + exportCode: '01', + issuer: { + id: escuelaKemperUrgateId + }, + recipient: { + id: karlaFuenteNolascoId + }, + items: invoiceItems, + complement: { + localTaxes: { + taxes: [ + { taxName: 'CEDULAR', taxRate: '3.00', taxAmount: '6.00', taxFlagCode: 'R' } + ] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 3. FACTURA INGRESO - IMPUESTOS LOCALES ISH (ByReferences) +// ============================================================================ +async function facturaImpuestosLocalesIshByReferences(client: FiscalapiClient): Promise { + console.log('\n=== Factura Ingreso con Impuestos Locales ISH (ByReferences) ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentFormCode: '01', + currencyCode: 'MXN', + typeCode: 'I', + expeditionZipCode: '42501', + paymentMethodCode: 'PUE', + exchangeRate: 1, + exportCode: '01', + issuer: { + id: escuelaKemperUrgateId + }, + recipient: { + id: karlaFuenteNolascoId + }, + items: invoiceItems, + complement: { + localTaxes: { + taxes: [ + { taxName: 'ISH', taxRate: '8.00', taxAmount: '16.00', taxFlagCode: 'R' } + ] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + + +// ============================================================================ +// FUNCION PRINCIPAL +// ============================================================================ +async function main(): Promise { + console.log('=== Ejemplos de Factura con Impuestos Locales FiscalAPI (ByReferences) ===\n'); + + const client = FiscalapiClient.create(settings); + + try { + // Descomentar el caso de uso que se desea ejecutar + + //await facturaImpuestosLocalesCedularIshByReferences(client); + // await facturaImpuestosLocalesCedularByReferences(client); + await facturaImpuestosLocalesIshByReferences(client); + + + console.log('\nEjecución completada.'); + } catch (error) { + console.error('Error:', error); + } +} + +// Ejecutar función principal +main(); diff --git a/examples/ejemplos-factura-impuestos-locales-valores.ts b/examples/ejemplos-factura-impuestos-locales-valores.ts new file mode 100644 index 0000000..e6718ac --- /dev/null +++ b/examples/ejemplos-factura-impuestos-locales-valores.ts @@ -0,0 +1,243 @@ +/** + * Ejemplos de facturas con impuestos locales (CFDI complemento Impuestos Locales) usando el SDK de FiscalAPI + * Todos los métodos usan el modo "ByValues" - los datos se pasan directamente en la petición HTTP + */ + +import { FiscalapiClient, FiscalapiSettings, Invoice, InvoiceItem, ItemTax } from '../src/index'; +import { inspect } from 'util'; + +// Configuración de la consola para mostrar objetos anidados +inspect.defaultOptions.depth = null; +inspect.defaultOptions.colors = true; + +// Configuración de FiscalAPI +const settings: FiscalapiSettings = { + // apiUrl: 'https://test.fiscalapi.com', + // apiKey: '', + // tenant: '', + // debug: true + apiUrl: "http://localhost:5001", + apiKey: "sk_development_b470ea83_3c0f_4209_b933_85223b960d91", + tenant: "102e5f13-e114-41dd-bea7-507fce177281", + debug: true +}; + +// Sellos SAT de prueba +const escuelaKemperUrgateBase64Cer = "MIIFsDCCA5igAwIBAgIUMzAwMDEwMDAwMDA1MDAwMDM0MTYwDQYJKoZIhvcNAQELBQAwggErMQ8wDQYDVQQDDAZBQyBVQVQxLjAsBgNVBAoMJVNFUlZJQ0lPIERFIEFETUlOSVNUUkFDSU9OIFRSSUJVVEFSSUExGjAYBgNVBAsMEVNBVC1JRVMgQXV0aG9yaXR5MSgwJgYJKoZIhvcNAQkBFhlvc2Nhci5tYXJ0aW5lekBzYXQuZ29iLm14MR0wGwYDVQQJDBQzcmEgY2VycmFkYSBkZSBjYWxpejEOMAwGA1UEEQwFMDYzNzAxCzAJBgNVBAYTAk1YMRkwFwYDVQQIDBBDSVVEQUQgREUgTUVYSUNPMREwDwYDVQQHDAhDT1lPQUNBTjERMA8GA1UELRMIMi41LjQuNDUxJTAjBgkqhkiG9w0BCQITFnJlc3BvbnNhYmxlOiBBQ0RNQS1TQVQwHhcNMjMwNTE4MTE0MzUxWhcNMjcwNTE4MTE0MzUxWjCB1zEnMCUGA1UEAxMeRVNDVUVMQSBLRU1QRVIgVVJHQVRFIFNBIERFIENWMScwJQYDVQQpEx5FU0NVRUxBIEtFTVBFUiBVUkdBVEUgU0EgREUgQ1YxJzAlBgNVBAoTHkVTQ1VFTEEgS0VNUEVSIFVSR0FURSBTQSBERSBDVjElMCMGA1UELRMcRUtVOTAwMzE3M0M5IC8gVkFEQTgwMDkyN0RKMzEeMBwGA1UEBRMVIC8gVkFEQTgwMDkyN0hTUlNSTDA1MRMwEQYDVQQLEwpTdWN1cnNhbCAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtmecO6n2GS0zL025gbHGQVxznPDICoXzR2uUngz4DqxVUC/w9cE6FxSiXm2ap8Gcjg7wmcZfm85EBaxCx/0J2u5CqnhzIoGCdhBPuhWQnIh5TLgj/X6uNquwZkKChbNe9aeFirU/JbyN7Egia9oKH9KZUsodiM/pWAH00PCtoKJ9OBcSHMq8Rqa3KKoBcfkg1ZrgueffwRLws9yOcRWLb02sDOPzGIm/jEFicVYt2Hw1qdRE5xmTZ7AGG0UHs+unkGjpCVeJ+BEBn0JPLWVvDKHZAQMj6s5Bku35+d/MyATkpOPsGT/VTnsouxekDfikJD1f7A1ZpJbqDpkJnss3vQIDAQABox0wGzAMBgNVHRMBAf8EAjAAMAsGA1UdDwQEAwIGwDANBgkqhkiG9w0BAQsFAAOCAgEAFaUgj5PqgvJigNMgtrdXZnbPfVBbukAbW4OGnUhNrA7SRAAfv2BSGk16PI0nBOr7qF2mItmBnjgEwk+DTv8Zr7w5qp7vleC6dIsZFNJoa6ZndrE/f7KO1CYruLXr5gwEkIyGfJ9NwyIagvHHMszzyHiSZIA850fWtbqtythpAliJ2jF35M5pNS+YTkRB+T6L/c6m00ymN3q9lT1rB03YywxrLreRSFZOSrbwWfg34EJbHfbFXpCSVYdJRfiVdvHnewN0r5fUlPtR9stQHyuqewzdkyb5jTTw02D2cUfL57vlPStBj7SEi3uOWvLrsiDnnCIxRMYJ2UA2ktDKHk+zWnsDmaeleSzonv2CHW42yXYPCvWi88oE1DJNYLNkIjua7MxAnkNZbScNw01A6zbLsZ3y8G6eEYnxSTRfwjd8EP4kdiHNJftm7Z4iRU7HOVh79/lRWB+gd171s3d/mI9kte3MRy6V8MMEMCAnMboGpaooYwgAmwclI2XZCczNWXfhaWe0ZS5PmytD/GDpXzkX0oEgY9K/uYo5V77NdZbGAjmyi8cE2B2ogvyaN2XfIInrZPgEffJ4AB7kFA2mwesdLOCh0BLD9itmCve3A1FGR4+stO2ANUoiI3w3Tv2yQSg4bjeDlJ08lXaaFCLW2peEXMXjQUk7fmpb5MNuOUTW6BE="; +const escuelaKemperUrgateBase64Key = "MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIAgEAAoIBAQACAggAMBQGCCqGSIb3DQMHBAgwggS/AgEAMASCBMh4EHl7aNSCaMDA1VlRoXCZ5UUmqErAbucoZQObOaLUEm+I+QZ7Y8Giupo+F1XWkLvAsdk/uZlJcTfKLJyJbJwsQYbSpLOCLataZ4O5MVnnmMbfG//NKJn9kSMvJQZhSwAwoGLYDm1ESGezrvZabgFJnoQv8Si1nAhVGTk9FkFBesxRzq07dmZYwFCnFSX4xt2fDHs1PMpQbeq83aL/PzLCce3kxbYSB5kQlzGtUYayiYXcu0cVRu228VwBLCD+2wTDDoCmRXtPesgrLKUR4WWWb5N2AqAU1mNDC+UEYsENAerOFXWnmwrcTAu5qyZ7GsBMTpipW4Dbou2yqQ0lpA/aB06n1kz1aL6mNqGPaJ+OqoFuc8Ugdhadd+MmjHfFzoI20SZ3b2geCsUMNCsAd6oXMsZdWm8lzjqCGWHFeol0ik/xHMQvuQkkeCsQ28PBxdnUgf7ZGer+TN+2ZLd2kvTBOk6pIVgy5yC6cZ+o1Tloql9hYGa6rT3xcMbXlW+9e5jM2MWXZliVW3ZhaPjptJFDbIfWxJPjz4QvKyJk0zok4muv13Iiwj2bCyefUTRz6psqI4cGaYm9JpscKO2RCJN8UluYGbbWmYQU+Int6LtZj/lv8p6xnVjWxYI+rBPdtkpfFYRp+MJiXjgPw5B6UGuoruv7+vHjOLHOotRo+RdjZt7NqL9dAJnl1Qb2jfW6+d7NYQSI/bAwxO0sk4taQIT6Gsu/8kfZOPC2xk9rphGqCSS/4q3Os0MMjA1bcJLyoWLp13pqhK6bmiiHw0BBXH4fbEp4xjSbpPx4tHXzbdn8oDsHKZkWh3pPC2J/nVl0k/yF1KDVowVtMDXE47k6TGVcBoqe8PDXCG9+vjRpzIidqNo5qebaUZu6riWMWzldz8x3Z/jLWXuDiM7/Yscn0Z2GIlfoeyz+GwP2eTdOw9EUedHjEQuJY32bq8LICimJ4Ht+zMJKUyhwVQyAER8byzQBwTYmYP5U0wdsyIFitphw+/IH8+v08Ia1iBLPQAeAvRfTTIFLCs8foyUrj5Zv2B/wTYIZy6ioUM+qADeXyo45uBLLqkN90Rf6kiTqDld78NxwsfyR5MxtJLVDFkmf2IMMJHTqSfhbi+7QJaC11OOUJTD0v9wo0X/oO5GvZhe0ZaGHnm9zqTopALuFEAxcaQlc4R81wjC4wrIrqWnbcl2dxiBtD73KW+wcC9ymsLf4I8BEmiN25lx/OUc1IHNyXZJYSFkEfaxCEZWKcnbiyf5sqFSSlEqZLc4lUPJFAoP6s1FHVcyO0odWqdadhRZLZC9RCzQgPlMRtji/OXy5phh7diOBZv5UYp5nb+MZ2NAB/eFXm2JLguxjvEstuvTDmZDUb6Uqv++RdhO5gvKf/AcwU38ifaHQ9uvRuDocYwVxZS2nr9rOwZ8nAh+P2o4e0tEXjxFKQGhxXYkn75H3hhfnFYjik/2qunHBBZfcdG148MaNP6DjX33M238T9Zw/GyGx00JMogr2pdP4JAErv9a5yt4YR41KGf8guSOUbOXVARw6+ybh7+meb7w4BeTlj3aZkv8tVGdfIt3lrwVnlbzhLjeQY6PplKp3/a5Kr5yM0T4wJoKQQ6v3vSNmrhpbuAtKxpMILe8CQoo="; +const password = "12345678a"; +const currentDate = '2026-01-27T10:04:06'; + +// Items comunes para las facturas de ingreso +const invoiceItems: InvoiceItem[] = [ + { + 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' } as ItemTax + ] + }, + { + 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' } as ItemTax + ] + }, + { + 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' } as ItemTax, + { taxCode: '002', taxTypeCode: 'Tasa', taxRate: '0.106666', taxFlagCode: 'R' } as ItemTax + ] + } +]; + +// ============================================================================ +// 1. FACTURA INGRESO - IMPUESTOS LOCALES CEDULAR + ISH (ByValues) +// ============================================================================ +async function facturaImpuestosLocalesCedularIshByValues(client: FiscalapiClient): Promise { + console.log('\n=== Factura Ingreso con Impuestos Locales CEDULAR + ISH (ByValues) ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentFormCode: '01', + currencyCode: 'MXN', + typeCode: 'I', + expeditionZipCode: '42501', + paymentMethodCode: 'PUE', + exchangeRate: 1, + exportCode: '01', + issuer: { + tin: 'EKU9003173C9', + legalName: 'ESCUELA KEMPER URGATE', + taxRegimeCode: '601', + taxCredentials: [ + { base64File: escuelaKemperUrgateBase64Cer, fileType: 0, password }, + { base64File: escuelaKemperUrgateBase64Key, fileType: 1, password } + ] + }, + recipient: { + tin: 'EKU9003173C9', + legalName: 'ESCUELA KEMPER URGATE', + zipCode: '42501', + taxRegimeCode: '601', + cfdiUseCode: 'G01', + email: 'someone@somewhere.com' + }, + items: invoiceItems, + complement: { + localTaxes: { + taxes: [ + { taxName: 'CEDULAR', taxRate: '3.00', taxAmount: '6.00', taxFlagCode: 'R' }, + { taxName: 'ISH', taxRate: '8.00', taxAmount: '16.00', taxFlagCode: 'R' } + ] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 2. FACTURA INGRESO - IMPUESTOS LOCALES CEDULAR (ByValues) +// ============================================================================ +async function facturaImpuestosLocalesCedularByValues(client: FiscalapiClient): Promise { + console.log('\n=== Factura Ingreso con Impuestos Locales CEDULAR (ByValues) ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentFormCode: '01', + currencyCode: 'MXN', + typeCode: 'I', + expeditionZipCode: '42501', + paymentMethodCode: 'PUE', + exchangeRate: 1, + exportCode: '01', + issuer: { + tin: 'EKU9003173C9', + legalName: 'ESCUELA KEMPER URGATE', + taxRegimeCode: '601', + taxCredentials: [ + { base64File: escuelaKemperUrgateBase64Cer, fileType: 0, password }, + { base64File: escuelaKemperUrgateBase64Key, fileType: 1, password } + ] + }, + recipient: { + tin: 'EKU9003173C9', + legalName: 'ESCUELA KEMPER URGATE', + zipCode: '42501', + taxRegimeCode: '601', + cfdiUseCode: 'G01', + email: 'someone@somewhere.com' + }, + items: invoiceItems, + complement: { + localTaxes: { + taxes: [ + { taxName: 'CEDULAR', taxRate: '3.00', taxAmount: '6.00', taxFlagCode: 'R' } + ] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + +// ============================================================================ +// 3. FACTURA INGRESO - IMPUESTOS LOCALES ISH (ByValues) +// ============================================================================ +async function facturaImpuestosLocalesIshByValues(client: FiscalapiClient): Promise { + console.log('\n=== Factura Ingreso con Impuestos Locales ISH (ByValues) ===\n'); + + const invoice: Invoice = { + versionCode: '4.0', + series: 'F', + date: currentDate, + paymentFormCode: '01', + currencyCode: 'MXN', + typeCode: 'I', + expeditionZipCode: '42501', + paymentMethodCode: 'PUE', + exchangeRate: 1, + exportCode: '01', + issuer: { + tin: 'EKU9003173C9', + legalName: 'ESCUELA KEMPER URGATE', + taxRegimeCode: '601', + taxCredentials: [ + { base64File: escuelaKemperUrgateBase64Cer, fileType: 0, password }, + { base64File: escuelaKemperUrgateBase64Key, fileType: 1, password } + ] + }, + recipient: { + tin: 'EKU9003173C9', + legalName: 'ESCUELA KEMPER URGATE', + zipCode: '42501', + taxRegimeCode: '601', + cfdiUseCode: 'G01', + email: 'someone@somewhere.com' + }, + items: invoiceItems, + complement: { + localTaxes: { + taxes: [ + { taxName: 'ISH', taxRate: '8.00', taxAmount: '16.00', taxFlagCode: 'R' } + ] + } + } + }; + + const response = await client.invoices.create(invoice); + console.log('Response:', response); +} + + +// ============================================================================ +// FUNCION PRINCIPAL +// ============================================================================ +async function main(): Promise { + console.log('=== Ejemplos de Factura con Impuestos Locales FiscalAPI (ByValues) ===\n'); + + const client = FiscalapiClient.create(settings); + + try { + // Descomentar el caso de uso que se desea ejecutar + + await facturaImpuestosLocalesCedularIshByValues(client); + // await facturaImpuestosLocalesCedularByValues(client); + // await facturaImpuestosLocalesIshByValues(client); + + + console.log('\nEjecución completada.'); + } catch (error) { + console.error('Error:', error); + } +} + +// Ejecutar función principal +main(); diff --git a/payroll-invoice-requrements.md b/payroll-invoice-requrements.md deleted file mode 100644 index 3b6048b..0000000 --- a/payroll-invoice-requrements.md +++ /dev/null @@ -1,2585 +0,0 @@ - - -# IDs de personas para los ejemplos -escuela_kemper_urgate_id = "2e7b988f-3a2a-4f67-86e9-3f931dd48581" -karla_fuente_nolasco_id = "109f4d94-63ea-4a21-ab15-20c8b87d8ee9" -organicos_navez_osorio_id = "f645e146-f80e-40fa-953f-fd1bd06d4e9f" -xochilt_casas_chavez_id = "e3b4edaa-e4d9-4794-9c5b-3dd5b7e372aa" -ingrid_xodar_jimenez_id = "9367249f-f0ee-43f4-b771-da2fff3f185f" -OSCAR_KALA_HAAK = "5fd9f48c-a6a2-474f-944b-88a01751d432" - - -apiUrl: http://localhost:5001 -apikey: sk_development_b470ea83_3c0f_4209_b933_85223b960d91 -tenant: 102e5f13-e114-41dd-bea7-507fce177281 - -productId: 69d0aec0-5dbb-4db0-a908-61fe5c8e7d75 - - ----- - - -You are a senior Node.js engineer specializing in TypeScript, module systems, and mexican payroll cdfi invoicing. Your task is to -add payroll invoice support to the existing code base following best practices. - - -# Important --Make sure you follow the current project programing language, naming conventions and best practices for the current language and framework. --Make sure you DO NOT ADD ACCIDENTAL COMPLEXITY, only add essential complexity. You can achieve this by reading the codebase thoroughly. DO NOT ASUME ANYTHING, BASE IT ON FACTS AND THE CURRENT STATE OF THE CODE. DO NOT DUPLICATE CODE. - -## Stamp resource -Implememt following changes as follows: - -Create a new service called StampService and add a new property 'stamps' on FiscalApiClient facade -the ultimage goal is add support for /api/v4/stamps resource. - - -### Models - -StampTransaction: - consecutive: int, - from_person: UserLookupDto, - to_person: UserLookupDto, - amount: int, - transaction_type: int, - transaction_status: int, - reference_id: str, - comments: str, - id: Optional[str] = None, - -StampTransactionParams - from_person_id: str, - to_person_id: str, - amount: int, - comments: str, - -### Service -class StampService: - - def transfer_stamps(self, request: StampTransactionParams) -> bool: - # lógica real aquí (HTTP, DB, lo que sea) - return True - - def withdraw_stamps(self, request: StampTransactionParams) -> bool: - # lógica real aquí - return True - - - -#Resource endpoints - -Listar movimientos - -## Request -curl --location 'http://localhost:5001/api/v4/stamps?pageNumber=1&pageSize=2' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---data '' - -### Response -{ - "data": { - "items": [ - { - "consecutive": 9, - "fromPerson": { - "tin": "FAP240304AU3", - "legalName": "FISCAL API", - "id": "1", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": "2025-11-02T13:12:47.205" - }, - "toPerson": { - "tin": "KAHO641101B39", - "legalName": "OSCAR KALA HAAK", - "id": "5fd9f48c-a6a2-474f-944b-88a01751d432", - "createdAt": "2025-01-07T15:15:00.305", - "updatedAt": "2025-11-03T19:19:48.455" - }, - "amount": 100, - "transactionType": 1, - "transactionStatus": 1, - "referenceId": "46aecf10-5e63-48e9-a101-bbb3cda10b38", - "comments": null, - "id": "77678d6d-94b1-4635-aa91-15cdd7423aab", - "createdAt": "2025-08-08T21:01:07.583", - "updatedAt": "2025-08-08T21:01:07.583" - }, - { - "consecutive": 11, - "fromPerson": { - "tin": "FAP240304AU3", - "legalName": "FISCAL API", - "id": "1", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": "2025-11-02T13:12:47.205" - }, - "toPerson": { - "tin": "KAHO641101B39", - "legalName": "OSCAR KALA HAAK", - "id": "5fd9f48c-a6a2-474f-944b-88a01751d432", - "createdAt": "2025-01-07T15:15:00.305", - "updatedAt": "2025-11-03T19:19:48.455" - }, - "amount": 500, - "transactionType": 1, - "transactionStatus": 1, - "referenceId": "7452186b-f890-4cad-90df-f478335ce117", - "comments": null, - "id": "e22e17d1-48c5-49a5-af71-a56cae4bdd95", - "createdAt": "2025-08-10T12:12:50.496", - "updatedAt": "2025-08-10T12:12:50.496" - } - ], - "pageNumber": 1, - "totalPages": 21, - "totalCount": 207, - "hasPreviousPage": false, - "hasNextPage": true - }, - "succeeded": true, - "message": "", - "details": "", - "httpStatusCode": 200 -} - - ---- -Obtener movimiento por ID - -### Request -curl --location 'http://localhost:5001/api/v4/stamps/77678d6d-94b1-4635-aa91-15cdd7423aab' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data '' - -### Response -{ - "data": { - "consecutive": 9, - "fromPerson": { - "tin": "FAP240304AU3", - "legalName": "FISCAL API", - "id": "1", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": "2025-11-02T13:12:47.205" - }, - "toPerson": { - "tin": "KAHO641101B39", - "legalName": "OSCAR KALA HAAK", - "id": "5fd9f48c-a6a2-474f-944b-88a01751d432", - "createdAt": "2025-01-07T15:15:00.305", - "updatedAt": "2025-11-03T19:19:48.455" - }, - "amount": 100, - "transactionType": 1, - "transactionStatus": 1, - "referenceId": "46aecf10-5e63-48e9-a101-bbb3cda10b38", - "comments": null, - "id": "77678d6d-94b1-4635-aa91-15cdd7423aab", - "createdAt": "2025-08-08T21:01:07.583", - "updatedAt": "2025-08-08T21:01:07.583" - }, - "succeeded": true, - "message": "", - "details": "", - "httpStatusCode": 200 -} - ---- -Transferir Timbres - -### Request -curl --location 'http://localhost:5001/api/v4/stamps' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'Content-Type: application/json' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data '{ - "fromPersonId": "1", - "toPersonId": "bef56254-0892-4558-95c3-f9c8729e4b0e", - "amount": 1, - "comments": "Compra 001" -}' - -### Response -{ - "data": true, - "succeeded": true, - "message": "", - "details": "", - "httpStatusCode": 200 -} - - -### Retirar Timbres -curl --location 'http://localhost:5001/api/v4/stamps' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'Content-Type: application/json' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data '{ - "fromPersonId": "1", - "toPersonId": "1a18f812-c623-448f-a222-9b7e4e3fd4b2", - "amount": 99, - "comments": "No se confirmó el pago..." -}' - -### Response -{ - "data": true, - "succeeded": true, - "message": "", - "details": "", - "httpStatusCode": 200 -} - ---- - -You are a senior Node.js engineer specializing in TypeScript, module systems, and mexican payroll cdfi invoicing. Your task is to -add payroll invoice support to the existing code base following best practices. - - -# Important --Make sure you follow the current project programing language, naming conventions and best practices for the current language and framework. --Make sure you DO NOT ADD ACCIDENTAL COMPLEXITY, only add essential complexity. You can achieve this by reading the codebase thoroughly. DO NOT ASUME ANYTHING, BASE IT ON FACTS AND THE CURRENT STATE OF THE CODE. DO NOT DUPLICATE CODE. - -## Employee/Employer sub-resources - -Implememt following changes as follows: - -interface IEmployeeService { - getById(id: string): Promise> - create(requestModel: CreateEmployeeRequest): Promise> - update(requestModel: UpdateEmployeeRequest): Promise> - delete(personId: string): Promise> -} - -interface IEmployerService { - getById(id: string): Promise> - create(requestModel: CreateEmployerRequest): Promise> - update(requestModel: UpdateEmployerRequest): Promise> - delete(personId: string): Promise> -} - -interface PersonService { - employee: IEmployeeService - employer: IEmployerService -} - -interface FiscalapiClient { - persons: PersonsService -} - - -### Obtener datos de empleador -curl --location 'http://localhost:5001/api/v4/people/bef56254-0892-4558-95c3-f9c8729e4b0e/employer' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' - -response -{ - "data": { - "personId": "bef56254-0892-4558-95c3-f9c8729e4b0e", - "employerRegistration": "A1230768108", - "originEmployerTin": "ARE180429TM6", - "satFundSource": { - "id": "IP", - "description": "Ingresos propios.", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": null - }, - "ownResourceAmount": 1500, - "id": "23f0b555-68bc-48fd-bb90-deb36ed25ef6", - "createdAt": "2025-09-18T20:17:44.175", - "updatedAt": "2025-09-18T20:17:48.489" - }, - "succeeded": true, - "message": "", - "details": "", - "httpStatusCode": 200 -} - - -### Crear datos de empleador -curl --location 'http://localhost:5001/api/v4/people/bef56254-0892-4558-95c3-f9c8729e4b0e/employer' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'Content-Type: application/json' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data '{ - "personId": "bef56254-0892-4558-95c3-f9c8729e4b0e", - "employerRegistration": "B5510768108", - "originEmployerTin": "URE180429TM6", - "satFundSourceId": null, - "ownResourceAmount": null -} -' - -Response -{ - "data": { - "personId": "bef56254-0892-4558-95c3-f9c8729e4b0e", - "employerRegistration": "B5510768108", - "originEmployerTin": "URE180429TM6", - "satFundSource": null, - "ownResourceAmount": null, - "id": "23f0b555-68bc-48fd-bb90-deb36ed25ef6", - "createdAt": "2025-09-18T20:17:44.175", - "updatedAt": "2025-09-18T20:17:44.175" - }, - "succeeded": true, - "message": "", - "details": "", - "httpStatusCode": 200 -} - -### Actualizar datos de empleador - -curl --location --request PUT 'http://localhost:5001/api/v4/people/bef56254-0892-4558-95c3-f9c8729e4b0e/employer' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'Content-Type: application/json' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data '{ - "personId": "bef56254-0892-4558-95c3-f9c8729e4b0e", - "employerRegistration": "A1230768108", - "originEmployerTin": "ARE180429TM6", - "satFundSourceId": null, - "ownResourceAmount": null -}' - -Response -{ - "data": { - "personId": "bef56254-0892-4558-95c3-f9c8729e4b0e", - "employerRegistration": "A1230768108", - "originEmployerTin": "ARE180429TM6", - "satFundSource": null, - "ownResourceAmount": null, - "id": "23f0b555-68bc-48fd-bb90-deb36ed25ef6", - "createdAt": "2025-09-18T20:17:44.175", - "updatedAt": "2025-09-18T20:19:20.569" - }, - "succeeded": true, - "message": "", - "details": "", - "httpStatusCode": 200 -} - -### Eliminar datos de empleador - -curl --location --request DELETE 'http://localhost:5001/api/v4/people/bef56254-0892-4558-95c3-f9c8729e4b0e/employer' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data '' - -Response -{ - "data": true, - "succeeded": true, - "message": "", - "details": "", - "httpStatusCode": 200 -} - - -### Obtener datos de empleado -curl --location 'http://localhost:5001/api/v4/people/54fc14ae-c88f-4afc-996b-0574d63341e2/employee' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data '' - -Response -{ - "data": { - "employerPersonId": "bef56254-0892-4558-95c3-f9c8729e4b0e", - "employeePersonId": "54fc14ae-c88f-4afc-996b-0574d63341e2", - "employeeNumber": "123456789", - "socialSecurityNumber": "0101010101", - "laborRelationStartDate": "2020-01-12T00:00:00.000", - "satContractType": { - "id": "01", - "description": "Contrato de trabajo por tiempo indeterminado", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": null - }, - "satTaxRegimeType": { - "id": "02", - "description": "Sueldos (Incluye ingresos art. 94 LISR)", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": null - }, - "satWorkdayType": null, - "satJobRisk": { - "id": "1", - "description": "Clase I", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": null - }, - "satPaymentPeriodicity": { - "id": "04", - "description": "Quincenal", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": null - }, - "satBank": null, - "satPayrollState": { - "id": "JAL", - "description": "Jalisco", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": null - }, - "satUnionizedStatus": null, - "department": null, - "position": null, - "seniority": "P1Y5M15D", - "bankAccount": null, - "baseSalaryForContributions": 520, - "integratedDailySalary": 186, - "subcontractorRfc": null, - "timePercentage": 0 - }, - "succeeded": true, - "message": "", - "details": "", - "httpStatusCode": 200 -} - -### Crear datos de empleado -curl --location 'http://localhost:5001/api/v4/people/54fc14ae-c88f-4afc-996b-0574d63341e2/employee' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'Content-Type: application/json' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data ' -{ - "employerPersonId": "bef56254-0892-4558-95c3-f9c8729e4b0e", - "employeePersonId": "54fc14ae-c88f-4afc-996b-0574d63341e2", - "employeeNumber": "12345", - "satContractTypeId": "01", - "satTaxRegimeTypeId": "02", - "satPaymentPeriodicityId": "04", - "satPayrollStateId": "JAL", - "socialSecurityNumber": "123456789012345", - "laborRelationStartDate": "2023-01-15T00:00:00", - "satWorkdayTypeId": "01", - "satJobRiskId": "1", - "satBankId": "002", - "satUnionizedStatusId": "No", - "department": "Recursos Humanos", - "position": "Analista de Nóminas", - "seniority": "7Y3M1W", - "bankAccount": "12345678901234567890", - "baseSalaryForContributions": 490.22, - "integratedDailySalary": 146.47, - "subcontractorRfc": null, - "timePercentage": null -}' - -Response: -{ - "data": { - "employerPersonId": "bef56254-0892-4558-95c3-f9c8729e4b0e", - "employeePersonId": "54fc14ae-c88f-4afc-996b-0574d63341e2", - "employeeNumber": "12345", - "socialSecurityNumber": "123456789012345", - "laborRelationStartDate": "2023-01-15T00:00:00.000", - "satContractType": { - "id": "01", - "description": "Contrato de trabajo por tiempo indeterminado", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": null - }, - "satTaxRegimeType": { - "id": "02", - "description": "Sueldos (Incluye ingresos señalados en la fraccion I del articulo 94 de LISR)", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": null - }, - "satWorkdayType": { - "id": "01", - "description": "Diurna", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": null - }, - "satJobRisk": { - "id": "1", - "description": "Clase I", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": null - }, - "satPaymentPeriodicity": { - "id": "04", - "description": "Quincenal", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": null - }, - "satBank": { - "id": "002", - "description": "BANAMEX", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": null - }, - "satPayrollState": { - "id": "JAL", - "description": "Jalisco", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": null - }, - "satUnionizedStatus": { - "id": "No", - "description": "NO", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": null - }, - "department": "Recursos Humanos", - "position": "Analista de Nóminas", - "bankAccount": "12345678901234567890", - "baseSalaryForContributions": 490.22, - "integratedDailySalary": 146.47, - "subcontractorRfc": null, - "timePercentage": 0 - }, - "succeeded": true, - "message": "", - "details": "", - "httpStatusCode": 200 -} - -### Actualizar datos de empleado -curl --location --request PUT 'http://localhost:5001/api/v4/people/54fc14ae-c88f-4afc-996b-0574d63341e2/employee' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'Content-Type: application/json' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data ' -{ - "employerPersonId": "bef56254-0892-4558-95c3-f9c8729e4b0e", - "employeePersonId": "54fc14ae-c88f-4afc-996b-0574d63341e2", - "employeeNumber": "12345ABC", - "satContractTypeId": "02", - "satTaxRegimeTypeId": "02", - "satPaymentPeriodicityId": "02", - "satPayrollStateId": "AGU", - "socialSecurityNumber": "123456789012345", - "laborRelationStartDate": "2022-01-15T00:00:00", - "satWorkdayTypeId": "01", - "satJobRiskId": "2", - "satBankId": "012", - "satUnionizedStatusId": "Sí", - "department": "Sistemas", - "position": "Programador Jr.", - "seniority": "7Y3M1W", - "bankAccount": "12345678901234567890", - "baseSalaryForContributions": 290.22, - "integratedDailySalary": 46.47, - "subcontractorRfc": null, - "timePercentage": null -}' - -Response: -{ - "data": { - "employerPersonId": "bef56254-0892-4558-95c3-f9c8729e4b0e", - "employeePersonId": "54fc14ae-c88f-4afc-996b-0574d63341e2", - "employeeNumber": "12345ABC", - "socialSecurityNumber": "123456789012345", - "laborRelationStartDate": "2022-01-15T00:00:00.000", - "satContractType": { - "id": "02", - "description": "Contrato de trabajo para obra determinada", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": null - }, - "satTaxRegimeType": { - "id": "02", - "description": "Sueldos (Incluye ingresos señalados en la fraccion I del articulo 94 de LISR)", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": null - }, - "satWorkdayType": { - "id": "01", - "description": "Diurna", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": null - }, - "satJobRisk": { - "id": "2", - "description": "Clase II", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": null - }, - "satPaymentPeriodicity": { - "id": "02", - "description": "Semanal", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": null - }, - "satBank": { - "id": "012", - "description": "BBVA BANCOMER", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": null - }, - "satPayrollState": { - "id": "AGU", - "description": "Aguascalientes", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": null - }, - "satUnionizedStatus": { - "id": "Sí", - "description": "SI", - "createdAt": "2024-08-10T15:46:30.373", - "updatedAt": null - }, - "department": "Sistemas", - "position": "Programador Jr.", - "bankAccount": "12345678901234567890", - "baseSalaryForContributions": 290.22, - "integratedDailySalary": 46.47, - "subcontractorRfc": null, - "timePercentage": 0 - }, - "succeeded": true, - "message": "", - "details": "", - "httpStatusCode": 200 -} - - -### Eliminar datos de empleado -curl --location --request DELETE 'http://localhost:5001/api/v4/people/54fc14ae-c88f-4afc-996b-0574d63341e2/employee' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'Content-Type: application/json' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data-raw '{ - "legalName": "MI EMPRESA DUMMY", - "email": "miempresa@domain.com", - "password": "UserPass123!" -}' - -Response: -{ - "data": true, - "succeeded": true, - "message": "", - "details": "", - "httpStatusCode": 200 -} - ---- -You are a senior Node.js engineer specializing in TypeScript, module systems, and mexican payroll cdfi invoicing. Your task is to -add payroll invoice support to the existing code base following best practices. - - -# Important --Make sure you follow the current project programing language, naming conventions and best practices for the current language and framework. --Make sure you DO NOT ADD ACCIDENTAL COMPLEXITY, only add essential complexity. You can achieve this by reading the codebase thoroughly. DO NOT ASUME ANYTHING, BASE IT ON FACTS AND THE CURRENT STATE OF THE CODE. DO NOT DUPLICATE CODE. - - -## Invoices resource - -Implememt following changes as follows: - -- Change invoice enpoint to the unified version for all methods -- Update the invoice request model to the unified version -- creare a new file named ejemplos-factura-nomina.ts con una funcion para cada caso de uso un comentario y -un una funcion principal para que invoque todas las funciones de los casos de uso, asegurate de agregar el sufijo 'ByValues' al nombre del metodo, todos estos metodos son por valores, signifca que todo los datos se pasan en la peticion http. - - // ============================================================================ - // 1. NOMINA ORDINARIA (Facturación por valores) - // ============================================================================ - nominaOrdinariaByValues(){ - //implementation - } - -- Use this names for the models and make sure the any complement is property modeled. becarefull with payment complement that alrredy exist, only need to be moved from invoice.payments?: InvoicePayment[]; to Complement.PaymentComplement: -Models names to use. -* Invoice -* Complement -* Complement.LocalTaxesComplement (Invoice.complement.localTaxes) -* Complement.LocalTaxesComplement.LocalTax -* Complement.PaymentComplement (Invoice.complement.payments) -* Complement.PaymentComplement.PaidInvoice -* Complement.PaymentComplement.PaidInvoice.PaidInvoiceTax -* Complement.PayrollComplement (Invoice.complement.payroll) -* Complement.PayrollComplement.Earnings -* Complement.PayrollComplement.Earnings.Earning -* Complement.PayrollComplement.Earnings.Earning.StockOptions -* Complement.PayrollComplement.Earnings.Earning.Overtime -* Complement.PayrollComplement.Earnings.OtherPayment -* Complement.PayrollComplement.Earnings.OtherPayment.BalanceCompensation -* Complement.PayrollComplement.Earnings.Retirement -* Complement.PayrollComplement.Earnings.Severance -* Complement.PayrollComplement.Deduction -* Complement.PayrollComplement.Disability -* Complement.LadingComplement (Invoice.Complement.landing) -- Make sure all existing models are updated or new models are acreated. - - -## Unified Invoice Endpoint and model - -curl http://localhost:5001/api/v4/invoices \ - --request POST \ - --header 'Content-Type: application/json' \ - --data '{ - "versionCode": null, - "paymentFormCode": null, - "paymentMethodCode": null, - "currencyCode": null, - "typeCode": null, - "expeditionZipCode": null, - "pacConfirmation": null, - "series": null, - "number": null, - "date": "", - "paymentConditions": null, - "exchangeRate": 1, - "exportCode": null, - "issuer": { - "id": null, - "tin": null, - "legalName": null, - "taxRegimeCode": null, - "employerData": { - "curp": null, - "employerRegistration": null, - "originEmployerTin": null, - "satFundSourceId": null, - "ownResourceAmount": null - }, - "taxCredentials": [ - { - "id": null, - "base64File": null, - "fileType": 1, - "password": null - } - ] - }, - "recipient": { - "id": null, - "tin": null, - "legalName": null, - "zipCode": null, - "taxRegimeCode": null, - "cfdiUseCode": null, - "email": null, - "foreignCountryCode": null, - "foreignTin": null, - "employeeData": { - "curp": null, - "socialSecurityNumber": null, - "laborRelationStartDate": null, - "seniority": null, - "satContractTypeId": null, - "satUnionizedStatusId": null, - "satWorkdayTypeId": null, - "satTaxRegimeTypeId": null, - "employeeNumber": null, - "department": null, - "...": "[Additional Properties Truncated]" - } - }, - "items": [ - { - "id": null, - "itemCode": null, - "itemSku": null, - "quantity": 1, - "unitOfMeasurementCode": null, - "description": null, - "unitPrice": 1, - "discount": 1, - "taxObjectCode": null, - "itemTaxes": [ - { - "taxCode": null, - "taxTypeCode": null, - "taxRate": 1, - "taxFlagCode": null - } - ], - "onBehalfOf": { - "tin": null, - "legalName": null, - "taxRegimeCode": null, - "zipCode": null - }, - "customsInfo": [ - { - "customsNumber": null - } - ], - "propertyInfo": [ - { - "number": null - } - ], - "parts": [ - { - "itemCode": null, - "itemSku": null, - "quantity": 1, - "unitOfMeasurementCode": null, - "description": null, - "unitPrice": 1, - "customsInfo": [ - { - "customsNumber": null - } - ] - } - ] - } - ], - "globalInformation": { - "periodicityCode": null, - "monthCode": null, - "year": 1 - }, - "relatedInvoices": [ - { - "relationshipTypeCode": null, - "uuid": null - } - ], - "complement": { - "localTaxes": { - "taxes": [ - { - "taxName": null, - "taxRate": 1, - "taxAmount": 1, - "taxFlagCode": null - } - ] - }, - "payment": { - "paymentDate": "", - "paymentFormCode": null, - "currencyCode": "", - "exchangeRate": 1, - "amount": 1, - "operationNumber": null, - "sourceBankTin": null, - "sourceBankAccount": null, - "targetBankTin": null, - "targetBankAccount": null, - "...": "[Additional Properties Truncated]" - }, - "payroll": { - "version": "", - "payrollTypeCode": null, - "paymentDate": "", - "initialPaymentDate": "", - "finalPaymentDate": "", - "daysPaid": 1, - "earnings": { - "earnings": [ - { - "earningTypeCode": "", - "code": "", - "concept": "", - "taxedAmount": 1, - "exemptAmount": 1, - "stockOptions": { - "marketPrice": "[Max Depth Exceeded]", - "grantPrice": "[Max Depth Exceeded]" - }, - "overtime": [ - { - "days": "[Max Depth Exceeded]", - "hoursTypeCode": "[Max Depth Exceeded]", - "extraHours": "[Max Depth Exceeded]", - "amountPaid": "[Max Depth Exceeded]" - } - ] - } - ], - "otherPayments": [ - { - "otherPaymentTypeCode": "", - "code": "", - "concept": "", - "amount": 1, - "subsidyCaused": null, - "balanceCompensation": { - "favorableBalance": "[Max Depth Exceeded]", - "year": "[Max Depth Exceeded]", - "remainingFavorableBalance": "[Max Depth Exceeded]" - } - } - ], - "retirement": { - "totalOneTime": 1, - "totalInstallments": 1, - "dailyAmount": 1, - "accumulableIncome": 1, - "nonAccumulableIncome": 1 - }, - "severance": { - "totalPaid": 1, - "yearsOfService": 1, - "lastMonthlySalary": 1, - "accumulableIncome": 1, - "nonAccumulableIncome": 1 - } - }, - "deductions": [ - { - "deductionTypeCode": "", - "code": "", - "concept": "", - "amount": 1 - } - ], - "disabilities": [ - { - "disabilityDays": 1, - "disabilityTypeCode": "", - "monetaryAmount": 1 - } - ] - }, - "lading": {} - }, - "metadata": null -}' - - -## Payroll use cases - -### Factura Nómina - Nómina Ordinaria -curl --location 'http://localhost:5001/api/v4/invoices' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'Content-Type: application/json' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data '{ - "versionCode": "4.0", - "series": "F", - "date": "2026-01-18T18:04:06", - "paymentMethodCode": "PUE", - "currencyCode": "MXN", - "typeCode": "N", - "expeditionZipCode": "20000", - "exportCode": "01", - "issuer": { - "tin": "EKU9003173C9", - "legalName": "ESCUELA KEMPER URGATE", - "taxRegimeCode": "601", - "employerData": { - "employerRegistration": "B5510768108" - }, - "taxCredentials": [ - { - "base64File": "base64cer...", - "fileType": 0, - "password": "12345678a" - }, - { - "base64File": "base64key...", - "fileType": 1, - "password": "12345678a" - } - ] - }, - "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 - } - ] - } - } -}' - - -### Factura Nómina - Nómina Asimilados -curl --location 'http://localhost:5001/api/v4/invoices' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'Content-Type: application/json' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data '{ - "versionCode": "4.0", - "series": "F", - "date": "2026-01-18T18:04:06", - "paymentMethodCode": "PUE", - "currencyCode": "MXN", - "typeCode": "N", - "expeditionZipCode": "06880", - "exportCode": "01", - "issuer": { - "tin": "EKU9003173C9", - "legalName": "ESCUELA KEMPER URGATE", - "taxRegimeCode": "601", - "employerData": { - "originEmployerTin": "EKU9003173C9" - }, - "taxCredentials": [ - { - "base64File": "base64cer...", - "fileType": 0, - "password": "12345678a" - }, - { - "base64File": "base64key...", - "fileType": 1, - "password": "12345678a" - } - ] - }, - "recipient": { - "tin": "CACX7605101P8", - "legalName": "XOCHILT CASAS CHAVEZ", - "zipCode": "36257", - "taxRegimeCode": "605", - "cfdiUseCode": "CN01", - "employeeData": { - "curp": "XEXX010101HNEXXXA4", - "satContractTypeId": "09", - "satUnionizedStatusId": "No", - "satTaxRegimeTypeId": "09", - "employeeNumber": "00002", - "department": "ADMINISTRACION", - "position": "DIRECTOR DE ADMINISTRACION", - "satPaymentPeriodicityId": "99", - "satBankId": "012", - "bankAccount": "1111111111", - "satPayrollStateId": "CMX" - } - }, - "complement": { - "payroll": { - "version": "1.2", - "payrollTypeCode": "E", - "paymentDate": "2023-06-02T00:00:00", - "initialPaymentDate": "2023-06-01T00:00:00", - "finalPaymentDate": "2023-06-02T00:00:00", - "daysPaid": 1, - "earnings": { - "earnings": [ - { - "earningTypeCode": "046", - "code": "010046", - "concept": "INGRESOS ASIMILADOS A SALARIOS", - "taxedAmount": 111197.73, - "exemptAmount": 0.00 - } - ], - "otherPayments": [] - }, - "deductions": [ - { - "deductionTypeCode": "002", - "code": "020002", - "concept": "ISR", - "amount": 36197.73 - } - ] - } - } -}' - - -### Factura Nómina - Nómina Con Bonos, Fondo Ahorro y Deducciones -curl --location 'http://localhost:5001/api/v4/invoices' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'Content-Type: application/json' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data '{ - "versionCode": "4.0", - "series": "F", - "date": "2026-01-18T18:04:06", - "paymentMethodCode": "PUE", - "currencyCode": "MXN", - "typeCode": "N", - "expeditionZipCode": "20000", - "exportCode": "01", - "issuer": { - "tin": "EKU9003173C9", - "legalName": "ESCUELA KEMPER URGATE", - "taxRegimeCode": "601", - "employerData": { - "employerRegistration": "Z0000001234" - }, - "taxCredentials": [ - { - "base64File": "base64cer...", - "fileType": 0, - "password": "12345678a" - }, - { - "base64File": "base64key...", - "fileType": 1, - "password": "12345678a" - } - ] - }, - "recipient": { - "tin": "XOJI740919U48", - "legalName": "INGRID XODAR JIMENEZ", - "zipCode": "76028", - "taxRegimeCode": "605", - "cfdiUseCode": "CN01", - "employeeData": { - "curp": "XEXX010101MNEXXXA8", - "socialSecurityNumber": "0000000000", - "laborRelationStartDate": "2022-03-02T00:00:00", - "seniority": "P66W", - "satContractTypeId": "01", - "satUnionizedStatusId": "No", - "satTaxRegimeTypeId": "02", - "employeeNumber": "111111", - "satJobRiskId": "4", - "satPaymentPeriodicityId": "02", - "integratedDailySalary": 180.96, - "satPayrollStateId": "GUA" - } - }, - "complement": { - "payroll": { - "version": "1.2", - "payrollTypeCode": "O", - "paymentDate": "2023-06-11T00:00:00", - "initialPaymentDate": "2023-06-05T00:00:00", - "finalPaymentDate": "2023-06-11T00:00:00", - "daysPaid": 7, - "earnings": { - "earnings": [ - { - "earningTypeCode": "001", - "code": "SP01", - "concept": "SUELDO", - "taxedAmount": 1210.30, - "exemptAmount": 0.00 - }, - { - "earningTypeCode": "010", - "code": "SP02", - "concept": "PREMIO PUNTUALIDAD", - "taxedAmount": 121.03, - "exemptAmount": 0.00 - }, - { - "earningTypeCode": "029", - "code": "SP03", - "concept": "MONEDERO ELECTRONICO", - "taxedAmount": 0.00, - "exemptAmount": 269.43 - }, - { - "earningTypeCode": "010", - "code": "SP04", - "concept": "PREMIO DE ASISTENCIA", - "taxedAmount": 121.03, - "exemptAmount": 0.00 - }, - { - "earningTypeCode": "005", - "code": "SP54", - "concept": "APORTACION FONDO AHORRO", - "taxedAmount": 0.00, - "exemptAmount": 121.03 - } - ], - "otherPayments": [ - { - "otherPaymentTypeCode": "002", - "code": "ISRSUB", - "concept": "Subsidio ISR para empleo", - "amount": 0.0, - "subsidyCaused": 0.0, - "balanceCompensation": { - "favorableBalance": 0.0, - "year": 2022, - "remainingFavorableBalance": 0.0 - } - } - ] - }, - "deductions": [ - { - "deductionTypeCode": "004", - "code": "ZA09", - "concept": "APORTACION FONDO AHORRO", - "amount": 121.03 - }, - { - "deductionTypeCode": "002", - "code": "ISR", - "concept": "ISR", - "amount": 36.57 - }, - { - "deductionTypeCode": "001", - "code": "IMSS", - "concept": "Cuota de Seguridad Social EE", - "amount": 30.08 - }, - { - "deductionTypeCode": "004", - "code": "ZA68", - "concept": "DEDUCCION FDO AHORRO PAT", - "amount": 121.03 - }, - { - "deductionTypeCode": "018", - "code": "ZA11", - "concept": "APORTACION CAJA AHORRO", - "amount": 300.00 - } - ] - } - } -}' - -### Factura Nómina - Nómina Con Horas Extra - -curl --location 'http://localhost:5001/api/v4/invoices' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'Content-Type: application/json' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data '{ - "versionCode": "4.0", - "series": "F", - "date": "2026-01-18T18:04:06", - "paymentMethodCode": "PUE", - "currencyCode": "MXN", - "typeCode": "N", - "expeditionZipCode": "20000", - "exportCode": "01", - "issuer": { - "tin": "EKU9003173C9", - "legalName": "ESCUELA KEMPER URGATE", - "taxRegimeCode": "601", - "employerData": { - "employerRegistration": "B5510768108", - "originEmployerTin": "URE180429TM6" - }, - "taxCredentials": [ - { - "base64File": "base64cer...", - "fileType": 0, - "password": "12345678a" - }, - { - "base64File": "base64key...", - "fileType": 1, - "password": "12345678a" - } - ] - }, - "recipient": { - "tin": "XOJI740919U48", - "legalName": "INGRID XODAR JIMENEZ", - "zipCode": "76028", - "taxRegimeCode": "605", - "cfdiUseCode": "CN01", - "employeeData": { - "curp": "XEXX010101HNEXXXA4", - "socialSecurityNumber": "000000", - "laborRelationStartDate": "2015-01-01", - "seniority": "P437W", - "satContractTypeId": "01", - "satWorkdayTypeId": "01", - "satTaxRegimeTypeId": "03", - "employeeNumber": "120", - "department": "Desarrollo", - "position": "Ingeniero de Software", - "satJobRiskId": "1", - "satPaymentPeriodicityId": "04", - "satBankId": "002", - "bankAccount": "1111111111", - "baseSalaryForContributions": 490.22, - "integratedDailySalary": 146.47, - "satPayrollStateId": "JAL" - } - }, - "complement": { - "payroll": { - "version": "1.2", - "payrollTypeCode": "O", - "paymentDate": "2023-05-24T00:00:00", - "initialPaymentDate": "2023-05-09T00:00:00", - "finalPaymentDate": "2023-05-24T00:00:00", - "daysPaid": 15, - "earnings": { - "earnings": [ - { - "earningTypeCode": "001", - "code": "00500", - "concept": "Sueldos, Salarios Rayas y Jornales", - "taxedAmount": 2808.8, - "exemptAmount": 2191.2 - }, - { - "earningTypeCode": "019", - "code": "00100", - "concept": "Horas Extra", - "taxedAmount": 50.00, - "exemptAmount": 50.00, - "overtime": [ - { - "days": 1, - "hoursTypeCode": "01", - "extraHours": 2, - "amountPaid": 100.00 - } - ] - } - ], - "otherPayments": [] - }, - "deductions": [ - { - "deductionTypeCode": "001", - "code": "00301", - "concept": "Seguridad Social", - "amount": 200 - }, - { - "deductionTypeCode": "002", - "code": "00302", - "concept": "ISR", - "amount": 100 - } - ] - } - } -}' - -### Factura Nómina - Nómina Con Incapacidades -curl --location 'http://localhost:5001/api/v4/invoices' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'Content-Type: application/json' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data '{ - "versionCode": "4.0", - "series": "F", - "date": "2026-01-18T18:04:06", - "paymentMethodCode": "PUE", - "currencyCode": "MXN", - "typeCode": "N", - "expeditionZipCode": "20000", - "exportCode": "01", - "issuer": { - "tin": "EKU9003173C9", - "legalName": "ESCUELA KEMPER URGATE", - "taxRegimeCode": "601", - "employerData": { - "employerRegistration": "B5510768108", - "originEmployerTin": "URE180429TM6" - }, - "taxCredentials": [ - { - "base64File": "base64cer...", - "fileType": 0, - "password": "12345678a" - }, - { - "base64File": "base64key...", - "fileType": 1, - "password": "12345678a" - } - ] - }, - "recipient": { - "tin": "XOJI740919U48", - "legalName": "INGRID XODAR JIMENEZ", - "zipCode": "76028", - "taxRegimeCode": "605", - "cfdiUseCode": "CN01", - "employeeData": { - "curp": "XEXX010101HNEXXXA4", - "socialSecurityNumber": "000000", - "laborRelationStartDate": "2015-01-01T00:00:00", - "seniority": "P437W", - "satContractTypeId": "01", - "satWorkdayTypeId": "01", - "satTaxRegimeTypeId": "03", - "employeeNumber": "120", - "department": "Desarrollo", - "position": "Ingeniero de Software", - "satJobRiskId": "1", - "satPaymentPeriodicityId": "04", - "satBankId": "002", - "bankAccount": "1111111111", - "baseSalaryForContributions": 490.22, - "integratedDailySalary": 146.47, - "satPayrollStateId": "JAL" - } - }, - "complement": { - "payroll": { - "version": "1.2", - "payrollTypeCode": "O", - "paymentDate": "2023-05-24T00:00:00", - "initialPaymentDate": "2023-05-09T00:00:00", - "finalPaymentDate": "2023-05-24T00:00:00", - "daysPaid": 15, - "earnings": { - "earnings": [ - { - "earningTypeCode": "001", - "code": "00500", - "concept": "Sueldos, Salarios Rayas y Jornales", - "taxedAmount": 2808.8, - "exemptAmount": 2191.2 - } - ] - }, - "deductions": [ - { - "deductionTypeCode": "001", - "code": "00301", - "concept": "Seguridad Social", - "amount": 200 - }, - { - "deductionTypeCode": "002", - "code": "00302", - "concept": "ISR", - "amount": 100 - } - ], - "disabilities": [ - { - "disabilityDays": 1, - "disabilityTypeCode": "01" - } - ] - } - } -}' - -### Factura Nómina - Nómina con SNCF - -curl --location 'http://localhost:5001/api/v4/invoices' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'Content-Type: application/json' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data '{ - "versionCode": "4.0", - "series": "F", - "date": "2026-01-18T18:04:06", - "paymentMethodCode": "PUE", - "currencyCode": "MXN", - "typeCode": "N", - "expeditionZipCode": "39074", - "exportCode": "01", - "issuer": { - "tin": "OÑO120726RX3", - "legalName": "ORGANICOS ÑAVEZ OSORIO", - "taxRegimeCode": "601", - "employerData": { - "employerRegistration": "27112029", - "satFundSourceId": "IP" - }, - "taxCredentials": [ - { - "base64File": "base64cer...", - "fileType": 0, - "password": "12345678a" - }, - { - "base64File": "base64key...", - "fileType": 1, - "password": "12345678a" - } - ] - }, - "recipient": { - "tin": "CACX7605101P8", - "legalName": "XOCHILT CASAS CHAVEZ", - "zipCode": "36257", - "taxRegimeCode": "605", - "cfdiUseCode": "CN01", - "employeeData": { - "curp": "XEXX010101HNEXXXA4", - "socialSecurityNumber": "80997742673", - "laborRelationStartDate": "2021-09-01", - "seniority": "P88W", - "satContractTypeId": "01", - "satTaxRegimeTypeId": "02", - "employeeNumber": "273", - "satJobRiskId": "1", - "satPaymentPeriodicityId": "04", - "integratedDailySalary": 221.48, - "satPayrollStateId": "GRO" - } - }, - "complement": { - "payroll": { - "version": "1.2", - "payrollTypeCode": "O", - "paymentDate": "2023-05-16T00:00:00", - "initialPaymentDate": "2023-05-01T00:00:00", - "finalPaymentDate": "2023-05-16T00:00:00", - "daysPaid": 15, - "earnings": { - "earnings": [ - { - "earningTypeCode": "001", - "code": "P001", - "concept": "Sueldos, Salarios Rayas y Jornales", - "taxedAmount": 3322.20, - "exemptAmount": 0.0 - }, - { - "earningTypeCode": "038", - "code": "P540", - "concept": "Compensacion", - "taxedAmount": 100.0, - "exemptAmount": 0.0 - }, - { - "earningTypeCode": "038", - "code": "P550", - "concept": "Compensación Garantizada Extraordinaria", - "taxedAmount": 2200.0, - "exemptAmount": 0.0 - }, - { - "earningTypeCode": "038", - "code": "P530", - "concept": "Servicio Extraordinario", - "taxedAmount": 200.0, - "exemptAmount": 0.0 - }, - { - "earningTypeCode": "001", - "code": "P506", - "concept": "Otras Prestaciones", - "taxedAmount": 1500.0, - "exemptAmount": 0.0 - }, - { - "earningTypeCode": "001", - "code": "P505", - "concept": "Remuneración al Desempeño Legislativo", - "taxedAmount": 17500.0, - "exemptAmount": 0.0 - } - ], - "otherPayments": [ - { - "otherPaymentTypeCode": "002", - "code": "o002", - "concept": "Subsidio para el empleo efectivamente entregado al trabajador", - "amount": 0.0, - "subsidyCaused": 0.0 - } - ] - }, - "deductions": [ - { - "deductionTypeCode": "002", - "code": "D002", - "concept": "ISR", - "amount": 4716.61 - }, - { - "deductionTypeCode": "004", - "code": "D525", - "concept": "Redondeo", - "amount": 0.81 - }, - { - "deductionTypeCode": "001", - "code": "D510", - "concept": "Cuota Trabajador ISSSTE", - "amount": 126.78 - } - ] - } - } -}' - -### Factura Nómina - Nómina Extraordinaria - -curl --location 'http://localhost:5001/api/v4/invoices' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'Content-Type: application/json' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data '{ - "versionCode": "4.0", - "series": "F", - "date": "2026-01-18T18:04:06", - "paymentMethodCode": "PUE", - "currencyCode": "MXN", - "typeCode": "N", - "expeditionZipCode": "20000", - "exportCode": "01", - "issuer": { - "tin": "EKU9003173C9", - "legalName": "ESCUELA KEMPER URGATE", - "taxRegimeCode": "601", - "employerData": { - "employerRegistration": "B5510768108", - "originEmployerTin": "URE180429TM6" - }, - "taxCredentials": [ - { - "base64File": "base64cer...", - "fileType": 0, - "password": "12345678a" - }, - { - "base64File": "base64key...", - "fileType": 1, - "password": "12345678a" - } - ] - }, - "recipient": { - "tin": "XOJI740919U48", - "legalName": "INGRID XODAR JIMENEZ", - "zipCode": "76028", - "taxRegimeCode": "605", - "cfdiUseCode": "CN01", - "employeeData": { - "curp": "XEXX010101HNEXXXA4", - "socialSecurityNumber": "000000", - "laborRelationStartDate": "2015-01-01", - "seniority": "P439W", - "satContractTypeId": "01", - "satWorkdayTypeId": "01", - "satTaxRegimeTypeId": "03", - "employeeNumber": "120", - "department": "Desarrollo", - "position": "Ingeniero de Software", - "satJobRiskId": "1", - "satPaymentPeriodicityId": "99", - "satBankId": "002", - "bankAccount": "1111111111", - "integratedDailySalary": 146.47, - "satPayrollStateId": "JAL" - } - }, - "complement": { - "payroll": { - "version": "1.2", - "payrollTypeCode": "E", - "paymentDate": "2023-06-04T00:00:00", - "initialPaymentDate": "2023-06-04T00:00:00", - "finalPaymentDate": "2023-06-04T00:00:00", - "daysPaid": 30, - "earnings": { - "earnings": [ - { - "earningTypeCode": "002", - "code": "00500", - "concept": "Gratificación Anual (Aguinaldo)", - "taxedAmount": 0.00, - "exemptAmount": 10000.00 - } - ], - "otherPayments": [] - }, - "deductions": [] - } - } -}' - -### Factura Nómina - Nómina Separación Indemnización - -curl --location 'http://localhost:5001/api/v4/invoices' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'Content-Type: application/json' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data '{ - "versionCode": "4.0", - "series": "F", - "date": "2026-01-18T18:04:06", - "paymentMethodCode": "PUE", - "currencyCode": "MXN", - "typeCode": "N", - "expeditionZipCode": "20000", - "exportCode": "01", - "issuer": { - "tin": "EKU9003173C9", - "legalName": "ESCUELA KEMPER URGATE", - "taxRegimeCode": "601", - "employerData": { - "employerRegistration": "B5510768108", - "originEmployerTin": "URE180429TM6" - }, - "taxCredentials": [ - { - "base64File": "base64cer...", - "fileType": 0, - "password": "12345678a" - }, - { - "base64File": "base64key...", - "fileType": 1, - "password": "12345678a" - } - ] - }, - "recipient": { - "tin": "XOJI740919U48", - "legalName": "INGRID XODAR JIMENEZ", - "zipCode": "76028", - "taxRegimeCode": "605", - "cfdiUseCode": "CN01", - "employeeData": { - "curp": "XEXX010101HNEXXXA4", - "socialSecurityNumber": "000000", - "laborRelationStartDate": "2015-01-01", - "seniority": "P439W", - "satContractTypeId": "01", - "satWorkdayTypeId": "01", - "satTaxRegimeTypeId": "03", - "employeeNumber": "120", - "department": "Desarrollo", - "position": "Ingeniero de Software", - "satJobRiskId": "1", - "satPaymentPeriodicityId": "99", - "satBankId": "002", - "bankAccount": "1111111111", - "integratedDailySalary": 146.47, - "satPayrollStateId": "JAL" - } - }, - "complement": { - "payroll": { - "version": "1.2", - "payrollTypeCode": "E", - "paymentDate": "2023-06-04T00:00:00", - "initialPaymentDate": "2023-05-05T00:00:00", - "finalPaymentDate": "2023-06-04T00:00:00", - "daysPaid": 30, - "earnings": { - "earnings": [ - { - "earningTypeCode": "023", - "code": "00500", - "concept": "Pagos por separación", - "taxedAmount": 0.00, - "exemptAmount": 10000.00 - }, - { - "earningTypeCode": "025", - "code": "00900", - "concept": "Indemnizaciones", - "taxedAmount": 0.00, - "exemptAmount": 500.00 - } - ], - "otherPayments": [], - "severance": { - "totalPaid": 10500.00, - "yearsOfService": 1, - "lastMonthlySalary": 10000.00, - "accumulableIncome": 10000.00, - "nonAccumulableIncome": 0.00 - } - }, - "deductions": [] - } - } -}' - - -### Factura Nómina - Nómina Jubilación Pensión Retiro -curl --location 'http://localhost:5001/api/v4/invoices' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'Content-Type: application/json' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data '{ - "versionCode": "4.0", - "series": "F", - "date": "2026-01-18T18:04:06", - "paymentMethodCode": "PUE", - "currencyCode": "MXN", - "typeCode": "N", - "expeditionZipCode": "20000", - "exportCode": "01", - "issuer": { - "tin": "EKU9003173C9", - "legalName": "ESCUELA KEMPER URGATE", - "taxRegimeCode": "601", - "employerData": { - "employerRegistration": "B5510768108", - "originEmployerTin": "URE180429TM6" - }, - "taxCredentials": [ - { - "base64File": "base64cer...", - "fileType": 0, - "password": "12345678a" - }, - { - "base64File": "base64key...", - "fileType": 1, - "password": "12345678a" - } - ] - }, - "recipient": { - "tin": "XOJI740919U48", - "legalName": "INGRID XODAR JIMENEZ", - "zipCode": "76028", - "taxRegimeCode": "605", - "cfdiUseCode": "CN01", - "employeeData": { - "curp": "XEXX010101HNEXXXA4", - "socialSecurityNumber": "000000", - "laborRelationStartDate": "2015-01-01", - "seniority": "P439W", - "satContractTypeId": "01", - "satWorkdayTypeId": "01", - "satTaxRegimeTypeId": "03", - "employeeNumber": "120", - "department": "Desarrollo", - "position": "Ingeniero de Software", - "satJobRiskId": "1", - "satPaymentPeriodicityId": "99", - "satBankId": "002", - "bankAccount": "1111111111", - "integratedDailySalary": 146.47, - "satPayrollStateId": "JAL" - } - }, - "complement": { - "payroll": { - "version": "1.2", - "payrollTypeCode": "E", - "paymentDate": "2023-05-05T00:00:00", - "initialPaymentDate": "2023-06-04T00:00:00", - "finalPaymentDate": "2023-06-04T00:00:00", - "daysPaid": 30, - "earnings": { - "earnings": [ - { - "earningTypeCode": "039", - "code": "00500", - "concept": "Jubilaciones, pensiones o haberes de retiro", - "taxedAmount": 0.00, - "exemptAmount": 10000.00 - } - ], - "retirement": { - "totalOneTime": 10000.00, - "accumulableIncome": 10000.00, - "nonAccumulableIncome": 0.00 - } - }, - "deductions": [] - } - } -}' - -### Factura Nómina - Nómina Sin Deducciones - -curl --location 'http://localhost:5001/api/v4/invoices' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'Content-Type: application/json' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data '{ - "versionCode": "4.0", - "series": "F", - "date": "2026-01-18T18:04:06", - "paymentMethodCode": "PUE", - "currencyCode": "MXN", - "typeCode": "N", - "expeditionZipCode": "20000", - "exportCode": "01", - "issuer": { - "tin": "EKU9003173C9", - "legalName": "ESCUELA KEMPER URGATE", - "taxRegimeCode": "601", - "employerData": { - "employerRegistration": "B5510768108", - "originEmployerTin": "URE180429TM6" - }, - "taxCredentials": [ - { - "base64File": "base64cer...", - "fileType": 0, - "password": "12345678a" - }, - { - "base64File": "base64key...", - "fileType": 1, - "password": "12345678a" - } - ] - }, - "recipient": { - "tin": "XOJI740919U48", - "legalName": "INGRID XODAR JIMENEZ", - "zipCode": "76028", - "taxRegimeCode": "605", - "cfdiUseCode": "CN01", - "employeeData": { - "curp": "XEXX010101HNEXXXA4", - "socialSecurityNumber": "000000", - "laborRelationStartDate": "2015-01-01", - "seniority": "P437W", - "satContractTypeId": "01", - "satWorkdayTypeId": "01", - "satTaxRegimeTypeId": "03", - "employeeNumber": "120", - "department": "Desarrollo", - "position": "Ingeniero de Software", - "satJobRiskId": "1", - "satPaymentPeriodicityId": "04", - "satBankId": "002", - "bankAccount": "1111111111", - "baseSalaryForContributions": 490.22, - "integratedDailySalary": 146.47, - "satPayrollStateId": "JAL" - } - }, - "complement": { - "payroll": { - "version": "1.2", - "payrollTypeCode": "O", - "paymentDate": "2023-05-24T00:00:00", - "initialPaymentDate": "2023-05-09T00:00:00", - "finalPaymentDate": "2023-05-24T00:00:00", - "daysPaid": 15, - "earnings": { - "earnings": [ - { - "earningTypeCode": "001", - "code": "00500", - "concept": "Sueldos, Salarios Rayas y Jornales", - "taxedAmount": 2808.8, - "exemptAmount": 2191.2 - } - ], - "otherPayments": [] - }, - "deductions": [] - } - } -}' - - -### Factura Nómina - Nómina Subsidio causado al empleo - -curl --location 'http://localhost:5001/api/v4/invoices' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'Content-Type: application/json' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data '{ - "versionCode": "4.0", - "series": "F", - "date": "2026-01-18T18:04:06", - "paymentMethodCode": "PUE", - "currencyCode": "MXN", - "typeCode": "N", - "expeditionZipCode": "20000", - "exportCode": "01", - "issuer": { - "tin": "EKU9003173C9", - "legalName": "ESCUELA KEMPER URGATE", - "taxRegimeCode": "601", - "employerData": { - "employerRegistration": "B5510768108", - "originEmployerTin": "URE180429TM6" - }, - "taxCredentials": [ - { - "base64File": "base64cer...", - "fileType": 0, - "password": "12345678a" - }, - { - "base64File": "base64key...", - "fileType": 1, - "password": "12345678a" - } - ] - }, - "recipient": { - "tin": "XOJI740919U48", - "legalName": "INGRID XODAR JIMENEZ", - "zipCode": "76028", - "taxRegimeCode": "605", - "cfdiUseCode": "CN01", - "employeeData": { - "curp": "XEXX010101HNEXXXA4", - "socialSecurityNumber": "000000", - "laborRelationStartDate": "2015-01-01T00:00:00", - "seniority": "P437W", - "satContractTypeId": "01", - "satWorkdayTypeId": "01", - "satTaxRegimeTypeId": "02", - "employeeNumber": "120", - "department": "Desarrollo", - "position": "Ingeniero de Software", - "satJobRiskId": "1", - "satPaymentPeriodicityId": "04", - "satBankId": "002", - "bankAccount": "1111111111", - "baseSalaryForContributions": 490.22, - "integratedDailySalary": 146.47, - "satPayrollStateId": "JAL" - } - }, - "complement": { - "payroll": { - "version": "1.2", - "payrollTypeCode": "O", - "paymentDate": "2023-05-24T00:00:00", - "initialPaymentDate": "2023-05-09T00:00:00", - "finalPaymentDate": "2023-05-24T00:00:00", - "daysPaid": 15, - "earnings": { - "earnings": [ - { - "earningTypeCode": "001", - "code": "00500", - "concept": "Sueldos, Salarios Rayas y Jornales", - "taxedAmount": 2808.8, - "exemptAmount": 2191.2 - } - ], - "otherPayments": [ - { - "otherPaymentTypeCode": "007", - "code": "0002", - "concept": "ISR ajustado por subsidio", - "amount": 145.80, - "subsidyCaused": 0.0 - } - ] - }, - "deductions": [ - { - "deductionTypeCode": "107", - "code": "D002", - "concept": "Ajuste al Subsidio Causado", - "amount": 160.35 - }, - { - "deductionTypeCode": "002", - "code": "D002", - "concept": "ISR", - "amount": 145.80 - } - ] - } - } -}' - -### Factura Nómina - Nómina Viáticos - -curl --location 'http://localhost:5001/api/v4/invoices' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'Content-Type: application/json' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data '{ - "versionCode": "4.0", - "series": "F", - "date": "2026-01-18T18:04:06", - "paymentMethodCode": "PUE", - "currencyCode": "MXN", - "typeCode": "N", - "expeditionZipCode": "20000", - "exportCode": "01", - "issuer": { - "tin": "EKU9003173C9", - "legalName": "ESCUELA KEMPER URGATE", - "taxRegimeCode": "601", - "employerData": { - "employerRegistration": "B5510768108", - "originEmployerTin": "URE180429TM6" - }, - "taxCredentials": [ - { - "base64File": "base64cer...", - "fileType": 0, - "password": "12345678a" - }, - { - "base64File": "base64key...", - "fileType": 1, - "password": "12345678a" - } - ] - }, - "recipient": { - "tin": "XOJI740919U48", - "legalName": "INGRID XODAR JIMENEZ", - "zipCode": "76028", - "taxRegimeCode": "605", - "cfdiUseCode": "CN01", - "employeeData": { - "curp": "XEXX010101HNEXXXA4", - "socialSecurityNumber": "000000", - "laborRelationStartDate": "2015-01-01T00:00:00", - "seniority": "P438W", - "satContractTypeId": "01", - "satWorkdayTypeId": "01", - "satTaxRegimeTypeId": "03", - "employeeNumber": "120", - "department": "Desarrollo", - "position": "Ingeniero de Software", - "satJobRiskId": "1", - "satPaymentPeriodicityId": "04", - "satBankId": "002", - "bankAccount": "1111111111", - "baseSalaryForContributions": 490.22, - "integratedDailySalary": 146.47, - "satPayrollStateId": "JAL" - } - }, - "complement": { - "payroll": { - "version": "1.2", - "payrollTypeCode": "O", - "paymentDate": "2023-09-26T00:00:00", - "initialPaymentDate": "2023-09-11T00:00:00", - "finalPaymentDate": "2023-09-26T00:00:00", - "daysPaid": 15, - "earnings": { - "earnings": [ - { - "earningTypeCode": "050", - "code": "050", - "concept": "Viaticos", - "taxedAmount": 0, - "exemptAmount": 3000 - } - ] - }, - "deductions": [ - { - "deductionTypeCode": "081", - "code": "081", - "concept": "Ajuste en viaticos entregados al trabajador", - "amount": 3000 - } - ] - } - } -}' - -### Factura Nómina - Nómina - -curl --location 'http://localhost:5001/api/v4/invoices' \ ---header 'X-TENANT-KEY: 102e5f13-e114-41dd-bea7-507fce177281' \ ---header 'X-TIME-ZONE: America/Mexico_City' \ ---header 'Content-Type: application/json' \ ---header 'X-API-KEY: sk_development_b470ea83_3c0f_4209_b933_85223b960d91' \ ---data '{ - "versionCode": "4.0", - "series": "F", - "date": "2026-01-18T18:04:06", - "paymentMethodCode": "PUE", - "currencyCode": "MXN", - "typeCode": "N", - "expeditionZipCode": "20000", - "exportCode": "01", - "issuer": { - "tin": "EKU9003173C9", - "legalName": "ESCUELA KEMPER URGATE", - "taxRegimeCode": "601", - "employerData": { - "employerRegistration": "B5510768108", - "originEmployerTin": "URE180429TM6" - }, - "taxCredentials": [ - { - "base64File": "base64cer...", - "fileType": 0, - "password": "12345678a" - }, - { - "base64File": "base64key...", - "fileType": 1, - "password": "12345678a" - } - ] - }, - "recipient": { - "tin": "XOJI740919U48", - "legalName": "INGRID XODAR JIMENEZ", - "zipCode": "76028", - "taxRegimeCode": "605", - "cfdiUseCode": "CN01", - "employeeData": { - "curp": "XEXX010101HNEXXXA4", - "socialSecurityNumber": "000000", - "laborRelationStartDate": "2015-01-01T00:00:00", - "seniority": "P437W", - "satContractTypeId": "01", - "satWorkdayTypeId": "01", - "satTaxRegimeTypeId": "03", - "employeeNumber": "120", - "department": "Desarrollo", - "position": "Ingeniero de Software", - "satJobRiskId": "1", - "satPaymentPeriodicityId": "04", - "satBankId": "002", - "bankAccount": "1111111111", - "baseSalaryForContributions": 490.22, - "integratedDailySalary": 146.47, - "satPayrollStateId": "JAL" - } - }, - "complement": { - "payroll": { - "version": "1.2", - "payrollTypeCode": "O", - "paymentDate": "2023-05-24T00:00:00", - "initialPaymentDate": "2023-05-09T00:00:00", - "finalPaymentDate": "2023-05-24T00:00:00", - "daysPaid": 15, - "earnings": { - "earnings": [ - { - "earningTypeCode": "001", - "code": "00500", - "concept": "Sueldos, Salarios Rayas y Jornales", - "taxedAmount": 2808.8, - "exemptAmount": 2191.2 - } - ], - "otherPayments": [] - }, - "deductions": [ - { - "deductionTypeCode": "001", - "code": "00301", - "concept": "Seguridad Social", - "amount": 200 - }, - { - "deductionTypeCode": "002", - "code": "00302", - "concept": "ISR", - "amount": 100 - } - ] - } - } -}' - - -### Response (for any use case) - -{ - "data": { - "versionCode": "4.0", - "series": "F", - "number": "EKU9003173C9-136", - "date": "2025-10-19T10:25:16.000", - "paymentFormCode": null, - "paymentConditions": null, - "subtotal": 117408.96, - "discount": 42821.48, - "currencyCode": "MXN", - "exchangeRate": 1, - "total": 74587.48, - "typeCode": "N", - "exportCode": "01", - "uuid": "a25e3739-a0ce-4c12-9ac0-283e035b9bf8", - "consecutive": 338, - "status": null, - "paymentMethodCode": "PUE", - "expeditionZipCode": "20000", - "issuer": { - "id": null, - "tin": "EKU9003173C9", - "legalName": "ESCUELA KEMPER URGATE", - "taxRegimeCode": "601" - }, - "recipient": { - "id": null, - "tin": "FUNK671228PH6", - "legalName": "KARLA FUENTE NOLASCO", - "zipCode": "01160", - "taxRegimeCode": "605", - "cfdiUseCode": "CN01", - "email": null - }, - "items": [ - { - "itemCode": "84111505", - "quantity": 1, - "unitOfMeasurementCode": "ACT", - "description": "Pago de nómina", - "unitPrice": 117408.96, - "taxObjectCode": "01", - "itemSku": null, - "unitOfMeasurement": null, - "discount": 42821.48, - "itemTaxes": [] - } - ], - "responses": [ - { - "invoiceId": "00c6f323-cf1d-4192-b3d0-eae33202a17a", - "invoiceUuid": "a25e3739-a0ce-4c12-9ac0-283e035b9bf8", - "invoiceCertificateNumber": "30001000000500003416", - "invoiceBase64Sello": "base64...", - "invoiceSignatureDate": "2025-10-20T12:56:42.000", - "invoiceBase64QrCode": "base64...", - "invoiceBase64": "base64...", - "satBase64Sello": "base64...", - "satBase64OriginalString": "base64...", - "satCertificateNumber": "30001000000500003456", - "id": "493f66c5-e366-485b-a3ce-1927e3d59710", - "createdAt": "2025-10-20T12:56:41.840", - "updatedAt": "2025-10-20T12:56:41.840" - } - ], - "metadata": { - "mode": "values" - }, - "id": "00c6f323-cf1d-4192-b3d0-eae33202a17a", - "createdAt": "2025-10-20T12:56:41.840", - "updatedAt": "2025-10-20T12:56:41.840" - }, - "succeeded": true, - "message": "", - "details": "", - "httpStatusCode": 200 -} - - - - - - -## Facturas de nomina por referencias. - -Analyze the existing **13 value-based payroll invoice examples** (where all data is sent via the request body) on @ejemplos-factura-nomina.ts file - -**Task:** -Recreate these 13 examples using a **reference-based approach**. In this approach, the Issuer (*Emisor*) and Receiver (*Receptor*) are referenced by their Object IDs rather than embedding their full details in the invoice payload. - -**Constants:** -Map the entities to the following UUIDs: - -```typescript -const escuelaKemperUrgateId = "2e7b988f-3a2a-4f67-86e9-3f931dd48581"; -const karlaFuenteNolascoId = "109f4d94-63ea-4a21-ab15-20c8b87d8ee9"; -const organicosNavezOsorioId = "f645e146-f80e-40fa-953f-fd1bd06d4e9f"; -const xochiltCasasChavezId = "e3b4edaa-e4d9-4794-9c5b-3dd5b7e372aa"; -const ingridXodarJimenezId = "9367249f-f0ee-43f4-b771-da2fff3f185f"; - -``` - -**Requirements:** -For each of the 13 use cases, you must generate **two distinct operations**: - -1. **Configuration (Setup):** Create the code to configure/save the Employee and Employer objects first. -* *Crucial:* You must extract the specific attributes (name, RFC, fiscal regime, etc.) from the original value-based example to populate these objects correctly. - - -2. **Invoice Generation (Execution):** Create the payroll invoice request using the IDs defined above (referencing the objects created in step 1). -* *Note:* The "Payroll Complement" data (amounts, perceptions, deductions) must remain identical to the original examples. - -3. Add those samples to the main function to be executable uncommeting them as needed, follow the same patter that the by values version. - - -Example - -// ============================================================================ -// 1. NOMINA ORDINARIA (Facturación por referencias) -// ============================================================================ -async function nominaOrdinariaByReferencesSetupData(client: FiscalapiClient): Promise { - // fiscalapiClient.persons.employer.delete() - // fiscalapiClient.persons.employer.create({...}) - // fiscalapiClient.persons.employee.delete() - // fiscalapiClient.persons.employee.create({...}) -} -async function nominaOrdinariaByReferences(client: FiscalapiClient): Promise { - console.log('\n=== Nómina Ordinaria ByReferences ===\n'); - - const invoice: Invoice = { - versionCode: '4.0', - series: 'F', - date: currentDate, - paymentMethodCode: 'PUE', - currencyCode: 'MXN', - typeCode: 'N', - expeditionZipCode: '20000', - exportCode: '01', - issuer: { - id: escuelaKemperUrgateId, //legalName: 'ESCUELA KEMPER URGATE', - }, - recipient: { - id: karlaFuenteNolascoId // legalName: 'KARLA FUENTE NOLASCO', - }, - 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 response = await client.invoices.create(invoice); - console.log('Response:', response); -} diff --git a/src/models/invoice.ts b/src/models/invoice.ts index d4f9d9c..fffd497 100644 --- a/src/models/invoice.ts +++ b/src/models/invoice.ts @@ -126,11 +126,11 @@ export interface LocalTax { /** Nombre del impuesto local */ taxName?: string; - /** Tasa del impuesto local */ - taxRate?: number; + /** Tasa del impuesto local (debe tener 2 posiciones decimales) */ + taxRate?: number | string; - /** Monto del impuesto local */ - taxAmount?: number; + /** Monto del impuesto local (debe tener 2 posiciones decimales) */ + taxAmount?: number | string; /** Código que indica la naturaleza del impuesto. "T": Traslado, "R": Retenido */ taxFlagCode?: string; From 21185d220bd1eea9296c3b00384dc732ff383058 Mon Sep 17 00:00:00 2001 From: JesusMendoza Date: Tue, 27 Jan 2026 16:22:06 -0600 Subject: [PATCH 14/15] ejemplos facturas con complemento de impuesos locales added --- .../ejemplos-factura-impuestos-locales-referencias.ts | 11 ++++------- .../ejemplos-factura-impuestos-locales-valores.ts | 10 +++------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/examples/ejemplos-factura-impuestos-locales-referencias.ts b/examples/ejemplos-factura-impuestos-locales-referencias.ts index 163f570..ee3e619 100644 --- a/examples/ejemplos-factura-impuestos-locales-referencias.ts +++ b/examples/ejemplos-factura-impuestos-locales-referencias.ts @@ -12,13 +12,10 @@ inspect.defaultOptions.colors = true; // Configuración de FiscalAPI const settings: FiscalapiSettings = { - // apiUrl: 'https://test.fiscalapi.com', - // apiKey: '', - // tenant: '', - apiUrl: "http://localhost:5001", - apiKey: "sk_development_b470ea83_3c0f_4209_b933_85223b960d91", - tenant: "102e5f13-e114-41dd-bea7-507fce177281", - debug: true + apiUrl: 'https://test.fiscalapi.com', + apiKey: '', + tenant: '', + debug: true }; // IDs de personas pre-configuradas en FiscalAPI (modo ByReferences) diff --git a/examples/ejemplos-factura-impuestos-locales-valores.ts b/examples/ejemplos-factura-impuestos-locales-valores.ts index e6718ac..c8340e6 100644 --- a/examples/ejemplos-factura-impuestos-locales-valores.ts +++ b/examples/ejemplos-factura-impuestos-locales-valores.ts @@ -12,13 +12,9 @@ inspect.defaultOptions.colors = true; // Configuración de FiscalAPI const settings: FiscalapiSettings = { - // apiUrl: 'https://test.fiscalapi.com', - // apiKey: '', - // tenant: '', - // debug: true - apiUrl: "http://localhost:5001", - apiKey: "sk_development_b470ea83_3c0f_4209_b933_85223b960d91", - tenant: "102e5f13-e114-41dd-bea7-507fce177281", + apiUrl: 'https://test.fiscalapi.com', + apiKey: '', + tenant: '', debug: true }; From a8ee735a37963d7c5dbd143393216d9caf080acf Mon Sep 17 00:00:00 2001 From: JesusMendoza Date: Tue, 27 Jan 2026 16:35:53 -0600 Subject: [PATCH 15/15] readme updated --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index cf30065..46a82f3 100644 --- a/README.md +++ b/README.md @@ -389,10 +389,13 @@ try { ## 📂 Más Ejemplos -- [Gestión de Timbres](examples/ejemplo-timbres.ts) - Transferencias y retiros de timbres -- [Datos Empleador/Empleado](examples/ejemplo-datos-empleado-empleador.ts) - Configuración para nómina -- [Facturas de Nómina (Por Valores)](examples/ejemplos-factura-nomina-valores.ts) - 13 ejemplos completos -- [Facturas de Nómina (Por Referencias)](examples/ejemplos-factura-nomina-referencias.ts) - 13 ejemplos completos +- [Gestión de Timbres](examples/ejemplo-timbres.ts) +- [Datos Empleador/Empleado](examples/ejemplo-datos-empleado-empleador.ts) +- [Facturas de Nómina (Por Valores)](examples/ejemplos-factura-nomina-valores.ts) +- [Facturas de Nómina (Por Referencias)](examples/ejemplos-factura-nomina-referencias.ts) +- [Facturas de Impuestos Locales (Por Referencias)](examples/ejemplos-factura-impuestos-locales-referencias.ts) +- [Facturas de Impuestos Locales (Por Valores)](examples/ejemplos-factura-impuestos-locales-valores.ts) + ---