Skill: ivangdavila/invoice (version 1.0.0)

--- name: Invoice description: Create and send professional invoices with automatic numbering, tax calculation, templates, and payment tracking. --- ## Role Create invoices through a structured process. Gather client data, calculate taxes, generate PDF, send, track payment. **Key difference:** This skill CREATES invoices to send. The `invoices` skill MANAGES received invoices. --- ## Storage ``` ~/billing/ ├── drafts/ # Work in progress │ └── {client-name}/ │ ├── current.md # Latest version │ └── versions/ # v001.md, v002.md ├── sent/ # Finalized invoices │ └── 2026/ │ └── F-2026-001.pdf ├── clients/ # Client database │ └── index.json ├── config.json # User's business data, templates └── series.json # Numbering per series ``` --- ## Quick Reference | Topic | File | |-------|------| | Invoice creation phases | `phases.md` | | Client data management | `clients.md` | | Template and PDF generation | `templates.md` | | Legal requirements by country | `legal.md` | | Invoice types (regular, simplified, credit) | `types.md` | --- ## Process Summary 1. **Discovery** — Identify client, service, amount. Load or create client record. 2. **Draft** — Generate invoice with auto-calculated taxes and next number. 3. **Review** — Show preview, allow edits. 4. **Finalize** — Generate PDF, lock number. 5. **Send** — Email to client (optional). 6. **Track** — Monitor payment status. See `phases.md` for detailed workflow. --- ## Critical Rules - **Never reuse numbers** — Even cancelled invoices keep their number. Use credit notes for corrections. - **Correlative numbering** — No gaps within a series. F-001, F-002, F-003. - **Tax calculation** — Always show: base, rate, amount, total. Never hide taxes. - **Client data required** — For B2B: company name, tax ID, address. No invoice without complete data. --- ## Configuration Required Before first invoice, collect: - User's business name, tax ID, address - Bank details (IBAN) for payment - Default tax rate - Invoice series format (e.g., "F-2026-") - Email for sending (optional)

path: clients.md
content: # Client Database

## Schema

`clients/index.json`:
```json
{
  "clients": [
    {
      "id": "acme",
      "name": "Acme Corp S.L.",
      "tax_id": "B87654321",
      "address": {
        "street": "Av. Principal 456",
        "city": "Barcelona",
        "postal": "08001",
        "country": "ES"
      },
      "email": "[REDACTED_SECRET]",
      "payment_terms": 30,
      "default_rate": null,
      "notes": "Contact: María García",
      "created_at": "2025-01-15",
      "last_invoice": "2026-02-01"
    }
  ]
}
```

## Required Fields (B2B)

| Field | Required | Why |
|-------|----------|-----|
| name | ✓ | Legal name for invoice |
| tax_id | ✓ | Required for VAT deduction |
| address | ✓ | Legal requirement |
| email | Recommended | For delivery |

## Lookup and Matching

When user says "factura a Acme":
1. Search by name (case-insensitive, partial match)
2. If multiple matches → ask for clarification
3. If no match → offer to create new client

**Fuzzy matching:**
- "acme" → "Acme Corp S.L."
- "Hetzner" → "Hetzner Online GmbH"

## Creating New Client

Collect in order:
1. Legal name (exact as appears on their invoices)
2. Tax ID (validate format)
3. Address (street, city, postal, country)
4. Email (for sending invoices)
5. Payment terms (default: 30 days)

**Validation:**
- Tax ID format per country (see `legal.md`)
- Don't allow duplicate tax IDs

## Updating Client

"Cambia la dirección de Acme a..."
- Update in `index.json`
- Keep history? (optional)

## Client Reports

"¿Cuánto he facturado a Acme este año?"
- Sum all invoices where client.id = "acme" AND year = current
- Show breakdown by month


path: legal.md
content: # Invoice Legal Requirements

## Spain (RD 1619/2012)

### Required Fields

Every invoice must include:
1. **Número de factura** — Correlative within series
2. **Fecha de expedición**
3. **Datos del emisor:** Nombre/razón social, NIF, dirección
4. **Datos del destinatario:** Nombre/razón social, NIF, dirección
5. **Descripción de la operación**
6. **Base imponible**
7. **Tipo impositivo** (%)
8. **Cuota tributaria** (IVA amount)
9. **Importe total**

### Invoice Types

| Type | When to use |
|------|-------------|
| Factura completa | B2B, >400€, always for VAT deduction |
| Factura simplificada | B2C, <400€, no VAT deduction needed |
| Factura rectificativa | To correct or cancel previous invoice |

### Simplified Invoice (Ticket)

Allowed when:
- B2C transaction
- Amount ≤ 400€ (or ≤3,000€ for certain services)
- Recipient doesn't need VAT deduction

Can omit:
- Recipient tax ID
- Recipient address

### Credit Note (Rectificativa)

Required when:
- Error in original invoice
- Return of goods
- Discount after invoice issued
- Cancellation

Must include:
- Reference to original invoice (number, date)
- Reason for correction
- Original and corrected amounts

---

## VAT Rates (Spain)

| Rate | Name | Applies to |
|------|------|------------|
| 21% | General | Most goods and services |
| 10% | Reducido | Food, transport, hospitality |
| 4% | Superreducido | Bread, books, medicines |
| 0% | Exento | Insurance, finance, health |

### Intra-EU (B2B)

- No Spanish VAT
- Include: "Operación sujeta a inversión del sujeto pasivo"
- Client applies their local VAT

### Export (non-EU)

- No VAT (exempt)
- Include: "Exportación exenta de IVA"

---

## IRPF Retention (Freelancers)

When issuer is autonomous professional invoicing to company:

| Rate | When |
|------|------|
| 15% | Standard |
| 7% | First 3 years of activity |
| 0% | B2C, export, simplified regime |

**Calculation:**
```
Base: 1000€
IVA (21%): 210€
Total factura: 1210€
IRPF (15%): -150€
A cobrar: 1060€
```

Note: IRPF reduces what you receive, not the invoice total.

---

## Numbering Rules

- **Correlative** — No gaps: 001, 002, 003
- **By year** — Can reset each year (F-2026-001)
- **Multiple series** — Allowed for different activities
- **Never reuse** — Even cancelled invoices keep their number

---

## TicketBAI (País Vasco / Navarra)

If user is in Basque Country:
- All invoices must be registered with tax authority
- QR code required on invoice
- Digital signature required
- XML format submission

**Ask user:** "¿Necesitas facturación con TicketBAI?"

---

## Facturae (Public Administration)

If invoicing Spanish public entities (B2G):
- XML format required (Facturae 3.2.2)
- Submission via FACe portal
- Digital certificate required

**Ask user:** "¿Facturas a administración pública?"


path: phases.md
content: # Invoice Creation Phases

## Phase 1: Discovery

**Trigger:** User says "factura a X por Y" or similar.

**Questions to resolve:**
1. Who is the client? (existing or new)
2. What was delivered? (service description)
3. How much? (amount with or without tax)
4. Payment terms? (due date, method)

**For existing client:**
- Load from `clients/index.json`
- Confirm data is still current

**For new client:**
- Collect: name, tax ID, address, email
- Save to `clients/index.json`

**Never assume:**
- Tax ID (must be provided for B2B)
- Payment terms (ask if not in client defaults)

---

## Phase 2: Draft

**Auto-calculations:**
```
Input: "500€ por desarrollo web"

If user gives net amount:
  base = 500.00
  tax = 500.00 × 0.21 = 105.00
  total = 605.00

If user gives gross amount:
  total = 500.00
  base = 500.00 / 1.21 = 413.22
  tax = 86.78
```

**Number assignment:**
- Read current counter from `series.json`
- Assign next number (don't save yet—draft may be discarded)

**IRPF handling (Spain, freelancers):**
- If client is company AND user is freelancer → apply retention
- Default 15%, 7% for new freelancers (first 3 years)
- Retention reduces amount received, not total invoiced

**Output:** Draft invoice in `drafts/{client}/current.md`

---

## Phase 3: Review

**Show preview:**
```
┌──────────────────────────────────────────┐
│  FACTURA F-2026-015                      │
│  Fecha: 2026-02-13                       │
│  Vencimiento: 2026-03-13                 │
├──────────────────────────────────────────┤
│  EMISOR:                                 │
│  Tu Empresa S.L.                         │
│  CIF: B12345678                          │
│  Calle Example 123, Madrid               │
├──────────────────────────────────────────┤
│  CLIENTE:                                │
│  Acme Corp S.L.                          │
│  CIF: B87654321                          │
│  Av. Principal 456, Barcelona            │
├──────────────────────────────────────────┤
│  Concepto           Cantidad    Importe  │
│  Desarrollo web          1      500.00€  │
├──────────────────────────────────────────┤
│  Base imponible:               500.00€   │
│  IVA (21%):                    105.00€   │
│  IRPF (-15%):                  -75.00€   │
│  TOTAL FACTURA:                605.00€   │
│  A RECIBIR:                    530.00€   │
└──────────────────────────────────────────┘
```

**Allow edits:**
- "Cambia el concepto a 'Consultoría técnica'"
- "Añade otra línea: 2 horas extra a 50€/h"
- "Quita el IRPF, no aplica"
- "Cambia vencimiento a 60 días"

---

## Phase 4: Finalize

**Actions:**
1. Lock invoice number (save to `series.json`)
2. Save final version to `drafts/{client}/versions/v001.md`
3. Generate PDF using template
4. Save PDF to `sent/2026/F-2026-015.pdf`
5. Update `drafts/{client}/current.md` → point to finalized

**PDF generation:**
- Use HTML template from `templates.md`
- Convert via browser print or WeasyPrint

**No turning back:**
- Invoice number is now consumed
- To correct → use credit note (new invoice referencing original)

---

## Phase 5: Send

**If email configured:**
```
📧 Sending F-2026-015 to [REDACTED_SECRET]

Subject: Factura F-2026-015 - Tu Empresa S.L.
Body: [template with invoice details]
Attachment: F-2026-015.pdf

✓ Sent successfully
```

**If not configured:**
```
📎 Invoice saved to: ~/billing/sent/2026/F-2026-015.pdf
Ready to send manually or configure email.
```

---

## Phase 6: Track

**Status values:**
- `draft` → still editing
- `sent` → delivered to client
- `pending` → awaiting payment
- `paid` → payment received
- `overdue` → past due date

**Alerts:**
- 7 days before due date: "Factura F-2026-015 vence en 7 días"
- On due date: "Factura F-2026-015 vence hoy"
- After due date: "Factura F-2026-015 está vencida (3 días)"

**Mark as paid:**
- "Pagaron la F-2026-015"
- Record payment date
- Update status

---

## Recurring Invoices

For subscriptions:
```json
{
  "client": "acme",
  "description": "Mantenimiento mensual",
  "amount": 200.00,
  "frequency": "monthly",
  "day": 1,
  "active": true
}
```

**On trigger day:**
1. Generate draft automatically
2. Notify user: "📋 Factura recurrente lista para Acme"
3. User confirms or edits
4. Finalize and send


path: templates.md
content: # Invoice Templates

## HTML Template (Default)

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <style>
    body { font-family: -apple-system, sans-serif; margin: 40px; }
    .header { display: flex; justify-content: space-between; margin-bottom: 40px; }
    .logo { max-height: 60px; }
    .invoice-info { text-align: right; }
    .invoice-number { font-size: 24px; font-weight: bold; color: #2563eb; }
    .parties { display: flex; gap: 40px; margin-bottom: 40px; }
    .party { flex: 1; }
    .party-title { font-weight: bold; color: #666; margin-bottom: 8px; }
    table { width: 100%; border-collapse: collapse; margin: 20px 0; }
    th { background: #f3f4f6; text-align: left; padding: 12px; }
    td { padding: 12px; border-bottom: 1px solid #e5e7eb; }
    .amount { text-align: right; }
    .totals { margin-top: 20px; }
    .totals-row { display: flex; justify-content: flex-end; gap: 40px; padding: 8px 0; }
    .totals-label { color: #666; }
    .grand-total { font-size: 20px; font-weight: bold; border-top: 2px solid #333; padding-top: 12px; }
    .payment { margin-top: 40px; padding: 20px; background: #f9fafb; border-radius: 8px; }
    .footer { margin-top: 40px; font-size: 12px; color: #666; text-align: center; }
  </style>
</head>
<body>
  <div class="header">
    <div>
      <!-- {{logo}} -->
      <h2>{{issuer.name}}</h2>
      <div>{{issuer.tax_id}}</div>
      <div>{{issuer.address}}</div>
    </div>
    <div class="invoice-info">
      <div class="invoice-number">{{invoice_number}}</div>
      <div>Fecha: {{date}}</div>
      <div>Vencimiento: {{due_date}}</div>
    </div>
  </div>

  <div class="parties">
    <div class="party">
      <div class="party-title">CLIENTE</div>
      <div><strong>{{client.name}}</strong></div>
      <div>{{client.tax_id}}</div>
      <div>{{client.address}}</div>
    </div>
  </div>

  <table>
    <thead>
      <tr>
        <th>Descripción</th>
        <th class="amount">Cantidad</th>
        <th class="amount">Precio</th>
        <th class="amount">Total</th>
      </tr>
    </thead>
    <tbody>
      {{#each line_items}}
      <tr>
        <td>{{description}}</td>
        <td class="amount">{{quantity}}</td>
        <td class="amount">{{unit_price}}€</td>
        <td class="amount">{{total}}€</td>
      </tr>
      {{/each}}
    </tbody>
  </table>

  <div class="totals">
    <div class="totals-row">
      <span class="totals-label">Base imponible:</span>
      <span>{{subtotal}}€</span>
    </div>
    <div class="totals-row">
      <span class="totals-label">IVA ({{tax_rate}}%):</span>
      <span>{{tax_amount}}€</span>
    </div>
    {{#if retention}}
    <div class="totals-row">
      <span class="totals-label">IRPF (-{{retention_rate}}%):</span>
      <span>-{{retention_amount}}€</span>
    </div>
    {{/if}}
    <div class="totals-row grand-total">
      <span>TOTAL:</span>
      <span>{{total}}€</span>
    </div>
  </div>

  <div class="payment">
    <strong>Forma de pago:</strong> Transferencia bancaria<br>
    <strong>IBAN:</strong> {{issuer.iban}}<br>
    <strong>Concepto:</strong> {{invoice_number}}
  </div>

  <div class="footer">
    {{issuer.name}} · {{issuer.tax_id}} · {{issuer.email}}
  </div>
</body>
</html>
```

## PDF Generation

**Option 1: Browser print**
```bash
# Open HTML in browser, print to PDF
```

**Option 2: WeasyPrint**
```bash
weasyprint invoice.html invoice.pdf
```

**Option 3: Puppeteer/Playwright**
```javascript
await page.pdf({ path: 'invoice.pdf', format: 'A4' });
```

## Customization

Store user customizations in `config.json`:
```json
{
  "logo": "~/billing/logo.png",
  "primary_color": "#2563eb",
  "footer_text": "Gracias por su confianza",
  "payment_note": "Transferencia bancaria a 30 días"
}
```


path: types.md
content: # Invoice Types

## 1. Factura Completa (Standard)

**When:** Default for B2B transactions.

**Requirements:**
- All fields from legal requirements
- Recipient tax ID mandatory
- Full address required

**Example:**
```
FACTURA F-2026-015
Fecha: 2026-02-13
...
```

---

## 2. Factura Simplificada (Ticket)

**When:**
- B2C transactions
- Amount ≤ 400€
- Recipient doesn't need VAT deduction

**Simplified fields:**
- Issuer data (full)
- Date and number
- Description
- Total with VAT included

**Can omit:**
- Recipient name/address/tax ID
- Separate VAT breakdown (can show "IVA incluido")

**Example:**
```
TICKET T-2026-089
Fecha: 2026-02-13
Cliente: [no requerido]

Servicio de diseño: 100€ (IVA inc.)
TOTAL: 100€
```

---

## 3. Factura Rectificativa (Credit Note)

**When:**
- Error in original invoice (amount, data, description)
- Full or partial return
- Discount applied after invoicing
- Cancellation of transaction

**Required fields:**
- Reference to original: "Rectifica factura F-2026-010 de fecha..."
- Reason for rectification
- Original amounts
- Corrected amounts
- Difference

**Two methods:**

### Method 1: By difference
Show only the difference (negative amounts).
```
Rectifica: F-2026-010 (2026-02-01)
Motivo: Error en cantidad

Base original: 500€
Base correcta: 400€
Diferencia: -100€

IVA 21%: -21€
TOTAL: -121€
```

### Method 2: By substitution
Show both original and corrected full invoice.

**Numbering:**
- Use separate series (R-2026-001) or same series
- Still correlative, no gaps

---

## 4. Proforma

**When:**
- Quote/estimate before agreement
- Budget for approval
- Import/export documentation

**NOT a tax document:**
- No legal value
- No correlative number required
- Can be modified freely

**Mark clearly:**
```
FACTURA PROFORMA
(Sin valor fiscal)
```

**Convert to invoice:**
When client approves, create real invoice copying data.

---

## 5. Factura Recurrente

**Structure:**
Same as standard invoice, but:
- Generated automatically on schedule
- Links to subscription definition
- May note: "Correspondiente a periodo: Febrero 2026"

---

## Decision Tree

```
Is recipient a business (B2B)?
├─ YES → Factura Completa
│        ├─ Error found → Factura Rectificativa
│        └─ Public entity → Facturae XML
│
└─ NO (B2C)
         ├─ Amount ≤ 400€ → Factura Simplificada
         └─ Amount > 400€ → Factura Completa
                            (can omit recipient tax ID if no VAT deduction needed)
```

---

## Series Recommendations

| Series | Use |
|--------|-----|
| F-YYYY | Standard invoices |
| T-YYYY | Simplified (tickets) |
| R-YYYY | Rectificativas |
| P-YYYY | Proformas (optional) |

Example: F-2026-001, F-2026-002, R-2026-001, F-2026-003...


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: suspicious | SkillSpector: clean (LOW)