| Server IP : 103.161.17.216 / Your IP : 216.73.216.1 Web Server : nginx/1.18.0 System : Linux tipsysaigoncharming 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64 User : www-data ( 33) PHP Version : 7.4.3-4ubuntu2.29 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /var/www/app.houseland.info/application/helpers/ |
Upload File : |
<?php
defined('BASEPATH') or exit('No direct script access allowed');
/**
* Get invoice short_url
* @since Version 2.7.3
* @param object $invoice
* @return string Url
*/
function get_invoice_shortlink($invoice)
{
$long_url = site_url("invoice/{$invoice->id}/{$invoice->hash}");
if (!get_option('bitly_access_token')) {
return $long_url;
}
// Check if invoice has short link, if yes return short link
if (!empty($invoice->short_link)) {
return $invoice->short_link;
}
// Create short link and return the newly created short link
$short_link = app_generate_short_link([
'long_url' => $long_url,
'title' => format_invoice_number($invoice->id),
]);
if ($short_link) {
$CI = &get_instance();
$CI->db->where('id', $invoice->id);
$CI->db->update(db_prefix() . 'invoices', [
'short_link' => $short_link,
]);
return $short_link;
}
return $long_url;
}
/**
* Get invoice total left for paying if not payments found the original total from the invoice will be returned
* @since Version 1.0.1
* @param mixed $id invoice id
* @param mixed $invoice_total
* @return mixed total left
*/
function get_invoice_total_left_to_pay($id, $invoice_total = null)
{
$CI = &get_instance();
if ($invoice_total === null) {
$CI->db->select('total')
->where('id', $id);
$invoice_total = $CI->db->get(db_prefix() . 'invoices')->row()->total;
}
if (!class_exists('payments_model')) {
$CI->load->model('payments_model');
}
if (!class_exists('credit_notes_model')) {
$CI->load->model('credit_notes_model');
}
$payments = $CI->payments_model->get_invoice_payments($id);
$credits = $CI->credit_notes_model->get_applied_invoice_credits($id);
$payments = array_merge($payments, $credits);
$totalPayments = 0;
$bcadd = function_exists('bcadd');
foreach ($payments as $payment) {
if ($bcadd) {
$totalPayments = bcadd($totalPayments, $payment['amount'], get_decimal_places());
} else {
$totalPayments += $payment['amount'];
}
}
if (function_exists('bcsub')) {
return bcsub($invoice_total, $totalPayments, get_decimal_places());
}
return number_format($invoice_total - $totalPayments, get_decimal_places(), '.', '');
}
/**
* Check if invoice email template for overdue notices is enabled
* @return boolean
*/
function is_invoices_email_overdue_notice_enabled()
{
return total_rows(db_prefix() . 'emailtemplates', ['slug' => 'invoice-overdue-notice', 'active' => 1]) > 0;
}
/**
* Check if invoice email template for due notices is enabled
*
* @since 2.8.0
*
* @return boolean
*/
function is_invoices_email_due_notice_enabled()
{
return total_rows(db_prefix() . 'emailtemplates', ['slug' => 'invoice-due-notice', 'active' => 1]) > 0;
}
/**
* Check if there are sources for sending invoice overdue notices
* Will be either email or SMS
* @return boolean
*/
function is_invoices_overdue_reminders_enabled()
{
return is_invoices_email_overdue_notice_enabled() || is_sms_trigger_active(SMS_TRIGGER_INVOICE_OVERDUE);
}
/**
* Check if there are sources for sending invoice due notices
* Will be either email or SMS
*
* @since 2.8.0
*
* @return boolean
*/
function is_invoices_due_reminders_enabled()
{
return is_invoices_email_due_notice_enabled() || is_sms_trigger_active(SMS_TRIGGER_INVOICE_DUE);
}
/**
* Check invoice restrictions - hash, clientid
* @since Version 1.0.1
* @param mixed $id invoice id
* @param string $hash invoice hash
*/
function check_invoice_restrictions($id, $hash)
{
$CI = &get_instance();
$CI->load->model('invoices_model');
if (!$hash || !$id) {
show_404();
}
if (!is_client_logged_in() && !is_staff_logged_in()) {
if (get_option('view_invoice_only_logged_in') == 1) {
redirect_after_login_to_current_url();
redirect(site_url('authentication/login'));
}
}
$invoice = $CI->invoices_model->get($id);
if (!$invoice || ($invoice->hash != $hash)) {
show_404();
}
// Do one more check
if (!is_staff_logged_in()) {
if (get_option('view_invoice_only_logged_in') == 1) {
if ($invoice->clientid != get_client_user_id()) {
show_404();
}
}
}
}
/**
* Format invoice status
* @param integer $status
* @param string $classes additional classes
* @param boolean $label To include in html label or not
* @return mixed
*/
function format_invoice_status($status, $classes = '', $label = true)
{
if (!class_exists('Invoices_model', false)) {
get_instance()->load->model('invoices_model');
}
$id = $status;
$label_class = get_invoice_status_label($status);
if ($status == Invoices_model::STATUS_UNPAID) {
$status = _l('invoice_status_unpaid');
} elseif ($status == Invoices_model::STATUS_PAID) {
$status = _l('invoice_status_paid');
} elseif ($status == Invoices_model::STATUS_PARTIALLY) {
$status = _l('invoice_status_not_paid_completely');
} elseif ($status == Invoices_model::STATUS_OVERDUE) {
$status = _l('invoice_status_overdue');
} elseif ($status == Invoices_model::STATUS_CANCELLED) {
$status = _l('invoice_status_cancelled');
} else {
// status 6
$status = _l('invoice_status_draft');
}
if ($label == true) {
return '<span class="label label-' . $label_class . ' ' . $classes . ' s-status invoice-status-' . e($id) . '">' . e($status) . '</span>';
}
return e($status);
}
/**
* Return invoice status label class baed on twitter bootstrap classses
* @param mixed $status invoice status id
* @return string
*/
function get_invoice_status_label($status)
{
if (!class_exists('Invoices_model', false)) {
get_instance()->load->model('invoices_model');
}
$label_class = '';
if ($status == Invoices_model::STATUS_UNPAID) {
$label_class = 'danger';
} elseif ($status == Invoices_model::STATUS_PAID) {
$label_class = 'success';
} elseif ($status == Invoices_model::STATUS_PARTIALLY) {
$label_class = 'warning';
} elseif ($status == Invoices_model::STATUS_OVERDUE) {
$label_class = 'warning';
} elseif ($status == Invoices_model::STATUS_CANCELLED || $status == Invoices_model::STATUS_DRAFT) {
$label_class = 'default';
} else {
if (!is_numeric($status)) {
if ($status == 'not_sent') {
$label_class = 'default';
}
}
}
return $label_class;
}
/**
* Check whether the given invoice is overdue
*
* @since 2.7.1
*
* @param Object|array $invoice
*
* @return boolean
*/
function is_invoice_overdue($invoice)
{
if (!class_exists('Invoices_model', false)) {
get_instance()->load->model('invoices_model');
}
$invoice = (object) $invoice;
if (!$invoice->duedate) {
return false;
}
if ($invoice->status == Invoices_model::STATUS_OVERDUE) {
return true;
}
return $invoice->status == Invoices_model::STATUS_PARTIALLY && get_total_days_overdue($invoice->duedate) > 0;
}
/**
* Function used in invoice PDF, this function will return RGBa color for PDF dcouments
* @param mixed $status_id current invoice status id
* @return string
*/
function invoice_status_color_pdf($status_id)
{
$statusColor = '';
if (!class_exists('Invoices_model', false)) {
get_instance()->load->model('invoices_model');
}
if ($status_id == Invoices_model::STATUS_UNPAID) {
$statusColor = '252, 45, 66';
} elseif ($status_id == Invoices_model::STATUS_PAID) {
$statusColor = '0, 191, 54';
} elseif ($status_id == Invoices_model::STATUS_PARTIALLY) {
$statusColor = '255, 111, 0';
} elseif ($status_id == Invoices_model::STATUS_OVERDUE) {
$statusColor = '255, 111, 0';
} elseif ($status_id == Invoices_model::STATUS_CANCELLED || $status_id == Invoices_model::STATUS_DRAFT) {
$statusColor = '114, 123, 144';
}
return hooks()->apply_filters('invoice_status_pdf_color', $statusColor, $status_id);
}
/**
* Update invoice status
* @param mixed $id invoice id
* @return mixed invoice updates status / if no update return false
* @return boolean $prevent_logging do not log changes if the status is updated for the invoice activity log
*/
function update_invoice_status($id, $force_update = false, $prevent_logging = false)
{
$CI = &get_instance();
$CI->load->model('invoices_model');
$invoice = $CI->invoices_model->get($id);
$original_status = $invoice->status;
if (($original_status == Invoices_model::STATUS_DRAFT && $force_update == false)
|| ($original_status == Invoices_model::STATUS_CANCELLED && $force_update == false)
) {
return false;
}
$CI->db->select('amount')
->where('invoiceid', $id)
->order_by(db_prefix() . 'invoicepaymentrecords.id', 'asc');
$payments = $CI->db->get(db_prefix() . 'invoicepaymentrecords')->result_array();
if (!class_exists('credit_notes_model')) {
$CI->load->model('credit_notes_model');
}
$credits = $CI->credit_notes_model->get_applied_invoice_credits($id);
// Merge credits applied with payments, credits in this function are casted as payments directly to invoice
// This merge will help to update the status
$payments = array_merge($payments, $credits);
$totalPayments = [];
$status = Invoices_model::STATUS_UNPAID;
// Check if the first payments is equal to invoice total
if (isset($payments[0])) {
if ($payments[0]['amount'] == $invoice->total) {
// Paid status
$status = Invoices_model::STATUS_PAID;
} else {
foreach ($payments as $payment) {
array_push($totalPayments, $payment['amount']);
}
$totalPayments = array_sum($totalPayments);
if ((function_exists('bccomp')
? bccomp($invoice->total, $totalPayments, get_decimal_places()) === 0
|| bccomp($invoice->total, $totalPayments, get_decimal_places()) === -1
: number_format(($invoice->total - $totalPayments), get_decimal_places(), '.', '') == '0')
|| $totalPayments > $invoice->total
) {
// Paid status
$status = Invoices_model::STATUS_PAID;
} elseif ($totalPayments == 0) {
// Unpaid status
$status = Invoices_model::STATUS_UNPAID;
} else {
if ($invoice->duedate != null) {
if ($totalPayments > 0) {
// Not paid completely status
$status = Invoices_model::STATUS_PARTIALLY;
} elseif (date('Y-m-d', strtotime($invoice->duedate)) < date('Y-m-d')) {
$status = Invoices_model::STATUS_OVERDUE;
}
} else {
// Not paid completely status
$status = Invoices_model::STATUS_PARTIALLY;
}
}
}
} else {
if ($invoice->total == 0) {
$status = Invoices_model::STATUS_PAID;
} else {
if ($invoice->duedate != null) {
if (date('Y-m-d', strtotime($invoice->duedate)) < date('Y-m-d')) {
// Overdue status
$status = Invoices_model::STATUS_OVERDUE;
}
}
}
}
$CI->db->where('id', $id);
$CI->db->update(db_prefix() . 'invoices', [
'status' => $status,
]);
if ($CI->db->affected_rows() > 0) {
hooks()->do_action('invoice_status_changed', ['invoice_id' => $id, 'status' => $status]);
if ($prevent_logging == true) {
return $status;
}
$log = 'Invoice Status Updated [Invoice Number: ' . format_invoice_number($invoice->id) . ', From: ' . format_invoice_status($original_status, '', false) . ' To: ' . format_invoice_status($status, '', false) . ']';
log_activity($log, null);
$additional_activity = serialize([
'<original_status>' . $original_status . '</original_status>',
'<new_status>' . $status . '</new_status>',
]);
$CI->invoices_model->log_invoice_activity($invoice->id, 'invoice_activity_status_updated', false, $additional_activity);
return $status;
}
return false;
}
/**
* Check if the invoice id is last invoice
* @param mixed $id invoice id
* @return boolean
*/
function is_last_invoice($id)
{
$CI = &get_instance();
$CI->db->select('id')->from(db_prefix() . 'invoices')->order_by('id', 'desc')->limit(1);
$query = $CI->db->get();
$last_invoice_id = $query->row()->id;
if ($last_invoice_id == $id) {
return true;
}
return false;
}
/**
* Format invoice number based on description
* @param mixed $id
* @return string
*/
function format_invoice_number($id)
{
$CI = &get_instance();
if (!is_object($id)) {
$CI->db->select('date,number,prefix,number_format,status')
->from(db_prefix() . 'invoices')
->where('id', $id);
$invoice = $CI->db->get()->row();
} else {
$invoice = $id;
$id = $invoice->id;
}
if (!$invoice) {
return '';
}
if (!class_exists('Invoices_model', false)) {
get_instance()->load->model('invoices_model');
}
if ($invoice->status == Invoices_model::STATUS_DRAFT) {
$number = $invoice->prefix . 'DRAFT';
} else {
$number = sales_number_format($invoice->number, $invoice->number_format, $invoice->prefix, $invoice->date);
}
return hooks()->apply_filters('format_invoice_number', $number, [
'id' => $id,
'invoice' => $invoice,
]);
}
/**
* Function that return invoice item taxes based on passed item id
* @param mixed $itemid
* @return array
*/
function get_invoice_item_taxes($itemid)
{
$CI = &get_instance();
$CI->db->where('itemid', $itemid);
$CI->db->where('rel_type', 'invoice');
$taxes = $CI->db->get(db_prefix() . 'item_tax')->result_array();
$i = 0;
foreach ($taxes as $tax) {
$taxes[$i]['taxname'] = $tax['taxname'] . '|' . $tax['taxrate'];
$i++;
}
return $taxes;
}
/**
* Check if payment mode is allowed for specific invoice
* @param mixed $id payment mode id
* @param mixed $invoiceid invoice id
* @return boolean
*/
function is_payment_mode_allowed_for_invoice($id, $invoiceid)
{
$CI = &get_instance();
$CI->db->select('' . db_prefix() . 'currencies.name as currency_name,allowed_payment_modes')->from(db_prefix() . 'invoices')->join(db_prefix() . 'currencies', '' . db_prefix() . 'currencies.id = ' . db_prefix() . 'invoices.currency', 'left')->where(db_prefix() . 'invoices.id', $invoiceid);
$invoice = $CI->db->get()->row();
$allowed_modes = $invoice->allowed_payment_modes;
if (!is_null($allowed_modes)) {
$allowed_modes = unserialize($allowed_modes);
if (count($allowed_modes) == 0) {
return false;
}
foreach ($allowed_modes as $mode) {
if ($mode == $id) {
// is offline payment mode
if (is_numeric($id)) {
return true;
}
// check currencies
$currencies = explode(',', get_option('paymentmethod_' . $id . '_currencies'));
foreach ($currencies as $currency) {
$currency = trim($currency);
if (mb_strtoupper($currency) == mb_strtoupper($invoice->currency_name)) {
return true;
}
}
return false;
}
}
} else {
return false;
}
return false;
}
/**
* Check if invoice mode exists in invoice
* @since Version 1.0.1
* @param array $modes all invoice modes
* @param mixed $invoiceid invoice id
* @param boolean $offline should check offline or online modes
* @return boolean
*/
function found_invoice_mode($modes, $invoiceid, $offline = true, $show_on_pdf = false)
{
$CI = &get_instance();
$CI->db->select('' . db_prefix() . 'currencies.name as currency_name,allowed_payment_modes')->from(db_prefix() . 'invoices')->join(db_prefix() . 'currencies', '' . db_prefix() . 'currencies.id = ' . db_prefix() . 'invoices.currency', 'left')->where(db_prefix() . 'invoices.id', $invoiceid);
$invoice = $CI->db->get()->row();
if (!is_null($invoice->allowed_payment_modes)) {
$invoice->allowed_payment_modes = unserialize($invoice->allowed_payment_modes);
if (count($invoice->allowed_payment_modes) == 0) {
return false;
}
foreach ($modes as $mode) {
if ($offline == true) {
if (is_numeric($mode['id']) && is_array($invoice->allowed_payment_modes)) {
foreach ($invoice->allowed_payment_modes as $allowed_mode) {
if ($allowed_mode == $mode['id']) {
if ($show_on_pdf == false) {
return true;
}
if ($mode['show_on_pdf'] == 1) {
return true;
}
return false;
}
}
}
} else {
if (!is_numeric($mode['id']) && !empty($mode['id'])) {
foreach ($invoice->allowed_payment_modes as $allowed_mode) {
if ($allowed_mode == $mode['id']) {
// Check for currencies
$currencies = explode(',', get_option('paymentmethod_' . $mode['id'] . '_currencies'));
foreach ($currencies as $currency) {
$currency = trim($currency);
if (strtoupper($currency) == strtoupper($invoice->currency_name)) {
return true;
}
}
}
}
}
}
}
}
return false;
}
/**
* This function do not work with cancelled status
* Calculate invoices percent by status
* @param mixed $status estimate status
* @param mixed $total_invoices in case the total is calculated in other place
* @return array
*/
function get_invoices_percent_by_status($status)
{
$has_permission_view = staff_can('view', 'invoices');
$total_invoices = total_rows(db_prefix() . 'invoices', 'status NOT IN(5)' . (!$has_permission_view ? ' AND (' . get_invoices_where_sql_for_staff(get_staff_user_id()) . ')' : ''));
$data = [];
$total_by_status = 0;
if (!is_numeric($status)) {
if ($status == 'not_sent') {
$total_by_status = total_rows(db_prefix() . 'invoices', 'sent=0 AND status NOT IN(2,5)' . (!$has_permission_view ? ' AND (' . get_invoices_where_sql_for_staff(get_staff_user_id()) . ')' : ''));
}
} else {
$total_by_status = total_rows(db_prefix() . 'invoices', 'status = ' . $status . ' AND status NOT IN(5)' . (!$has_permission_view ? ' AND (' . get_invoices_where_sql_for_staff(get_staff_user_id()) . ')' : ''));
}
$percent = ($total_invoices > 0 ? number_format(($total_by_status * 100) / $total_invoices, 2) : 0);
$data['total_by_status'] = $total_by_status;
$data['percent'] = $percent;
$data['total'] = $total_invoices;
return $data;
}
/**
* Check if staff member have assigned invoices / added as sale agent
* @param mixed $staff_id staff id to check
* @return boolean
*/
function staff_has_assigned_invoices($staff_id = '')
{
$CI = &get_instance();
$staff_id = is_numeric($staff_id) ? $staff_id : get_staff_user_id();
$cache = $CI->app_object_cache->get('staff-total-assigned-invoices-' . $staff_id);
if (is_numeric($cache)) {
$result = $cache;
} else {
$result = total_rows(db_prefix() . 'invoices', ['sale_agent' => $staff_id]);
$CI->app_object_cache->add('staff-total-assigned-invoices-' . $staff_id, $result);
}
return $result > 0 ? true : false;
}
/**
* Load invoices total templates
* This is the template where is showing the panels Outstanding Invoices, Paid Invoices and Past Due invoices
* @return string
*/
function load_invoices_total_template()
{
$CI = &get_instance();
$CI->load->model('invoices_model');
$_data = $CI->input->post();
if (!$CI->input->post('customer_id')) {
$multiple_currencies = call_user_func('is_using_multiple_currencies');
} else {
$_data['customer_id'] = $CI->input->post('customer_id');
$multiple_currencies = call_user_func('is_client_using_multiple_currencies', $CI->input->post('customer_id'));
}
if ($CI->input->post('project_id')) {
$_data['project_id'] = $CI->input->post('project_id');
}
if ($multiple_currencies) {
$CI->load->model('currencies_model');
$data['invoices_total_currencies'] = $CI->currencies_model->get();
}
$data['invoices_years'] = $CI->invoices_model->get_invoices_years();
if (
count($data['invoices_years']) >= 1
&& !\app\services\utilities\Arr::inMultidimensional($data['invoices_years'], 'year', date('Y'))
) {
array_unshift($data['invoices_years'], ['year' => date('Y')]);
}
$data['total_result'] = $CI->invoices_model->get_invoices_total($_data);
$data['_currency'] = $data['total_result']['currencyid'];
$CI->load->view('admin/invoices/invoices_total_template', $data);
}
function get_invoices_where_sql_for_staff($staff_id)
{
$CI = &get_instance();
$has_permission_view_own = staff_can('view_own', 'invoices');
$allow_staff_view_invoices_assigned = get_option('allow_staff_view_invoices_assigned');
$whereUser = '';
if ($has_permission_view_own) {
$whereUser = '((' . db_prefix() . 'invoices.addedfrom=' . $CI->db->escape_str($staff_id) . ' AND ' . db_prefix() . 'invoices.addedfrom IN (SELECT staff_id FROM ' . db_prefix() . 'staff_permissions WHERE feature = "invoices" AND capability="view_own"))';
if ($allow_staff_view_invoices_assigned == 1) {
$whereUser .= ' OR sale_agent=' . $CI->db->escape_str($staff_id);
}
$whereUser .= ')';
} else {
$whereUser .= 'sale_agent=' . $CI->db->escape_str($staff_id);
}
return $whereUser;
}
/**
* Check if staff member can view invoice
* @param mixed $id invoice id
* @param mixed $staff_id
* @return boolean
*/
function user_can_view_invoice($id, $staff_id = false)
{
$CI = &get_instance();
$staff_id = $staff_id ? $staff_id : get_staff_user_id();
if (has_permission('invoices', $staff_id, 'view')) {
return true;
}
$CI->db->select('id, addedfrom, sale_agent');
$CI->db->from(db_prefix() . 'invoices');
$CI->db->where('id', $id);
$invoice = $CI->db->get()->row();
if ((has_permission('invoices', $staff_id, 'view_own') && $invoice->addedfrom == $staff_id)
|| ($invoice->sale_agent == $staff_id && get_option('allow_staff_view_invoices_assigned') == '1')
) {
return true;
}
return false;
}