feat(08-10-receipt-module): phases 08-10 complete — receipt issuing from orders

Phase 08 — DB Foundation:
- 3 new tables: receipt_configs, receipts, receipt_number_counters
- company_settings extended with BDO, REGON, KRS, logo fields

Phase 09 — Receipt Config:
- CRUD for receipt configurations (Settings > Accounting)
- ReceiptConfigController + ReceiptConfigRepository

Phase 10 — Receipt Issuing:
- ReceiptRepository with atomic numbering (INSERT ON DUPLICATE KEY UPDATE)
- ReceiptController with snapshot pattern (seller/buyer/items as JSON)
- "Wystaw paragon" button in order view
- Documents tab showing both receipts and marketplace documents
- Activity log entry on receipt creation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-15 19:49:06 +01:00
parent 3bccc7a533
commit ed057fc304
31 changed files with 2539 additions and 39 deletions

View File

@@ -10,7 +10,9 @@ use App\Core\Security\Csrf;
use App\Core\View\Template;
use App\Core\Support\Flash;
use App\Core\Support\StringHelper;
use App\Modules\Accounting\ReceiptRepository;
use App\Modules\Auth\AuthService;
use App\Modules\Settings\ReceiptConfigRepository;
use App\Modules\Shipments\ShipmentPackageRepository;
final class OrdersController
@@ -20,7 +22,9 @@ final class OrdersController
private readonly Translator $translator,
private readonly AuthService $auth,
private readonly OrdersRepository $orders,
private readonly ?ShipmentPackageRepository $shipmentPackages = null
private readonly ?ShipmentPackageRepository $shipmentPackages = null,
private readonly ?ReceiptRepository $receiptRepo = null,
private readonly ?ReceiptConfigRepository $receiptConfigRepo = null
) {
}
@@ -162,6 +166,18 @@ final class OrdersController
? $this->shipmentPackages->findByOrderId($orderId)
: [];
$receipts = $this->receiptRepo !== null
? $this->receiptRepo->findByOrderId($orderId)
: [];
$activeReceiptConfigs = [];
if ($this->receiptConfigRepo !== null) {
$activeReceiptConfigs = array_filter(
$this->receiptConfigRepo->listAll(),
static fn(array $c): bool => (int) ($c['is_active'] ?? 0) === 1
);
}
$flashSuccess = (string) Flash::get('order.success', '');
$flashError = (string) Flash::get('order.error', '');
@@ -188,6 +204,8 @@ final class OrdersController
'currentStatusCode' => $statusCode,
'flashSuccess' => $flashSuccess,
'flashError' => $flashError,
'receipts' => $receipts,
'receiptConfigs' => $activeReceiptConfigs,
], 'layouts/app');
return Response::html($html);