storno/laravel-storno
Composer 安装命令:
composer require storno/laravel-storno
包简介
Laravel package for Storno invoicing API — e-Factura, clients, invoices, webhooks
README 文档
README
Laravel package for Storno — self-hosted invoicing with Romanian e-Factura (ANAF) integration.
Requirements
- PHP 8.1+
- Laravel 10, 11, or 12
Installation
composer require storno/laravel-storno
Publish the config file:
php artisan vendor:publish --tag=storno-config
Add to your .env:
STORNO_API_URL=https://invoices.yourapp.com STORNO_API_KEY=your-api-key STORNO_COMPANY_ID=your-company-uuid
Quick Start
Create a client and invoice
use Storno\Laravel\Facades\Storno; use Storno\Laravel\DTOs\Client; use Storno\Laravel\DTOs\Invoice; use Storno\Laravel\DTOs\InvoiceLine; // 1. Create or find a client $result = Storno::createClient(new Client( name: 'Acme SRL', type: 'company', email: 'billing@acme.ro', country: 'RO', city: 'București', cui: '12345678', )); $clientId = $result['client']['id']; $isNew = ! $result['existing']; // 2. Create an invoice $invoice = Storno::createInvoice(new Invoice( clientId: $clientId, currency: 'RON', paymentMethod: 'bank_transfer', orderNumber: 'ORD-2026-001', lines: [ new InvoiceLine( description: 'Widget Pro', quantity: 2, unitPrice: 100.00, vatRate: 21, ), new InvoiceLine( description: 'Shipping', quantity: 1, unitPrice: 15.00, vatRate: 21, ), ], )); $invoiceId = $invoice['invoice']['id']; // 3. Issue the invoice (changes status from draft to issued) if (config('storno.auto_issue')) { Storno::issueInvoice($invoiceId); } // 4. Download and store the PDF $pdf = Storno::downloadPdf($invoiceId); Storage::put("invoices/{$invoiceId}.pdf", $pdf);
Submit to e-Factura (ANAF)
// After issuing, optionally submit to Romanian e-Factura system Storno::submitInvoice($invoiceId);
Look up a company by CUI (Romanian tax ID)
$company = Storno::anafLookup('12345678'); // Returns name, address, VAT status, etc.
Configuration Reference
See config/storno.php for all options. Full docs at docs.storno.ro.
| Key | Default | Description |
|---|---|---|
api_url |
— | Your Storno instance URL |
api_key |
— | API key from Storno dashboard |
company_id |
— | Company UUID from Storno |
auto_issue |
true |
Automatically issue invoices after creation |
auto_apply_vat_rules |
true |
Apply VAT rules automatically |
document_series_id |
— | Default document series UUID |
invoice_language |
— | Invoice language (ro, en, etc.) |
payment_term_days |
30 |
Default payment term in days |
default_vat_rate |
21 |
Default VAT rate percentage |
shipping_vat_rate |
21 |
VAT rate for shipping lines |
default_unit |
buc |
Default unit of measure |
shipping_label |
Shipping |
Label for shipping line items |
discount_label |
Discount |
Label for discount line items |
invoice_notes |
— | Default notes on invoices |
internal_note_format |
#{order_number} |
Template for internal notes |
webhook_secret |
— | Secret for webhook signature verification |
webhook_path |
storno/webhook |
URL path for the webhook endpoint |
webhook_middleware |
['api'] |
Middleware for the webhook route |
timeout |
30 |
HTTP request timeout (seconds) |
retry.times |
3 |
Number of retry attempts |
retry.sleep |
1000 |
Delay between retries (ms) |
API Reference
All methods are available via the Storno:: facade or by injecting StornoClient.
Companies
$companies = Storno::listCompanies();
Clients
// Create or find a client (idempotent by email/CUI) $result = Storno::createClient(new Client( name: 'Acme SRL', type: 'company', // 'company' or 'individual' email: 'billing@acme.ro', address: 'Str. Victoriei 1', city: 'București', county: 'Ilfov', country: 'RO', postalCode: '012345', phone: '+40700000000', cui: '12345678', vatCode: 'RO12345678', isVatPayer: true, registrationNumber: 'J40/1234/2020', bankName: 'BCR', bankAccount: 'RO49AAAA1B31007593840000', contactPerson: 'Ion Popescu', notes: 'VIP', )); // Returns: ['client' => [...], 'existing' => bool] // Get client by ID $client = Storno::getClient('client-uuid'); // ANAF lookup by CUI $company = Storno::anafLookup('12345678');
Invoices
// Create invoice $invoice = Storno::createInvoice(new Invoice( clientId: 'client-uuid', lines: [...], currency: 'RON', // 'RON', 'EUR', 'USD', etc. paymentMethod: 'bank_transfer', // 'bank_transfer'|'cash'|'card'|'cheque'|'other' issueDate: '2026-04-04', dueDate: '2026-05-04', orderNumber: 'ORD-001', internalNote: '#ORD-001', idempotencyKey: 'unique-key-for-order', autoApplyVatRules: true, documentSeriesId: 'series-uuid', language: 'ro', notes: 'Thank you for your business.', )); // Get invoice $invoice = Storno::getInvoice('invoice-uuid'); // Issue invoice (draft -> issued) Storno::issueInvoice('invoice-uuid'); // Submit to e-Factura ANAF Storno::submitInvoice('invoice-uuid'); // Download PDF (returns raw binary) $pdfContent = Storno::downloadPdf('invoice-uuid'); file_put_contents('/path/to/invoice.pdf', $pdfContent);
Document Series
$series = Storno::listDocumentSeries(); // Returns array of series with id, name, prefix, nextNumber
VAT Rates
$rates = Storno::listVatRates(); // Returns array of available VAT rates for this company
Webhooks
// Register a webhook $webhook = Storno::createWebhook( url: 'https://yourapp.com/storno/webhook', events: ['invoice.issued', 'invoice.validated', 'invoice.rejected', 'invoice.paid'], description: 'My app webhook', ); // Returns: ['uuid' => '...', 'secret' => '...'] // Save the 'secret' as STORNO_WEBHOOK_SECRET in your .env // Delete a webhook Storno::deleteWebhook('webhook-uuid');
Webhooks
Setup
Register a webhook using the Artisan command (recommended):
php artisan storno:webhook:register
# or with explicit URL:
php artisan storno:webhook:register --url=https://yourapp.com/storno/webhook
The command automatically saves the secret to your .env file.
The webhook endpoint is registered automatically at POST /storno/webhook (configurable via STORNO_WEBHOOK_PATH).
Events
Listen for Storno events in your EventServiceProvider or using #[AsListener]:
use Storno\Laravel\Events\InvoiceIssued; use Storno\Laravel\Events\InvoiceValidated; use Storno\Laravel\Events\InvoiceRejected; use Storno\Laravel\Events\InvoicePaid; use Storno\Laravel\Events\WebhookReceived; // fires for every webhook class AppServiceProvider extends ServiceProvider { public function boot(): void { Event::listen(InvoiceIssued::class, function (InvoiceIssued $event) { $invoiceId = $event->payload->data['invoiceId']; // Send confirmation email, update order status, etc. }); Event::listen(InvoicePaid::class, function (InvoicePaid $event) { // Mark order as paid }); Event::listen(InvoiceRejected::class, function (InvoiceRejected $event) { // Handle ANAF rejection — log, notify admin, etc. }); } }
The WebhookPayload object has:
$event->payload->event // e.g. 'invoice.issued' $event->payload->id // event UUID $event->payload->data // array with invoice data $event->payload->occurredAt // ISO 8601 timestamp $event->payload->raw // full raw payload array
Excluding the webhook route from CSRF
Add the webhook path to your VerifyCsrfToken middleware exceptions:
// app/Http/Middleware/VerifyCsrfToken.php protected $except = [ 'storno/webhook', ];
Artisan Commands
Test connection
php artisan storno:test
Verifies the API connection and lists companies on the instance.
Register webhook
php artisan storno:webhook:register
php artisan storno:webhook:register --url=https://yourapp.com/storno/webhook
php artisan storno:webhook:register --url=... --events=invoice.issued --events=invoice.paid
php artisan storno:webhook:register --url=... --description="Production webhook"
List document series
php artisan storno:series
Shows all available document series with their ID, prefix, and next number.
Error Handling
use Storno\Laravel\Exceptions\StornoApiException; use Storno\Laravel\Exceptions\StornoConnectionException; use Storno\Laravel\Exceptions\InvalidSignatureException; try { $invoice = Storno::createInvoice($dto); } catch (StornoApiException $e) { // HTTP 4xx/5xx from the Storno API $statusCode = $e->getStatusCode(); // int $body = $e->getResponseBody(); // array Log::error('Storno API error', ['status' => $statusCode, 'body' => $body]); } catch (StornoConnectionException $e) { // Network error, timeout, etc. Log::error('Storno connection error', ['message' => $e->getMessage()]); }
Dependency Injection
You can inject StornoClient directly instead of using the facade:
use Storno\Laravel\StornoClient; class InvoiceService { public function __construct(private StornoClient $storno) {} public function createForOrder(Order $order): array { return $this->storno->createInvoice(/* ... */); } }
Links
License
MIT — see LICENSE.
storno/laravel-storno 适用场景与选型建议
storno/laravel-storno 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 0 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 04 月 04 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「laravel」 「invoicing」 「Romania」 「anaf」 「storno」 「e-factura」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 storno/laravel-storno 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 storno/laravel-storno 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 storno/laravel-storno 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Space invoices PHP sdk
WeFact API client library for PHP.
Accounting module for atmosphere and laravel
Alfabank REST API integration
Official PHP SDK for the Vorgio API. Issue invoices, send them to clients, and verify webhooks.
Paymill integration with Magento 2
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 42
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-04-04