/home/smartonegroup/www/veroserv/system/models/Invoice.php
<?php
use chillerlan\QRCode\QRCode;
use Illuminate\Database\Eloquent\Model;
class Invoice extends Model
{
protected $table = 'sys_invoices';
public static function createInvoice($data)
{
global $config;
$datetime = date("Y-m-d H:i:s");
$today = date('Y-m-d');
$discount_type = 'f';
$discount_value = '0.00';
$actual_discount = '0.00';
$taxval = '0.00';
$taxname = '';
$taxrate = '0.00';
$notes = '';
$invoicenum = '';
$r = '0';
$nd = $today;
$currency = 0;
$currency_symbol = $config['currency_code'];
$currency_rate = 1.0;
$u = ORM::for_table('crm_accounts')->find($data['contact_id']);
$cid = $data['contact_id'];
if (!$u) {
return false;
}
$ticket_id = 0;
if (isset($data['ticket_id'])) {
$ticket_id = $data['ticket_id'];
}
$title = '';
if (isset($data['title'])) {
$title = $data['title'];
}
$cn = '';
if (isset($data['cn'])) {
$cn = $data['cn'];
}
$receipt_number = '';
if (isset($data['receipt_number'])) {
$receipt_number = $data['receipt_number'];
}
$fTotal = 0.0;
$idate = $today;
$its = strtotime($idate);
if (isset($config['invoice_default_date'])) {
$duedate = $config['invoice_default_date'];
if ($duedate == 'due_on_receipt') {
$dd = $today;
} elseif ($duedate == 'days3') {
$dd = date('Y-m-d', strtotime('+3 days', $its));
} elseif ($duedate == 'days5') {
$dd = date('Y-m-d', strtotime('+5 days', $its));
} elseif ($duedate == 'days7') {
$dd = date('Y-m-d', strtotime('+7 days', $its));
} elseif ($duedate == 'days10') {
$dd = date('Y-m-d', strtotime('+10 days', $its));
} elseif ($duedate == 'days15') {
$dd = date('Y-m-d', strtotime('+15 days', $its));
} elseif ($duedate == 'days30') {
$dd = date('Y-m-d', strtotime('+30 days', $its));
} elseif ($duedate == 'days45') {
$dd = date('Y-m-d', strtotime('+45 days', $its));
} elseif ($duedate == 'days60') {
$dd = date('Y-m-d', strtotime('+60 days', $its));
} else {
$dd = $today;
}
}
$vtoken = strtolower(Str::random(20));
$ptoken = strtolower(Str::random(20));
$d = ORM::for_table('sys_invoices')->create();
$d->userid = $cid;
$d->account = $u->account;
$d->date = $today;
$d->duedate = $dd;
$d->datepaid = $datetime;
$d->subtotal = $fTotal;
$d->discount_type = $discount_type;
$d->discount_value = $discount_value;
$d->discount = $actual_discount;
$d->total = $fTotal;
$d->tax = $taxval;
$d->taxname = $taxname;
$d->taxrate = $taxrate;
$d->vtoken = $vtoken;
$d->ptoken = $ptoken;
$d->status = 'Unpaid';
$d->notes = $notes;
$d->r = $r;
$d->nd = $nd;
$d->invoicenum = $invoicenum;
$d->cn = $cn;
$d->tax2 = '0.00';
$d->taxrate2 = '0.00';
$d->paymentmethod = '';
$d->currency = $currency;
$d->currency_symbol = $currency_symbol;
$d->currency_rate = $currency_rate;
$d->ticket_id = $ticket_id;
$d->title = $title;
$d->receipt_number = $receipt_number;
$d->save();
$invoiceid = $d->id();
$current_items = $data['items'];
foreach ($current_items as $e_i) {
$d = ORM::for_table('sys_invoiceitems')->create();
$d->invoiceid = $invoiceid;
$d->userid = $cid;
$d->description = $e_i['name'];
$d->qty = $e_i['qty'];
$d->amount = $e_i['price'];
$d->total = $e_i['price'] * $e_i['qty'];
$d->taxed = '0';
//others
$d->type = '';
$d->relid = '0';
$d->itemcode = '';
$d->taxamount = '0.00';
$d->duedate = date('Y-m-d');
$d->paymentmethod = '';
$d->notes = '';
$d->save();
}
return $invoiceid;
}
private static function getInvoiceNumberFromInvoice($next_invoice)
{
$invoice_number = '';
if (!empty($next_invoice->invoicenum)) {
$invoice_number .= $next_invoice->invoicenum;
}
return $invoice_number . ($next_invoice->cn ?? $next_invoice->id);
}
public function scopePaid($query)
{
return $query->where('status', '=', 'Paid');
}
public function scopeUnpaid($query)
{
return $query->where('status', '=', 'Unpaid');
}
public static function gen_email(
$iid,
$etpl,
$config = false,
$invoice = false
) {
if (!$config) {
global $config;
}
if (!$invoice) {
$invoice = Invoice::find($iid);
}
if ($etpl === 'created') {
$template_name = 'Invoice:Invoice Created';
} elseif ($etpl === 'reminder') {
$template_name = 'Invoice:Invoice Payment Reminder';
} elseif ($etpl === 'overdue') {
$template_name = 'Invoice:Invoice Overdue Notice';
} elseif ($etpl === 'confirm') {
$template_name = 'Invoice:Invoice Payment Confirmation';
} elseif ($etpl === 'refund') {
$template_name = 'Invoice:Invoice Refund Confirmation';
} else {
$invoice = false;
}
if ($invoice) {
$client = Contact::find($invoice->userid);
$email_template = EmailTemplate::where(
'tplname',
$template_name
)->first();
if ($email_template && $client) {
$dispid = $invoice->cn != '' ? $invoice->cn : $invoice->id;
$invoice_num = $invoice->invoicenum . $dispid;
$total = $invoice->total;
$credit = $invoice->credit;
$due_amount = $total - $credit;
$tax = $invoice->tax;
$taxrate = $invoice->taxrate;
$subtotal = $invoice->subtotal;
$subject = new Template($email_template->subject);
$subject->set('business_name', $config['CompanyName']);
$subject->set('invoice_id', $invoice_num);
$subj = $subject->output();
$message = new Template($email_template->message);
$message->set('name', $client->account);
$message->set('customer_name', $client->account);
$message->set('client_name', $client->account);
$message->set('company', $client->company);
$message->set('business_name', $config['CompanyName']);
$message->set(
'invoice_url',
BASE_URL .
'client/iview/' .
$invoice->id .
'/token_' .
$invoice->vtoken
);
$message->set('invoice_id', $invoice_num);
$message->set('invoice_status', $invoice->status);
$message->set(
'invoice_amount_paid',
number_format(
$credit,
2,
$config['dec_point'],
$config['thousands_sep']
)
);
$message->set(
'invoice_due_amount',
number_format(
$due_amount,
2,
$config['dec_point'],
$config['thousands_sep']
)
);
$message->set('invoice_taxname', $invoice->taxname);
$message->set(
'invoice_tax_amount',
number_format(
$tax,
2,
$config['dec_point'],
$config['thousands_sep']
)
);
$message->set(
'invoice_tax_rate',
number_format(
$taxrate,
2,
$config['dec_point'],
$config['thousands_sep']
)
);
$message->set(
'invoice_subtotal',
number_format(
$subtotal,
2,
$config['dec_point'],
$config['thousands_sep']
)
);
$message->set(
'invoice_due_date',
date($config['df'], strtotime($invoice->duedate))
);
$message->set(
'invoice_date',
date($config['df'], strtotime($invoice->date))
);
$message->set(
'invoice_amount',
number_format(
$total,
2,
$config['dec_point'],
$config['thousands_sep']
)
);
$message_o = $message->output();
$gen = [];
$gen['cid'] = $client->id;
$gen['name'] = $client->account;
$gen['email'] = $client->email;
$gen['subject'] = $subj;
$gen['body'] = $message_o;
return $gen;
}
} else {
return false;
}
}
public static function pdf($id, $r_type = '', $token = '')
{
global $app, $config, $_L, $pdf_tpl, $extraHtml;
$d = ORM::for_table('sys_invoices')->find($id);
if ($d) {
if ($token != '') {
$token = str_replace('token_', '', $token);
$vtoken = $d->vtoken;
if ($token != $vtoken) {
echo 'Sorry Token does not match!';
exit();
}
}
$items = ORM::for_table('sys_invoiceitems')
->where('invoiceid', $id)
->order_by_asc('id')
->find_many();
$trs_c = ORM::for_table('sys_transactions')
->where('iid', $id)
->count();
$trs = ORM::for_table('sys_transactions')
->where('iid', $id)
->order_by_desc('id')
->find_many();
$a = ORM::for_table('crm_accounts')->find($d['userid']);
$i_credit = $d['credit'];
$i_due = 0.0;
$i_total = $d['total'];
$i_due = $d['credit'] != '0.00' ? $i_total - $i_credit : $d['total'];
$cf = ORM::for_table('crm_customfields')
->where('showinvoice', 'Yes')
->order_by_asc('id')
->find_many();
$quote = false;
if ($d->quote_id != '0') {
$quote = ORM::for_table('sys_quotes')->find($d->quote_id);
}
$dispid = $d['cn'] != '' ? $d['cn'] : $d['id'];
$in = $d['invoicenum'] . $dispid;
$company = $a->cid != '' || $a->cid != 0 ? Company::find($a->cid) : false;
$pdf_c = '';
$ib_w_font = 'dejavusanscondensed';
if (!empty($config['pdf_font']) && $config['pdf_font'] == 'default') {
$pdf_c = 'c';
$ib_w_font = 'Helvetica';
}
try {
$mpdf = new \Mpdf\Mpdf();
$mpdf->SetTitle(($config['CompanyName'] ?? '') . ' Invoice');
$mpdf->SetAuthor($config['CompanyName']);
$mpdf->SetWatermarkText(__($d['status']));
if ($config['invoice_show_watermark'] == 1) {
$mpdf->showWatermarkText = true;
$mpdf->watermark_font = $ib_w_font;
$mpdf->watermarkTextAlpha = 0.1;
}
$mpdf->SetDisplayMode('fullpage');
if ($config['rtl'] == 1) {
$mpdf->SetDirectionality('rtl');
}
if ($config['pdf_font'] == 'AdobeCJK') {
$mpdf->useAdobeCJK = true;
$mpdf->autoScriptToLang = true;
$mpdf->autoLangToFont = true;
if (
isset($config['pdf_watermark_font']) &&
file_exists(
'vendor/mpdf/mpdf/ttfonts/' .
$config['pdf_watermark_font']
)
) {
$mpdf->watermark_font = $config['pdf_watermark_font'];
}
}
$invoice_append_footer = '';
global $invoice_append_footer;
$app->emit('client_invoice_printable', [&$d, &$a]);
$creating_pdf = true;
$pdf_tpl = APP_SYSTEM_PATH . '/lib/invoices/render.php';
if (file_exists(APP_SYSTEM_PATH . '/overrides/invoice_pdf.php')) {
$pdf_tpl = APP_SYSTEM_PATH . '/overrides/invoice_pdf.php';
}
$format_currency_override = [];
if (isset($config['decimal_places_products_and_services'])) {
$format_currency_override['precision'] =
$config['decimal_places_products_and_services'];
}
$invoice_url =
U . 'client/iview/' . $d->id . '/token_' . $d->vtoken;
$qr_code = (new QRCode())->render($invoice_url);
ob_start();
require $pdf_tpl;
$html = ob_get_contents();
ob_end_clean();
$mpdf->WriteHTML($html);
if ($r_type == 'dl') {
$mpdf->Output(date('Y-m-d') . _raid(4) . '.pdf', 'D'); # D
} elseif ($r_type == 'inline') {
$mpdf->Output(date('Y-m-d') . _raid(4) . '.pdf', 'I'); # D
} elseif ($r_type == 'store') {
$mpdf->Output(
__DIR__ .
'/../../storage/temp/' .
__('Invoice') .
'_' .
$in .
'.pdf',
'F'
); # D
} else {
$mpdf->Output(date('Y-m-d') . _raid(4) . '.pdf', 'I'); # D
}
} catch (\Exception $e) {
dd(
'An error occurred, probably related to your server! : ',
$e->getMessage(),
"\n"
);
}
}
}
public static function forSingleItem(
$cid,
$item,
$amount,
$is_credit_invoice = '0'
) {
global $config;
$datetime = date("Y-m-d H:i:s");
$today = date('Y-m-d');
$discount_type = 'f';
$discount_value = '0.00';
$actual_discount = '0.00';
$fTotal = $amount;
$taxval = '0.00';
$taxname = '';
$taxrate = '0.00';
$notes = '';
$invoicenum = $config['invoice_code_prefix'];
$r = '0';
$nd = $today;
$cn = str_pad(
$config['invoice_code_current_number'],
$config['number_pad'],
'0',
STR_PAD_LEFT
);
$currency = 0;
$currency_symbol = $config['currency_code'];
$currency_rate = 1.0;
$u = ORM::for_table('crm_accounts')->find($cid);
if (!$u) {
return false;
}
$vtoken = strtolower(Str::random(20));
$ptoken = strtolower(Str::random(20));
$d = ORM::for_table('sys_invoices')->create();
$d->userid = $cid;
$d->account = $u->account;
$d->date = $today;
$d->duedate = $today;
$d->datepaid = $datetime;
$d->subtotal = $amount;
$d->discount_type = $discount_type;
$d->discount_value = $discount_value;
$d->discount = $actual_discount;
$d->total = $fTotal;
$d->tax = $taxval;
$d->taxname = $taxname;
$d->taxrate = $taxrate;
$d->vtoken = $vtoken;
$d->ptoken = $ptoken;
$d->status = 'Unpaid';
$d->notes = $notes;
$d->r = $r;
$d->nd = $nd;
$d->invoicenum = $invoicenum;
$d->cn = $cn;
$d->tax2 = '0.00';
$d->taxrate2 = '0.00';
$d->paymentmethod = '';
$d->currency = $currency;
$d->currency_symbol = $currency_symbol;
$d->currency_rate = $currency_rate;
$d->is_credit_invoice = $is_credit_invoice;
$d->save();
$invoiceid = $d->id();
$sqty = 1;
$samount = $amount;
$ltotal = $amount;
$d = ORM::for_table('sys_invoiceitems')->create();
$d->invoiceid = $invoiceid;
$d->userid = $cid;
$d->description = $item;
$d->qty = $sqty;
$d->amount = $samount;
$d->total = $ltotal;
$d->taxed = '0';
$d->type = '';
$d->relid = '0';
$d->itemcode = '';
$d->taxamount = '0.00';
$d->duedate = date('Y-m-d');
$d->paymentmethod = '';
$d->notes = '';
$d->save();
$invoice = [];
$invoice['id'] = $invoiceid;
$invoice['vtoken'] = $vtoken;
update_option(
'invoice_code_current_number',
current_number_would_be($config['invoice_code_current_number'])
);
return $invoice;
}
public static function fromCart()
{
global $config;
$datetime = date("Y-m-d H:i:s");
$today = date('Y-m-d');
$discount_type = 'f';
$discount_value = '0.00';
$actual_discount = '0.00';
$taxval = '0.00';
$taxname = '';
$taxrate = '0.00';
$notes = $config['invoice_terms'] ?? '';
$invoicenum = $config['invoice_code_prefix'];
$r = '0';
$nd = $today;
$cn = str_pad(
$config['invoice_code_current_number'],
$config['number_pad'],
'0',
STR_PAD_LEFT
);
$currency = 0;
$currency_symbol = $config['currency_code'];
$currency_rate = 1.0;
if (isset($_COOKIE['ib_cart_secret'])) {
$secret = $_COOKIE['ib_cart_secret'];
$cart = ORM::for_table('sys_cart')
->where('secret', $secret)
->first();
if ($cart) {
$u = ORM::for_table('crm_accounts')->find($cart->cid);
$cid = $cart->cid;
if (!$u) {
return false;
}
$fTotal = $cart->total;
$vtoken = strtolower(Str::random(20));
$ptoken = strtolower(Str::random(20));
$d = ORM::for_table('sys_invoices')->create();
$d->userid = $cid;
$d->account = $u->account;
$d->date = $today;
$d->duedate = $today;
$d->datepaid = $datetime;
$d->subtotal = $fTotal;
$d->discount_type = $discount_type;
$d->discount_value = $discount_value;
$d->discount = $actual_discount;
$d->total = $fTotal;
$d->tax = $taxval;
$d->taxname = $taxname;
$d->taxrate = $taxrate;
$d->vtoken = $vtoken;
$d->ptoken = $ptoken;
$d->status = 'Unpaid';
$d->notes = $notes;
$d->r = $r;
$d->nd = $nd;
//others
$d->invoicenum = $invoicenum;
$d->cn = $cn;
$d->tax2 = '0.00';
$d->taxrate2 = '0.00';
$d->paymentmethod = '';
$d->currency = $currency;
$d->currency_symbol = $currency_symbol;
$d->currency_rate = $currency_rate;
$d->save();
$invoiceid = $d->id();
$invoice = $d;
update_option(
'invoice_code_current_number',
current_number_would_be(
$config['invoice_code_current_number']
)
);
$current_items = $cart->items;
$current_items_d = json_decode($current_items, true);
$tax_total = 0;
$subtotal = 0;
foreach ($current_items_d as $e_i) {
$item_obj = Item::find($e_i['id']);
$d = ORM::for_table('sys_invoiceitems')->create();
$d->invoiceid = $invoiceid;
$d->userid = $cid;
$d->description = $e_i['name'];
$d->qty = $e_i['qty'];
$d->amount = $e_i['price'];
$total = $e_i['price'] * $e_i['qty'];
$taxamount = 0.00;
if(!empty($e_i['tax1_rate']))
{
$tax1_rate = $e_i['tax1_rate'];
$taxamount = ($total * $tax1_rate) / 100;
}
$tax_total += $taxamount;
$subtotal += $total;
$d->total = $total;
// $total = $total + $taxamount;
$d->taxed = '0';
$d->tax_code = $item_obj->tax_code ?? '';
$d->type = '';
$d->relid = '0';
$d->itemcode = '';
$d->taxamount = '0.00';
$d->duedate = date('Y-m-d');
$d->paymentmethod = '';
$d->notes = '';
$d->save();
}
$invoice->tax = $tax_total;
$invoice->subtotal = $subtotal;
$invoice->save();
$cart->delete();
return $invoiceid;
}
}
return false;
}
public static function files($invoice_id)
{
$file_ids = ORM::for_table('ib_doc_rel')
->where('rtype', 'invoice')
->where('rid', $invoice_id)
->find_array();
$ids = [];
foreach ($file_ids as $f) {
$ids[] = $f['did'];
}
return empty($ids) ? [] : ORM::for_table('sys_documents')
->where_in('id', $ids)
->find_many();
}
public static function cloneInvoice($id)
{
global $config;
$inv = ORM::for_table('sys_invoices')->find($id);
if ($inv) {
$vtoken = strtolower(Str::random(20));
$ptoken = strtolower(Str::random(20));
$d = ORM::for_table('sys_invoices')->create();
$d->userid = $inv->userid;
$d->account = $inv->account;
$d->date = $inv->date;
$d->duedate = $inv->duedate;
$d->datepaid = $inv->datepaid;
$d->subtotal = $inv->subtotal;
$d->discount_type = $inv->discount_type;
$d->discount_value = $inv->discount_value;
$d->discount = $inv->discount;
$d->total = $inv->total;
$d->tax = $inv->tax;
$d->taxname = $inv->taxname;
$d->taxrate = $inv->taxrate;
$d->vtoken = $vtoken;
$d->ptoken = $ptoken;
$d->status = 'Unpaid';
$d->notes = $inv->notes;
$d->r = $inv->r;
$d->nd = $inv->nd;
$d->invoicenum = $inv->invoicenum;
$cn = str_pad(
$config['invoice_code_current_number'],
$config['number_pad'],
'0',
STR_PAD_LEFT
);
$d->cn = $cn;
update_option(
'invoice_code_current_number',
current_number_would_be($cn)
);
$d->tax2 = $inv->tax2;
$d->taxrate2 = $inv->taxrate2;
$d->paymentmethod = $inv->paymentmethod;
$d->currency = $inv->currency;
$d->currency_symbol = $inv->currency_symbol;
$d->currency_rate = $inv->currency_rate;
$d->save();
$invoiceid = $d->id();
$items = ORM::for_table('sys_invoiceitems')
->where('invoiceid', $id)
->order_by_asc('id')
->find_array();
foreach ($items as $item) {
$t = ORM::for_table('sys_invoiceitems')->create();
$t->invoiceid = $invoiceid;
$t->userid = $item['userid'];
$t->description = $item['description'];
$t->qty = $item['qty'];
$t->amount = $item['amount'];
$t->total = $item['total'];
$t->taxed = $item['taxed'];
$t->type = '';
$t->relid = '0';
$t->itemcode = '';
$t->taxamount = '0.00';
$t->duedate = date('Y-m-d');
$t->paymentmethod = '';
$t->notes = '';
$t->save();
}
return $invoiceid;
}
return false;
}
public static function genSMS($invoice, $tpl, $customer = false)
{
global $config;
if(!is_object($invoice))
{
$invoice = self::find($invoice);
}
if (!$invoice) {
return false;
}
if(!$customer)
{
$customer = Contact::find($invoice->userid);
}
if (!$customer) {
return false;
}
switch ($tpl) {
case 'created':
$tpl = SMSTemplate::where('tpl', 'Invoice Created')->first();
break;
case 'reminder':
$tpl = SMSTemplate::where(
'tpl',
'Invoice Payment Reminder'
)->first();
break;
case 'refund':
$tpl = SMSTemplate::where(
'tpl',
'Invoice Refund Confirmation'
)->first();
break;
case 'overdue':
$tpl = SMSTemplate::where(
'tpl',
'Invoice Overdue Notice'
)->first();
break;
case 'confirm':
$tpl = SMSTemplate::where(
'tpl',
'Invoice Payment Confirmation'
)->first();
break;
default:
$tpl = false;
break;
}
$dispid = $invoice->cn != '' ? $invoice->cn : $invoice->id;
$invoice_num = $invoice->invoicenum . $dispid;
$total = $invoice->total;
$credit = $invoice->credit;
$due_amount = $total - $credit;
$tax = $invoice->tax;
$taxrate = $invoice->taxrate;
$subtotal = $invoice->subtotal;
if ($invoice && $tpl) {
$message = new Template($tpl->sms);
$message->set('name', $customer->account);
$message->set('customer_name', $customer->account);
$message->set('client_name', $customer->account);
$message->set('company', $customer->company);
$message->set('business_name', $config['CompanyName']);
$message->set(
'invoice_url',
U .
'client/iview/' .
$invoice->id .
'/token_' .
$invoice->vtoken
);
$message->set(
'invoice_pdf_url',
U . 'client/ipdf/' . $invoice->id . '/token_' . $invoice->vtoken
);
$message->set('invoice_id', $invoice_num);
$message->set('invoice_status', $invoice->status);
$message->set(
'invoice_amount_paid',
number_format(
$credit,
2,
$config['dec_point'],
$config['thousands_sep']
)
);
$message->set(
'invoice_due_amount',
number_format(
$due_amount,
2,
$config['dec_point'],
$config['thousands_sep']
)
);
$message->set('invoice_taxname', $invoice->taxname);
$message->set(
'invoice_tax_amount',
number_format(
$tax,
2,
$config['dec_point'],
$config['thousands_sep']
)
);
$message->set(
'invoice_tax_rate',
number_format(
$taxrate,
2,
$config['dec_point'],
$config['thousands_sep']
)
);
$message->set(
'invoice_subtotal',
number_format(
$subtotal,
2,
$config['dec_point'],
$config['thousands_sep']
)
);
$message->set(
'invoice_due_date',
date($config['df'], strtotime($invoice->duedate))
);
$message->set(
'invoice_date',
date($config['df'], strtotime($invoice->date))
);
$message->set(
'invoice_amount',
number_format(
$total,
2,
$config['dec_point'],
$config['thousands_sep']
)
);
$message_o = $message->output();
return [
'tpl' => $tpl->tpl,
'to' => $customer->phone,
'sms' => $message_o,
];
} else {
return false;
}
}
public static function fromTicket($ticket_id, $extras)
{
$ticket = Ticket::find($ticket_id);
if (!$ticket) {
return [
'success' => false,
'error' => 'Ticket not found',
];
}
$invoice_exist = Invoice::where('ticket_id', $ticket_id)->first();
if ($invoice_exist) {
return [
'success' => false,
'error' => 'Invoice already exist for this ticket.',
];
}
$tasks = Task::where('rel_type', 'Ticket')
->where('rel_id', $ticket_id)
->get();
$replies = TicketReply::where('tid', $ticket->id)
->orderBy('id', 'desc')
->first();
$items = [];
$reply = TicketReply::where('tid', $ticket->id)
->orderBy('id', 'desc')
->first();
$qty = 1;
$ttotal = $ticket->ttotal;
if ($ttotal != '') {
$ttotal = explode(':', $ttotal);
if (isset($ttotal[0])) {
$hour = $ttotal[0];
}
if (isset($ttotal[1])) {
$minute = $ttotal[1];
$minute = round($minute / 60, 2);
}
$qty = $hour + $minute;
}
$price = 0.0;
$ticket_admin_id = $ticket->aid;
if ($ticket_admin_id != '' || $ticket_admin_id != '0') {
$ticket_admin = User::find($ticket_admin_id);
}
if ($reply) {
$items[] = [
'name' => $reply->message,
'qty' => $qty,
'price' => $price,
];
}
$receipt_number = '';
if (isset($extras['receipt_number'])) {
$receipt_number = $extras['receipt_number'];
}
$invoice = self::createInvoice([
'contact_id' => $ticket->userid,
'ticket_id' => $ticket_id,
'cn' => $ticket->tid,
'items' => $items,
'receipt_number' => $receipt_number,
]);
if ($invoice) {
$ticket->status = 'Closed';
$ticket->save();
return [
'success' => true,
'invoice' => $invoice,
];
}
return [
'success' => false,
'error' => 'An error occurred',
];
}
public static function getInvoicesSummaryForCustomer($customer_id)
{
$total_invoice_amount = 0.0;
$total_paid_amount = 0.0;
$total_unpaid_amount = 0.0;
$total_cancelled_amount = 0.0;
$total_partially_paid_amount = 0.0;
$invoices = Invoice::where('userid', $customer_id)->get();
$currencies = Currency::all()
->keyBy('cname')
->toArray();
$home_currency = homeCurrency();
foreach ($invoices as $invoice) {
if ($invoice->currency_iso_code != $home_currency->cname) {
$rate = 1;
if (isset($currencies[$invoice->currency_iso_code])) {
$rate = $currencies[$invoice->currency_iso_code]['rate'];
}
} else {
$rate = 1;
}
$invoice_total = $invoice->total;
$total_invoice_amount += $invoice_total * $rate;
if ($invoice->status == 'Unpaid') {
$total_unpaid_amount += $invoice_total * $rate;
} elseif ($invoice->status == 'Paid') {
$total_paid_amount += $invoice_total * $rate;
} elseif ($invoice->status == 'Partially Paid') {
$credit = $invoice->credit;
$invoice_total *= $rate;
$invoice_due = $invoice_total - $credit;
$total_paid_amount += $credit;
$total_unpaid_amount += $invoice_due;
$total_partially_paid_amount += $credit;
} elseif ($invoice->status == 'Cancelled') {
$total_cancelled_amount += $invoice_total * $rate;
}
}
return [
'invoices' => $invoices,
'total_invoiced_amount' => $total_invoice_amount,
'total_paid_amount' => $total_paid_amount,
'total_unpaid_amount' => $total_unpaid_amount,
'total_partially_paid_amount' => $total_partially_paid_amount,
'total_cancelled_amount' => $total_cancelled_amount,
];
}
public static function getInvoiceNumberById($id)
{
$invoice = Invoice::find($id);
if ($invoice) {
$ret_value = '';
if ($invoice->invoicenum) {
$ret_value .= $invoice->invoicenum;
}
if ($invoice->cn) {
$ret_value .= $invoice->cn;
}
if (!empty($ret_value)) {
return $ret_value;
}
}
return $id;
}
public static function getInvoiceNumber($invoice)
{
$ret_value = '';
if ($invoice->invoicenum) {
$ret_value .= $invoice->invoicenum;
}
if ($invoice->cn) {
$ret_value .= $invoice->cn;
}
if (!empty($ret_value)) {
return $ret_value;
}
return $invoice->id;
}
public static function generateRecurringInvoices($settings, $_L)
{
$today = date('Y-m-d');
$invoices_should_create_today = self::where('r', '!=', 0)
->where('nd', $today)
->get();
foreach ($invoices_should_create_today as $previous_invoice) {
$next_invoice_custom_number = str_pad(
$settings['invoice_code_current_number'],
$settings['number_pad'],
'0',
STR_PAD_LEFT
);
$previous_invoice_r = $previous_invoice->r;
$previous_invoice_due_date_timestamp = strtotime(
$previous_invoice->duedate
);
$next_invoice_date = $today;
$next_invoice_due_date = $today;
$previous_invoice_date = $previous_invoice->date;
$previous_invoice_due_date = $previous_invoice->due_date;
if ($previous_invoice_date && $previous_invoice_due_date) {
$previous_invoice_date_obj = new DateTime(
$previous_invoice_date
);
$previous_invoice_due_date_obj = new DateTime(
$previous_invoice_due_date
);
$payment_terms = $previous_invoice_due_date_obj->diff(
$previous_invoice_date_obj
);
if ($payment_terms->days) {
$interval = $payment_terms->days;
$next_invoice_due_date = date(
'Y-m-d',
strtotime('+' . $interval)
);
}
}
#nd = next date
$next_invoice_nd = date('Y-m-d', strtotime($previous_invoice_r));
$next_invoice = new self();
$next_invoice->userid = $previous_invoice->userid;
$next_invoice->account = $previous_invoice->account;
$next_invoice->date = $next_invoice_date;
$next_invoice->duedate = $next_invoice_due_date;
$next_invoice->subtotal = $previous_invoice->subtotal;
$next_invoice->total = $previous_invoice->total;
$next_invoice->tax = $previous_invoice->tax;
$next_invoice->taxname = $previous_invoice->taxname;
$next_invoice->taxrate = $previous_invoice->taxrate;
$next_invoice->vtoken = strtolower(Str::random(20));
$next_invoice->ptoken = strtolower(Str::random(20));
$next_invoice->status = 'Unpaid';
$next_invoice->notes = $previous_invoice->notes;
$next_invoice->currency_iso_code =
$previous_invoice->currency_iso_code;
$next_invoice->is_same_state = $previous_invoice->is_same_state;
$next_invoice->r = $previous_invoice->r;
$next_invoice->nd = $next_invoice_nd;
$next_invoice->invoicenum = $settings['invoice_code_prefix'] ?? '';
$next_invoice->cn = $next_invoice_custom_number;
$next_invoice->tax2 = $previous_invoice->tax2;
$next_invoice->taxrate2 = $previous_invoice->taxrate2;
$next_invoice->paymentmethod = $previous_invoice->paymentmethod;
$next_invoice->save();
$previous_invoice->r = 0;
$previous_invoice->save();
update_option(
'invoice_code_current_number',
current_number_would_be($next_invoice_custom_number)
);
$previous_invoice_items = InvoiceItem::where(
'invoiceid',
$previous_invoice->id
)
->orderBy('id', 'asc')
->get();
foreach ($previous_invoice_items as $previous_invoice_item) {
$new_invoice_item = new InvoiceItem();
$new_invoice_item->invoiceid = $next_invoice->id;
$new_invoice_item->userid = $previous_invoice_item->userid;
$new_invoice_item->description =
$previous_invoice_item->description;
$new_invoice_item->qty = $previous_invoice_item->qty;
$new_invoice_item->amount = $previous_invoice_item->amount;
$new_invoice_item->total = $previous_invoice_item->total;
$new_invoice_item->itemcode = $previous_invoice_item->itemcode;
$new_invoice_item->notes = $previous_invoice_item->notes;
$new_invoice_item->paymentmethod =
$previous_invoice_item->paymentmethod;
$new_invoice_item->relid = 0;
$new_invoice_item->type = '';
$new_invoice_item->taxed = $previous_invoice_item->taxed;
$new_invoice_item->save();
}
$msg = Invoice::gen_email(
$next_invoice->id,
'created',
$settings,
$next_invoice
);
$subject = $msg['subject'];
$body = $msg['body'];
$email = $msg['email'];
$name = $msg['name'];
Invoice::pdf($next_invoice->id, 'store');
$invoice_number = self::getInvoiceNumberFromInvoice($next_invoice);
$attachment_path =
'storage/temp/' .
__('Invoice') .
'_' .
$invoice_number .
'.pdf';
$attachment_file = __('Invoice') . '_' . $invoice_number . '.pdf';
Email::sendEmail(
$settings,
$_L,
$name,
$email,
$subject,
$body,
0,
$next_invoice->id,
'',
'',
$attachment_path,
$attachment_file
);
}
}
public static function sendPaymentReminder($settings, $_L)
{
$from = date('Y-m-d', strtotime('-3 days'));
$to = date('Y-m-d', strtotime('-1 days'));
$invoices = Invoice::where('status', 'Unpaid')
->whereBetween('duedate', [$from, $to])
->get();
foreach ($invoices as $invoice) {
$msg = Invoice::gen_email(
$invoice->id,
'reminder',
$settings,
$invoice
);
$subject = $msg['subject'];
$body = $msg['body'];
$email = $msg['email'];
$name = $msg['name'];
Email::sendEmail(
$settings,
$_L,
$name,
$email,
$subject,
$body,
0,
$invoice->id
);
}
}
public static function saveInvoice($data)
{
global $config;
$total = 0;
$tax = 0.0;
$taxname = '';
$tax2 = 0.0;
$taxrate = 0.0;
$taxrate2 = 0.0;
$paymentmethod = '';
$notes = $data['notes'] ?? '';
$next_invoice_custom_number = str_pad(
get_option('invoice_code_current_number'),
$config['number_pad'],
'0',
STR_PAD_LEFT
);
$today = date('Y-m-d');
$subtotal = 0;
foreach ($data['invoice_items'] as $item) {
$line_total = $item['amount'] * $item['quantity'];
$tax_amount = 0.0;
if(!empty($item['tax_rate']))
{
$tax_amount = $line_total * ($item['tax_rate'] / 100);
}
$tax += $tax_amount;
$total += $line_total + $tax_amount;
}
$invoice = new self();
$invoice->userid = $data['contact']->id;
$invoice->account = $data['contact']->account;
$invoice->date = $today;
$invoice->duedate = $data['due_date'] ?? $today;
$invoice->subtotal = $total;
$invoice->total = $total;
$invoice->tax = $tax;
$invoice->taxname = $taxname;
$invoice->taxrate = $taxrate;
$invoice->vtoken = strtolower(Str::random(20));
$invoice->ptoken = strtolower(Str::random(20));
$invoice->status = 'Unpaid';
$invoice->notes = $notes;
$invoice->currency_iso_code = $config['home_currency'];
$invoice->invoicenum = $config['invoice_code_prefix'] ?? '';
$invoice->cn = $next_invoice_custom_number;
$invoice->tax2 = $tax2;
$invoice->taxrate2 = $taxrate2;
$invoice->paymentmethod = $paymentmethod;
$invoice->save();
foreach ($data['invoice_items'] as $item) {
$line_total = $item['amount'] * $item['quantity'];
$invoice_item = new InvoiceItem();
$invoice_item->invoiceid = $invoice->id;
$invoice_item->userid = $data['contact']->id;
$invoice_item->relid = 0;
$invoice_item->itemcode = '';
$invoice_item->type = '';
$invoice_item->taxed = 1;
$invoice_item->description = $item['name'];
$invoice_item->amount = $item['amount'];
$invoice_item->total = $line_total;
$invoice_item->qty = $item['quantity'];
$invoice_item->paymentmethod = '';
$invoice_item->notes = '';
$invoice_item->save();
}
$invoice_code_current_number =
(int) $config['invoice_code_current_number'];
update_option(
'invoice_code_current_number',
$invoice_code_current_number + 1
);
return $invoice;
}
}