aichadigital/larabill

Professional billing & invoicing package for Laravel with UUID v7, VAT verification, EU compliance, and agnostic user models (UUID/ULID/Int)

Fund package maintenance!
AichaDigital

Installs: 13

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/aichadigital/larabill


README

Tests codecov PHP Version Laravel License

⚠️ DEVELOPMENT VERSION - This package is under active development (dev-main). Target: v1.0 stable by December 15, 2025.

Larabill is a professional, agnostic billing and invoicing package for Laravel applications. It provides comprehensive VAT verification, tax calculation for Spain/EU/worldwide, and flexible invoice generation with immutability protection.

🎯 Features

Core Functionality

  • Invoice Management: UUID-based IDs, sequential numbering, proforma invoices, immutable records
  • Tax Calculation: Spanish (IVA), Canary Islands (IGIC), Ceuta/Melilla (IPSI), EU reverse charge, worldwide
  • VAT/Tax Code Verification: Integration with AbstractAPI and APILayer for real-time validation
  • Fiscal Data Management: Company and customer fiscal configurations with temporal validity
  • PDF Generation: Built-in invoice PDF generation using DomPDF
  • EU Compliance: Full support for EU B2B reverse charge and destination VAT rules

Technical Excellence

  • String UUID v7: Ordered UUIDs for invoices (optimal for MySQL indexes)
  • Base-100 Integers: Precise monetary calculations (no floating-point errors)
  • User Agnostic: Works with any User model (UUID, ULID, or integer IDs)
  • Temporal Validity: Fiscal configurations with valid_from/valid_until dates
  • Invoice Immutability: Protection against modifications after issuance

πŸ“¦ Requirements

  • PHP ^8.3
  • Laravel ^11.0 | ^12.0

πŸš€ Installation

Via Composer

composer require aichadigital/larabill

Publish Configuration

php artisan vendor:publish --tag="larabill-config"

Run the Installer

php artisan larabill:install

This will:

  1. Publish migrations
  2. Run database migrations
  3. Seed default tax categories and rates

Manual Installation (if preferred)

# Publish migrations
php artisan vendor:publish --tag="larabill-migrations"

# Run migrations
php artisan migrate

# Seed default data
php artisan db:seed --class="AichaDigital\Larabill\Database\Seeders\TaxCategoriesSeeder"
php artisan db:seed --class="AichaDigital\Larabill\Database\Seeders\TaxRatesSeeder"

βš™οΈ Configuration

Environment Variables

Add these to your .env file:

# Tax Code Verification APIs
LARABILL_ABSTRACTAPI_KEY="your_abstractapi_key"
LARABILL_APILAYER_KEY="your_apilayer_key"
LARABILL_VAT_PREFERRED_API="abstractapi"
LARABILL_VAT_CACHE_DAYS=30

# Invoice Numbering
LARABILL_INVOICE_PREFIX="FAC"
LARABILL_PROFORMA_PREFIX="PRO"

# User ID Type (auto-detected if not set)
LARABILL_USER_ID_TYPE="uuid"  # Options: uuid, int, ulid

Model Configuration

Configure your user model in config/larabill.php:

'models' => [
    'user' => \App\Models\User::class,
    'invoice' => \AichaDigital\Larabill\Models\Invoice::class,
    'invoice_item' => \AichaDigital\Larabill\Models\InvoiceItem::class,
    // ...
],

πŸ—οΈ Architecture

Fiscal Data Model

Larabill separates company and customer fiscal data with temporal validity:

CompanyFiscalConfig    β†’ Company fiscal settings (one active at a time)
CustomerFiscalData     β†’ Customer fiscal data (historical per customer)
Invoice                β†’ Immutable invoice with fiscal snapshot

Key principles:

  • Company config changes apply from a specific date forward
  • Customer data changes are historical (never modify past records)
  • Invoices capture fiscal snapshot at creation time
  • Invoices are absolutely immutable once issued

UUID Strategy

Larabill uses string UUID v7 for invoices:

// Model with UUID
use AichaDigital\Larabill\Concerns\HasUuid;

class Invoice extends Model
{
    use HasUuid;
}

// Migration
$table->uuid('id')->primary();

Monetary Values (Base 100)

All monetary values use integers in base 100 to avoid floating-point errors:

// €12.34 stored as:
$invoice->total_amount = 1234;

// 21% IVA stored as:
$taxRate->rate = 2100;

Use the Base100Int cast from the lara100 package.

πŸ“– Usage

Creating an Invoice

use AichaDigital\Larabill\Services\BillingService;

$billingService = app(BillingService::class);

$invoice = $billingService->createInvoice([
    'user_id' => $user->id,
    'items' => [
        [
            'description' => 'Professional Service',
            'quantity' => 1,
            'unit_price' => 10000, // €100.00 in base 100
            'tax_rate' => 2100,    // 21% in base 100
        ]
    ]
]);

Tax Calculation

use AichaDigital\Larabill\Services\TaxCalculationService;

$taxService = app(TaxCalculationService::class);

// EU B2B reverse charge
$result = $taxService->calculateTax(10000, 'ES', 'DE', isB2B: true);
// Returns: tax_rate = 0 (reverse charge applies)

// EU B2C destination VAT
$result = $taxService->calculateTax(10000, 'ES', 'FR', isB2B: false);
// Returns: tax_rate = 2000 (20% French VAT)

VAT Verification

use AichaDigital\Larabill\Services\VatVerificationService;

$vatService = app(VatVerificationService::class);

$result = $vatService->verifyVatCode('ESB12345678', 'ES');

if ($result['is_valid']) {
    echo "Valid VAT for: " . $result['company_name'];
}

Company Fiscal Configuration

use AichaDigital\Larabill\Models\CompanyFiscalConfig;

// Get current active config
$config = CompanyFiscalConfig::getActive();

// Create new config (previous becomes inactive)
$newConfig = CompanyFiscalConfig::create([
    'tax_id' => 'ESB12345678',
    'company_name' => 'Your Company S.L.',
    'address' => 'Calle Test 123',
    'city' => 'Madrid',
    'postal_code' => '28001',
    'country_code' => 'ES',
    'is_oss' => true,
    'valid_from' => now(),
]);

Customer Fiscal Data

use AichaDigital\Larabill\Models\CustomerFiscalData;

// Get current fiscal data for a customer
$fiscalData = CustomerFiscalData::getActiveForUser($userId);

// Create new fiscal data (historical record)
$newData = CustomerFiscalData::createForUser($userId, [
    'tax_id' => 'FR12345678901',
    'business_name' => 'Client SARL',
    'country_code' => 'FR',
    'is_business' => true,
]);

πŸ§ͺ Testing

# Run all tests
composer test

# Run specific tests
composer test -- --filter=Invoice

# Run with coverage
composer test-coverage

# Static analysis
vendor/bin/phpstan analyse

Current status: 866 tests passing, 34 skipped (external dependencies)

πŸ“š Documentation

Document Description
ARCHITECTURE.md Core architecture and domain model
CHANGELOG.md Version history and breaking changes
TAX_SYSTEM_ANALYSIS.md Tax system design decisions

For AI agents working with this package, see .claude/project.md.

πŸ—ΊοΈ Roadmap

v1.0.0 (Target: December 15, 2025)

  • βœ… Core invoice management
  • βœ… Spanish tax system (IVA, IGIC, IPSI)
  • βœ… EU reverse charge (B2B)
  • βœ… Fiscal data with temporal validity
  • πŸ”„ VeriFACTU integration (Spain AEAT)
  • πŸ”„ WHMCS migration tools

v2.0.0 (Future)

  • Multi-tenancy support
  • Subscription billing
  • Payment gateway integration (Stripe, PayPal, Redsys)
  • Advanced reporting

🀝 Contributing

Please see CONTRIBUTING for details.

πŸ”’ Security

Please review our security policy on how to report security vulnerabilities.

πŸ“„ License

GNU Affero General Public License v3.0 (AGPL-3.0-or-later). See LICENSE.md for details.

This means:

  • βœ… You can use, modify, and distribute this software
  • βœ… You must share any modifications under the same license
  • ⚠️ If you run this as a network service, you must provide the source code to users
  • ⚠️ You must preserve copyright and attribution notices

πŸ‘₯ Credits