infogrambeg/efiskalizacija-php-sdk

PHP SDK za eFiskalizacija.cloud - fiskalizacija računa u Srbiji (VSDC API)

Installs: 4

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/infogrambeg/efiskalizacija-php-sdk

v1.0.2 2026-02-13 21:34 UTC

This package is auto-updated.

Last update: 2026-02-13 22:29:00 UTC


README

PHP SDK za eFiskalizacija.cloud - fiskalizacija računa u Srbiji (VSDC API).

Zahtevi

  • PHP >= 8.1
  • ext-curl
  • ext-json

Instalacija

composer require infogrambeg/efiskalizacija-php-sdk

Brzi početak

use Efiskalizacija\EfiskalizacijaClient;
use Efiskalizacija\DTO\Invoice;
use Efiskalizacija\DTO\InvoiceItem;
use Efiskalizacija\DTO\Customer;
use Efiskalizacija\Enum\PaymentType;

// Kreiranje klijenta
$client = EfiskalizacijaClient::create($apiKey, $apiSecret);

// Kreiranje računa
$invoice = Invoice::create()
    ->setInvoiceNumber('SHOP-2026-001')
    ->setPaymentType(PaymentType::Kartica)
    ->setCashier('Web Shop')
    ->setCustomer(Customer::pravnoLice('123456789', 'Firma DOO'))
    ->addItem(new InvoiceItem(
        naziv: 'Laptop HP ProBook',
        kolicina: 1,
        jedinicnaCena: 85000.00,
        pdvStopa: 20,
        sifra: 'HP-PB-450',
    ));

// Fiskalizacija
$result = $client->fiskalizacija()->fiskalizuj($invoice);

echo $result->pfrBroj;   // "AB12CD34-Ef5Gh6i7-101"
echo $result->qrCode;    // URL za QR verifikaciju
echo $result->racunId;   // ID u sistemu

API Metode

// Fiskalizacija računa
$result = $client->fiskalizacija()->fiskalizuj($invoice);

// Status tenanta
$status = $client->status()->fetch();

// Lista računa
$list = $client->invoices()->list(limit: 20, offset: 0);

// PDF preuzimanje
$pdf = $client->pdf()->download($pfrBroj);
$client->pdf()->downloadToFile($pfrBroj, '/path/racun.pdf');

// Slanje na email
$client->email()->send($pfrBroj, 'kupac@example.com');

// Test (samo sandbox)
$test = $client->test()->run();

Načini plaćanja

use Efiskalizacija\Enum\PaymentType;

PaymentType::Gotovina   // Gotovina
PaymentType::Kartica    // Platna kartica
PaymentType::Virman     // Virmanski prenos
PaymentType::Vaucer     // Vaučer
PaymentType::Instant    // Instant plaćanje (IPS)
PaymentType::Drugo      // Drugo bezgotovinsko

Split payment (podeljeno plaćanje)

use Efiskalizacija\DTO\Payment;

$invoice->setSplitPayments([
    new Payment(PaymentType::Gotovina, 5000.00),
    new Payment(PaymentType::Kartica, 7800.00),
]);

Kupac

use Efiskalizacija\DTO\Customer;

// Pravno lice (PIB - 9 cifara)
Customer::pravnoLice('123456789', 'Firma DOO', 'Adresa 1', 'Beograd');

// Fizičko lice (JMBG - 13 cifara)
Customer::fizickoLice('1234567890123', 'Petar Petrović');

// Javni sektor (JBKJS)
Customer::javniSektor('12345', 'Ministarstvo');

// Anonimni kupac
Customer::anonimni('email@example.com');

PDV kategorije (za 0% PDV)

use Efiskalizacija\Enum\TaxCategory;

new InvoiceItem(
    naziv: 'Oslobođena usluga',
    kolicina: 1,
    jedinicnaCena: 5000.00,
    pdvStopa: 0,
    pdvKategorija: TaxCategory::Oslobodjen,   // Oslobođen PDV-a
);

new InvoiceItem(
    naziv: 'Van sistema PDV',
    kolicina: 1,
    jedinicnaCena: 3000.00,
    pdvStopa: 0,
    pdvKategorija: TaxCategory::NijeUPdv,     // Nije u sistemu PDV-a
);

Popusti

// Fiksni popust (iznos u RSD)
new InvoiceItem(
    naziv: 'Laptop',
    kolicina: 1,
    jedinicnaCena: 85000.00,
    pdvStopa: 20,
    popust: 5000.00,
);

// Procentualni popust (0-100%)
new InvoiceItem(
    naziv: 'Miš',
    kolicina: 2,
    jedinicnaCena: 4500.00,
    pdvStopa: 20,
    rabatProcenat: 10.0,
);

Avansni računi

use Efiskalizacija\Enum\InvoiceType;
use Efiskalizacija\Enum\TransactionType;

// 1. Avans prodaja
$avans = Invoice::create()
    ->setInvoiceType(InvoiceType::Avans)
    ->setPaymentType(PaymentType::Kartica)
    ->setCustomer(Customer::pravnoLice('123456789'))
    ->addItem(new InvoiceItem(naziv: 'Avans', kolicina: 1, jedinicnaCena: 50000, pdvStopa: 20));

// 2. Avans refundacija (referenca na poslednji avans)
$refund = Invoice::create()
    ->setInvoiceType(InvoiceType::Avans)
    ->setTransactionType(TransactionType::Refund)
    ->setReferentDocument($avansResult->pfrBroj)
    ->setPaymentType(PaymentType::Kartica)
    ->setCustomer(Customer::pravnoLice('123456789'))
    ->addItem(new InvoiceItem(naziv: 'Refundacija avansa', kolicina: 1, jedinicnaCena: 50000, pdvStopa: 20));

// 3. Konačni račun (referenca na avans refundaciju)
$final = Invoice::create()
    ->setReferentDocument($refundResult->pfrBroj)
    ->setPaymentType(PaymentType::Kartica)
    ->setCustomer(Customer::pravnoLice('123456789'))
    ->addItem(new InvoiceItem(naziv: 'Laptop Dell XPS', kolicina: 1, jedinicnaCena: 250000, pdvStopa: 20));

Idempotency

$invoice->setIdempotencyKey('wc:a1b2c3d4:1234');

Sprečava duplu fiskalizaciju istog računa. Preporučeni format: {sistem}:{site_hash}:{order_id}.

Error handling

use Efiskalizacija\Exception\AuthenticationException;
use Efiskalizacija\Exception\ValidationException;
use Efiskalizacija\Exception\RateLimitException;
use Efiskalizacija\Exception\ServerException;
use Efiskalizacija\Exception\NetworkException;

try {
    $result = $client->fiskalizacija()->fiskalizuj($invoice);
} catch (AuthenticationException $e) {
    // 401 - Neispravan API key ili HMAC potpis
} catch (ValidationException $e) {
    // 400/422 - Neispravni podaci
    $errors = $e->getErrors();
} catch (RateLimitException $e) {
    // 429 - Previše zahteva
    $retryAfter = $e->getRetryAfter(); // sekunde
} catch (ServerException $e) {
    // 500/503 - Greška na serveru (retry automatski)
} catch (NetworkException $e) {
    // Timeout, DNS (retry automatski)
}

Retry logika

SDK automatski ponavlja zahteve za retryable greške:

Greška Retry Strategija
429 (Rate Limit) Da Exponential backoff
502 (Bad Gateway) Da Exponential backoff
503 (Unavailable) Da Exponential backoff
504 (Timeout) Da Exponential backoff
Network error Da Exponential backoff
400/422 (Validacija) Ne Permanentan fail
401/403 (Auth) Ne Permanentan fail

Default: 3 retry-a, delay 1s/2s/4s. Konfigurisano u Config.

Webhook

use Efiskalizacija\Webhook\WebhookPayload;

// U vašem webhook handler-u
$payload = WebhookPayload::fromJson(file_get_contents('php://input'));

if ($payload->isFiscalized()) {
    // Račun uspešno fiskalizovan
    $pfr = $payload->pfrBroj;
}

if ($payload->isFailed()) {
    // Fiskalizacija neuspešna
}

Custom HTTP klijent

SDK koristi cURL po defaultu. Možete ubaciti svoj HTTP klijent (npr. za WordPress wp_remote_request):

use Efiskalizacija\Http\HttpClientInterface;
use Efiskalizacija\Http\Response;

class WpHttpClient implements HttpClientInterface
{
    public function request(string $method, string $url, array $headers = [], string $body = ''): Response
    {
        $response = wp_remote_request($url, [
            'method' => $method,
            'headers' => $headers,
            'body' => $body,
            'timeout' => 30,
        ]);

        return new Response(
            wp_remote_retrieve_response_code($response),
            wp_remote_retrieve_body($response),
            wp_remote_retrieve_headers($response)->getAll(),
        );
    }
}

$client = new EfiskalizacijaClient($config, new WpHttpClient());

Konfiguracija

Okruženja

Okruženje URL Namena
Production https://efiskalizacija.cloud Pravi fiskalni računi
Sandbox https://staging.efiskalizacija.cloud Testiranje integracije
// Sandbox (testiranje)
$client = EfiskalizacijaClient::sandbox($apiKey, $apiSecret);

// Production (podrazumevano)
$client = EfiskalizacijaClient::create($apiKey, $apiSecret);

Preporučena konfiguracija (.env)

Nikad ne čuvajte API kredencijale u kodu. Koristite environment varijable:

EFISK_API_KEY=efisk_1_abc123...
EFISK_API_SECRET=your-64-char-secret
EFISK_SANDBOX=true
$apiKey = $_ENV['EFISK_API_KEY'] ?? getenv('EFISK_API_KEY');
$apiSecret = $_ENV['EFISK_API_SECRET'] ?? getenv('EFISK_API_SECRET');
$sandbox = filter_var($_ENV['EFISK_SANDBOX'] ?? getenv('EFISK_SANDBOX'), FILTER_VALIDATE_BOOLEAN);

$client = $sandbox
    ? EfiskalizacijaClient::sandbox($apiKey, $apiSecret)
    : EfiskalizacijaClient::create($apiKey, $apiSecret);

Napredna konfiguracija

use Efiskalizacija\Config;

$config = new Config(
    apiKey: $apiKey,
    apiSecret: $apiSecret,
    baseUrl: 'https://efiskalizacija.cloud',  // default
    timeout: 30,              // HTTP timeout (sekunde)
    connectTimeout: 10,       // Connection timeout (sekunde)
    maxRetries: 3,            // Broj retry pokušaja
    retryBaseDelayMs: 1000,   // Početni delay (ms)
    retryMultiplier: 2,       // Multiplier za exponential backoff
);

$client = new EfiskalizacijaClient($config);

Testiranje

composer test

Licenca

MIT