Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Tax Calculator Laravel Package

spatie/tax-calculator

Interfaces and helpers to simplify tax calculations in PHP. Use TaxCalculation with plain numbers or items implementing HasTax to compute base, tax, and total prices, and combine calculations (e.g., cart items + delivery) on the fly.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require spatie/tax-calculator
    

    No additional configuration is required—just start using the package.

  2. First Use Case:

    • Implement HasTax on your model (e.g., CartItem):
      use Spatie\TaxCalculator\HasTax;
      
      class CartItem implements HasTax
      {
          public function getTaxablePrice(): float
          {
              return $this->price;
          }
      
          public function getTaxRate(): float
          {
              return 0.21; // 21% tax rate
          }
      }
      
    • Calculate taxes in a controller or service:
      $taxCalculation = TaxCalculation::fromCollection($cartItems);
      $basePrice = $taxCalculation->basePrice(); // Sum of all pre-tax prices
      $taxedPrice = $taxCalculation->taxedPrice(); // Sum + tax
      
  3. Key Classes to Explore:

    • TaxCalculation: Core class for calculations.
    • HasTax: Interface for taxable objects.
    • TaxCalculationException: Handle edge cases (e.g., invalid tax rates).

Implementation Patterns

Common Workflows

  1. Cart/Checkout Calculations:

    • Aggregate taxable items and compute totals:
      $subtotal = TaxCalculation::fromCollection($cartItems)->basePrice();
      $taxAmount = TaxCalculation::fromCollection($cartItems)->taxPrice();
      $total = $subtotal + $taxAmount;
      
    • Apply tax to non-taxable items (e.g., shipping):
      $shippingTax = TaxCalculation::fromTaxedPrice($shippingCost, $taxRate);
      $totalWithShipping = $taxCalculation->add($shippingTax)->taxedPrice();
      
  2. Dynamic Tax Rates:

    • Override getTaxRate() per item (e.g., for exempt products):
      public function getTaxRate(): float
      {
          return $this->isTaxExempt() ? 0.0 : 0.21;
      }
      
  3. Testing:

    • Mock HasTax implementations or use TaxCalculation directly:
      $this->assertEquals(12.10, TaxCalculation::fromTaxedPrice(10.00, 0.21)->taxedPrice());
      

Integration Tips

  • Laravel Services: Bind TaxCalculation to a service container for dependency injection:
    $this->app->bind(TaxCalculation::class, function () {
        return new TaxCalculation();
    });
    
  • API Responses: Return calculated values in JSON:
    return response()->json([
        'subtotal' => $taxCalculation->basePrice(),
        'tax' => $taxCalculation->taxPrice(),
        'total' => $taxCalculation->taxedPrice(),
    ]);
    
  • Database Storage: Store pre-calculated tax values (e.g., tax_rate, tax_amount) alongside orders for reporting.

Gotchas and Tips

Pitfalls

  1. Floating-Point Precision:

    • Tax calculations may suffer from floating-point errors. Round results for display:
      $taxedPrice = round($taxCalculation->taxedPrice(), 2);
      
    • Use bcmath or gmp for high-precision needs (not built into the package).
  2. Negative Tax Rates:

    • The package doesn’t validate tax rates. Ensure getTaxRate() returns >= 0:
      public function getTaxRate(): float
      {
          return max(0.0, $this->rate); // Clamp to 0
      }
      
  3. Empty Collections:

    • fromCollection([]) returns 0 for all methods. Handle edge cases explicitly:
      $price = $taxCalculation->basePrice() ?? 0.0;
      
  4. Immutable Operations:

    • Methods like add() return new TaxCalculation instances. Chain operations carefully:
      // Correct: Chained operations
      $total = TaxCalculation::fromCollection($items)
          ->add($shipping)
          ->taxedPrice();
      
      // Avoid: Overwriting variables
      $calc = TaxCalculation::fromCollection($items);
      $calc = $calc->add($shipping); // New instance!
      

Debugging

  • Log Intermediate Values:
    $calc = TaxCalculation::fromCollection($items);
    logger()->debug([
        'base' => $calc->basePrice(),
        'tax' => $calc->taxPrice(),
        'items' => $items->map(fn ($item) => [
            'price' => $item->getTaxablePrice(),
            'rate' => $item->getTaxRate(),
        ]),
    ]);
    
  • Check for HasTax Implementation: Use instanceof to verify:
    if (!$item instanceof HasTax) {
        throw new \InvalidArgumentException('Item must implement HasTax');
    }
    

Extension Points

  1. Custom Calculations: Extend TaxCalculation for complex logic (e.g., tiered taxes):
    class CustomTaxCalculation extends TaxCalculation
    {
        public function applyTieredTax(float $threshold, float $rate): self
        {
            // Custom logic here
            return $this;
        }
    }
    
  2. Tax Rate Providers: Decouple tax rates from models using a service:
    class TaxRateProvider
    {
        public function getRateForItem($item): float
        {
            return $item->category === 'exempt' ? 0.0 : config('tax.default_rate');
        }
    }
    
    Then update getTaxRate() to delegate:
    public function getTaxRate(): float
    {
        return app(TaxRateProvider::class)->getRateForItem($this);
    }
    
  3. Localization: Format tax values for specific locales:
    $formattedTax = number_format($taxCalculation->taxPrice(), 2, ',', ' ');
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport