PHPackages                             hypertractor/laravel-eet - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. hypertractor/laravel-eet

ActiveLibrary

hypertractor/laravel-eet
========================

Laravel package for Czech EET 2.0 electronic sales registration — SOAP signing, PKP/BKP generation, and certificate management

1.0.3(1mo ago)25MITPHPPHP ^8.2

Since Jul 13Pushed 1mo agoCompare

[ Source](https://github.com/hypertractor/laravel-eet)[ Packagist](https://packagist.org/packages/hypertractor/laravel-eet)[ RSS](/packages/hypertractor-laravel-eet/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (10)Versions (5)Used By (0)

Laravel EET
===========

[](#laravel-eet)

Laravel package for Czech Electronic Sales Registration (EET 2.0) — SOAP signing, PKP/BKP generation, certificate management, and receipt submission to the Financni sprava endpoint.

Requirements
------------

[](#requirements)

- PHP 8.2+
- Laravel 12+
- PHP `openssl` extension (for certificate handling and signing)
- PHP `dom` extension (for XML building and signing)

Installation
------------

[](#installation)

```
composer require hypertractor/laravel-eet
```

Publish the config and bundleed playground certificates:

```
php artisan vendor:publish --tag=eet-config
php artisan vendor:publish --tag=eet-certs
```

Run the migrations to add EET fields to your `receipts` table and create the `eet_submissions` audit table:

```
php artisan vendor:publish --tag=eet-migrations
php artisan migrate
```

Configuration
-------------

[](#configuration)

The `.env` file:

```
EET_TEST_MODE=true
EET_UNIT_ID=1
EET_TERMINAL_ID=1
EET_CERTIFICATE_PATH=storage/eet/certs/CA_EET-Playground-CZ00000019.p12
EET_CERTIFICATE_PASSWORD=aaaa1111
```

For production, swap to your real certificate:

```
EET_TEST_MODE=false
EET_CERTIFICATE_PATH=/path/to/your-production.p12
EET_CERTIFICATE_PASSWORD=your-password
```

Full config reference (`config/eet.php`):

KeyEnv VariableDefault`endpoint_playground``EET_ENDPOINT_PLAYGROUND``https://pg.trzbyeet.gov.cz/eet/services/EETServiceSOAP/v4``endpoint_production``EET_ENDPOINT_PRODUCTION``https://trzbyeet.gov.cz/eet/services/EETServiceSOAP/v4``test_mode``EET_TEST_MODE``true``unit_id``EET_UNIT_ID``1``terminal_id``EET_TERMINAL_ID``1``certificate.path``EET_CERTIFICATE_PATH`bundled playground cert`certificate.password``EET_CERTIFICATE_PASSWORD``aaaa1111``jwt_renewal.enabled``EET_JWT_RENEWAL_ENABLED``false``jwt_renewal.renew_days_before_expiry``EET_RENEW_DAYS_BEFORE``14``timeouts.soap``EET_SOAP_TIMEOUT``30.0``retries.max_attempts``EET_RETRY_MAX_ATTEMPTS``3``validate_xml``EET_VALIDATE_XML``true`Quick Start
-----------

[](#quick-start)

### Using the Facade

[](#using-the-facade)

```
use Pomocnik\Eet\Facades\Eet;
use Pomocnik\Eet\DTOs\EetRequest;

$request = new EetRequest(
    eicPopl: 'CZ1234567890',
    idJednotky: '1',
    idPokl: '1',
    poradCis: '1',
    datTrzby: '2026-07-13T10:00:00+02:00',
    celkTrzba: '100.00',
);

$result = Eet::submit($request);

if ($result->success) {
    echo $result->fikCode; // e.g. "ac51eb11-1f89-4c49-8b2f-986a62bc0ba2-ff"
}
```

### Using the Service directly

[](#using-the-service-directly)

```
use Pomocnik\Eet\Services\EetService;

$eet = app(EetService::class);

$request = $eet->createRequestFromReceipt([
    'eic_popl' => 'CZ1234567890',
    'porad_cis' => '1',
    'celk_trzba' => 100.00,
    'dat_trzby' => now()->format('Y-m-d\TH:i:s'),
]);

$result = $eet->submit($request);
```

EetRequest DTO
--------------

[](#eetrequest-dto)

Immutable value object representing an EET submission.

### Properties

[](#properties)

PropertyTypeRequiredDescription`eicPopl``string`yesEIC of the payer (`CZ` + 9-10 digits)`idJednotky``string`yesEvidence unit ID`idPokl``string`yesCash register / terminal ID`poradCis``string`yesReceipt sequence number`datTrzby``string`yesTransaction date (ISO 8601)`celkTrzba``string`yesTotal amount (2 decimal places)`rezim``int`no0 = bunch mode (default), 1 = online`prvniZaslani``bool`noFirst submission (default `true`)`uuidZpravy``?string`noMessage UUID (auto-generated if null)`overeni``bool`noTest mode flag`urcenoCerpZuct``?string`noAmount intended for withdrawal`cerpZuct``?string`noAmount withdrawn`eicPoverujiciho``?string`noEIC of the authorizing entity`povereniVicePopl``?bool`noAuthorization for multiple payers### Factory method

[](#factory-method)

```
$request = EetRequest::fromReceipt(
    data: $receipt->toArray(),
    unitId: config('eet.unit_id'),
    terminalId: config('eet.terminal_id'),
);
```

Expects array keys: `eic_popl`, `porad_cis`, `celk_trzba`, and optionally `dat_trzby`, `rezim`, `prvni_zaslani`, `uuid_zpravy`, `overeni`.

EetResult DTO
-------------

[](#eetresult-dto)

Immutable value object returned by `EetService::submit()`.

PropertyTypeDescription`success``bool`Whether the submission succeeded`fikCode``?string`Fiscal identification code from EET (on success)`bkpCode``?string`Security code (SHA-256 of PKP)`pkpCode``?string`Signature code (RSA-SHA-256, base64)`testFikCode``?string`Test FIK code (when in test mode)`errorCode``?int`Error code from EET server`errorMessage``?string`Human-readable error message`uuidZpravy``?string`Message UUID`rawResponse``?string`Raw XML responseHasEetFields Trait
------------------

[](#haseetfields-trait)

Add this trait to your `Receipt` model to get EET columns, accessors, scopes, and auto-defaults.

```
use Pomocnik\Eet\Models\Concerns\HasEetFields;

class Receipt extends Model
{
    use HasEetFields;
}
```

### Columns added to `receipts` table

[](#columns-added-to-receipts-table)

ColumnTypeDescription`fik_code``VARCHAR(64)` nullFIK code on success`bkp_code``VARCHAR(64)` nullBKP code`pkp_code``TEXT` nullPKP code (base64 signature)`eet_status``ENUM('pending','sent','failed','cancelled')`Current status`eet_submitted_at``TIMESTAMP` nullWhen submitted successfully`eet_first_send``BOOLEAN`First submission flag`eet_test_mode``BOOLEAN`Was submitted in test mode`eet_uuid``CHAR(36)` nullMessage UUID### Auto-defaults

[](#auto-defaults)

On `creating`, the trait sets:

- `eet_status` = `'pending'`
- `eet_first_send` = `true`
- `eet_test_mode` = current `config('eet.test_mode')`

### Accessors

[](#accessors)

```
$receipt->is_eet_registered; // true when status === 'sent'
$receipt->is_eet_pending;    // true when status === 'pending'
$receipt->is_eet_failed;     // true when status === 'failed'
```

### Query scopes

[](#query-scopes)

```
Receipt::eetPending()->get();
Receipt::eetSent()->get();
Receipt::eetFailed()->get();
Receipt::eetMandatory()->get(); // receipts where paymentType->eet_mandatory = true
```

EetSubmission Model &amp; Audit Trail
-------------------------------------

[](#eetsubmission-model--audit-trail)

Every submission is logged in the `eet_submissions` table with full request/response XML. The `EetSubmission` model provides a `receipt()` relationship.

```
use Pomocnik\Eet\Models\EetSubmission;

$submissions = EetSubmission::where('receipt_id', $receipt->id)
    ->orderByDesc('created_at')
    ->get();

$submissions->first()->request_xml;   // full SOAP request
$submissions->first()->response_xml;  // full SOAP response
$submissions->first()->fik_code;
$submissions->first()->error_code;
```

Events
------

[](#events)

The package dispatches events on submission result. Listen for them in your `EventServiceProvider`:

```
use Pomocnik\Eet\Events\EetSubmissionSucceeded;
use Pomocnik\Eet\Events\EetSubmissionFailed;

protected $listen = [
    EetSubmissionSucceeded::class => [
        UpdateReceiptEetFields::class,
    ],
    EetSubmissionFailed::class => [
        LogEetFailure::class,
    ],
];
```

Both events expose `public readonly EetResult $result`.

Certificate Management
----------------------

[](#certificate-management)

### Checking certificate status

[](#checking-certificate-status)

```
use Pomocnik\Eet\Certificates\CertificateManager;

$cm = app(CertificateManager::class);
$info = $cm->getInfo();

echo $info->subject;          // "CN=CZ00000019, ..."
echo $info->validTo->format('Y-m-d'); // "2027-05-14"
echo $info->daysUntilExpiry(); // 304
echo $info->isExpired();       // false
```

### Bundled playground certificates

[](#bundled-playground-certificates)

The package ships with 3 playground `.p12` files for testing:

- `CA_EET-Playground-CZ00000019.p12` (password: `aaaa1111`)
- `CA_EET-Playground-CZ683555118.p12`
- `CA_EET-Playground-CZ8551015704.p12`

These are automatically published to `storage/eet/certs/` via `vendor:publish --tag=eet-certs`.

### JWT certificate renewal (CAEET API)

[](#jwt-certificate-renewal-caeet-api)

The package supports automated certificate renewal via the CAEET REST API. Certificates are renewed as JWT tokens (RS256, `x5t#S256` header) before expiry.

```
EET_JWT_RENEWAL_ENABLED=true
EET_JWT_API_URL=https://caeet.gov.cz/api
EET_RENEW_DAYS_BEFORE=14
```

XML Validation
--------------

[](#xml-validation)

The package bundles the official EET XSD schema and can validate both request and response XML before/after submission:

```
use Pomocnik\Eet\Xml\XmlValidator;

$validator = app(XmlValidator::class);

$trzbaXml = app(XmlBuilder::class)->buildTrzbaXml($request);
$validator->validateTrzba($trzbaXml); // true or throws XmlValidationException
```

Disable validation in config if needed:

```
EET_VALIDATE_XML=false
```

Exceptions
----------

[](#exceptions)

All exceptions extend `Pomocnik\Eet\Exceptions\EetException` (which extends `RuntimeException`).

ExceptionWhen`CertificateException`Certificate file not found, invalid, or missing private key`SoapException`SOAP transport failure or unparseable server response`XmlValidationException`XML fails XSD schema validation`EetException`XML signing failure or PKP generation failureLow-Level Components
--------------------

[](#low-level-components)

### XmlBuilder

[](#xmlbuilder)

```
$xmlBuilder = app(XmlBuilder::class);

$trzbaXml = $xmlBuilder->buildTrzbaXml($request);                // bare
$unsignedEnvelope = $xmlBuilder->buildSoapEnvelope($request);     //
$signedEnvelope = $xmlBuilder->buildSignedSoapEnvelope($request, $certManager); // WS-Security signed
```

### PkpGenerator &amp; BkpGenerator

[](#pkpgenerator--bkpgenerator)

```
$pkp = app(PkpGenerator::class)->generate($request, $certManager); // base64 RSA-SHA256
$bkp = app(BkpGenerator::class)->generate($pkp);                   // UUID-like hex
```

### XmlSigner

[](#xmlsigner)

Signs a SOAP envelope with WS-Security XML Digital Signature using Exclusive C14N and RSA-SHA256.

EET 2.0 Timeline
----------------

[](#eet-20-timeline)

- **1.7.2026** — Playground available for testing
- **1.1.2027** — Pilot mode (mandatory for some industries)
- **1.2.2027** — Full production launch

Testing
-------

[](#testing)

The package includes 91 tests (PHPUnit 11 + Orchestra Testbench):

```
cd packages/eet-client
php vendor/bin/phpunit
```

To run the live Playground test (requires internet):

```
php vendor/bin/phpunit --filter=EetServiceTest::testSubmitToPlayground
```

License
-------

[](#license)

MIT

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance90

Actively maintained with recent releases

Popularity7

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

4

Last Release

48d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/bcee49d4641a173064bf11757b50e8d727275d5ecccfc7c59122e209e5fc5004?d=identicon)[hypertractor](/maintainers/hypertractor)

###  Code Quality

TestsPHPUnit

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/hypertractor-laravel-eet/health.svg)

```
[![Health](https://phpackages.com/badges/hypertractor-laravel-eet/health.svg)](https://phpackages.com/packages/hypertractor-laravel-eet)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3365.5M359](/packages/psalm-plugin-laravel)[pressbooks/pressbooks

Pressbooks is an open source book publishing tool built on a WordPress multisite platform. Pressbooks outputs books in multiple formats, including PDF, EPUB, web, and a variety of XML flavours, using a theming/templating system, driven by CSS.

45945.2k1](/packages/pressbooks-pressbooks)[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

255.2k](/packages/aedart-athenaeum)[laravel/socialite

Laravel wrapper around OAuth 1 &amp; OAuth 2 libraries.

5.7k118.2M1.0k](/packages/laravel-socialite)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

1.0k2.5M152](/packages/roots-acorn)[laravel/ai

The official AI SDK for Laravel.

1.1k6.4M360](/packages/laravel-ai)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
