Skip to main content

Overview

Expenses (Accrued Expenses) in Tresa Contafy represent deductible costs incurred by a profile. Unlike invoices which track income, expenses track CFDIs received as a customer along with manual expense entries.
Expenses support both XML-imported CFDIs and manual entries, providing flexibility for managing deductible costs.

Why Expenses Matter

Proper expense tracking is essential for Mexican tax compliance:
  • Tax Deductions: Valid CFDIs are required to claim business expense deductions
  • ISR Calculation: Expenses reduce taxable income for ISR (Impuesto Sobre la Renta)
  • IVA Credits: Transferred IVA on expenses can be credited against IVA collected
  • Audit Documentation: Complete expense records support SAT audits

Data Structure

interface AccruedExpenseAttributes {
  id: string;                    // UUID primary key
  profile_id: string;            // Profile (RFC) reference
  tipo_origen: 'XML' | 'MANUAL'; // Source type
  
  // Date information
  fecha: Date;                   // Expense date
  mes: number;                   // Month (1-12)
  año: number;                   // Year
  
  // Financial amounts
  total: number;                 // Total with taxes
  subtotal: number;              // Subtotal before taxes
  iva: number;                   // IVA calculated
  iva_amount: number;            // IVA transferred
  retencion_iva_amount: number;  // IVA withheld
  retencion_isr_amount: number;  // ISR withheld
  
  // Payment status
  is_paid: boolean;
  payment_date: Date | null;
  
  // Categorization
  concepto: string | null;       // Description
  categoria: string | null;      // Expense category
  
  // CFDI fields (XML only)
  uuid: string | null;           // SAT fiscal folio
  tipo: 'PUE' | 'PPD' | 'COMPLEMENTO_PAGO' | null;
  rfc_emisor: string | null;
  nombre_emisor: string | null;
  regimen_fiscal_emisor: string | null;
  rfc_receptor: string | null;
  nombre_receptor: string | null;
  regimen_fiscal_receptor: string | null;
  
  // Payment tracking (PPD)
  pagos: PagoParcial[];
  complemento_pago: ComplementoPago | null;
  
  // Validation
  validacion: EstadoValidacionGasto;
  
  created_at: Date;
  updated_at: Date;
}

Origin Types

XML

XML-sourced expensesCreated from CFDI XML files uploaded or synced from SAT. Contains full fiscal information including UUID, RFC details, and tax breakdowns.Required fields: All CFDI fields populated

MANUAL

Manual entriesCreated manually by users for expenses that don’t have a CFDI (simplified regime, foreign expenses, etc.).Required fields: Only fecha, total, subtotal, iva, concepto

XML vs Manual Expenses

XML-Sourced Expenses

When an expense CFDI is uploaded or synced:
{
  "tipo_origen": "XML",
  "uuid": "98765432-4321-4321-4321-210987654321",
  "fecha": "2026-03-10T09:00:00.000Z",
  "total": 5800.00,
  "subtotal": 5000.00,
  "iva": 800.00,
  "iva_amount": 800.00,
  "tipo": "PUE",
  "rfc_emisor": "PRO850101XXX",
  "nombre_emisor": "Proveedor SA de CV",
  "regimen_fiscal_emisor": "601",
  "rfc_receptor": "PEXJ850101XXX",
  "nombre_receptor": "Juan Pérez",
  "concepto": "Compra de equipo de oficina",
  "categoria": "Equipo y Mobiliario",
  "validacion": {
    "rfcVerificado": true,
    "regimenFiscalVerificado": true,
    "uuidDuplicado": false,
    "advertencias": [],
    "errores": [],
    "valido": true
  }
}

Manual Expenses

Manually created expense entries:
{
  "tipo_origen": "MANUAL",
  "uuid": null,
  "fecha": "2026-03-12T12:00:00.000Z",
  "total": 2320.00,
  "subtotal": 2000.00,
  "iva": 320.00,
  "iva_amount": 320.00,
  "tipo": null,
  "rfc_emisor": null,
  "nombre_emisor": "Taxi Ejecutivo",
  "rfc_receptor": null,
  "nombre_receptor": null,
  "concepto": "Transporte a reunión de negocios",
  "categoria": "Viáticos",
  "validacion": {
    "rfcVerificado": false,
    "regimenFiscalVerificado": false,
    "uuidDuplicado": false,
    "advertencias": ["Gasto manual sin CFDI"],
    "errores": [],
    "valido": true
  }
}
Manual expenses without CFDIs may have limited deductibility. Consult with a tax advisor for proper categorization.

Payment Tracking

Expenses track payment status to differentiate between accrued and paid expenses:
{
  "is_paid": false,
  "payment_date": null
}
Represents expenses that have been incurred but not yet paid. Important for cash vs. accrual accounting.
For PPD (partial payment) expenses, the pagos array tracks individual payments:
{
  "tipo": "PPD",
  "is_paid": false,
  "pagos": [
    {
      "fechaPago": "2026-03-20T10:00:00.000Z",
      "formaPago": "03",
      "monedaPago": "MXN",
      "monto": 2900.00,
      "numParcialidad": 1,
      "origen": "COMPLEMENTO"
    },
    {
      "fechaPago": "2026-04-20T10:00:00.000Z",
      "formaPago": "03",
      "monedaPago": "MXN",
      "monto": 2900.00,
      "numParcialidad": 2,
      "origen": "COMPLEMENTO"
    }
  ]
}

Expense Categories

The categoria field helps organize expenses for reporting: Common categories include:
  • Renta y Arrendamiento
  • Servicios Profesionales
  • Equipo y Mobiliario
  • Viáticos y Gastos de Viaje
  • Publicidad y Marketing
  • Servicios Públicos
  • Seguros
  • Mantenimiento
Categories are user-defined and can be customized per profile’s accounting needs.

Validation System

interface EstadoValidacionGasto {
  rfcVerificado: boolean;           // RFC matches profile
  regimenFiscalVerificado: boolean; // Tax regime verified
  uuidDuplicado: boolean;           // Duplicate check
  advertencias: string[];           // Warning messages
  errores: string[];                // Error messages
  valido: boolean;                  // Overall valid status
}

Validation Rules

  1. XML Expenses: Full validation like invoices (RFC, regime, UUID uniqueness)
  2. Manual Expenses: Limited validation (amount consistency, date validity)
  3. Duplicate Prevention: UUID uniqueness check for XML expenses
  4. Amount Validation: Ensure total = subtotal + iva - retenciones

Relationships

Profile Relationship

AccruedExpense.belongsTo(Profile, {
  foreignKey: 'profile_id',
  as: 'profile',
  onDelete: 'CASCADE',
  onUpdate: 'CASCADE',
});

Indexes

indexes: [
  { fields: ['profile_id'] },     // List by profile
  { fields: ['uuid'] },           // Find by UUID
  { fields: ['fecha'] },          // Date range queries
  { fields: ['mes', 'año'] },     // Monthly reports
  { fields: ['tipo_origen'] },    // Filter by source
  { fields: ['is_paid'] },        // Filter by payment status
]

Usage Examples

Upload Expense CFDI

POST /api/profiles/:profileId/expenses/upload
Content-Type: multipart/form-data
Authorization: Bearer <token>

- xml: [expense.xml file]
- categoria: "Servicios Profesionales"
- is_paid: true
- payment_date: "2026-03-15"

Create Manual Expense

POST /api/profiles/:profileId/expenses
Content-Type: application/json
Authorization: Bearer <token>

{
  "tipo_origen": "MANUAL",
  "fecha": "2026-03-12",
  "total": 2320.00,
  "subtotal": 2000.00,
  "iva": 320.00,
  "nombre_emisor": "Taxi Ejecutivo",
  "concepto": "Transporte a reunión de negocios",
  "categoria": "Viáticos",
  "is_paid": true,
  "payment_date": "2026-03-12"
}

Query Expenses

GET /api/profiles/:profileId/expenses?mes=3&año=2026&categoria=Viáticos
Authorization: Bearer <token>
Response:
{
  "message": "Gastos obtenidos exitosamente",
  "data": [
    {
      "id": "880e8400-e29b-41d4-a716-446655440000",
      "profile_id": "550e8400-e29b-41d4-a716-446655440000",
      "tipo_origen": "MANUAL",
      "fecha": "2026-03-12T12:00:00.000Z",
      "mes": 3,
      "año": 2026,
      "total": 2320.00,
      "subtotal": 2000.00,
      "iva": 320.00,
      "iva_amount": 320.00,
      "categoria": "Viáticos",
      "concepto": "Transporte a reunión de negocios",
      "is_paid": true,
      "payment_date": "2026-03-12T12:00:00.000Z",
      "validacion": {
        "rfcVerificado": false,
        "regimenFiscalVerificado": false,
        "uuidDuplicado": false,
        "advertencias": ["Gasto manual sin CFDI"],
        "errores": [],
        "valido": true
      }
    }
  ],
  "count": 1,
  "total": 2320.00
}

Mark Expense as Paid

PATCH /api/expenses/:id
Content-Type: application/json
Authorization: Bearer <token>

{
  "is_paid": true,
  "payment_date": "2026-03-15"
}

Best Practices

Prefer XML CFDIs

Always request and upload XML CFDIs from vendors for maximum deductibility and audit protection.

Categorize Consistently

Use consistent category names across expenses to simplify reporting and analysis.

Track Payment Status

Maintain accurate payment dates for cash flow management and cash-basis tax calculation.

Document Manual Entries

Add detailed descriptions in concepto field for manual expenses to support audit inquiries.

Common Queries

Monthly Expense Report

GET /api/profiles/:profileId/metrics?mes=3&año=2026&tipo=gasto

Unpaid Expenses (Accounts Payable)

GET /api/profiles/:profileId/expenses?is_paid=false

Expenses by Category

GET /api/profiles/:profileId/expenses?categoria=Servicios%20Profesionales

Expenses Without CFDIs

GET /api/profiles/:profileId/expenses?tipo_origen=MANUAL

Tax Deduction Considerations

Important for Tax ComplianceTo be fully deductible for ISR and IVA purposes, expenses must:
  1. Have a valid CFDI (tipo_origen: “XML”)
  2. Be strictly indispensable for business operations
  3. Be properly registered in accounting records
  4. Match the taxpayer’s RFC as receptor
  5. Be paid (for cash-basis taxpayers)
Manual expenses may have limited or no deductibility. Always consult with a tax professional.

Profiles

RFC entities that own expenses

Invoices

Complementary income tracking

Subscriptions

Plan limits on expense storage

Build docs developers (and LLMs) love