Added new functionality to Invoice class: generate invoice PDF, save to database, and send email. Also, updated language file with new translations.
This commit is contained in:
parent
5caa9f905b
commit
ba19b1c569
@ -88,84 +88,49 @@ class Invoice
|
||||
}, $template);
|
||||
}
|
||||
|
||||
public static function sendInvoice($userId, $status = "Unpaid")
|
||||
/**
|
||||
* Send invoice to user
|
||||
*
|
||||
* @param int $userId
|
||||
* @param array $invoice
|
||||
* @param array $bills
|
||||
* @param string $status
|
||||
* @param string $invoiceNo
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
public static function sendInvoice($userId, $invoice = [], $bills = [], $status = "Unpaid", $invoiceNo = "INV-" . Package::_raid())
|
||||
{
|
||||
global $config, $root_path, $UPLOAD_PATH;
|
||||
|
||||
if (empty($config['currency_code'])) {
|
||||
$config['currency_code'] = '$';
|
||||
}
|
||||
// Set default currency code
|
||||
$config['currency_code'] ??= '$';
|
||||
|
||||
$account = ORM::for_table('tbl_customers')->find_one($userId);
|
||||
self::validateAccount($account);
|
||||
|
||||
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();
|
||||
|
||||
// Fetch invoice if not provided
|
||||
$invoice = $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;
|
||||
throw new Exception("Transaction not found for user: {$userId}");
|
||||
}
|
||||
|
||||
[$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}");
|
||||
}
|
||||
}
|
||||
// Get additional bills if not provided
|
||||
if (empty($bills)) {
|
||||
[$bills, $add_cost] = User::getBills($account->id);
|
||||
}
|
||||
|
||||
$tax_rate = (float) ($config['tax_rate'] ?? 0);
|
||||
$invoiceItems = self::generateInvoiceItems($invoice, $bills, $add_cost);
|
||||
$subtotal = array_sum(array_column($invoiceItems, 'amount'));
|
||||
$tax = $config['enable_tax'] ? Package::tax($subtotal) : 0;
|
||||
$total = ($tax > 0) ? $subtotal + $tax : $subtotal + $tax;
|
||||
$tax_rate = $config['tax_rate'] ?? 0;
|
||||
$total = $subtotal + $tax;
|
||||
|
||||
$token = User::generateToken($account->id, 1);
|
||||
if (!empty($token['token'])) {
|
||||
$tur = ORM::for_table('tbl_user_recharges')
|
||||
->where('customer_id', $account->id)
|
||||
->where('namebp', $invoice->plan_name);
|
||||
$payLink = self::generatePaymentLink($account, $invoice, $status);
|
||||
$logo = self::getCompanyLogo($UPLOAD_PATH, $root_path);
|
||||
|
||||
switch ($status) {
|
||||
case 'Paid':
|
||||
$tur->where('status', 'on');
|
||||
break;
|
||||
default:
|
||||
$tur->where('status', 'off');
|
||||
break;
|
||||
}
|
||||
$turResult = $tur->find_one();
|
||||
$payLink = $turResult ? '?_route=home&recharge=' . $turResult['id'] . '&uid=' . urlencode($token['token']) : '?_route=home';
|
||||
} else {
|
||||
$payLink = '?_route=home';
|
||||
}
|
||||
|
||||
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
|
||||
$logo = (file_exists($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png')) ? $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'logo.png?' . time() : $UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'logo.default.png';
|
||||
$invoiceData = [
|
||||
'invoice' => "INV-" . Package::_raid(),
|
||||
'invoice' => $invoiceNo,
|
||||
'fullname' => $account->fullname,
|
||||
'email' => $account->email,
|
||||
'address' => $account->address,
|
||||
@ -182,31 +147,90 @@ class Invoice
|
||||
'payment_link' => $payLink
|
||||
];
|
||||
|
||||
if (!isset($invoiceData['bill_rows']) || empty($invoiceData['bill_rows'])) {
|
||||
_log("Invoice Error: Bill rows data is empty.");
|
||||
if (empty($invoiceData['bill_rows'])) {
|
||||
throw new Exception("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;
|
||||
}
|
||||
if (!$filename) {
|
||||
throw new Exception("Failed to generate invoice PDF");
|
||||
}
|
||||
|
||||
return false;
|
||||
$pdfPath = "system/uploads/invoices/{$filename}";
|
||||
self::saveToDatabase($filename, $account->id, $invoiceData, $total);
|
||||
|
||||
try {
|
||||
Message::sendEmail(
|
||||
$account->email,
|
||||
"Invoice for Account {$account->fullname}",
|
||||
"Please find your invoice attached",
|
||||
$pdfPath
|
||||
);
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
throw new Exception("Failed to send invoice email: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static function validateAccount($account)
|
||||
{
|
||||
if (!$account) {
|
||||
throw new Exception("User not found");
|
||||
}
|
||||
if (!$account->email || !filter_var($account->email, FILTER_VALIDATE_EMAIL)) {
|
||||
throw new Exception("Invalid user email");
|
||||
}
|
||||
}
|
||||
|
||||
private static function generateInvoiceItems($invoice, $bills, $add_cost)
|
||||
{
|
||||
$items = [
|
||||
[
|
||||
'description' => $invoice->plan_name,
|
||||
'details' => 'Monthly Subscription',
|
||||
'amount' => (float) $invoice->price
|
||||
]
|
||||
];
|
||||
|
||||
if ($add_cost > 0 && $invoice->routers != 'balance') {
|
||||
foreach ($bills as $description => $amount) {
|
||||
if (is_numeric($amount)) {
|
||||
$items[] = [
|
||||
'description' => $description,
|
||||
'details' => 'Additional Bill',
|
||||
'amount' => (float) $amount
|
||||
];
|
||||
} else {
|
||||
_log("Invalid bill amount for {$description}: {$amount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
private static function generatePaymentLink($account, $invoice, $status)
|
||||
{
|
||||
$token = User::generateToken($account->id, 1);
|
||||
if (empty($token['token'])) {
|
||||
return '?_route=home';
|
||||
}
|
||||
|
||||
$tur = ORM::for_table('tbl_user_recharges')
|
||||
->where('customer_id', $account->id)
|
||||
->where('namebp', $invoice->plan_name);
|
||||
|
||||
$tur->where('status', $status === 'Paid' ? 'on' : 'off');
|
||||
$turResult = $tur->find_one();
|
||||
|
||||
return $turResult ? '?_route=home&recharge=' . $turResult['id'] . '&uid=' . urlencode($token['token']) : '?_route=home';
|
||||
}
|
||||
|
||||
private static function getCompanyLogo($UPLOAD_PATH, $root_path)
|
||||
{
|
||||
$UPLOAD_URL_PATH = str_replace($root_path, '', $UPLOAD_PATH);
|
||||
return file_exists($UPLOAD_PATH . DIRECTORY_SEPARATOR . 'logo.png') ?
|
||||
$UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'logo.png?' . time() :
|
||||
$UPLOAD_URL_PATH . DIRECTORY_SEPARATOR . 'logo.default.png';
|
||||
}
|
||||
|
||||
private static function generateBillRows($items, $currency, $subtotal, $tax_rate, $tax, $total)
|
||||
@ -247,6 +271,22 @@ class Invoice
|
||||
return $html;
|
||||
}
|
||||
|
||||
|
||||
private static function saveToDatabase($filename, $customer_id, $invoiceData, $total)
|
||||
{
|
||||
$invoice = ORM::for_table('tbl_invoices')->create();
|
||||
$invoice->number = $invoiceData['invoice'];
|
||||
$invoice->customer_id = $customer_id;
|
||||
$invoice->fullname = $invoiceData['fullname'];
|
||||
$invoice->email = $invoiceData['email'];
|
||||
$invoice->address = $invoiceData['address'];
|
||||
$invoice->status = $invoiceData['status'];
|
||||
$invoice->due_date = $invoiceData['due_date'];
|
||||
$invoice->filename = $filename;
|
||||
$invoice->amount = $total;
|
||||
$invoice->data = json_encode($invoiceData);
|
||||
$invoice->created_at = date('Y-m-d H:i:s');
|
||||
$invoice->save();
|
||||
return $invoice->id;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user