- Redesign AWB PDF with barcode, From/To, Value, Service, Type - Redesign Invoice PDF with 9-row table, legal declaration, barcode - Redesign Label PDF to A5 landscape with large barcode - Add DOC/PARCEL condition for Invoice (only PARCEL has invoice) - Fix ShipmentType enum names (DocNormal/DocEconomy) - Add migration for shipment_items (row_number, unit_price) - Add migration to make name nullable - Update PdfService with base64 barcode embedding - Update ShipmentPdfController with DOC type handling - Add test_pdf_generation.php script Phase 3.5 — PDF redesign complete"
250 lines
7.3 KiB
PHP
250 lines
7.3 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<style>
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
body {
|
|
font-family: DejaVu Sans, Arial, sans-serif;
|
|
color: #000;
|
|
background: #fff;
|
|
}
|
|
/* A5 افقی: 210x148 mm — استفاده از min-height نه height */
|
|
.label-page {
|
|
width: 200mm;
|
|
padding: 4mm;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
/* ─── HEADER ─── */
|
|
.header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
border-bottom: 3px solid #f37021;
|
|
padding-bottom: 2mm;
|
|
margin-bottom: 3mm;
|
|
}
|
|
.brand-name {
|
|
font-size: 16px;
|
|
font-weight: bold;
|
|
color: #f37021;
|
|
}
|
|
.brand-tagline {
|
|
font-size: 8px;
|
|
color: #666;
|
|
}
|
|
.header-date {
|
|
font-size: 10px;
|
|
color: #666;
|
|
}
|
|
|
|
/* ─── MAIN: 2 ستون ─── */
|
|
.main {
|
|
display: flex;
|
|
gap: 4mm;
|
|
}
|
|
|
|
/* ─── ستون چپ: بارکد ─── */
|
|
.barcode-col {
|
|
width: 45%;
|
|
border: 2px solid #000;
|
|
padding: 3mm;
|
|
text-align: center;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
.barcode-col img {
|
|
max-width: 100%;
|
|
height: 25mm;
|
|
width: auto;
|
|
display: block;
|
|
margin: 0 auto;
|
|
}
|
|
.awb-label {
|
|
font-size: 8px;
|
|
color: #666;
|
|
margin-top: 2mm;
|
|
text-transform: uppercase;
|
|
}
|
|
.awb-display {
|
|
font-size: 16px;
|
|
font-weight: bold;
|
|
letter-spacing: 2px;
|
|
margin-top: 1mm;
|
|
font-family: 'Courier New', monospace;
|
|
}
|
|
|
|
/* ─── ستون راست: اطلاعات ─── */
|
|
.info-col {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2mm;
|
|
}
|
|
|
|
/* ─── مسیر کشورها ─── */
|
|
.route {
|
|
border: 2px solid #000;
|
|
padding: 2mm;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
background: #f9f9f9;
|
|
}
|
|
.country-box {
|
|
text-align: center;
|
|
flex: 1;
|
|
}
|
|
.country-label {
|
|
font-size: 7px;
|
|
color: #666;
|
|
text-transform: uppercase;
|
|
}
|
|
.country-name {
|
|
font-size: 11px;
|
|
font-weight: bold;
|
|
}
|
|
.country-iso {
|
|
font-size: 20px;
|
|
font-weight: bold;
|
|
color: #f37021;
|
|
}
|
|
.arrow {
|
|
font-size: 20px;
|
|
color: #f37021;
|
|
padding: 0 2mm;
|
|
}
|
|
|
|
/* ─── جدول وزن ─── */
|
|
.weights {
|
|
display: flex;
|
|
border: 2px solid #000;
|
|
}
|
|
.weight-cell {
|
|
flex: 1;
|
|
border-right: 1px solid #000;
|
|
padding: 2mm;
|
|
text-align: center;
|
|
}
|
|
.weight-cell:last-child {
|
|
border-right: none;
|
|
}
|
|
.weight-label {
|
|
font-size: 7px;
|
|
color: #666;
|
|
text-transform: uppercase;
|
|
}
|
|
.weight-value {
|
|
font-size: 12px;
|
|
font-weight: bold;
|
|
margin-top: 1mm;
|
|
}
|
|
|
|
/* ─── ZIP ─── */
|
|
.zip {
|
|
border: 2px solid #000;
|
|
padding: 2mm;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
background: #fffde7;
|
|
}
|
|
.zip-label {
|
|
font-size: 8px;
|
|
color: #666;
|
|
text-transform: uppercase;
|
|
}
|
|
.zip-value {
|
|
font-size: 16px;
|
|
font-weight: bold;
|
|
font-family: 'Courier New', monospace;
|
|
letter-spacing: 2px;
|
|
}
|
|
|
|
/* ─── FOOTER ─── */
|
|
.footer {
|
|
border-top: 2px solid #f37021;
|
|
padding-top: 2mm;
|
|
margin-top: 3mm;
|
|
font-size: 8px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
color: #666;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="label-page">
|
|
<!-- HEADER -->
|
|
<div class="header">
|
|
<div>
|
|
<div class="brand-name">IFNEx LOGISTICS</div>
|
|
<div class="brand-tagline">We Deliver Value</div>
|
|
</div>
|
|
<div class="header-date">Date: {{ $shipment->created_at?->format('m/d/Y') }}</div>
|
|
</div>
|
|
|
|
<!-- MAIN -->
|
|
<div class="main">
|
|
<!-- BARCODE -->
|
|
<div class="barcode-col">
|
|
@if($barcode_base64)
|
|
<img src="{{ $barcode_base64 }}" alt="barcode">
|
|
@endif
|
|
<div class="awb-label">AWB Number</div>
|
|
<div class="awb-display">{{ $shipment->awb_no }}</div>
|
|
</div>
|
|
|
|
<!-- INFO -->
|
|
<div class="info-col">
|
|
<!-- ROUTE -->
|
|
<div class="route">
|
|
<div class="country-box">
|
|
<div class="country-label">ORIGIN</div>
|
|
<div class="country-name">{{ $shipment->fromCountry?->name ?? '—' }}</div>
|
|
<div class="country-iso">{{ $origin_iso }}</div>
|
|
</div>
|
|
<div class="arrow">→</div>
|
|
<div class="country-box">
|
|
<div class="country-label">DESTINATION</div>
|
|
<div class="country-name">{{ $shipment->toCountry?->name ?? '—' }}</div>
|
|
<div class="country-iso">{{ $dest_iso }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- WEIGHTS -->
|
|
<div class="weights">
|
|
<div class="weight-cell">
|
|
<div class="weight-label">Gross Weight</div>
|
|
<div class="weight-value">{{ $shipment->weight }} kg</div>
|
|
</div>
|
|
<div class="weight-cell">
|
|
<div class="weight-label">Volumetric</div>
|
|
<div class="weight-value">{{ $shipment->volumetric_weight }} kg</div>
|
|
</div>
|
|
<div class="weight-cell">
|
|
<div class="weight-label">W*L*H</div>
|
|
<div class="weight-value">{{ $shipment->dimensions ?: '—' }} cm</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ZIP -->
|
|
<div class="zip">
|
|
<span class="zip-label">DEST ZIP</span>
|
|
<span class="zip-value">{{ $shipment->receiver_zip ?: '—' }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- FOOTER -->
|
|
<div class="footer">
|
|
<span>IFNEx Logistics — We Deliver Value</span>
|
|
<span><strong>{{ $shipment->awb_no }}</strong></span>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|