PHP code example of banelsems / lara-sgmef-qr

1. Go to this page and download the library: Download banelsems/lara-sgmef-qr library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

banelsems / lara-sgmef-qr example snippets


    // config/lara_sgmef_qr.php
    
    'web_interface' => [
        'enabled' => env('SGMEF_WEB_INTERFACE_ENABLED', true),
        // Protégez l'accès avec le middleware d'authentification de votre application
        'middleware' => ['web', 'auth'], 
        'route_prefix' => env('SGMEF_ROUTE_PREFIX', 'sgmef'),
    ],
    

use Banelsems\LaraSgmefQr\Contracts\InvoiceManagerInterface;
use Banelsems\LaraSgmefQr\DTOs\InvoiceRequestDto;
use Banelsems\LaraSgmefQr\DTOs\ClientDto;
use Banelsems\LaraSgmefQr\DTOs\OperatorDto;
use Banelsems\LaraSgmefQr\DTOs\InvoiceItemDto;
use Banelsems\LaraSgmefQr\DTOs\PaymentDto;

// Injection de dépendance
$invoiceManager = app(InvoiceManagerInterface::class);

// Création des DTOs
$client = new ClientDto(
    ifu: '1234567890123',
    name: 'ACME Corporation',
    contact: '+229 12 34 56 78',
    address: '123 Rue de la Paix, Cotonou'
);

// Opérateur - Utilise automatiquement la configuration par défaut si non spécifié
$operator = new OperatorDto(
    id: config('lara_sgmef_qr.default_operator.id', '1'),
    name: config('lara_sgmef_qr.default_operator.name', 'Opérateur Principal')
);

$items = [
    new InvoiceItemDto(
        name: 'Consultation Médicale',
        price: 15000,
        quantity: 1,
        taxGroup: 'B', // TVA 18%
        code: 'CONS001'
    )
];

$payments = [
    new PaymentDto(
        name: 'ESPECES',
        amount: 15000
    )
];

// Création de la facture
    $invoiceData = InvoiceRequestDto::fromArray([
        'ifu' => config('lara_sgmef_qr.default_ifu'),
        'type' => 'FV', // Facture de Vente
        'items' => $items,
        'client' => $client,
        'operator' => $operator,
        'payment' => $payments,
        'aib' => 'A' // AIB 1%
    ]);

try {
    $invoice = $invoiceManager->createInvoice($invoiceData);
    echo "Facture créée avec succès ! UID: {$invoice->uid}";
} catch (\Exception $e) {
    echo "Erreur : {$e->getMessage()}";
}

try {
    $confirmedInvoice = $invoiceManager->confirmInvoice($invoice->uid);
    echo "Facture confirmée ! QR Code: {$confirmedInvoice->qr_code_data}";
} catch (\Exception $e) {
    echo "Erreur de confirmation : {$e->getMessage()}";
}

// app/Http/Controllers/OrderController.php

use App\Models\Order;
use App\Models\Customer;
use Banelsems\LaraSgmefQr\Contracts\InvoiceManagerInterface;
use Banelsems\LaraSgmefQr\DTOs\InvoiceRequestDto;
use Banelsems\LaraSgmefQr\DTOs\ClientDto;
use Banelsems\LaraSgmefQr\DTOs\OperatorDto;
use Banelsems\LaraSgmefQr\DTOs\InvoiceItemDto;
use Banelsems\LaraSgmefQr\DTOs\PaymentDto;
use Illuminate\Support\Facades\Log;

public function store(Request $request)
{
    // ... (logique existante pour créer la vente, valider le panier, etc.)

    // 1. Créer la commande dans votre base de données
    $order = Order::create([
        'customer_id' => $request->customer_id,
        'total_amount' => $request->total_amount,
        'status' => 'completed',
        // ...
    ]);

    // 2. Préparer les données pour l'API e-MECeF en mappant vos modèles
    $customer = Customer::find($request->customer_id);

    // Mapper le client de votre app vers le DTO du package
    $clientDto = new ClientDto(
        ifu: $customer->ifu,
        name: $customer->name,
        contact: $customer->phone,
        address: $customer->address
    );

    // Mapper l'opérateur (l'utilisateur connecté qui a fait la vente)
    $operatorDto = new OperatorDto(
        id: (string) auth()->id(),
        name: auth()->user()->name
    );

    // Mapper les articles de la commande vers les DTOs du package
    $invoiceItems = $order->items->map(function ($item) {
        return new InvoiceItemDto(
            name: $item->product->name,
            price: $item->unit_price,
            quantity: $item->quantity,
            taxGroup: $item->product->tax_group, // Assurez-vous d'avoir ce champ dans votre modèle Product
            code: $item->product->sku
        );
    })->all();

    // Mapper le paiement
    $paymentDto = new PaymentDto(
        name: $request->payment_method, // Ex: 'ESPECES', 'CARTEBANCAIRE'
        amount: $order->total_amount
    );

    // 3. Créer le DTO principal pour la facture
    $invoiceData = InvoiceRequestDto::from([
        'ifu' => config('lara_sgmef_qr.default_ifu'),
        'type' => 'FV',
        'client' => [
            'name' => $customer->name,
            'ifu' => $customer->ifu,
            'contact' => $customer->phone,
            'address' => $customer->address,
        ],
        'operator' => [
            'id' => (string) auth()->id(),
            'name' => auth()->user()->name,
        ],
        'items' => $order->items->map(function ($item) {
            return [
                'name' => $item->product->name,
                'price' => $item->unit_price,
                'quantity' => $item->quantity,
                'taxGroup' => $item->product->tax_group,
                'code' => $item->product->sku,
            ];
        })->toArray(),
        'payment' => [[
            'name' => $request->payment_method,
            'amount' => $order->total_amount,
        ]],
    ]);

    // 4. Appeler le service de LaraSgmefQR
    try {
        $invoiceManager = app(InvoiceManagerInterface::class);
        
        // Créer la facture sur l'API e-MECeF
        $invoice = $invoiceManager->createInvoice($invoiceData);
        
        // Confirmer la facture pour obtenir le QR Code et le code MECeF
        $confirmedInvoice = $invoiceManager->confirmInvoice($invoice->uid);

        // 5. Mettre à jour votre commande avec les informations de l'e-MECeF
        $order->update([
            'mECeF_uid' => $confirmedInvoice->uid,
            'mECeF_code' => $confirmedInvoice->mecf_code,
            'qr_code_data' => $confirmedInvoice->qr_code_data,
            'status' => 'invoiced'
        ]);

        return redirect()->route('orders.show', $order->id)
                         ->with('success', 'Vente et facture e-MECeF créées avec succès !');

    } catch (\Exception $e) {
        // GESTION D'ERREUR CRUCIALE
        Log::error("Échec de la création de la facture e-MECeF pour la commande {$order->id}", [
            'error' => $e->getMessage()
        ]);

        // On ne fait pas échouer la vente, mais on la marque comme en attente
        $order->update(['status' => 'pending_emecf_invoice']);

        return redirect()->route('orders.show', $order->id)
                         ->with('warning', 'Vente enregistrée, mais la facture e-MECeF a échoué. Veuillez réessayer depuis le détail de la commande.');
    }
}

// Dans votre modèle Order.php
use Banelsems\LaraSgmefQr\Models\Invoice;

class Order extends Model
{
    // ...

    /**
     * Get the e-MECeF invoice associated with the order.
     */
    public function emecfInvoice()
    {
        return $this->belongsTo(Invoice::class, 'mECeF_uid', 'uid');
    }
}

// app/Providers/RouteServiceProvider.php
public function boot()
{
    // ... autres configurations

    // Protéger les routes du package avec authentification
    Route::middleware(['web', 'auth'])
         ->prefix('sgmef')
         ->group(function () {
             // Les routes du package seront automatiquement protégées
         });
}

// config/lara_sgmef_qr.php
'web_interface' => [
    'enabled' => true,
    'middleware' => ['web', 'auth'], // Ajouter 'auth' pour protéger
    'route_prefix' => 'sgmef',
],

// routes/web.php
Route::middleware(['auth', 'verified'])->group(function () {
    Route::get('/sgmef', function () {
        return redirect()->route('sgmef.dashboard');
    });
});

// config/lara_sgmef_qr.php
'cache' => [
    'enabled' => true,
    'ttl' => 3600, // 1 heure
    'prefix' => 'sgmef_',
],

try {
    $invoice = $invoiceManager->createInvoice($data);
} catch (\Banelsems\LaraSgmefQr\Exceptions\InvoiceException $e) {
    // Erreur métier
    \Log::error('Erreur facture', ['error' => $e->getMessage()]);
} catch (\Banelsems\LaraSgmefQr\Exceptions\SgmefApiException $e) {
    // Erreur API
    \Log::error('Erreur API', ['code' => $e->getCode(), 'message' => $e->getMessage()]);
}

enum InvoiceStatusEnum: string
{
    case PENDING = 'pending';      // En attente de confirmation
    case CONFIRMED = 'confirmed';  // Confirmée avec QR Code et MECeF
    case CANCELLED = 'cancelled';  // Annulée
    case ERROR = 'error';         // Erreur lors du traitement
}

'api' => [
    'url' => env('SGMEF_API_URL', 'https://developper.impots.bj/sygmef-emcf'),
    'token' => env('SGMEF_TOKEN'),
    'timeout' => env('SGMEF_HTTP_TIMEOUT', 30),
    'verify_ssl' => env('SGMEF_VERIFY_SSL', true),
    'retry_attempts' => env('SGMEF_RETRY_ATTEMPTS', 3),
    'retry_delay' => env('SGMEF_RETRY_DELAY', 1000), // millisecondes
],

'company' => [
    'default_ifu' => env('SGMEF_DEFAULT_IFU'),
    'name' => env('SGMEF_COMPANY_NAME'),
    'address' => env('SGMEF_COMPANY_ADDRESS'),
],

'default_operator' => [
    'name' => env('SGMEF_DEFAULT_OPERATOR_NAME', 'Opérateur Principal'),
    'id' => env('SGMEF_DEFAULT_OPERATOR_ID', '1'),
],

'web_interface' => [
    'enabled' => env('SGMEF_WEB_INTERFACE_ENABLED', true),
    'middleware' => ['web'], // Ajouter 'auth' pour protéger
    'route_prefix' => env('SGMEF_ROUTE_PREFIX', 'sgmef'),
    'items_per_page' => env('SGMEF_ITEMS_PER_PAGE', 15),
],

'cache' => [
    'enabled' => env('SGMEF_CACHE_ENABLED', true),
    'ttl' => env('SGMEF_CACHE_TTL', 3600), // 1 heure
    'prefix' => 'sgmef_',
    'store' => env('SGMEF_CACHE_STORE', 'default'),
],

'logging' => [
    'enabled' => env('SGMEF_LOGGING_ENABLED', true),
    'level' => env('SGMEF_LOG_LEVEL', 'info'),
    'channel' => env('SGMEF_LOG_CHANNEL', 'daily'),
    'log_requests' => env('SGMEF_LOG_REQUESTS', true),
    'log_responses' => env('SGMEF_LOG_RESPONSES', true),
],

interface InvoiceManagerInterface
{
    /**
     * Créer une nouvelle facture
     */
    public function createInvoice(InvoiceRequestDto $data): Invoice;
    
    /**
     * Confirmer une facture (génère QR Code et MECeF)
     */
    public function confirmInvoice(string $uid): Invoice;
    
    /**
     * Annuler une facture
     */
    public function cancelInvoice(string $uid): Invoice;
    
    /**
     * Récupérer le statut d'une facture
     */
    public function getInvoiceStatus(string $uid): InvoiceStatusEnum;
    
    /**
     * Synchroniser une facture avec l'API
     */
    public function syncInvoice(string $uid): Invoice;
    
    /**
     * Récupérer une facture par UID
     */
    public function getInvoice(string $uid): ?Invoice;
    
    /**
     * Lister les factures avec pagination
     */
    public function listInvoices(array $filters = [], int $perPage = 15): LengthAwarePaginator;
}

interface SgmefApiClientInterface
{
    /**
     * Créer une facture via l'API
     */
    public function createInvoice(InvoiceRequestDto $data): InvoiceResponseDto;
    
    /**
     * Confirmer une facture via l'API
     */
    public function confirmInvoice(string $uid): InvoiceResponseDto;
    
    /**
     * Annuler une facture via l'API
     */
    public function cancelInvoice(string $uid): InvoiceResponseDto;
    
    /**
     * Récupérer le statut d'une facture
     */
    public function getInvoiceStatus(string $uid): InvoiceResponseDto;
    
    /**
     * Tester la connexion à l'API
     */
    public function testConnection(): bool;
}

class InvoiceRequestDto
{
    public string $ifu;              // IFU entreprise (13 chiffres)
    public string $type;             // Type: FV, FA, EV, EA
    public ?string $aib;             // AIB: A (1%) ou B (5%)
    public ?string $reference;       // Référence interne
    public ClientDto $client;        // Informations client
    public OperatorDto $operator;    // Informations opérateur
    public array $items;             // Articles (InvoiceItemDto[])
    public array $payment;           // Paiements (PaymentDto[])
    
    public static function fromArray(array $data): self;
    public function toArray(): array;
    public function validate(): array; // Retourne les erreurs
}

class ClientDto
{
    public string $name;             // Nom du client (requis)
    public ?string $ifu;             // IFU client (13 chiffres, optionnel)
    public ?string $contact;         // Téléphone/Email
    public ?string $address;         // Adresse complète
}

class OperatorDto
{
    public string $id;               // ID unique de l'opérateur
    public string $name;             // Nom de l'opérateur
}

class InvoiceItemDto
{
    public string $name;             // Nom de l'article
    public float $price;             // Prix unitaire HT
    public int $quantity;            // Quantité
    public string $taxGroup;         // Groupe de taxe: A, B, C, D, E, F
    public ?string $code;            // Code article (SKU)
    public ?string $description;     // Description détaillée
}

class PaymentDto
{
    public string $name;             // Type: ESPECES, CARTEBANCAIRE, CHEQUE, VIREMENT
    public float $amount;            // Montant du paiement
}

class InvoiceResponseDto
{
    public string $uid;              // UID de la facture
    public string $status;           // Statut de la facture
    public float $totalAmount;       // Montant total TTC (mappé depuis 'total')
    public float $totalTaxAmount;    // Total des taxes (mappé depuis 'ts')
    public float $totalAibAmount;    // Total AIB (mappé depuis 'aib')
    public array $items;             // Articles avec calculs
    public ?string $qrCodeData;      // Données QR Code (si confirmée)
    public ?string $mecfCode;        // Code MECeF (si confirmée)
    public ?SecurityElementsDto $security; // Éléments de sécurité
}

class InvoiceCreated
{
    public Invoice $invoice;
    public InvoiceRequestDto $requestData;
    
    // Déclenché après la création réussie d'une facture
}

class InvoiceConfirmed
{
    public Invoice $invoice;
    public string $qrCodeData;
    public string $mecfCode;
    
    // Déclenché après la confirmation d'une facture
}

class InvoiceCancelled
{
    public Invoice $invoice;
    public string $reason;
    
    // Déclenché après l'annulation d'une facture
}

class InvoiceCreationFailed
{
    public Exception $exception;
    public InvoiceRequestDto $requestData;
    public ?string $errorCode;
    
    // Déclenché en cas d'échec de création
}

// Dans EventServiceProvider.php
protected $listen = [
    InvoiceCreated::class => [
        SendInvoiceNotification::class,
        UpdateOrderStatus::class,
    ],
    InvoiceConfirmed::class => [
        SendConfirmationEmail::class,
        GeneratePdfInvoice::class,
    ],
];

// Récupérer l'opérateur par défaut
$operator = LaraSgmefQRServiceProvider::getDefaultOperator();

// Accéder aux services via l'IoC
$apiClient = app('sgmef.api');
$invoiceManager = app('sgmef.invoices');
$defaultOperator = app('sgmef.default_operator');

// Valider un IFU béninois
if (preg_match('/^\d{13}$/', $ifu)) {
    // IFU valide
}

$taxGroups = [
    'A' => 'Exonéré (0%)',
    'B' => 'TVA 18%',
    'C' => 'TVA 18% + AIB 1%',
    'D' => 'TVA 18% + AIB 5%',
    'E' => 'Régime spécial',
    'F' => 'Exportation (0%)',
];

// Exception générale du package
SgmefException extends Exception

// Exception liée aux factures
InvoiceException extends SgmefException
- InvoiceNotFoundException
- InvoiceAlreadyConfirmedException
- InvoiceValidationException

// Exception liée à l'API
SgmefApiException extends SgmefException
- ApiConnectionException
- ApiAuthenticationException
- ApiRateLimitException
- ApiServerException

const ERROR_CODES = [
    'INVALID_IFU' => 'IFU invalide ou non reconnu',
    'INVALID_TOKEN' => 'Token d\'authentification invalide',
    'INVOICE_NOT_FOUND' => 'Facture introuvable',
    'ALREADY_CONFIRMED' => 'Facture déjà confirmée',
    'NETWORK_ERROR' => 'Erreur de connexion réseau',
    'SERVER_ERROR' => 'Erreur serveur API',
];
bash
# Publier la configuration
php artisan vendor:publish --tag=lara-sgmef-qr-config

# Publier les migrations
php artisan vendor:publish --tag=lara-sgmef-qr-migrations

# Publier les vues (optionnel)
php artisan vendor:publish --tag=lara-sgmef-qr-views
bash
php artisan migrate
bash
    php artisan vendor:publish --tag=lara-sgmef-qr-config
    
blade
{{-- resources/views/orders/show.blade.php --}}

<h1>Détails de la Commande #{{ $order->id }}</h1>

<p>Client : {{ $order->customer->name }}</p>
<p>Montant : {{ number_format($order->total_amount, 0, ',', ' ') }} XOF</p>

@if ($order->emecfInvoice)
    <div class="alert alert-success">
        <h3>Facture e-MECeF</h3>
        <p><strong>Code MECeF/DGI :</strong> {{ $order->emecfInvoice->mecf_code }}</p>
        <p><strong>Statut :</strong> {{ $order->emecfInvoice->status }}</p>
        
        {{-- Vous pouvez même afficher le QR Code --}}
        <img src="data:image/png;base64, {{ base64_encode(QRCode::format('png')->size(150)->generate($order->emecfInvoice->qr_code_data)) }}" alt="QR Code">

        {{-- Lien pour télécharger le PDF généré par le package --}}
        <a href="{{ route('sgmef.invoices.download', $order->emecfInvoice->id) }}" class="btn btn-primary" target="_blank">
            Télécharger la Facture PDF
        </a>
    </div>
@elseif($order->status === 'pending_emecf_invoice')
    <div class="alert alert-warning">
        La facture e-MECeF est en attente de génération. Veuillez réessayer plus tard.
    </div>
@endif
bash
# Tests complets
php artisan test

# Tests avec couverture
php artisan test --coverage

# Tests spécifiques
php artisan test --filter=InvoiceManagerTest