Fix custom login page image uploading

This commit is contained in:
Focuslinkstech 2025-03-18 13:08:19 +01:00
parent 1cb0e30e6b
commit 8b8a0357f0
3 changed files with 425 additions and 1 deletions

188
debug_invoice.html Normal file
View File

@ -0,0 +1,188 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Invoice No: INV-284</title>
<style>
.invoice-box {
max-width: 800px;
margin: auto;
padding: 30px;
border: 1px solid #eee;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
font-size: 16px;
line-height: 24px;
font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;
color: #555;
}
.invoice-box table {
width: 100%;
line-height: inherit;
text-align: left;
}
.invoice-box table td {
padding: 5px;
vertical-align: top;
}
.invoice-box table tr td:nth-child(2) {
text-align: right;
}
.invoice-box table tr.top table td {
padding-bottom: 20px;
}
.invoice-box table tr.top table td.title {
font-size: 45px;
line-height: 45px;
color: #333;
}
.invoice-box table tr.information table td {
padding-bottom: 40px;
}
.invoice-box table tr.heading td {
background: #eee;
border-bottom: 1px solid #ddd;
font-weight: bold;
}
.invoice-box table tr.details td {
padding-bottom: 20px;
}
.invoice-box table tr.item td {
border-bottom: 1px solid #eee;
}
.invoice-box table tr.item.last td {
border-bottom: none;
}
.invoice-box table tr.total td:nth-child(2) {
border-top: 2px solid #eee;
font-weight: bold;
}
@media only screen and (max-width: 600px) {
.invoice-box table tr.top table td {
width: 100%;
display: block;
text-align: center;
}
.invoice-box table tr.information table td {
width: 100%;
display: block;
text-align: center;
}
}
/** RTL **/
.invoice-box.rtl {
direction: rtl;
font-family: Tahoma, 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif;
}
.invoice-box.rtl table {
text-align: right;
}
.invoice-box.rtl table tr td:nth-child(2) {
text-align: left;
}
</style>
</head>
<body>
<div class="invoice-box">
<table cellpadding="0" cellspacing="0">
<tr class="top">
<td colspan="2">
<table>
<tr>
<td class="title">
<img src="system/uploads/logo.default.png" style="max-width: 100px" />
</td>
<td>
Invoice #: INV-284<br />
Created: March 16, 2025<br />
Due: March 23, 2025
</td>
</tr>
</table>
</td>
</tr>
<tr class="information">
<td colspan="2">
<table>
<tr>
<td>
PHPNuxBill<br />
No 2, udo wogu street chevy view estate, Road c17 mercyland, losoro lakowe<br />
+2347054020007<br />
</td>
<td>
admin<br />
admin <br />
admin@gmail.com <br />
9006721321 <br />
</td>
</tr>
</table>
</td>
</tr>
<table style="width: 100%; border-collapse: collapse; margin: 20px 0;">
<thead>
<tr>
<th style="background: #3498db; color: white; padding: 12px; text-align: left;">Service
Description</th>
<th style="background: #3498db; color: white; padding: 12px; text-align: left;">Plan Details
</th>
<th style="background: #3498db; color: white; padding: 12px; text-align: left;">Amount</th>
</tr>
</thead>
<tbody>
<tr>
<td style='padding: 12px; border-bottom: 1px solid #ddd;'>Test Plan</td>
<td style='padding: 12px; border-bottom: 1px solid #ddd;'>Monthly Subscription</td>
<td style='padding: 12px; border-bottom: 1px solid #ddd;'>₦200</td>
</tr>
</tbody>
</table>
</table>
<div style="text-align: right; margin-top: 20px;">
<p style="margin: 0;">Subtotal: ₦202.00<br>
TAX (1%): ₦2.00<br>
<strong>Total Due: ₦202.00</strong>
</p>
</div>
<div style="background: #f8f9fa; padding: 15px; border-radius: 5px; margin-top: 20px;">
<h4 style="margin: 0;">Payment Options:</h4>
<p style="margin: 0;">Online Portal: <a href="pay.phpnuxbill.com">pay.phpnuxbill.com</a> <br>
Bank Transfer: Account # 1234-567890<br>
Auto Pay: Enabled (Next payment: 2023-11-12)</p>
</div>
<footer
style="margin-top: 30px; padding-top: 20px; border-top: 1px solid #ddd; font-size: 0.9em; color: #666; text-align: center;">
<p style="margin: 0;">Thank you for choosing PHPNuxBill!<br>
Late payments may result in service interruption<br>
Need help? Contact support@PHPNuxBill.com or call +2347054020007</p>
</footer>
</div>
</body>
</html>

235
system/autoload/Invoice.php Normal file
View File

@ -0,0 +1,235 @@
<?php
use Mpdf\Mpdf;
class Invoice
{
public static function generateInvoice($invoiceData)
{
try {
if (empty($invoiceData['id'])) {
throw new Exception("Invoice ID is required");
}
$templatePath = 'pages/custom_invoice.html';
if (!file_exists($templatePath)) {
$templatePath = 'pages/default_invoice.html';
}
$template = file_get_contents($templatePath);
if (!$template) {
throw new Exception("Invoice template not found");
}
if (strpos($template, '<body') === false) {
$template = "<html><body>$template</body></html>";
}
$processedHtml = self::renderTemplate($template, $invoiceData);
// Debugging: Save processed HTML to file for review
// file_put_contents('debug_invoice.html', $processedHtml);
// Generate PDF
$mpdf = new Mpdf([
'mode' => 'utf-8',
'format' => 'A4',
'margin_left' => 10,
'margin_right' => 10,
'margin_top' => 10,
'margin_bottom' => 10,
'default_font' => 'helvetica',
'orientation' => 'P',
]);
$mpdf->SetDisplayMode('fullpage');
$mpdf->SetProtection(['print']);
$mpdf->shrink_tables_to_fit = 1;
$mpdf->SetWatermarkText(strtoupper($invoiceData['status'] ?? 'UNPAID'), 0.15);
$mpdf->showWatermarkText = true;
$mpdf->WriteHTML($processedHtml);
// Save PDF
$filename = "invoice_{$invoiceData['id']}.pdf";
$outputPath = "system/uploads/invoices/{$filename}";
$mpdf->Output($outputPath, 'F');
if (!file_exists($outputPath)) {
throw new Exception("Failed to save PDF file");
}
return $filename;
} catch (\Exception $e) {
_log("Invoice generation failed: " . $e->getMessage());
sendTelegram("Invoice generation failed: " . $e->getMessage());
return false;
}
}
private static function renderTemplate($template, $invoiceData)
{
return preg_replace_callback('/\[\[(\w+)\]\]/', function ($matches) use ($invoiceData) {
$key = $matches[1];
if (!isset($invoiceData[$key])) {
_log("Missing invoice key: $key");
return '';
}
if (in_array($key, ['created_at', 'due_date'])) {
return date('F j, Y', strtotime($invoiceData[$key]));
}
if (in_array($key, ['amount', 'total', 'subtotal', 'tax'])) {
return $invoiceData['currency_code'] . number_format((float) $invoiceData[$key], 2);
}
if ($key === 'bill_rows') {
return html_entity_decode($invoiceData[$key]);
}
return htmlspecialchars($invoiceData[$key] ?? '');
}, $template);
}
public static function sendInvoice($userId, $status = "Unpaid")
{
global $config;
if (empty($config['currency_code'])) {
$config['currency_code'] = '$';
}
$account = ORM::for_table('tbl_customers')->find_one($userId);
if (!$account) {
_log("Failed to send invoice: User not found");
sendTelegram("Failed to send invoice: User not found");
return false;
}
$invoice = ORM::for_table("tbl_transactions")->where("username", $account->username)->find_one();
if (!$invoice) {
_log("Failed to send invoice: Transaction not found");
sendTelegram("Failed to send invoice: Transaction not found");
return false;
}
[$additionalBills, $add_cost] = User::getBills($account->id);
$invoiceItems = [
[
'description' => $invoice->plan_name,
'details' => 'Monthly Subscription',
'amount' => (float) $invoice->price
]
];
$subtotal = (float) $invoice->price;
if ($add_cost > 0 && $invoice->routers != 'balance') {
foreach ($additionalBills as $description => $amount) {
if (is_numeric($amount)) {
$invoiceItems[] = [
'description' => $description,
'details' => 'Additional Bill',
'amount' => (float) $amount
];
$subtotal += (float) $amount;
} else {
_log("Invalid bill amount for {$description}: {$amount}");
}
}
}
$tax_rate = (float) ($config['tax_rate'] ?? 0);
$tax = $config['enable_tax'] ? Package::tax($subtotal) : 0;
$total = ($tax > 0) ? $subtotal + $tax : $subtotal + $tax;
$invoiceData = [
'id' => "INV-" . Package::_raid(),
'fullname' => $account->fullname,
'email' => $account->email,
'address' => $account->address,
'phone' => $account->phonenumber,
'bill_rows' => self::generateBillRows($invoiceItems, $config['currency_code'], $subtotal, $tax_rate, $tax, $total),
'status' => $status,
'created_at' => date('Y-m-d H:i:s'),
'due_date' => date('Y-m-d H:i:s', strtotime('+7 days')),
'currency' => $config['currency_code'],
'company_address' => $config['address'],
'company_name' => $config['CompanyName'],
'company_phone' => $config['phone'],
'logo' => $config['logo'],
];
if (!isset($invoiceData['bill_rows']) || empty($invoiceData['bill_rows'])) {
_log("Invoice Error: Bill rows data is empty.");
}
$filename = self::generateInvoice($invoiceData);
if ($filename) {
$pdfPath = "system/uploads/invoices/{$filename}";
try {
Message::sendEmail(
$account->email,
"Invoice for Account {$account->fullname}",
"Please find your invoice attached",
$pdfPath
);
return true;
} catch (\Exception $e) {
_log("Failed to send invoice email: " . $e->getMessage());
sendTelegram("Failed to send invoice email: " . $e->getMessage());
return false;
}
}
return false;
}
private static function generateBillRows($items, $currency, $subtotal, $tax_rate, $tax, $total)
{
$html = "<table style='width: 100%; border-collapse: collapse; margin: 20px 0;'>
<thead>
<tr>
<th style='background: #3498db; color: white; padding: 12px; text-align: left;'>Description</th>
<th style='background: #3498db; color: white; padding: 12px; text-align: left;'>Details</th>
<th style='background: #3498db; color: white; padding: 12px; text-align: left;'>Amount</th>
</tr>
</thead>
<tbody>";
foreach ($items as $item) {
$html .= "<tr>
<td style='padding: 10px; border-bottom: 1px solid #ddd;'>{$item['description']}</td>
<td style='padding: 10px; border-bottom: 1px solid #ddd;'>{$item['details']}</td>
<td style='padding: 10px; border-bottom: 1px solid #ddd;'>{$currency}" . number_format((float) $item['amount'], 2) . "</td>
</tr>";
}
$html .= "<tr>
<td colspan='2' style='text-align: right; padding: 10px; border-top: 2px solid #3498db;'>Subtotal:</td>
<td style='padding: 10px; border-top: 2px solid #3498db;'>{$currency}" . number_format($subtotal, 2) . "</td>
</tr>
<tr>
<td colspan='2' style='text-align: right; padding: 10px;'>TAX ({$tax_rate}%):</td>
<td style='padding: 10px;'>{$currency}" . number_format($tax, 2) . "</td>
</tr>
<tr>
<td colspan='2' style='text-align: right; padding: 10px; font-weight: bold;'>Total:</td>
<td style='padding: 10px; font-weight: bold;'>{$currency}" . number_format($total, 2) . "</td>
</tr>";
$html .= "</tbody></table>";
return $html;
}
}

View File

@ -1148,5 +1148,6 @@
"Continue_the_process_of_sending_messages": "Continue the process of sending messages", "Continue_the_process_of_sending_messages": "Continue the process of sending messages",
"Yours_Balances": "Yours Balances", "Yours_Balances": "Yours Balances",
"Friend_username": "Friend username", "Friend_username": "Friend username",
"This_will_sync_dan_send_Customer_active_package_to_Mikrotik": "This will sync dan send Customer active package to Mikrotik" "This_will_sync_dan_send_Customer_active_package_to_Mikrotik": "This will sync dan send Customer active package to Mikrotik",
"Email_not_sent__Mailer_Error__": "Email not sent, Mailer Error: "
} }