Files
portal-api/resources/views/pdf/invoice.blade.php
T
baodev0 520f21cb11 feat: add GeneratesUniqueSlug class for unique slug generation
feat: create PostCategoryFactory for generating post category data

feat: create PostFactory for generating post data

feat: add retry_requested_at column to services table

feat: add vcenter provisioning fields to products table

feat: add module_host_id to os table

feat: create email_notification_templates table for email templates

feat: add scenario and format fields to template table

feat: add admin fields to transactions table

fix: update ticket table columns and types

feat: add uuid to ticket table and backfill existing records

fix: make ticket_reply user_id nullable

feat: create notifications table for user notifications

fix: make ticket uuid nullable

feat: create post_categories table for blog categories

feat: create posts table for blog posts

feat: add invoice email template for PDF generation
2026-05-25 15:39:42 +07:00

302 lines
11 KiB
PHP

@php
$companyLogo = $companyLogo ?? '';
$companyName = $companyName ?? '';
$companyAddress = $companyAddress ?? '';
$companyPhone = $companyPhone ?? '';
$companyEmail = $companyEmail ?? '';
$companyTaxCode = $companyTaxCode ?? '';
$brandColor = $brandColor ?? '#1a56db';
$cfg = array_merge([
'accent_color' => $brandColor,
'show_logo' => true,
'show_company_info' => true,
'show_customer_info' => true,
'show_order_info' => true,
'show_items_table' => true,
'show_summary' => true,
'show_note' => true,
'footer_text' => 'Cảm ơn quý khách đã sử dụng dịch vụ.',
'footer_note' => 'Đây là hóa đơn điện tử được tạo tự động, không cần chữ ký số.',
], $cfg ?? []);
@endphp
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8"/>
<title>Hóa đơn #{{ $invoice->invoice_number }}</title>
<style>
@page {
size: A4;
margin: 0;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body {
width: 210mm;
min-height: 297mm;
}
body {
font-family: "DejaVu Sans", "Times New Roman", serif;
color: #000;
font-size: 12px;
background: #fff;
}
.page {
width: 210mm;
min-height: 297mm;
padding: 12mm 15mm;
}
/* Header */
.top-table { width: 100%; border-collapse: collapse; margin-bottom: 6px; }
.top-table td { vertical-align: top; }
.logo-cell { width: 140px; }
.logo-cell img { width: 130px; max-height: 55px; }
.title-cell { text-align: center; padding: 0 8px; }
.title-cell h1 { font-size: 18px; font-weight: bold; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 2px; }
.title-cell h2 { font-size: 12px; font-style: italic; font-weight: normal; margin-bottom: 4px; }
.title-cell .date-line { font-size: 12px; }
.meta-cell { width: 180px; font-size: 11px; line-height: 1.7; vertical-align: top; padding-top: 2px; }
.meta-cell strong { display: block; }
.divider { border: none; border-top: 1px solid #999; margin: 6px 0; }
/* Company */
.company-table { width: 100%; border-collapse: collapse; }
.company-main { vertical-align: top; }
.company-main h3 { font-size: 14px; text-transform: uppercase; font-weight: bold; margin-bottom: 5px; }
.company-qr { width: 100px; vertical-align: top; text-align: right; }
.qr-box { width: 85px; height: 85px; border: 1px solid #ccc; background: #f9f9f9; }
.info-line { margin-bottom: 4px; font-size: 12px; line-height: 1.45; }
.lbl { font-weight: bold; }
/* Buyer */
.buyer-section { margin-top: 8px; }
.payment-table { width: 100%; border-collapse: collapse; }
.payment-table td { vertical-align: top; }
/* Items table */
.items-table { width: 100%; border-collapse: collapse; margin-top: 8px; font-size: 12px; }
.items-table th, .items-table td { border: 1px solid #333; padding: 5px 6px; vertical-align: top; }
.items-table thead th { font-weight: bold; text-align: center; }
.items-table td.center { text-align: center; }
.items-table td.right { text-align: right; }
.items-table tr.sum td { font-weight: bold; }
.items-table tr.total-row td { font-weight: bold; font-size: 13px; background: #fafafa; }
/* Amount words */
.amount-words {
border: 1px solid #333; border-top: none;
padding: 6px 8px; font-size: 12px;
}
/* Signature */
.sign-table { width: 100%; border-collapse: collapse; margin-top: 20mm; text-align: center; }
.sign-table td { vertical-align: top; padding: 0 8px; }
.sign-table h4 { font-size: 12px; margin-bottom: 3px; }
.sign-table p { font-size: 11px; font-style: italic; color: #555; }
.sign-spacer { height: 40px; }
/* Note */
.note-box { margin-top: 8px; border-left: 3px solid #e6a817; background: #fefce8; padding: 6px 10px; font-size: 11px; }
/* Footer */
.footer { margin-top: 16px; text-align: center; font-size: 11px; line-height: 1.7; color: #444; border-top: 1px solid #ddd; padding-top: 8px; }
.status-paid { color: #065f46; font-weight: bold; }
.status-unpaid { color: #991b1b; font-weight: bold; }
.status-cancelled { color: #6b7280; font-weight: bold; }
.accent { color: {{ $cfg['accent_color'] ?? '#1a56db' }}; }
.items-table thead th { background: {{ $cfg['accent_color'] ?? '#1a56db' }}; color: #fff; }
</style>
</head>
<body>
<div class="page">
{{-- ══ HEADER ══ --}}
<table class="top-table">
<tr>
<td class="logo-cell">
@if(($cfg['show_logo'] ?? true) && $companyLogo)
<img src="{{ $companyLogo }}" alt="{{ $companyName }}"/>
@endif
</td>
<td class="title-cell">
<h1>HÓA ĐƠN ĐẶT HÀNG</h1>
<h2>(INVOICE ORDER)</h2>
<div class="date-line">
Ngày <strong>{{ $invoice->created_at?->format('d') ?? '—' }}</strong>
tháng <strong>{{ $invoice->created_at?->format('m') ?? '—' }}</strong>
năm <strong>{{ $invoice->created_at?->format('Y') ?? '—' }}</strong>
</div>
</td>
<td class="meta-cell">
<strong>Mã hóa đơn:</strong> {{ $invoice->invoice_number }}
@if($order)
<strong style="margin-top:4px">Mã đơn hàng:</strong> {{ $order->order_num }}
@endif
<strong style="margin-top:4px">Hạn TT:</strong>
{{ $invoice->due_date ? \Carbon\Carbon::parse($invoice->due_date)->format('d/m/Y') : '—' }}
<strong style="margin-top:4px">Trạng thái:</strong>
@if($invoice->status == 2)<span class="status-paid">Đã thanh toán</span>
@elseif($invoice->status == 1)<span class="status-unpaid">Chưa thanh toán</span>
@else<span class="status-cancelled">Đã hủy</span>@endif
</td>
</tr>
</table>
<hr class="divider"/>
{{-- ══ COMPANY ══ --}}
@if($cfg['show_company_info'] ?? true)
<table class="company-table">
<tr>
<td class="company-main">
<h3>{{ $companyName }}</h3>
@if($companyTaxCode)
<div class="info-line"><span class="lbl">Mã số thuế (Tax code):</span> {{ $companyTaxCode }}</div>
@endif
@if($companyAddress)
<div class="info-line"><span class="lbl">Địa chỉ (Address):</span> {{ $companyAddress }}</div>
@endif
@if($companyPhone)
<div class="info-line"><span class="lbl">Điện thoại (Tel):</span> {{ $companyPhone }}</div>
@endif
@if($companyEmail)
<div class="info-line"><span class="lbl">Email:</span> {{ $companyEmail }}</div>
@endif
</td>
<td class="company-qr"><div class="qr-box"></div></td>
</tr>
</table>
<hr class="divider"/>
@endif
{{-- ══ BUYER ══ --}}
@if($cfg['show_customer_info'] ?? true)
<div class="buyer-section">
<div class="info-line">
<span class="lbl">Họ tên người mua hàng (Buyer):</span> {{ $customer?->fullname ?? '—' }}
</div>
@if($customer?->company)
<div class="info-line"><span class="lbl">Tên đơn vị:</span> {{ $customer->company }}</div>
@endif
@if($customer?->identity_number)
<div class="info-line"><span class="lbl">MST / CMND:</span> {{ $customer->identity_number }}</div>
@endif
@if($customer?->address)
<div class="info-line"><span class="lbl">Địa chỉ (Address):</span> {{ $customer->address }}</div>
@endif
<table class="payment-table">
<tr>
<td style="width:55%">
<div class="info-line">
<span class="lbl">Hình thức thanh toán:</span>
{{ $invoice->payment_method ? strtoupper($invoice->payment_method) : 'TM/CK' }}
</div>
</td>
<td>
<div class="info-line"><span class="lbl">Email:</span> {{ $customer?->email ?? '—' }}</div>
</td>
</tr>
</table>
</div>
@endif
{{-- ══ ITEMS TABLE ══ --}}
@if($cfg['show_items_table'] ?? true)
<table class="items-table">
<thead>
<tr>
<th style="width:40px">STT</th>
<th>Tên hàng hóa, dịch vụ</th>
<th style="width:80px">Đơn vị tính</th>
<th style="width:70px">Số lượng</th>
<th style="width:120px">Đơn giá (đ)</th>
<th style="width:130px">Thành tiền (đ)</th>
</tr>
</thead>
<tbody>
@foreach($invoiceItems as $i => $item)
<tr>
<td class="center">{{ $i + 1 }}</td>
<td>{{ $item->description ?? ($item->product?->name ?? 'Dịch vụ') }}</td>
<td class="center">{{ ($item->months && $item->months > 0) ? 'Tháng' : 'Lần' }}</td>
<td class="center">{{ number_format($item->quantity ?? 1, 2, ',', '.') }}</td>
<td class="right">{{ number_format($item->unit_price, 0, ',', '.') }}</td>
<td class="right">{{ number_format($item->total_price, 0, ',', '.') }}</td>
</tr>
@endforeach
@if($cfg['show_summary'] ?? true)
{{-- Sub-total --}}
<tr class="sum">
<td colspan="5" class="right">Cộng tiền hàng (Total amount excl. VAT)</td>
<td class="right">{{ number_format($invoice->sub_total, 0, ',', '.') }}</td>
</tr>
@if($invoice->discount_amount > 0)
<tr class="sum">
<td colspan="5" class="right">Giảm giá (Discount)</td>
<td class="right">-{{ number_format($invoice->discount_amount, 0, ',', '.') }}</td>
</tr>
@endif
@php $taxRate = ($invoice->total > 0 && $invoice->tax > 0) ? round($invoice->tax / ($invoice->total - $invoice->tax) * 100) : 0; @endphp
<tr class="sum">
<td colspan="3">Thuế suất GTGT (VAT rate): {{ $taxRate > 0 ? $taxRate.'%' : 'Không áp dụng' }}</td>
<td colspan="2" class="right">Tiền thuế GTGT (VAT amount)</td>
<td class="right">{{ number_format($invoice->tax, 0, ',', '.') }}</td>
</tr>
<tr class="sum total-row">
<td colspan="5" class="right">Tổng tiền thanh toán (Total amount)</td>
<td class="right">{{ number_format($invoice->total, 0, ',', '.') }}</td>
</tr>
@endif
</tbody>
</table>
<div class="amount-words">
<strong>Số tiền viết bằng chữ (Total amount in words):</strong>
{{ \App\Helpers\NumberToWords::convert((int) $invoice->total) }}.
</div>
@endif
{{-- ══ NOTE ══ --}}
@if(($cfg['show_note'] ?? true) && $invoice->note)
<div class="note-box"><strong>Ghi chú:</strong> {{ $invoice->note }}</div>
@endif
{{-- ══ SIGNATURE ══ --}}
<table class="sign-table">
<tr>
<td>
<h4>Người mua hàng<br/><em style="font-size:11px">(Buyer's signature)</em></h4>
<p>Ký, ghi rõ họ tên</p>
<div class="sign-spacer"></div>
<p>{{ $customer?->fullname ?? '' }}</p>
</td>
<td></td>
<td>
<h4>Người bán hàng<br/><em style="font-size:11px">(Seller's signature)</em></h4>
<p>Ký, đóng dấu, ghi rõ họ tên</p>
<div class="sign-spacer"></div>
<p>{{ $companyName }}</p>
</td>
</tr>
</table>
{{-- ══ FOOTER ══ --}}
<div class="footer">
@if($cfg['footer_text'] ?? ''){{ $cfg['footer_text'] }}<br/>@endif
@if($cfg['footer_note'] ?? ''){{ $cfg['footer_note'] }}<br/>@endif
Mã tra cứu: <strong>{{ $invoice->invoice_number }}</strong>
</div>
</div>
</body>
</html>