216 lines
8.0 KiB
PHP
216 lines
8.0 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'] : [];
|
|
|
|
$deliveryPrice = (float) ($order['delivery_price'] ?? 0);
|
|
$totalGross = $this->receiptService->calculateTotalGross($items, $deliveryPrice);
|
|
|
|
$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,
|
|
'deliveryPrice' => $deliveryPrice,
|
|
'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,
|
|
];
|
|
}
|
|
}
|