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

Sped Gtin Laravel Package

nfephp-org/sped-gtin

Valide GTINs (EAN-8/12/13/14) para NFe/NFCe layout 4.00 conforme NT 2021.003: verifica estrutura, prefixo 789/790, região e dígito verificador, ajudando a evitar rejeições da SEFAZ por código inválido.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require nfephp-org/sped-gtin
    

    Ensure your composer.json has "minimum-stability": "dev" if using the dev-master branch.

  2. First Use Case: Validate a GTIN in a Laravel request or model:

    use NFePHP\Gtin\Gtin;
    
    // In a controller or service
    $gtin = request('gtin');
    try {
        if (Gtin::check($gtin)->isValid()) {
            // Proceed with NFe/NFCe generation
            return response()->json(['success' => true]);
        }
        return response()->json(['error' => 'Invalid GTIN'], 400);
    } catch (\Exception $e) {
        return response()->json(['error' => $e->getMessage()], 400);
    }
    
  3. Where to Look First:

    • Class Properties: region, prefix, checkDigit, restricted, type (for debugging).
    • Exceptions Table: Map error messages to SEFAZ rejection codes (e.g., "prefix INVALIDO" → 0405).
    • README’s "Validações e Exceptions": Reference for handling edge cases (e.g., "SEM GTIN" string).

Implementation Patterns

Core Workflows

  1. Product Onboarding Validation:

    • Laravel Form Request:
      use NFePHP\Gtin\Gtin;
      use Illuminate\Validation\Rule;
      
      public function rules()
      {
          return [
              'gtin' => [
                  'required',
                  Rule::custom(function ($attribute, $value) {
                      try {
                          return Gtin::check($value)->isValid();
                      } catch (\Exception $e) {
                          return false;
                      }
                  }),
              ],
          ];
      }
      
    • Service Layer:
      class GtinValidator
      {
          public function validate(string $gtin): bool
          {
              try {
                  return Gtin::check($gtin)->isValid();
              } catch (\Exception) {
                  return false;
              }
          }
      }
      
  2. NFe/NFCe Payload Sanitization:

    • Laravel Service Provider Boot:
      public function boot()
      {
          app()->resolving('nfe.generator', function ($generator) {
              $generator->setGtinValidator(new GtinValidator());
          });
      }
      
    • Dynamic Validation in XML Builder:
      $gtin = $product->gtin;
      $validator = new GtinValidator();
      if (!$validator->validate($gtin)) {
          throw new \InvalidArgumentException("GTIN {$gtin} rejected by SEFAZ rules.");
      }
      
  3. Bulk Validation:

    • Laravel Collection Macro:
      Collect::macro('validateGtins', function () {
          return $this->filter(function ($gtin) {
              try {
                  return Gtin::check($gtin)->isValid();
              } catch (\Exception) {
                  return false;
              }
          });
      });
      
      // Usage:
      $validGtins = Product::pluck('gtin')->validateGtins();
      

Integration Tips

  • Laravel Artisan Command: Validate GTINs in a CSV import:

    public function handle()
    {
        Excel::load('products.csv', function ($reader) {
            $reader->each(function ($row) {
                if (!Gtin::check($row['gtin'])->isValid()) {
                    $this->error("Invalid GTIN: {$row['gtin']}");
                }
            });
        });
    }
    
  • Event Listeners: Log GTIN validation failures to a compliance audit table:

    public function handle(ProductValidated $event)
    {
        if (!$event->isValid) {
            GtinAudit::create([
                'gtin' => $event->gtin,
                'error' => $event->exception?->getMessage(),
            ]);
        }
    }
    
  • API Response Wrapping: Standardize error messages for frontend consumption:

    try {
        $gtin = Gtin::check($request->gtin);
        return ['valid' => $gtin->isValid(), 'region' => $gtin->region];
    } catch (\Exception $e) {
        return ['error' => 'GTIN_'.strtoupper(str_replace(' ', '_', $e->getMessage()))];
    }
    

Gotchas and Tips

Pitfalls

  1. Prefix Restrictions:

    • GTINs starting with 789 or 790 are Brazil-only. Others (e.g., 0, 30–37, 400–440) are invalid for SEFAZ and will throw:
      Somente prefixos do Brasil [789, 790] são aceitáveis.
      
    • Fix: Add a custom rule to reject non-Brazilian GTINs early:
      Rule::custom(function ($value) {
          return Gtin::check($value)->prefix === '789' || Gtin::check($value)->prefix === '790';
      });
      
  2. GTIN Length Ambiguity:

    • The package accepts 8, 12, 13, or 14 digits, but SEFAZ may enforce stricter rules (e.g., only 13/14 for certain products).
    • Tip: Extend the class to validate against your business rules:
      class StrictGtin extends \NFePHP\Gtin\Gtin
      {
          public function isStrictlyValid(): bool
          {
              return $this->isValid() && ($this->type === 13 || $this->type === 14);
          }
      }
      
  3. "SEM GTIN" Edge Case:

    • The package returns true only for the exact string "SEM GTIN" (case-sensitive).
    • Gotcha: "sem gtin", "Sem GTIN", or null will throw exceptions.
    • Fix: Normalize input:
      $normalizedGtin = strtoupper(trim($gtin ?? ''));
      if ($normalizedGtin === 'SEM GTIN') {
          return true;
      }
      return Gtin::check($normalizedGtin)->isValid();
      
  4. Check Digit Calculation:

    • The package uses modulo-10 for validation. If SEFAZ changes the algorithm (unlikely but possible), the package will fail silently.
    • Tip: Add a version check or log validation failures to monitor for rule changes.
  5. Performance with Bulk Data:

    • Validating thousands of GTINs in a loop can be slow. Cache results if reprocessing:
      $cacheKey = "gtin_{$gtin}";
      if (!Cache::has($cacheKey)) {
          Cache::put($cacheKey, Gtin::check($gtin)->isValid(), now()->addHours(1));
      }
      

Debugging Tips

  • Exception Mapping: Create a helper to translate exceptions to SEFAZ error codes:

    function gtinExceptionToSefazCode(\Exception $e): string
    {
        $message = strtolower($e->getMessage());
        if (str_contains($message, 'prefix invalido')) return '0405';
        if (str_contains($message, 'digito verificador')) return '0406';
        return '9999'; // Unknown
    }
    
  • Log Validation Details:

    try {
        $gtin = Gtin::check($request->gtin);
        \Log::info('GTIN Validation', [
            'gtin' => $request->gtin,
            'valid' => $gtin->isValid(),
            'region' => $gtin->region,
            'prefix' => $gtin->prefix,
            'type' => $gtin->type,
        ]);
    } catch (\Exception $e) {
        \Log::error('GTIN Validation Failed', [
            'gtin' => $request->gtin,
            'error' => $e->getMessage(),
            'sefas_code' => gtinExceptionToSefazCode($e),
        ]);
    }
    

Extension Points

  1. Custom Prefix Rules: Override the prefix validation logic (e.g., to allow testing with 788):
    class CustomGtin extends \NFePHP\Gtin\Gtin
    {
        protected function validatePrefix(): void
        {
            if (!in_array($this->prefix, ['788', '789', '790'])) {
                throw new \InvalidArgumentException("Prefixo {$this->prefix} não permitido.");
            }
        }
    
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.
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium