npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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

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.

Medusa v2 License: MIT


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 unificadascompany_name, company_ruc, company_address, company_phone, company_email y company_logo_base64 están disponibles en todos los tipos de plantilla gracias a buildCompanyContext() 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-invoice

Configuració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 tipos

Separació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-pdf consulta el módulo order (via query graph), resuelve países del módulo country, 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:

  1. template.company_id — si la plantilla tiene una empresa asignada.
  2. is_default = true — la empresa marcada como predeterminada.
  3. Primera empresa — fallback al primer registro.

Changelog

1.2.0

  • Variables de empresa unificadasbuildCompanyContext() en BaseDocumentStrategy garantiza 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_id en plantillas para vincular a una empresa específica.
  • API CRUD completa — nuevos endpoints GET/POST/DELETE /admin/invoice-config/:id y POST /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_default y company_id.

1.0.0

  • Release inicial: generación PDF, plantillas editables, configuración de empresa, strategy pattern.

License

MIT — CodeMind