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

Opensalestax Laravel Package

ejosterberg/opensalestax

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Install the Package

    composer require ejosterberg/opensalestax
    

    Requires PHP 8.2+.

  2. Set Up the Engine Deploy the OpenSalesTax engine (e.g., via Docker) and ensure it’s reachable at a baseUrl (e.g., http://localhost:8080).

  3. First Use Case: Calculate Tax for a Transaction

    use OpenSalesTax\Client;
    use OpenSalesTax\Address;
    use OpenSalesTax\LineItem;
    
    $client = new Client(baseUrl: 'http://localhost:8080');
    
    $result = $client->calculate(
        address: new Address(zip5: '55401'),
        lineItems: [
            new LineItem(amount: '100.00', category: 'general'),
        ]
    );
    
    echo "Tax Total: {$result->taxTotal}"; // Output: "Tax Total: 8.025"
    

Where to Look First

  • README.md: Quickstart guide, API surface, and examples.
  • Client Class: Core entry point for all API calls.
  • DTOs (Address, LineItem, CalculateResponse): Data structures for requests/responses.
  • Exceptions: Handle errors like OpenSalesTaxApiException or OpenSalesTaxNetworkException.

Implementation Patterns

Core Workflows

  1. Basic Tax Calculation

    $client = new Client(baseUrl: 'http://your-engine:8080');
    $result = $client->calculate(
        address: new Address(zip5: '90210'),
        lineItems: [new LineItem(amount: '50.00', category: 'clothing')]
    );
    
    • Use result->taxTotal for customer-facing totals.
    • Use result->lines for jurisdiction-level breakdowns (e.g., state/county splits).
  2. Shipping Tax (Engine v0.59.0+)

    $result = $client->calculate(
        address: new Address(zip5: '55401'),
        lineItems: [new LineItem(amount: '100.00', category: 'general')],
        shipping: new Shipping(amount: '12.50', method: 'standard')
    );
    
    • Check $result->shipping for shipping tax details.
    • Verify engine supports shipping via $client->capabilities()->features->shippingFirstClass.
  3. Rate Lookup

    $rates = $client->rates(zip5: '90210');
    echo "Combined Rate: {$rates->combinedRatePct}%";
    
  4. Health Checks

    $health = $client->health();
    if (!$health->databaseConnected) {
        throw new RuntimeException("Engine database unavailable");
    }
    

Integration Tips

  • Caching: Implement platform-specific caching (e.g., Redis) for rates or calculate responses. The SDK does not include caching logic.
  • Error Handling: Wrap calls in try-catch blocks to handle:
    try {
        $result = $client->calculate(...);
    } catch (OpenSalesTaxApiException $e) {
        logError("Engine error: {$e->statusCode}");
    } catch (OpenSalesTaxNetworkException $e) {
        logError("Network failure: " . $e->getMessage());
    }
    
  • Amount Handling: Use decimal strings (e.g., "100.00") to avoid floating-point precision issues. Convert cents to strings manually:
    $cents = 10000;
    $amount = number_format($cents / 100, 2, '.', '');
    
  • Feature Detection: Use capabilities() to gate features (e.g., shipping) based on engine version:
    if ($client->capabilities()->features->shippingFirstClass) {
        // Enable shipping tax logic
    }
    

Advanced Patterns

  1. Bulk Calculations Loop over line items or addresses and batch requests if the engine supports it (not natively supported in this SDK).

  2. Tax Category Mapping Map your product categories to OpenSalesTax categories (e.g., general, clothing, groceries). Example:

    $categoryMap = [
        'electronics' => 'general',
        'apparel' => 'clothing',
    ];
    
  3. Jurisdiction Breakdowns Use result->lines[*]->jurisdictions for accounting splits:

    foreach ($result->lines as $line) {
        foreach ($line->jurisdictions as $jurisdiction) {
            echo "{$jurisdiction->type}: {$jurisdiction->tax}\n";
        }
    }
    
  4. Testing

    • Use the SDK’s built-in unit tests as a reference.
    • Mock the Client or HTTP client for isolated tests (e.g., with Mockery or PHPUnit’s createMock).

Gotchas and Tips

Pitfalls

  1. Engine Version Mismatch

    • The SDK is tested against engine v0.14–v0.24 (v0.1.x) and v0.59.0+ (v0.3.x).
    • Shipping requires engine v0.59.0+. Older engines ignore the shipping field.
    • Solution: Pin both the SDK and engine versions in production:
      ejosterberg/opensalestax: ^0.3
      opensalestax engine:      v0.59.0+
      
  2. Decimal String Precision

    • Never use floats or integers for amounts. The engine expects strings (e.g., "100.00").
    • Gotcha: Converting cents to floats (e.g., 100.0010000) loses precision. Always use number_format():
      // Wrong:
      $amount = 10000 / 100; // Float: 100.00000000000001
      
      // Right:
      $amount = number_format(10000 / 100, 2, '.', ''); // String: "100.00"
      
  3. ZIP Code Validation

    • The SDK validates ZIP codes via regex. Invalid ZIPs (e.g., "123") throw OpenSalesTaxValidationException.
    • Solution: Pre-validate ZIPs or handle the exception:
      try {
          $result = $client->calculate(...);
      } catch (OpenSalesTaxValidationException $e) {
          echo "Invalid ZIP: {$e->getMessage()}";
      }
      
  4. Shipping Field Ignored in Older Engines

    • If the engine is < v0.59.0, the shipping field in calculate() is silently ignored.
    • Solution: Check capabilities at startup:
      if (!$client->capabilities()->features->shippingFirstClass) {
          throw new RuntimeException("Shipping tax requires engine v0.59.0+");
      }
      
  5. No Built-in Caching

    • The SDK does not cache responses. Implement caching (e.g., Redis) for performance:
      $cacheKey = "tax_{$zip}_{$subtotal}";
      $cachedResult = cache()->get($cacheKey);
      if (!$cachedResult) {
          $result = $client->calculate(...);
          cache()->put($cacheKey, $result, now()->addHours(1));
      }
      
  6. Tax Category Quirks

    • Some states have special rules (e.g., clothing is non-taxable in Minnesota).
    • Solution: Review the engine’s taxability rules or use the note field in CalculateResponse for hints:
      if ($line->note) {
          echo "Note: {$line->note}"; // e.g., "Clothing is non-taxable in Minnesota..."
      }
      
  7. Network Timeouts

    • Default timeout is 10 seconds. Adjust via the timeoutSeconds constructor argument:
      $client = new Client(baseUrl: 'http://engine:8080', timeoutSeconds: 30.0);
      

Debugging Tips

  1. Enable HTTP Logging
    • Inject a custom PSR-18 HTTP client (e.g., Guzzle with middleware) to log requests/responses:
      $client = new Client(
          baseUrl: 'http://engine:8080',
          httpClient: new \GuzzleHttp\Client([
              'handler' => \GuzzleHttp\HandlerStack::create([
                  new \GuzzleHttp\
      
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky