unGuardable
Elite
mga lods, meron akong small problem sa printing at sa pag gawa ng layout siguro ng print.
ang gusto ko sana maging responsive yung pag print, na every page merong header, merong page number, merong footer.
ang nangyayari is if sa ganitong type merong siyang header pero kapag masyadong mahaba, nag nenext page lang walang header sa next page. ang footer niya rin ay nasa ilalim lang ng record mismo.
attach ko po yung code ko.

ang gusto ko sana maging responsive yung pag print, na every page merong header, merong page number, merong footer.
ang nangyayari is if sa ganitong type merong siyang header pero kapag masyadong mahaba, nag nenext page lang walang header sa next page. ang footer niya rin ay nasa ilalim lang ng record mismo.
attach ko po yung code ko.
PHP:
<?php
session_start();
require_once __DIR__ . '/config/db.php';
requireModulePermission('t-twlist');
include 'include_global_functions.php';
if (!isset($_SESSION['user_id'])) {
header("Location: auth_signin.php");
exit;
}
date_default_timezone_set('Asia/Manila');
$today = date("Y-m-d");
$display_today = date("F d, Y g:i A");
$display_today2 = date("F d, Y");
$printed_by = ($_SESSION['first_name'] ?? '') . ' ' . ($_SESSION['last_name'] ?? '');
$sql = "SELECT
a.driver_signature_path, a.hauler_name, a.quantity, a.driver_name, a.plate_no, a.created_at,
d.do_number, t.trader_name, c.crop_year_label,
wt.type_name AS withdrawal_type, rs.subtype_name, raws.raw_subtype_name
FROM atw_records a
INNER JOIN delivery_orders d ON a.do_id = d.do_id
INNER JOIN traders t ON d.trader_id = t.trader_id
INNER JOIN crop_years c ON d.crop_year_id = c.crop_year_id
INNER JOIN withdrawal_types wt ON d.withdrawal_type_id = wt.withdrawal_type_id
LEFT JOIN raw_subtypes raws ON d.raw_subtype_id = raws.raw_subtype_id
LEFT JOIN refined_subtypes rs ON d.refined_subtype_id = rs.refined_subtype_id
WHERE a.status = 'completed' -- AND a.created_at >= '$today'
ORDER BY c.crop_year_label, wt.type_name, d.do_number, a.created_at";
$result = $conn->query($sql);
$tickets_data = [];
while ($row = $result->fetch_assoc()) {
$cy = $row['crop_year_label'];
$type = $row['withdrawal_type'];
$subtype = !empty($row['subtype_name']) ? " ({$row['subtype_name']})" : '';
$raw_subtype = !empty($row['raw_subtype_name']) ? " ({$row['raw_subtype_name']})" : '';
$do = $row['do_number'] . $subtype . $raw_subtype;
$tickets_data[$cy][$type][$do][] = $row;
}
// $today = date("F d, Y");
audit_log(
$conn,
'print',
'atw_records',
[
'description' => 'Printed Completed Dispatches'
]
);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Completed Withdrawal Tickets</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
* {
box-sizing: border-box;
}
@font-face {
font-family: 'Inter';
src: url('assets/fonts/Inter/Inter-VariableFont_opsz,wght.ttf') format('truetype');
font-weight: 400 700;
}
body {
font-family: "Inter", "Segoe UI", Tahoma, sans-serif;
font-size: 12px;
color: #212529;
margin: 0;
padding: 0;
}
.page {
padding: 20mm 15mm;
display: flex;
flex-direction: column;
page-size: 8.5in 13in;
min-height: 100vh;
}
.header {
text-align: center;
font-size: 14px;
color: #333;
/* page-break-before: always; */
}
.content {
flex: 1;
}
/* .footer {
display: flex;
justify-content: space-between;
font-size: 12px;
color: #777;
margin-top: 20px;
border-top: 1px solid #ccc;
padding-top: 8px;
} */
.footer {
margin-top: auto;
padding: 10px 30px;
font-size: 13px;
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #dee2e6;
background: #ffffff;
}
.crop-year-title {
text-align: center;
font-size: 18px;
font-weight: 600;
/* border-bottom: 1px solid #444; */
padding-bottom: 6px;
letter-spacing: 0.5px;
color: #343a40;
margin-bottom: 20px;
}
.withdrawal-type-title {
font-size: 16px;
font-weight: 500;
margin: 5px 0 5px;
color: #343a40;
border-bottom: 1px solid #bbb;
padding-bottom: 4px;
}
.do-header {
margin-top: 14px;
font-weight: 600;
color: rgb(0, 0, 0);
}
.ticket-table {
width: 100%;
border-collapse: collapse;
margin-top: 8px;
font-size: 13px;
}
.ticket-table th,
.ticket-table td {
border: 1px solid #aaa;
padding: 6px 8px;
text-align: left;
vertical-align: middle;
}
.ticket-table th {
background: #f8f8f8;
font-weight: bold;
color: #222;
}
.do-total-line {
font-weight: bold;
text-align: right;
margin-top: 4px;
margin-bottom: 12px;
color: #000;
}
.page-total {
font-weight: bold;
color: #000;
}
.signature-img {
max-height: 30px;
max-width: 60px;
}
@media print {
.page {
page-break-after: auto;
}
.page:not(:first-child) {
page-break-before: always;
}
.page:last-of-type {
page-break-after: avoid;
}
}
</style>
</head>
<body>
<?php
if (empty($tickets_data)) {
echo "<div style='padding: 100px; text-align: center;'>No completed withdrawal tickets found.</div>";
} else {
$page_number = 1;
$total_pages = 0;
foreach ($tickets_data as $types) {
foreach ($types as $dos) {
$total_pages++;
}
}
foreach ($tickets_data as $crop_year => $types) {
// if ($page_number > 1) {
// echo '<div class="page-empty"></div>'; // Add empty page for each header
// }
foreach ($types as $withdrawal_type => $dos):
$page_total_qty = 0;
?>
<div class="page">
<div class="header">
<div style="display: flex; align-items: center; justify-content: center; gap: 10px;">
<img src="assets/images/biscom-logo.png" alt="BISCOM Logo" style="height: 40px; width: 40px;">
<div>
<h1 style="margin: 0;">BISCOM Inc.</h1>
<div class="subtitle">Binalbagan, Negros Occidental</div>
</div>
</div>
<div class="subtitle2" style="font-weight: bold; margin-top: 6px;">Completed Dispatches</div>
<div style="margin-top: 4px;"><?= $display_today2 ?></div>
</div>
<div class="content">
<div class="crop-year-title">Crop Year <?= htmlspecialchars($crop_year) ?></div>
<div class="withdrawal-type-title">Withdrawal Type: <?= htmlspecialchars($withdrawal_type) ?></div>
<?php foreach ($dos as $do_number => $tickets):
$first = $tickets[0];
$do_total_qty = array_sum(array_map(fn($t) => (float)$t['quantity'], $tickets));
$page_total_qty += $do_total_qty;
?>
<div class="do-header">
DO #<?= htmlspecialchars($do_number) ?>
|
Trader: <?= htmlspecialchars($first['trader_name']) ?>
</div>
<table class="ticket-table">
<thead>
<tr>
<th>#</th>
<th>Hauler</th>
<th>Driver</th>
<th>Plate No.</th>
<th>Qty</th>
<th>Withdrawal Date</th>
<th>Signature</th>
</tr>
</thead>
<tbody>
<?php foreach ($tickets as $i => $ticket): ?>
<tr>
<td><?= $i + 1 ?></td>
<td><?= htmlspecialchars($ticket['hauler_name']) ?></td>
<td><?= htmlspecialchars($ticket['driver_name']) ?></td>
<td><?= htmlspecialchars($ticket['plate_no']) ?></td>
<td><?= number_format($ticket['quantity'], 2) ?></td>
<td><?= htmlspecialchars($ticket['created_at']) ?></td>
<td>
<?php if (!empty($ticket['driver_signature_path'])): ?>
<img class="signature-img" src="<?= htmlspecialchars($ticket['driver_signature_path']) ?>" alt="Signature">
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<div class="do-total-line">Subtotal: <?= number_format($do_total_qty, 2) ?></div>
<?php endforeach; ?>
</div>
<!-- <div class="footer">
<div>
Printed on <?= $display_today ?>
</div>
<div class="page-total">
Grand Total: <u><?= number_format($page_total_qty, 2) ?></u>
</div>
</div> -->
<div class="footer">
<span>Printed on <?= $display_today ?></span>
<span>Printed by: <?= htmlspecialchars($printed_by) ?></span>
<span class="footer-right page-total">Grand Total: <u><?= number_format($page_total_qty, 2) ?></u></span>
</div>
</div>
<?php
$page_number++;
endforeach;
}
}
?>
<script>
window.addEventListener('DOMContentLoaded', function() {
setTimeout(function() {
window.print();
}, 800); // 800ms delay for better data preparation
});
</script>
</body>
</html>
