2026-05-29 14:52:16 -04:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
require_once ("tcpdf/tcpdf.php");
|
|
|
|
|
|
|
|
|
|
// ===============================
|
|
|
|
|
// Print Planning/Zoning Facts PDF
|
|
|
|
|
// ===============================
|
|
|
|
|
|
|
|
|
|
class Print_PZFactsPDF extends Base {
|
|
|
|
|
|
|
|
|
|
// Variables.
|
|
|
|
|
|
|
|
|
|
private $output_type = "normal";
|
|
|
|
|
|
|
|
|
|
// ==================
|
|
|
|
|
// Class Constructor.
|
|
|
|
|
// ==================
|
|
|
|
|
|
|
|
|
|
public function __construct($output_type = "normal") {
|
|
|
|
|
|
|
|
|
|
set_error_handler(array($this, "displayError"));
|
|
|
|
|
|
|
|
|
|
date_default_timezone_set(self::TIMEZONE);
|
|
|
|
|
|
|
|
|
|
$this->output_type = $output_type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ================
|
|
|
|
|
// Print the Report
|
|
|
|
|
// ================
|
|
|
|
|
|
|
|
|
|
public function print() {
|
|
|
|
|
|
|
|
|
|
$report = new PZFacts_Print();
|
|
|
|
|
|
|
|
|
|
$report->subscription_serial = $_SESSION['subscription_serial'];
|
|
|
|
|
$report->usersubscription_serial = $_SESSION['usersubscription_serial'];
|
|
|
|
|
$report->output_type = $this->output_type;
|
|
|
|
|
|
|
|
|
|
ob_clean();
|
|
|
|
|
|
|
|
|
|
if ($this->output_type == "string") {
|
|
|
|
|
return $report->render();
|
|
|
|
|
} else {
|
|
|
|
|
$report->render();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ==========================
|
|
|
|
|
// Class to Generate the .pdf
|
|
|
|
|
// ==========================
|
|
|
|
|
|
|
|
|
|
class PZFacts_Print extends TCPDF {
|
|
|
|
|
|
|
|
|
|
// Variables
|
|
|
|
|
|
|
|
|
|
public $subscription_serial = 0;
|
|
|
|
|
public $usersubscription_serial = 0;
|
|
|
|
|
public $report_header_title = "";
|
|
|
|
|
public $first_page = true;
|
|
|
|
|
public $output_type = "normal";
|
|
|
|
|
|
|
|
|
|
// ===============
|
|
|
|
|
// Debug an Object
|
|
|
|
|
// ===============
|
|
|
|
|
|
|
|
|
|
public function debug($object = "") {
|
|
|
|
|
|
|
|
|
|
echo "<pre>";
|
|
|
|
|
print_r($object);
|
|
|
|
|
exit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// =================
|
|
|
|
|
// Render the Report
|
|
|
|
|
// =================
|
|
|
|
|
|
|
|
|
|
public function render() {
|
|
|
|
|
|
|
|
|
|
set_time_limit(0);
|
|
|
|
|
|
|
|
|
|
$subscription = (new Subscriptions())->getSubscription($this->subscription_serial);
|
|
|
|
|
|
|
|
|
|
if ($subscription->count() === 0) {
|
|
|
|
|
$this->logError("Invalid Subscription ({$this->subscription_serial}): " . __METHOD__);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$userssubscription = (new Users())->getUserSubscription($this->usersubscription_serial);
|
|
|
|
|
|
|
|
|
|
$user_subscription_start_date = $userssubscription->record->usersubscription_start_date;
|
2026-06-13 11:13:36 -04:00
|
|
|
$user_subscription_end_date = $userssubscription->record->usersubscription_end_date;
|
2026-05-29 14:52:16 -04:00
|
|
|
|
|
|
|
|
$planningzoningfacts = (new PlanningAndZoningFacts())->getPZFactsPage($user_subscription_start_date, $user_subscription_end_date);
|
|
|
|
|
|
|
|
|
|
// Set report defaults
|
|
|
|
|
$this->report_header_title = $subscription->record->subscription_full_title;
|
|
|
|
|
$this->title = $subscription->record->subscription_full_title;
|
|
|
|
|
|
|
|
|
|
$this->SetFont("Calibri");
|
|
|
|
|
$this->SetMargins(2, 26, 10);
|
|
|
|
|
$this->SetHeaderMargin(10);
|
|
|
|
|
$this->SetFooterMargin(10);
|
|
|
|
|
$this->setCellPaddings(0, 0, 0, 0);
|
|
|
|
|
$this->setCellMargins(2, 0, 0, 0);
|
|
|
|
|
|
|
|
|
|
$card = function (float $x, float $y, float $w, float $h, array $d) {
|
|
|
|
|
|
|
|
|
|
// Card background + border
|
|
|
|
|
$this->SetDrawColor(210, 210, 210);
|
|
|
|
|
$this->SetFillColor(250, 250, 250);
|
|
|
|
|
$this->Rect($x, $y, $w, $h, 'DF');
|
|
|
|
|
|
|
|
|
|
// Header bar
|
|
|
|
|
$headerH = 10;
|
|
|
|
|
$this->SetFillColor(30, 93, 168); // Bootstrap-ish primary
|
|
|
|
|
$this->Rect($x, $y, $w, $headerH, 'F');
|
|
|
|
|
|
|
|
|
|
// Header text
|
|
|
|
|
$this->SetTextColor(255, 255, 255);
|
|
|
|
|
$this->SetFont('helvetica', 'B', 11);
|
|
|
|
|
$this->SetXY($x + 3, $y + 2.5);
|
|
|
|
|
$this->Cell($w - 6, 0, "Project Name: {$d['pzfact_project_name']}", 0, 0, 'L', false);
|
|
|
|
|
|
|
|
|
|
// Body
|
|
|
|
|
$this->SetTextColor(20, 20, 20);
|
|
|
|
|
$this->SetFont('helvetica', '', 9);
|
|
|
|
|
|
|
|
|
|
$padX = 3;
|
|
|
|
|
$padY = 3;
|
|
|
|
|
|
|
|
|
|
$curY = $y + $headerH + $padY;
|
|
|
|
|
|
|
|
|
|
$bodyX = $x + $padX;
|
|
|
|
|
$bodyW = $w - ($padX * 2);
|
|
|
|
|
|
|
|
|
|
$colGap = 6;
|
|
|
|
|
$colW = ($bodyW - $colGap) / 2;
|
|
|
|
|
|
|
|
|
|
$leftX = $bodyX;
|
|
|
|
|
$rightX = $bodyX + $colW + $colGap;
|
|
|
|
|
|
|
|
|
|
$labelW = 38; // tweak to taste
|
|
|
|
|
|
|
|
|
|
$row2 = function (string $l1, string $v1, string $l2, string $v2) use (&$curY, $leftX, $rightX, $colW, $labelW) {
|
|
|
|
|
|
|
|
|
|
$yStart = $curY;
|
|
|
|
|
|
|
|
|
|
// LEFT Cell
|
|
|
|
|
|
|
|
|
|
$this->SetXY($leftX, $yStart);
|
|
|
|
|
$this->SetFont('helvetica', 'B', 9);
|
|
|
|
|
$this->Cell($labelW, 0, $l1, 0, 0, 'L');
|
|
|
|
|
$this->Cell(2, 0, '', 0, 0); // spacer
|
|
|
|
|
$this->SetFont('helvetica', '', 9);
|
|
|
|
|
$this->MultiCell($colW - $labelW - 2, 0, $v1, 0, 'L', false, 1);
|
|
|
|
|
|
|
|
|
|
$yAfterLeft = $this->GetY();
|
|
|
|
|
|
|
|
|
|
// RIGHT Cell (reset to same starting Y)
|
|
|
|
|
|
|
|
|
|
$this->SetXY($rightX, $yStart);
|
|
|
|
|
$this->SetFont('helvetica', 'B', 9);
|
|
|
|
|
$this->Cell($labelW, 0, $l2, 0, 0, 'L');
|
|
|
|
|
$this->SetFont('helvetica', '', 9);
|
|
|
|
|
$this->MultiCell($colW - $labelW, 0, $v2, 0, 'L', false, 1);
|
|
|
|
|
$yAfterRight = $this->GetY();
|
|
|
|
|
|
|
|
|
|
// Advance cursor to max height used
|
|
|
|
|
$curY = max($yAfterLeft, $yAfterRight) + 1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
$row1 = function (string $label, string $value) use (&$curY, $leftX, $bodyW, $labelW) {
|
|
|
|
|
|
|
|
|
|
$yStart = $curY;
|
|
|
|
|
|
|
|
|
|
$this->SetXY($leftX, $yStart);
|
|
|
|
|
$this->SetFont('helvetica', 'B', 9);
|
|
|
|
|
$this->Cell($labelW, 0, $label, 0, 0, 'L');
|
|
|
|
|
$this->Cell(2, 0, '', 0, 0); // spacer
|
|
|
|
|
|
|
|
|
|
$this->SetFont('helvetica', '', 9);
|
|
|
|
|
$this->MultiCell($bodyW - $labelW - 10, 0, $value, 0, 'L', false, 1);
|
|
|
|
|
|
|
|
|
|
$curY = $this->GetY() + 1;
|
|
|
|
|
};
|
|
|
|
|
|
2026-06-13 11:13:36 -04:00
|
|
|
$row2('Project Description:', $d['pzfact_project_description'], 'Project Type:', $d['pzfact_project_type']);
|
|
|
|
|
$row2('Architect/Engineer: ', $d['pzfact_professional_name'], 'Estimated Project Value:', $d['pzfact_dollar_value']);
|
|
|
|
|
$row2('', '', 'District:', $d['pzfact_district']);
|
|
|
|
|
$row2('Owner Name: ', $d['pzfact_owner_name'], 'Land Lot:', $d['pzfact_land_lot']);
|
|
|
|
|
$row2('Owner Address: ', $d['pzfact_owner_address'], 'Action Code:', $d['pzfact_action_code']);
|
|
|
|
|
$row2('Owner Phone: ', $d['pzfact_owner_phone'], 'Action Date:', $d['pzfact_action_date']);
|
|
|
|
|
$row2('', '', 'Lot Acres:', $d['pzfact_acres']);
|
|
|
|
|
$row2('', '', '', '');
|
2026-05-29 14:52:16 -04:00
|
|
|
|
|
|
|
|
$row1('Status:', $d['pzfact_status']);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Get the data for the report
|
|
|
|
|
|
|
|
|
|
$this->AddPage('L', 'LETTER');
|
|
|
|
|
|
|
|
|
|
$marginL = 10;
|
|
|
|
|
$marginT = 20; // below header area
|
2026-06-13 11:13:36 -04:00
|
|
|
$pageW = $this->getPageWidth();
|
|
|
|
|
$pageH = $this->getPageHeight();
|
2026-05-29 14:52:16 -04:00
|
|
|
|
|
|
|
|
$usableW = $pageW - ($marginL * 2);
|
|
|
|
|
$usableH = $pageH - $marginT - 12; // leave footer space
|
|
|
|
|
|
2026-06-13 11:13:36 -04:00
|
|
|
$gapY = 6;
|
2026-05-29 14:52:16 -04:00
|
|
|
|
|
|
|
|
// Two rows per page
|
2026-06-13 11:13:36 -04:00
|
|
|
$cardW = $usableW;
|
|
|
|
|
$cardH = ($usableH - $gapY) / 2;
|
2026-05-29 14:52:16 -04:00
|
|
|
|
2026-06-13 11:13:36 -04:00
|
|
|
$index = 0;
|
2026-05-29 14:52:16 -04:00
|
|
|
|
|
|
|
|
foreach ($planningzoningfacts->record as $planningzoningfact) {
|
|
|
|
|
|
|
|
|
|
// Add a new page every 2 cards
|
|
|
|
|
if ($index > 0 && $index % 2 === 0) {
|
|
|
|
|
$this->AddPage('L', 'LETTER');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$slot = $index % 2;
|
|
|
|
|
|
|
|
|
|
$x = $marginL;
|
|
|
|
|
$y = $marginT + ($slot * ($cardH + $gapY));
|
|
|
|
|
|
|
|
|
|
// Map your XML fields to the card placeholders (use verbose)
|
|
|
|
|
|
|
|
|
|
$d = [
|
|
|
|
|
// Left Side of Card
|
|
|
|
|
'subscription_serial' => trim((string) $planningzoningfact->pzfact_legacy_id),
|
|
|
|
|
'pzfact_project_description' => trim((string) $planningzoningfact->pzfact_project_description),
|
|
|
|
|
'pzfact_project_name' => trim((string) $planningzoningfact->pzfact_project_name),
|
|
|
|
|
'pzfact_project_type' => trim((string) $planningzoningfact->pzfact_project_type_verbose),
|
|
|
|
|
'pzfact_professional_name' => trim((string) $planningzoningfact->pzfact_professional_name),
|
|
|
|
|
'pzfact_owner_name' => trim((string) $planningzoningfact->pzfact_owner_name),
|
|
|
|
|
'pzfact_owner_address' => trim((string) $planningzoningfact->pzfact_owner_address),
|
|
|
|
|
'pzfact_owner_phone' => $this->formatPhoneNumber(trim((string) $planningzoningfact->pzfacts_owner_phone)),
|
|
|
|
|
// Right Side of Card
|
|
|
|
|
'pzfact_dollar_value' => trim((string) $planningzoningfact->pzfact_dollar_value),
|
|
|
|
|
'pzfact_district' => trim((string) $planningzoningfact->pzfact_district),
|
|
|
|
|
'pzfact_land_lot' => trim((string) $planningzoningfact->pzfact_land_lot),
|
|
|
|
|
'pzfact_action_code' => trim((string) $planningzoningfact->pzfact_action_code_verbose),
|
|
|
|
|
'pzfact_action_date' => trim((string) $planningzoningfact->pzfact_action_date_verbose),
|
|
|
|
|
'pzfact_acres' => trim((string) $planningzoningfact->pzfact_acres),
|
|
|
|
|
'pzfact_entry_date' => trim((string) $planningzoningfact->pzfact_entry_date_verbose),
|
|
|
|
|
'pzfact_status' => trim((string) $planningzoningfact->pzfact_status),
|
|
|
|
|
'pzfact_dollar_value' => trim((string) $planningzoningfact->pzfact_dollar_value),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$card($x, $y, $cardW, $cardH, $d);
|
|
|
|
|
|
|
|
|
|
$index++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// -----------------
|
|
|
|
|
// Render the Report
|
|
|
|
|
// -----------------
|
|
|
|
|
|
|
|
|
|
$this->SetFont('helvetica', '', 9);
|
|
|
|
|
|
|
|
|
|
// --------------
|
|
|
|
|
// Return the pdf
|
|
|
|
|
// --------------
|
|
|
|
|
|
|
|
|
|
if ($this->output_type == "string") {
|
|
|
|
|
return $this->Output("{$subscription->record->subscription_full_title}.pdf", "S");
|
|
|
|
|
} else {
|
|
|
|
|
$this->Output("{$subscription->record->subscription_full_title}.pdf");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ======
|
|
|
|
|
// Header
|
|
|
|
|
// ======
|
|
|
|
|
|
|
|
|
|
public function Header() {
|
|
|
|
|
|
|
|
|
|
$this->setCellPaddings(0, 0, 0, 0);
|
|
|
|
|
$this->setCellMargins(2, 0, 0, 0);
|
|
|
|
|
|
|
|
|
|
$this->Image("images/dec-international-logo.png", 250, 8, 20, 8);
|
|
|
|
|
|
|
|
|
|
$this->SetFont("Calibri", "B", 16);
|
|
|
|
|
|
|
|
|
|
$this->Cell(4, 0, "", 0, 0, "L");
|
|
|
|
|
$this->Cell(0, 0, $this->report_header_title . " Report", 0, 0, "L");
|
|
|
|
|
|
|
|
|
|
$this->Ln(10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ======
|
|
|
|
|
// Footer
|
|
|
|
|
// ======
|
|
|
|
|
|
|
|
|
|
public function Footer() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$this->SetFont("Calibri ", "I", 8);
|
|
|
|
|
|
|
|
|
|
$X = $this->GetX();
|
|
|
|
|
|
|
|
|
|
$this->Cell(0, 10, "DEC International ", 0, false, "C");
|
|
|
|
|
|
|
|
|
|
$this->SetX($X);
|
|
|
|
|
|
|
|
|
|
$this->Cell(40, 10, "Page " . $this->getAliasNumPage() . "/" . $this->getAliasNbPages(), 0, false, "L");
|
|
|
|
|
$this->Cell(0, 10, date("n/j/Y g:i A "), 0, false, "R"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// =======================
|
|
|
|
|
// Stripe the printed line
|
|
|
|
|
// =======================
|
|
|
|
|
|
|
|
|
|
private function stripeLine($pRowCount = 0, $pRowWidth = 0) {
|
|
|
|
|
|
|
|
|
|
$this->SetFillColor(($pRowCount % 2) ? 220 : 255);
|
|
|
|
|
$X = $this->GetX();
|
|
|
|
|
$this->Cell($pRowWidth, 0, "", 0, 0, "L", true);
|
|
|
|
|
$this->SetX($X);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// =======================
|
|
|
|
|
// Format Raw Phone Number
|
|
|
|
|
// =======================
|
|
|
|
|
|
|
|
|
|
public function formatPhoneNumber(string $phonenumber): string {
|
|
|
|
|
|
|
|
|
|
// Remove everything except digits
|
|
|
|
|
$digits = preg_replace('/\D+/', '', $phonenumber);
|
|
|
|
|
|
|
|
|
|
// Handle leading country code (US)
|
|
|
|
|
if (strlen($digits) === 11 && str_starts_with($digits, '1')) {
|
|
|
|
|
$digits = substr($digits, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// // Must be exactly 10 digits to format
|
|
|
|
|
// if (strlen($digits) !== 10) {
|
|
|
|
|
// return $phonenumber; // return original if invalid
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return substr($digits, 0, 3) . '-' .
|
|
|
|
|
substr($digits, 3, 3) . '-' .
|
|
|
|
|
substr($digits, 6, 4);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
?>
|