@codemind.ec/medusa-plugin-invoice
v1.2.0
Published
Invoice & quotation PDF widget for Medusa v2 admin — download order receipts and manage company billing config.
Downloads
834
Maintainers
Readme
@codemind.ec/medusa-plugin-invoice
Plugin de facturación y cotización PDF para Medusa v2 — genera facturas de pedido y proformas de cotización con plantillas HTML personalizables desde el admin.
Features
- Multi-empresa — registra múltiples empresas (InvoiceConfig) y asigna una por defecto. Cada plantilla puede vincularse a una empresa específica.
- Generación de PDFs — facturas de pedido y proformas de cotización vía pdfmake + Handlebars/Puppeteer.
- Variables de empresa unificadas —
company_name,company_ruc,company_address,company_phone,company_emailycompany_logo_base64están disponibles en todos los tipos de plantilla gracias abuildCompanyContext()en la clase base. - Plantillas HTML editables — CRUD completo de plantillas con preview en tiempo real, paleta de variables categorizada y selector de empresa.
- Strategy Pattern — cada tipo de documento (factura, proforma) tiene su propia estrategia extensible.
- Templates embebidos — plantillas por defecto incluidas en el código; restaurables con un clic.
- Admin UI — dashboard "Comprobantes y Cotizaciones" con gestión de empresas, editor de plantillas con CodeMirror, widget de descarga en pedidos.
Requisitos
| Requisito | Versión | |-----------|----------| | Node.js | >= 20 | | Medusa | >= 2.13 |
Instalación
pnpm add @codemind.ec/medusa-plugin-invoiceConfiguración
1. Registrar el plugin y módulo en medusa-config.ts
import { defineConfig } from "@medusajs/framework/utils"
export default defineConfig({
// ...
plugins: [
{
resolve: "@codemind.ec/medusa-plugin-invoice",
options: {},
},
],
modules: [
{
resolve: "@codemind.ec/medusa-plugin-invoice/modules/invoice-generator",
options: {},
},
],
})2. Variables de entorno (opcionales)
El loader del módulo puede leer estas variables para configurar los valores iniciales de la empresa al crear la base de datos por primera vez:
| Variable | Descripción | Default |
|-----------------------|------------------------------------|----------------|
| STORE_NAME | Nombre de la empresa | — |
| STORE_ADDRESS | Dirección de la empresa | — |
| STORE_PHONE | Teléfono de la empresa | — |
| ADMIN_EMAIL | Email de notificaciones admin | — |
| MEDUSA_BACKEND_URL | URL base para embeber imágenes | http://localhost:9000 |
Todos los valores se pueden editar después desde el admin.
Arquitectura
medusa-plugin-invoice/
├── src/
│ ├── admin/ # UI del admin (widgets + rutas)
│ │ ├── widgets/order-invoice.tsx # Botón "Descargar comprobante" en pedidos
│ │ └── routes/invoice-config/
│ │ ├── page.tsx # Dashboard: Comprobantes y Cotizaciones
│ │ ├── companies/
│ │ │ ├── page.tsx # Lista de empresas
│ │ │ ├── new/page.tsx # Crear empresa
│ │ │ └── [id]/page.tsx # Editar empresa
│ │ └── invoice-templates/
│ │ ├── page.tsx # Lista de plantillas
│ │ └── [id]/page.tsx # Editor de plantilla (CodeMirror + variables)
│ ├── api/admin/
│ │ ├── invoice-config/ # CRUD multi-empresa
│ │ │ ├── route.ts # GET (listar) / POST (crear)
│ │ │ └── [id]/
│ │ │ ├── route.ts # GET / POST / DELETE por ID
│ │ │ └── set-default/route.ts # POST marcar como default
│ │ └── invoice-templates/ # CRUD de plantillas + preview + restore
│ └── modules/
│ └── invoice-generator/
│ ├── models/ # Invoice, InvoiceConfig, InvoiceTemplate
│ ├── templates/
│ │ ├── strategy.ts # BaseDocumentStrategy + buildCompanyContext()
│ │ ├── order-invoice.ts # Estrategia de factura de pedido
│ │ ├── quote-proforma.ts # Estrategia de proforma de cotización
│ │ └── defaults/index.ts # HTML embebido de plantillas por defecto
│ ├── loaders/ # Seed de config y plantillas iniciales
│ ├── migrations/ # Migraciones de base de datos
│ ├── service.ts # InvoiceGeneratorService
│ └── index.ts # INVOICE_MODULE export
└── index.d.ts # Declaraciones de tiposSeparación de responsabilidades
| Capa | Ubicación | Responsabilidad |
|------|-----------|-----------------|
| Módulo (modelos, servicio, migraciones, loader) | Plugin | Datos y lógica de dominio aislada |
| API routes | Plugin | Endpoints CRUD del módulo (config, plantillas) |
| Admin UI | Plugin | Widgets y páginas de administración |
| Workflows / Steps | App (apps/medusa/) | Orquestación cross-module |
| Subscribers | App (apps/medusa/) | Reacción a eventos del sistema |
¿Por qué los workflows NO están en el plugin?
Los workflows son orquestación cross-module por naturaleza. Por ejemplo,
generate-invoice-pdfconsulta el móduloorder(via query graph), resuelve países del módulocountry, verifica metadata de cotizaciones desde tipos de la app, y luego llama al módulo invoice. Moverlos al plugin crearía dependencias circulares (plugin → app) y eliminaría la capacidad de la app de personalizar la orquestación. Esta es la convención recomendada por Medusa v2: los plugins exponen módulos + API, las apps controlan la orquestación.
API Routes
Invoice Config (Multi-empresa)
| Método | Ruta | Descripción |
|--------|------|-------------|
| GET | /admin/invoice-config | Listar todas las empresas |
| POST | /admin/invoice-config | Crear nueva empresa |
| GET | /admin/invoice-config/:id | Obtener empresa por ID |
| POST | /admin/invoice-config/:id | Actualizar empresa |
| DELETE | /admin/invoice-config/:id | Eliminar empresa |
| POST | /admin/invoice-config/:id/set-default | Marcar empresa como predeterminada |
Invoice Templates
| Método | Ruta | Descripción |
|--------|------|-------------|
| GET | /admin/invoice-templates | Listar plantillas |
| POST | /admin/invoice-templates | Crear plantilla |
| GET | /admin/invoice-templates/:id | Obtener plantilla |
| POST | /admin/invoice-templates/:id | Actualizar plantilla |
| DELETE | /admin/invoice-templates/:id | Eliminar plantilla (no defaults) |
| POST | /admin/invoice-templates/:id/preview | Generar PDF de preview |
| POST | /admin/invoice-templates/:id/restore | Restaurar HTML por defecto |
Uso desde la app
Imports disponibles
// Módulo y servicio
import { INVOICE_MODULE, InvoiceGeneratorService } from "@codemind.ec/medusa-plugin-invoice"
// Tipos de factura de pedido
import type { InvoiceOrder, InvoiceLineItem, InvoiceOrderAddress, OrderInvoiceInput } from "@codemind.ec/medusa-plugin-invoice"
// Tipos de proforma de cotización
import type { QuoteProformaInput, ProformaConfigField, QuoteCustomerInfo, QuoteScheduleRules } from "@codemind.ec/medusa-plugin-invoice"
// Enums
import { InvoiceStatus, TemplateType } from "@codemind.ec/medusa-plugin-invoice"Generar un PDF desde un workflow/step
const invoiceService = container.resolve<InvoiceGeneratorService>(INVOICE_MODULE)
// Factura de pedido
const pdfBuffer = await invoiceService.generatePdf({
template: "order_invoice",
data: { order, items, invoiceDisplayId: 1, created_at: "2025-01-01" },
invoice_id: "inv_01ABC...",
})
// Proforma de cotización
const pdfBuffer = await invoiceService.generatePdf({
template: "quote_proforma",
data: { serviceType: "Catering", /* ... */ },
})Extensibilidad
Registrar una nueva estrategia de documento
import { TemplateFactory, BaseDocumentStrategy } from "@codemind.ec/medusa-plugin-invoice"
class MyCustomStrategy extends BaseDocumentStrategy<MyInput> {
async buildDocumentDefinition(input, config, htmlTemplate?) {
// buildCompanyContext() inyecta automáticamente las 6 variables de empresa
const companyCtx = await this.buildCompanyContext(config)
if (htmlTemplate) {
return this.renderHtmlTemplate(htmlTemplate, { ...companyCtx, ...myData })
}
// ... construir doc pdfmake programáticamente
}
}
TemplateFactory.register("my_custom_doc", MyCustomStrategy)Variables de empresa disponibles en todas las plantillas
buildCompanyContext(config) retorna:
| Variable | Descripción |
|----------|-------------|
| company_name | Nombre de la empresa |
| company_ruc | RUC / NIT / identificador fiscal |
| company_address | Dirección de la empresa |
| company_phone | Teléfono |
| company_email | Email |
| company_logo_base64 | Logo en base64 (data URI) |
Resolución de empresa en plantillas
Cuando se genera un PDF, el servicio resuelve la empresa con esta prioridad:
template.company_id— si la plantilla tiene una empresa asignada.is_default = true— la empresa marcada como predeterminada.- Primera empresa — fallback al primer registro.
Changelog
1.2.0
- Variables de empresa unificadas —
buildCompanyContext()enBaseDocumentStrategygarantiza que las 6 variables de empresa (company_name,company_ruc,company_address,company_phone,company_email,company_logo_base64) estén disponibles en todos los tipos de plantilla (factura y proforma). - Paleta de variables categorizada en el editor ahora muestra las mismas variables de empresa para ambos tipos de documento.
- Datos de preview actualizados para proforma con campos de empresa completos.
1.1.0
- Soporte multi-empresa — múltiples configuraciones de empresa con
is_default. - Asociación plantilla-empresa — campo
company_iden plantillas para vincular a una empresa específica. - API CRUD completa — nuevos endpoints
GET/POST/DELETE /admin/invoice-config/:idyPOST /admin/invoice-config/:id/set-default. - Dashboard renovado — página principal "Comprobantes y Cotizaciones" con tarjetas de navegación.
- Gestión de empresas — páginas de listado, creación y edición de empresas.
- Editor de plantillas mejorado — paleta de variables categorizada, selector de empresa, preview con logo placeholder.
- Migración automática para
is_defaultycompany_id.
1.0.0
- Release inicial: generación PDF, plantillas editables, configuración de empresa, strategy pattern.
License
MIT — CodeMind
