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

Vatin Laravel Package

ddeboer/vatin

Validate EU VAT identification numbers and check their status via the VIES service. Provides simple PHP utilities to format, validate, and verify VATINs for customers and companies, making it easy to add VAT checks to invoicing and checkout flows.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install via Composer:

    composer require ddeboer/vatin
    

    No additional configuration is required—just require the package in your Laravel project.

  2. First Use Case: Validate a VAT number in a Laravel request or form submission:

    use Ddeboer\VatNumber\VatNumber;
    
    $vatNumber = new VatNumber('DE123456789');
    if ($vatNumber->isValid()) {
        $countryCode = $vatNumber->getCountryCode(); // 'DE'
        $number = $vatNumber->getNumber(); // '123456789'
    }
    
  3. Where to Look First:

    • Package Documentation (if available).
    • Ddeboer\VatNumber\VatNumber class for core functionality.
    • Ddeboer\VatNumber\Exception\InvalidVatNumberException for error handling.

Implementation Patterns

Core Workflows

  1. Validation in Requests (Laravel Forms/Checkouts):

    use Illuminate\Http\Request;
    use Ddeboer\VatNumber\VatNumber;
    
    public function validateVat(Request $request) {
        $vatInput = $request->input('vat_number');
        $vat = new VatNumber($vatInput);
    
        if (!$vat->isValid()) {
            return back()->withErrors(['vat_number' => 'Invalid VAT number']);
        }
        // Proceed with valid VAT data
    }
    
  2. Normalization Before Storage:

    $vat = new VatNumber($request->vat_number);
    $normalizedVat = $vat->getNormalized(); // e.g., "NL123456789B01"
    $user->vat_number = $normalizedVat;
    $user->save();
    
  3. Country-Specific Logic:

    $vat = new VatNumber('IT12345678901');
    if ($vat->getCountryCode() === 'IT') {
        // Apply Italian VAT-specific business logic
    }
    
  4. Batch Validation (e.g., CSV Imports):

    $vatNumbers = ['DE123', 'FR456', 'INVALID'];
    $validVats = array_filter($vatNumbers, fn($vat) => (new VatNumber($vat))->isValid());
    

Integration Tips

  • Laravel Form Requests: Use validate() with custom rules:

    public function rules() {
        return [
            'vat_number' => ['required', function ($attribute, $value, $fail) {
                if (!(new VatNumber($value))->isValid()) {
                    $fail('The VAT number is invalid.');
                }
            }]
        ];
    }
    
  • API Responses: Return structured VAT data in responses:

    return response()->json([
        'vat' => [
            'valid' => $vat->isValid(),
            'country' => $vat->getCountryCode(),
            'number' => $vat->getNumber(),
        ]
    ]);
    
  • Caching Valid VATs: Cache validated VATs to avoid reprocessing:

    $cacheKey = "vat_{$vatInput}";
    $vat = Cache::remember($cacheKey, now()->addHours(1), function() use ($vatInput) {
        return new VatNumber($vatInput);
    });
    

Gotchas and Tips

Pitfalls

  1. False Positives/Negatives:

    • Some country-specific rules (e.g., checksums) may not cover all edge cases. Test with real-world VAT numbers from your target countries.
    • Example: GB VAT numbers use a complex checksum; invalid formats may slip through if not tested thoroughly.
  2. Non-EU VAT Numbers:

    • The package only validates EU VATINs. Non-EU numbers (e.g., US tax IDs) will fail validation. Handle these cases explicitly:
      try {
          $vat = new VatNumber($input);
      } catch (InvalidVatNumberException $e) {
          if (str_starts_with($input, 'US')) {
              // Handle US tax ID separately
          } else {
              return back()->withError('Invalid EU VAT number');
          }
      }
      
  3. Case Sensitivity:

    • Country codes are case-insensitive (e.g., de123 = DE123), but consistency in storage/processing is recommended.
  4. Whitespace/Format Variations:

    • The package normalizes input (e.g., DE 123456789DE123456789), but ensure your UI/formats match expectations to avoid user confusion.

Debugging

  • Check Raw Input: Use getNormalized() to see how the package processes the input:

    $vat = new VatNumber('  DE-123456789  ');
    dd($vat->getNormalized()); // Output: "DE123456789"
    
  • Country-Specific Rules: If validation fails unexpectedly, inspect the country’s rules:

    $vat = new VatNumber('invalid');
    dd($vat->getCountryCode(), $vat->getNumber()); // Debug components
    
  • Exception Handling: Catch InvalidVatNumberException for invalid VATs and UnsupportedCountryException for non-EU countries:

    try {
        $vat = new VatNumber('US123');
    } catch (UnsupportedCountryException $e) {
        // Handle non-EU VAT numbers
    }
    

Extension Points

  1. Custom Validation Logic: Extend the VatNumber class for business-specific rules:

    class CustomVatNumber extends VatNumber {
        public function isValidForBusiness() {
            return $this->isValid() && $this->getCountryCode() === 'NL';
        }
    }
    
  2. Add New Country Support: While the package covers all EU countries, you can manually add rules for non-EU VATs (though this is unsupported):

    $vat = new VatNumber('CH123.456.789');
    // Manually validate Swiss VAT format (e.g., regex + checksum)
    
  3. Laravel Service Provider: Bind the package to the container for dependency injection:

    // app/Providers/AppServiceProvider.php
    public function register() {
        $this->app->bind(VatNumber::class, function () {
            return new VatNumber('');
        });
    }
    
  4. Testing: Use the package’s built-in test cases as a reference:

    $this->assertTrue((new VatNumber('NL123456789B01'))->isValid());
    $this->assertFalse((new VatNumber('INVALID'))->isValid());
    
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.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui