Claude
Skills
Sign in
Back

Invoice Generator

Included with Lifetime
$97 forever

Create professional invoices with line items, calculations, payment terms, and branding

document-creationinvoicebillingfinancepaymentaccounting

What this skill does


# Invoice Generator

The Invoice Generator skill automates the creation of professional, branded invoices in multiple formats (PDF, HTML, DOCX). It handles all standard invoice components including line items, tax calculations, discounts, payment terms, and company branding. Perfect for freelancers, agencies, and businesses that need to generate invoices programmatically.

Create invoices from templates, automate recurring billing, generate batch invoices for multiple clients, and maintain consistent branding across all billing documents.

## Core Workflows

### Workflow 1: Generate Standard Invoice (PDF)
**Purpose:** Create a professional PDF invoice with all standard elements

**Steps:**
1. Collect invoice data (client info, line items, amounts)
2. Calculate subtotal, tax, discounts, and total
3. Load invoice template or create layout
4. Add company branding (logo, colors, contact info)
5. Populate invoice details (number, date, due date)
6. Add line items table with descriptions and amounts
7. Display payment terms and methods
8. Generate PDF with proper formatting

**Implementation:**
```javascript
const PDFDocument = require('pdfkit');
const fs = require('fs');

function generateInvoice(invoiceData, outputPath) {
  const doc = new PDFDocument({ margin: 50 });
  const stream = fs.createWriteStream(outputPath);
  doc.pipe(stream);

  // Company header
  doc.fontSize(20)
     .text(invoiceData.company.name, 50, 50)
     .fontSize(10)
     .text(invoiceData.company.address, 50, 80)
     .text(invoiceData.company.email, 50, 95)
     .text(invoiceData.company.phone, 50, 110);

  // Company logo (if exists)
  if (invoiceData.company.logo) {
    doc.image(invoiceData.company.logo, 450, 50, { width: 100 });
  }

  // Invoice title and number
  doc.fontSize(24)
     .text('INVOICE', 400, 150, { align: 'right' })
     .fontSize(12)
     .text(`Invoice #: ${invoiceData.invoiceNumber}`, 400, 180, { align: 'right' })
     .text(`Date: ${invoiceData.date}`, 400, 195, { align: 'right' })
     .text(`Due: ${invoiceData.dueDate}`, 400, 210, { align: 'right' });

  // Bill to section
  doc.fontSize(12)
     .text('BILL TO:', 50, 150)
     .fontSize(10)
     .text(invoiceData.client.name, 50, 170)
     .text(invoiceData.client.address, 50, 185)
     .text(invoiceData.client.email, 50, 200);

  // Line items table
  const tableTop = 250;
  doc.fontSize(10);

  // Table header
  doc.fillColor('#2C3E50')
     .rect(50, tableTop, 500, 25)
     .fill()
     .fillColor('#FFFFFF')
     .text('Description', 60, tableTop + 8)
     .text('Quantity', 320, tableTop + 8)
     .text('Rate', 390, tableTop + 8)
     .text('Amount', 470, tableTop + 8);

  // Table rows
  let currentY = tableTop + 30;
  doc.fillColor('#000000');

  invoiceData.lineItems.forEach((item, index) => {
    const y = currentY + (index * 25);
    const bgColor = index % 2 === 0 ? '#FFFFFF' : '#F8F9FA';

    doc.fillColor(bgColor)
       .rect(50, y, 500, 25)
       .fill()
       .fillColor('#000000')
       .text(item.description, 60, y + 8, { width: 240 })
       .text(item.quantity, 320, y + 8)
       .text(`$${item.rate.toFixed(2)}`, 390, y + 8)
       .text(`$${(item.quantity * item.rate).toFixed(2)}`, 470, y + 8);
  });

  // Totals section
  const totalsY = currentY + (invoiceData.lineItems.length * 25) + 30;

  doc.text('Subtotal:', 380, totalsY)
     .text(`$${invoiceData.subtotal.toFixed(2)}`, 470, totalsY);

  if (invoiceData.tax) {
    doc.text(`Tax (${invoiceData.taxRate}%):`, 380, totalsY + 20)
       .text(`$${invoiceData.tax.toFixed(2)}`, 470, totalsY + 20);
  }

  if (invoiceData.discount) {
    doc.text('Discount:', 380, totalsY + 40)
       .text(`-$${invoiceData.discount.toFixed(2)}`, 470, totalsY + 40);
  }

  // Total
  doc.fontSize(14)
     .fillColor('#2C3E50')
     .rect(380, totalsY + 60, 170, 30)
     .fill()
     .fillColor('#FFFFFF')
     .text('TOTAL:', 390, totalsY + 68)
     .text(`$${invoiceData.total.toFixed(2)}`, 470, totalsY + 68);

  // Payment terms
  doc.fillColor('#000000')
     .fontSize(10)
     .text('Payment Terms:', 50, totalsY + 120)
     .fontSize(9)
     .text(invoiceData.paymentTerms, 50, totalsY + 135, { width: 500 });

  // Footer
  doc.fontSize(8)
     .fillColor('#7F8C8D')
     .text('Thank you for your business!', 50, doc.page.height - 80, {
       align: 'center',
       width: 500
     });

  doc.end();

  return new Promise((resolve, reject) => {
    stream.on('finish', () => resolve(outputPath));
    stream.on('error', reject);
  });
}
```

### Workflow 2: Calculate Invoice Totals
**Purpose:** Automatically calculate subtotals, taxes, discounts, and final total

**Steps:**
1. Sum all line item amounts for subtotal
2. Apply discount (percentage or fixed amount)
3. Calculate tax on discounted subtotal
4. Compute final total
5. Handle rounding to 2 decimal places
6. Validate calculations

**Implementation:**
```javascript
function calculateInvoiceTotals(lineItems, options = {}) {
  // Calculate subtotal
  const subtotal = lineItems.reduce((sum, item) => {
    return sum + (item.quantity * item.rate);
  }, 0);

  // Apply discount
  let discount = 0;
  if (options.discountPercent) {
    discount = subtotal * (options.discountPercent / 100);
  } else if (options.discountAmount) {
    discount = options.discountAmount;
  }

  const afterDiscount = subtotal - discount;

  // Calculate tax
  let tax = 0;
  if (options.taxRate) {
    tax = afterDiscount * (options.taxRate / 100);
  }

  // Calculate total
  const total = afterDiscount + tax;

  return {
    subtotal: parseFloat(subtotal.toFixed(2)),
    discount: parseFloat(discount.toFixed(2)),
    discountedSubtotal: parseFloat(afterDiscount.toFixed(2)),
    tax: parseFloat(tax.toFixed(2)),
    taxRate: options.taxRate || 0,
    total: parseFloat(total.toFixed(2)),
    lineItemCount: lineItems.length
  };
}
```

### Workflow 3: Generate from Template
**Purpose:** Use a branded invoice template for consistency

**Steps:**
1. Load HTML/Word template with placeholders
2. Define data mapping for template variables
3. Replace placeholders with actual data
4. Process line items loop
5. Calculate and insert totals
6. Convert to PDF or save as Word document
7. Apply company branding automatically

**Implementation:**
```javascript
const Handlebars = require('handlebars');
const puppeteer = require('puppeteer');
const fs = require('fs');

async function generateFromTemplate(templatePath, invoiceData, outputPath) {
  // Load template
  const templateHtml = fs.readFileSync(templatePath, 'utf8');
  const template = Handlebars.compile(templateHtml);

  // Register helpers
  Handlebars.registerHelper('currency', function(value) {
    return `$${parseFloat(value).toFixed(2)}`;
  });

  Handlebars.registerHelper('multiply', function(a, b) {
    return (a * b).toFixed(2);
  });

  // Prepare data
  const data = {
    ...invoiceData,
    currentYear: new Date().getFullYear(),
    formattedDate: new Date(invoiceData.date).toLocaleDateString(),
    formattedDueDate: new Date(invoiceData.dueDate).toLocaleDateString()
  };

  // Render template
  const html = template(data);

  // Convert to PDF
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.setContent(html);
  await page.pdf({
    path: outputPath,
    format: 'A4',
    margin: { top: '20mm', right: '20mm', bottom: '20mm', left: '20mm' },
    printBackground: true
  });
  await browser.close();

  return outputPath;
}

// Template example (invoice-template.html):
/*
<html>
<head>
  <style>
    body { font-family: Arial, sans-serif; }
    .header { background: #2C3E50; color: white; padding: 20px; }
    .line-items { width: 100%; border-collapse: collapse; }
    .line-items th { background: #34495E; color: white; padding: 10px; }
    .line-items td { border-bottom: 1px solid #ddd; padding: 8px; }
    .totals { text-align: right; margin-top: 20px; }
  </style>
</head>
<body>
  <div class="header">
    <h1>{{company.name}}</h1>

Related in document-creation