Files
orderPRO/src/Modules/Accounting/ReceiptController.php
2026-04-03 22:35:49 +02:00

214 lines
7.8 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Modules\Accounting;
use App\Core\Http\Request;
use App\Core\Http\Response;
use App\Core\I18n\Translator;
use App\Core\Security\Csrf;
use App\Core\Support\Flash;
use App\Core\View\Template;
use App\Modules\Auth\AuthService;
use App\Modules\Automation\AutomationService;
use App\Modules\Orders\OrdersRepository;
use App\Modules\Settings\CompanySettingsRepository;
use App\Modules\Settings\ReceiptConfigRepository;
use Throwable;
final class ReceiptController
{
public function __construct(
private readonly Template $template,
private readonly Translator $translator,
private readonly AuthService $auth,
private readonly ReceiptRepository $receipts,
private readonly ReceiptConfigRepository $receiptConfigs,
private readonly CompanySettingsRepository $companySettings,
private readonly OrdersRepository $orders,
private readonly AutomationService $automation,
private readonly ReceiptService $receiptService
) {
}
public function create(Request $request): Response
{
$orderId = max(0, (int) $request->input('id', 0));
$details = $this->orders->findDetails($orderId);
if ($details === null) {
return Response::html('Not found', 404);
}
$configs = array_filter($this->receiptConfigs->listAll(), static fn(array $c): bool => (int) ($c['is_active'] ?? 0) === 1);
if ($configs === []) {
Flash::set('order.error', $this->translator->get('receipts.create.no_configs'));
return Response::redirect('/orders/' . $orderId);
}
$existingReceipts = $this->receipts->findByOrderId($orderId);
$order = is_array($details['order'] ?? null) ? $details['order'] : [];
$items = is_array($details['items'] ?? null) ? $details['items'] : [];
$totalGross = $this->receiptService->calculateTotalGross($items);
$html = $this->template->render('orders/receipt-create', [
'title' => $this->translator->get('receipts.create.title'),
'activeMenu' => 'orders',
'activeOrders' => 'list',
'user' => $this->auth->user(),
'csrfToken' => Csrf::token(),
'orderId' => $orderId,
'order' => $order,
'items' => $items,
'configs' => array_values($configs),
'seller' => $this->companySettings->getSettings(),
'totalGross' => $totalGross,
'existingReceipts' => $existingReceipts,
], 'layouts/app');
return Response::html($html);
}
public function store(Request $request): Response
{
$orderId = max(0, (int) $request->input('id', 0));
if (!Csrf::validate((string) $request->input('_token', ''))) {
Flash::set('order.error', 'Nieprawidlowy token CSRF');
return Response::redirect('/orders/' . $orderId);
}
$configId = (int) $request->input('config_id', '0');
if ($configId <= 0) {
Flash::set('order.error', $this->translator->get('receipts.create.no_config_selected'));
return Response::redirect('/orders/' . $orderId . '/receipt/create');
}
$user = $this->auth->user();
try {
$result = $this->receiptService->issue([
'order_id' => $orderId,
'config_id' => $configId,
'issue_date_override' => (string) $request->input('issue_date', ''),
'created_by' => is_array($user) ? ($user['id'] ?? null) : null,
]);
$userName = is_array($user) ? trim((string) ($user['name'] ?? $user['email'] ?? '')) : '';
$this->orders->recordActivity(
$orderId,
'receipt_issued',
'Wystawiono paragon: ' . $result['receipt_number'],
['receipt_number' => $result['receipt_number'], 'config_id' => $configId, 'total_gross' => $result['total_gross']],
'user',
$userName !== '' ? $userName : null
);
Flash::set('order.success', 'Paragon wystawiony: ' . $result['receipt_number']);
try {
$this->automation->trigger('receipt.created', $orderId);
} catch (Throwable) {
}
} catch (ReceiptIssueException $e) {
Flash::set('order.error', $e->getMessage());
} catch (Throwable) {
Flash::set('order.error', 'Blad wystawiania paragonu');
}
return Response::redirect('/orders/' . $orderId);
}
public function show(Request $request): Response
{
$orderId = max(0, (int) $request->input('id', 0));
$receiptId = max(0, (int) $request->input('receiptId', 0));
$receipt = $this->receipts->findById($receiptId);
if ($receipt === null || (int) ($receipt['order_id'] ?? 0) !== $orderId) {
return Response::html('Not found', 404);
}
$data = $this->buildReceiptViewData($receipt, $orderId);
$html = $this->template->render('receipts/show', $data, 'layouts/app');
return Response::html($html);
}
public function printView(Request $request): Response
{
$orderId = max(0, (int) $request->input('id', 0));
$receiptId = max(0, (int) $request->input('receiptId', 0));
$receipt = $this->receipts->findById($receiptId);
if ($receipt === null || (int) ($receipt['order_id'] ?? 0) !== $orderId) {
return Response::html('Not found', 404);
}
$data = $this->buildReceiptViewData($receipt, $orderId);
$html = $this->template->render('receipts/print', $data);
return Response::html($html);
}
public function pdf(Request $request): Response
{
$orderId = max(0, (int) $request->input('id', 0));
$receiptId = max(0, (int) $request->input('receiptId', 0));
$receipt = $this->receipts->findById($receiptId);
if ($receipt === null || (int) ($receipt['order_id'] ?? 0) !== $orderId) {
return Response::html('Not found', 404);
}
$data = $this->buildReceiptViewData($receipt, $orderId);
$html = $this->template->render('receipts/print', $data);
$dompdf = new \Dompdf\Dompdf();
$dompdf->loadHtml($html);
$dompdf->setPaper('A4');
$dompdf->render();
$filename = str_replace(['/', '\\'], '_', (string) ($receipt['receipt_number'] ?? 'receipt')) . '.pdf';
return new Response($dompdf->output() ?: '', 200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'attachment; filename="' . $filename . '"',
]);
}
/**
* @param array<string, mixed> $receipt
* @return array<string, mixed>
*/
private function buildReceiptViewData(array $receipt, int $orderId): array
{
$seller = json_decode((string) ($receipt['seller_data_json'] ?? '{}'), true);
$buyer = ($receipt['buyer_data_json'] ?? null) !== null
? json_decode((string) $receipt['buyer_data_json'], true)
: null;
$items = json_decode((string) ($receipt['items_json'] ?? '[]'), true);
$configName = '';
$config = $this->receiptConfigs->findById((int) ($receipt['config_id'] ?? 0));
if ($config !== null) {
$configName = (string) ($config['name'] ?? '');
}
return [
'title' => $this->translator->get('receipts.show.title') . ' ' . ($receipt['receipt_number'] ?? ''),
'activeMenu' => 'orders',
'activeOrders' => 'list',
'user' => $this->auth->user(),
'orderId' => $orderId,
'receipt' => $receipt,
'seller' => is_array($seller) ? $seller : [],
'buyer' => is_array($buyer) ? $buyer : null,
'items' => is_array($items) ? $items : [],
'configName' => $configName,
];
}
}