andreaballarin/acube-italy-receipts

Acube Italy Receipts Library

Maintainers

Package info

github.com/andreaballarin/acube-italy-receipts

pkg:composer/andreaballarin/acube-italy-receipts

Transparency log

Statistics

Installs: 15

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.4 2026-07-10 15:00 UTC

This package is auto-updated.

Last update: 2026-07-10 15:01:58 UTC


README

SDK PHP 8.3+ per l'integrazione delle API Acube per gli Scontrini Elettronici (Documento Commerciale italiano).

Installazione

composer require andreaballarin/acube-italy-receipts

Requisiti

  • PHP: ^8.3
  • PSR-18 HTTP Client: Guzzle ^7.8 (incluso)
  • Certificati mTLS: Rilasciati da Acube per il tuo cash register

Quick Start

1. Login e ottieni il token JWT

use AndreaBallarin\ACubeItalyReceipts\{AuthenticationService, Environment};

$auth = new AuthenticationService(environment: Environment::Sandbox);
$token = $auth->login(
    email: 'your@email.com',
    password: 'your-password',
);

2. Setup del Client

use AndreaBallarin\ACubeItalyReceipts\Client;

$client = new Client(
    bearerToken: $token,
    environment: Environment::Sandbox,
    mtlsCertPath: '/path/to/cert.pem',
    mtlsKeyPath: '/path/to/key.pem',
    mtlsKeyPassphrase: 'passphrase-if-any', // opzionale
);

3. Registra il Client per l'utilizzo statico

use AndreaBallarin\ACubeItalyReceipts\Resources\Receipt;

Receipt::setClient($client);

4. Crea uno scontrino

use AndreaBallarin\ACubeItalyReceipts\Resources\{ReceiptDraft, ReceiptItem};

$item = new ReceiptItem(
    quantity: '1.00',
    description: 'Espresso',
    unitPrice: '1.20',
    vatRateCode: '10.00',
);

$draft = new ReceiptDraft(
    items: [$item],
    cashPaymentAmount: '1.20',
);

$receipt = Receipt::create($draft);
echo "UUID: " . $receipt->uuid;
echo "Documento: " . $receipt->documentNumber;

5. Recupera e annulla

$fetched = Receipt::get($receipt->uuid);
$voided = $fetched->void('Customer returned');

Onboarding: Merchant → PEM → Cash Register

Prima di poter emettere scontrini serve completare l'onboarding: creare un merchant, creare e attivare un PEM, poi creare il cash register che rilascia il certificato mTLS. Vedi examples/complete-supplier-onboarding.php per il flusso completo.

Importante: Merchant/Pem::create()/Pem::get()/Pem::activate()/CashRegister::create() usano la porta standard (nessun mTLS) — solo gli endpoint /mf1/receipts* (Receipt, ReceiptDetails) richiedono mTLS e vengono chiamati automaticamente sulla porta 444 quando il Client ha mtlsCertPath configurato. Usa quindi Client separati: uno senza mTLS per l'onboarding, uno con mTLS per gli scontrini. Poiché ApiResource::setClient() condivide un unico slot statico tra tutte le resource, richiama setClient() ogni volta che cambi Client.

1. Crea un merchant

use AndreaBallarin\ACubeItalyReceipts\Resources\{Merchant, MerchantDraft};
use AndreaBallarin\ACubeItalyReceipts\ValueObjects\Address;

Merchant::setClient($supplierClient); // Client con il token del Supplier, senza mTLS

$merchant = Merchant::create(new MerchantDraft(
    vatNumber: '12345678901',
    address: new Address(
        streetAddress: 'street name',
        streetNumber: 'xx',
        zipCode: '00000',
        city: 'City',
        province: 'XX',
    ),
    businessName: 'business name',
    email: 'merchant@example.com',
    password: 'MerchantP4$$w0rd',
));

2. Crea e attiva un PEM

use AndreaBallarin\ACubeItalyReceipts\Resources\Pem;

$pem = Pem::create($merchant->uuid); // ancora col client Supplier

Pem::setClient($merchantClient); // Client col token del Merchant, senza mTLS
Pem::activate($pem->serialNumber, $pem->registrationKey);

3. Crea il cash register (rilascia il certificato mTLS)

use AndreaBallarin\ACubeItalyReceipts\Resources\CashRegister;

CashRegister::setClient($merchantClient);

$cashRegister = CashRegister::create($pem->serialNumber, 'Cash register first floor');

// mtlsCertificate e privateKey sono già "unescaped" (newline reali), pronti per il disco
file_put_contents('/var/certs/pems/A2F4-000001/cr-cert.pem', $cashRegister->mtlsCertificate);
file_put_contents('/var/certs/pems/A2F4-000001/cr-key.pem', $cashRegister->privateKey);

4. Recupera il dettaglio fiscale completo di uno scontrino

use AndreaBallarin\ACubeItalyReceipts\Resources\ReceiptDetails;

$details = ReceiptDetails::get($receipt->uuid); // richiede lo stesso Client mTLS di Receipt
echo "Imponibile: {$details->totalTaxableAmount}, IVA: {$details->totalVatAmount}";
foreach ($details->items as $item) {
    echo "{$item->description}: {$item->unitPrice}\n";
}

Login & Autenticazione

L'SDK include AuthenticationService per gestire il login presso Acube:

use AndreaBallarin\ACubeItalyReceipts\AuthenticationService;

$auth = new AuthenticationService(environment: Environment::Sandbox);
try {
    $token = $auth->login(email: 'user@example.com', password: 'secret');
    // Usa il token con il Client
} catch (AcubeAuthenticationException $e) {
    echo "Login failed: invalid credentials";
}

Note:

  • AuthenticationService chiama POST https://common-sandbox.api.acubeapi.com/login (endpoint separato)
  • Non richiede mTLS (diversamente da eReceipts)
  • Ritorna direttamente il JWT Bearer token
  • Il token è necessario per creare il Client che accede agli scontrini

Features

Punto 1: Dependency Injection

Due modalità di utilizzo:

  • Statica (Service Locator): Receipt::setClient($client) + Receipt::create(...)
  • Instance-based (DI-friendly): Passa il client al costruttore se la tua classe lo supporta

Punto 2: DecimalAmount Validation

Tutti gli importi/quantità sono string per preservare la precisione. DecimalAmount::assertValid() fallisce velocemente:

new ReceiptItem(
    quantity: '1.00',      // validato automaticamente
    unitPrice: '10.50',    // validato
);

Punto 3: UUID Validation

UuidValidator valida localmente prima di fare richieste HTTP:

Receipt::get('invalid-uuid'); // InvalidArgumentException locale, non 404 da Acube

Punto 4: PSR-3 Logging

Inietta un logger PSR-3 per registrare:

  • Richieste POST critiche (creazione documenti)
  • Errori API (status ≥400)
  • Errori di trasporto
$client = new Client(
    bearerToken: $token,
    logger: $myLogger, // Psr\Log\LoggerInterface
);

Gestione Errori

use AndreaBallarin\ACubeItalyReceipts\Exceptions\{
    AcubeValidationException,
    AcubeNotFoundException,
    AcubeException,
};

try {
    $receipt = Receipt::create($draft);
} catch (AcubeValidationException $e) {
    foreach ($e->violations() as $field => $msg) {
        echo "$field: $msg";
    }
} catch (AcubeNotFoundException $e) {
    echo "Document not found";
} catch (AcubeException $e) {
    echo "API Error [{$e->problem->status}]: {$e->problem->detail}";
}

Idempotenza (Best-Effort, Client-Side)

$receipt = Receipt::create(
    draft: $draft,
    idempotencyKey: 'unique-key-123',
    idempotencyWindowSeconds: 60,
);
// Se ripeti la stessa chiave entro 60 secondi: AcubeDuplicateRequestException

Nota: Questa guardia protegge solo dentro lo stesso processo. Acube non offre idempotency key server-side, quindi un timeout di rete potrebbe causare duplicati.

Test

composer test

Struttura

src/
  Client.php                    # Transport PSR-18, logging PSR-3
  Environment.php               # Enum Sandbox|Production
  Model.php                     # Base per i dati
  ApiResource.php               # Base per le risorse (setClient/client)
  Internal/
    DecimalAmount.php           # Validazione importi
    UuidValidator.php           # Validazione UUID RFC 4122
    IdempotencyGuard.php        # Guardia client-side idempotenza
  Exceptions/
    AcubeException.php          # Base astratta
    AcubeAuthenticationException.php    # 401
    AcubeValidationException.php        # 422
    ... (e altre per 403, 404, 409, 500, 503)
  ValueObjects/
    ProblemDetails.php          # RFC 7807
    Address.php                 # Indirizzo (merchant/PEM)
  Resources/
    Merchant.php                # Merchant registrato (MerchantOutput)
    MerchantDraft.php           # Payload di creazione (MerchantInput)
    Pem.php                     # PEM: create/get/activate
    CashRegister.php            # Cash register: create (rilascia mTLS)
    Receipt.php                 # Documento emesso (ReceiptOutput)
    ReceiptDraft.php            # Payload di creazione (ReceiptInput)
    ReceiptItem.php             # Riga di dettaglio
    ReceiptDetails.php          # Dettaglio fiscale completo (righe + totali)
    Enums/
      ReceiptType.php
      ReceiptStatus.php
      ReceiptItemType.php

Licenza

MIT

Autore

Andrea Ballarin ballarinandrea@icloud.com