<?php
	
	defined('BASEPATH') or exit('No direct script access allowed');
	
	/**
	 * Get proforma total left for paying if not payments found the original total from the proforma will be returned
	 * @since  Version 1.0.1
	 * @param  mixed $id     proforma id
	 * @param  mixed $proforma_total
	 * @return mixed  total left
	 */
	function get_proforma_total_left_to_pay($id, $proforma_total = null)
	{
		$CI = & get_instance();
		
		if ($proforma_total === null) {
			$CI->db->select('total')
						 ->where('id', $id);
			$proforma_total = $CI->db->get(db_prefix() . 'proformas')->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_proforma_payments($id);
		//$credits  = $CI->credit_notes_model->get_applied_proforma_credits($id);
		$payments = $credits = array();
		$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($proforma_total, $totalPayments, get_decimal_places());
		}
		
		return number_format($proforma_total - $totalPayments, get_decimal_places(), '.', '');
	}
	
	/**
	 * Check if proforma email template for overdue notices is enabled
	 * @return boolean
	 */
	function is_proformas_email_overdue_notice_enabled()
	{
		return total_rows(db_prefix() . 'emailtemplates', ['slug' => 'proforma-overdue-notice', 'active' => 1]) > 0;
	}
	
	/**
	 * Check if there are sources for sending proforma overdue notices
	 * Will be either email or SMS
	 * @return boolean
	 */
	function is_proformas_overdue_reminders_enabled()
	{
		return is_proformas_email_overdue_notice_enabled() || is_sms_trigger_active(SMS_TRIGGER_INVOICE_OVERDUE);
	}
	
	/**
	 * Check proforma restrictions - hash, clientid
	 * @since  Version 1.0.1
	 * @param  mixed $id   proforma id
	 * @param  string $hash proforma hash
	 */
	function check_proforma_restrictions($id, $hash)
	{
		$CI = & get_instance();
		$CI->load->model('proformas_model');
		if (!$hash || !$id) {
			show_404();
		}
		if (!is_client_logged_in() && !is_staff_logged_in()) {
			if (get_option('view_proforma_only_logged_in') == 1) {
				redirect_after_login_to_current_url();
				redirect(site_url('authentication/login'));
			}
		}
		$proforma = $CI->proformas_model->get($id);
		if (!$proforma || ($proforma->hash != $hash)) {
			show_404();
		}
		
		// Do one more check
		if (!is_staff_logged_in()) {
			if (get_option('view_proforma_only_logged_in') == 1) {
				if ($proforma->clientid != get_client_user_id()) {
					show_404();
				}
			}
		}
	}
	
	/**
	 * Format proforma status
	 * @param  integer  $status
	 * @param  string  $classes additional classes
	 * @param  boolean $label   To include in html label or not
	 * @return mixed
	 */
	function format_proforma_status($status, $classes = '', $label = true)
	{
		if (!class_exists('Proformas_model', false)) {
			get_instance()->load->model('proformas_model');
		}
		
		$id          = $status;
		$label_class = get_proforma_status_label($status);
		if ($status == Proformas_model::STATUS_UNPAID) {
			$status = _l('proforma_status_unpaid');
		} elseif ($status == Proformas_model::STATUS_PAID) {
			$status = _l('proforma_status_paid');
		} elseif ($status == Proformas_model::STATUS_PARTIALLY) {
			$status = _l('proforma_status_not_paid_completely');
		} elseif ($status == Proformas_model::STATUS_OVERDUE) {
			$status = _l('proforma_status_overdue');
		} elseif ($status == Proformas_model::STATUS_CANCELLED) {
			$status = _l('proforma_status_cancelled');
		} else {
			// status 6
			$status = _l('proforma_status_draft');
		}
		if ($label == true) {
            return '<span class="label label-' . $label_class . ' ' . $classes . ' s-status proforma-status-' . $id . '">' . $status . '</span>';
        }
		
		return $status;
	}

/**
 * Format proforma status
 * @param  integer  $status
 * @param  string  $classes additional classes
 * @param  boolean $label   To include in html label or not
 * @return mixed
 */
function format_proforma_status_portal($status, $classes = '', $label = true)
{
    if (!class_exists('Proformas_model', false)) {
        get_instance()->load->model('proformas_model');
    }

    $id          = $status;
    $label_class = get_proforma_status_label($status);
    if ($status == Proformas_model::STATUS_UNPAID) {
        $status = _l('portal_proforma_status_unpaid');
    } elseif ($status == Proformas_model::STATUS_PAID) {
        $status = _l('portal_proforma_status_paid');
    } elseif ($status == Proformas_model::STATUS_PARTIALLY) {
        $status = _l('portal_proforma_status_not_paid_completely');
    } elseif ($status == Proformas_model::STATUS_OVERDUE) {
        $status = _l('portal_proforma_status_overdue');
    } elseif ($status == Proformas_model::STATUS_CANCELLED) {
        $status = _l('portal_proforma_status_cancelled');
    } else {
        // status 6
        $status = _l('portal_proforma_status_draft');
    }
    if ($label == true) {
        return '<span class="label label-' . $label_class . ' ' . $classes . ' s-status proforma-status-' . $id . '">' . $status . '</span>';
    }

    return $status;
}

	/**
	 * Return proforma status label class baed on twitter bootstrap classses
	 * @param  mixed $status proforma status id
	 * @return string
	 */
	function get_proforma_status_label($status)
	{
		if (!class_exists('Proformas_model', false)) {
			get_instance()->load->model('proformas_model');
		}
		
		$label_class = '';
		if ($status == Proformas_model::STATUS_UNPAID) {
			$label_class = 'danger';
		} elseif ($status == Proformas_model::STATUS_PAID) {
			$label_class = 'success';
		} elseif ($status == Proformas_model::STATUS_PARTIALLY) {
			$label_class = 'warning';
		} elseif ($status == Proformas_model::STATUS_OVERDUE) {
			$label_class = 'warning';
		} elseif ($status == Proformas_model::STATUS_CANCELLED || $status == Proformas_model::STATUS_DRAFT) {
			$label_class = 'default';
		} else {
			if (!is_numeric($status)) {
				if ($status == 'not_sent') {
					$label_class = 'default';
				}
			}
		}
		
		return $label_class;
	}
	
	/**
	 * Function used in proforma PDF, this function will return RGBa color for PDF dcouments
	 * @param  mixed $status_id current proforma status id
	 * @return string
	 */
	function proforma_status_color_pdf($status_id)
	{
		$statusColor = '';
		
		if (!class_exists('Proformas_model', false)) {
			get_instance()->load->model('proformas_model');
		}
		
		if ($status_id == Proformas_model::STATUS_UNPAID) {
			$statusColor = '252, 45, 66';
		} elseif ($status_id == Proformas_model::STATUS_PAID) {
			$statusColor = '0, 191, 54';
		} elseif ($status_id == Proformas_model::STATUS_PARTIALLY) {
			$statusColor = '255, 111, 0';
		} elseif ($status_id == Proformas_model::STATUS_OVERDUE) {
			$statusColor = '255, 111, 0';
		} elseif ($status_id == Proformas_model::STATUS_CANCELLED || $status_id == Proformas_model::STATUS_DRAFT) {
			$statusColor = '114, 123, 144';
		}
		
		return hooks()->apply_filters('proforma_status_pdf_color', $statusColor, $status_id);
	}
	
	/**
	 * Update proforma status
	 * @param  mixed $id proforma id
	 * @return mixed proforma updates status / if no update return false
	 * @return boolean $prevent_logging do not log changes if the status is updated for the proforma activity log
	 */
	function update_proforma_status($id, $force_update = false, $prevent_logging = false)
	{
		$CI = & get_instance();
		
		$CI->load->model('proformas_model');
		$proforma = $CI->proformas_model->get($id);
		
		$original_status = $proforma->status;
		
		if (($original_status == Proformas_model::STATUS_DRAFT && $force_update == false)
			|| ($original_status == Proformas_model::STATUS_CANCELLED && $force_update == false)) {
			return false;
		}
		
		$CI->db->select('amount')
					 ->where('proformaid', $id)
					 ->order_by(db_prefix() . 'proformapaymentrecords.id', 'asc');
		$payments = $CI->db->get(db_prefix() . 'proformapaymentrecords')->result_array();
		
		if (!class_exists('credit_notes_model')) {
			$CI->load->model('credit_notes_model');
		}
		
		//$credits = $CI->credit_notes_model->get_applied_proforma_credits($id);
		// Merge credits applied with payments, credits in this function are casted as payments directly to proforma
		// This merge will help to update the status
		$payments = $credits = array();
		$payments = array_merge($payments, $credits);
		
		$totalPayments = [];
		$status        = Proformas_model::STATUS_UNPAID;
		
		// Check if the first payments is equal to proforma total
		if (isset($payments[0])) {
			if ($payments[0]['amount'] == $proforma->total) {
				// Paid status
				$status = Proformas_model::STATUS_PAID;
			} else {
				foreach ($payments as $payment) {
					array_push($totalPayments, $payment['amount']);
				}
				
				$totalPayments = array_sum($totalPayments);
				
				if ((function_exists('bccomp')
						?  bccomp($proforma->total, $totalPayments, get_decimal_places()) === 0
						|| bccomp($proforma->total, $totalPayments, get_decimal_places()) === -1
						: number_format(($proforma->total - $totalPayments), get_decimal_places(), '.', '') == '0')
					|| $totalPayments > $proforma->total) {
					// Paid status
					$status = Proformas_model::STATUS_PAID;
				} elseif ($totalPayments == 0) {
					// Unpaid status
					$status = Proformas_model::STATUS_UNPAID;
				} else {
					if ($proforma->duedate != null) {
						if ($totalPayments > 0) {
							// Not paid completely status
							$status = Proformas_model::STATUS_PARTIALLY;
						} elseif (date('Y-m-d', strtotime($proforma->duedate)) < date('Y-m-d')) {
							$status = Proformas_model::STATUS_OVERDUE;
						}
					} else {
						// Not paid completely status
						$status = Proformas_model::STATUS_PARTIALLY;
					}
				}
			}
		} else {
			if ($proforma->total == 0) {
				$status = Proformas_model::STATUS_PAID;
			} else {
				if ($proforma->duedate != null) {
					if (date('Y-m-d', strtotime($proforma->duedate)) < date('Y-m-d')) {
						// Overdue status
						$status = Proformas_model::STATUS_OVERDUE;
					}
				}
			}
		}
		
		$CI->db->where('id', $id);
		$CI->db->update(db_prefix() . 'proformas', [
			'status' => $status,
		]);
		
		if ($CI->db->affected_rows() > 0) {
			hooks()->do_action('proforma_status_changed', ['proforma_id' => $id, 'status' => $status]);
			if ($prevent_logging == true) {
				return $status;
			}
			
			$log = 'Invoice Status Updated [Invoice Number: ' . format_proforma_number($proforma->id) . ', From: ' . format_proforma_status($original_status, '', false) . ' To: ' . format_proforma_status($status, '', false) . ']';
			
			log_activity($log, null);
			
			$additional_activity = serialize([
				'<original_status>' . $original_status . '</original_status>',
				'<new_status>' . $status . '</new_status>',
			]);
			
			$CI->proformas_model->log_proforma_activity($proforma->id, 'proforma_activity_status_updated', false, $additional_activity);
			
			return $status;
		}
		
		return false;
	}
	
	
	/**
	 * Check if the proforma id is last proforma
	 * @param  mixed  $id proforma id
	 * @return boolean
	 */
	function is_last_proforma($id)
	{
		$CI = & get_instance();
		$CI->db->select('id')->from(db_prefix() . 'proformas')->order_by('id', 'desc')->limit(1);
		$query           = $CI->db->get();
		$last_proforma_id = $query->row()->id;
		if ($last_proforma_id == $id) {
			return true;
		}
		
		return false;
	}
	
	/**
	 * Format proforma number based on description
	 * @param  mixed $id
	 * @return string
	 */
	function format_proforma_number($id)
	{
		$CI = & get_instance();
		$CI->db->select('date,number,prefix,number_format')->from(db_prefix() . 'proformas')->where('id', $id);
		$proforma = $CI->db->get()->row();
		//pre($proforma);
		if (!$proforma) {
			return '';
		}
		
		$number = (string)$proforma->prefix.' '.(string)$proforma->number;
		//pre($number);
		return $number;
		return hooks()->apply_filters('format_proforma_number', $number, [
			'id'      => $id,
			'proforma' => $proforma,
		]);
	}
	
	/**
	 * Function that return proforma item taxes based on passed item id
	 * @param  mixed $itemid
	 * @return array
	 */
	function get_proforma_item_taxes($itemid)
	{
		$CI = & get_instance();
		$CI->db->where('itemid', $itemid);
		$CI->db->where('rel_type', 'proforma');
		$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 proforma
	 * @param  mixed  $id payment mode id
	 * @param  mixed  $proformaid proforma id
	 * @return boolean
	 */
	function is_payment_mode_allowed_for_proforma($id, $proformaid)
	{
		$CI = & get_instance();
		$CI->db->select('' . db_prefix() . 'currencies.name as currency_name,allowed_payment_modes')->from(db_prefix() . 'proformas')->join(db_prefix() . 'currencies', '' . db_prefix() . 'currencies.id = ' . db_prefix() . 'proformas.currency', 'left')->where(db_prefix() . 'proformas.id', $proformaid);
		$proforma       = $CI->db->get()->row();
		$allowed_modes = $proforma->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($proforma->currency_name)) {
							return true;
						}
					}
					
					return false;
				}
			}
		} else {
			return false;
		}
		
		return false;
	}
	/**
	 * Check if proforma mode exists in proforma
	 * @since  Version 1.0.1
	 * @param  array  $modes     all proforma modes
	 * @param  mixed  $proformaid proforma id
	 * @param  boolean $offline   should check offline or online modes
	 * @return boolean
	 */
	function found_proforma_mode($modes, $proformaid, $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() . 'proformas')->join(db_prefix() . 'currencies', '' . db_prefix() . 'currencies.id = ' . db_prefix() . 'proformas.currency', 'left')->where(db_prefix() . 'proformas.id', $proformaid);
		$proforma = $CI->db->get()->row();
		if (!is_null($proforma->allowed_payment_modes)) {
			$proforma->allowed_payment_modes = unserialize($proforma->allowed_payment_modes);
			if (count($proforma->allowed_payment_modes) == 0) {
				return false;
			}
			foreach ($modes as $mode) {
				if ($offline == true) {
					if (is_numeric($mode['id']) && is_array($proforma->allowed_payment_modes)) {
						foreach ($proforma->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 ($proforma->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($proforma->currency_name)) {
										return true;
									}
								}
							}
						}
					}
				}
			}
		}
		
		return false;
	}
	
	/**
	 * This function do not work with cancelled status
	 * Calculate proformas percent by status
	 * @param  mixed $status          estimate status
	 * @param  mixed $total_proformas in case the total is calculated in other place
	 * @return array
	 */
	function get_proformas_percent_by_status($status)
	{
		$has_permission_view = has_permission('proformas', '', 'view');
		$total_proformas      = total_rows(db_prefix() . 'proformas', 'status NOT IN(5)' . (!$has_permission_view ? ' AND (' . get_proformas_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() . 'proformas', 'sent=0 AND status NOT IN(2,5)' . (!$has_permission_view ? ' AND (' . get_proformas_where_sql_for_staff(get_staff_user_id()) . ')' : ''));
			}
		} else {
			$total_by_status = total_rows(db_prefix() . 'proformas', 'status = ' . $status . ' AND status NOT IN(5)' . (!$has_permission_view ? ' AND (' . get_proformas_where_sql_for_staff(get_staff_user_id()) . ')' : ''));
		}
		$percent                 = ($total_proformas > 0 ? number_format(($total_by_status * 100) / $total_proformas, 2) : 0);
		$data['total_by_status'] = $total_by_status;
		$data['percent']         = $percent;
		$data['total']           = $total_proformas;
		
		return $data;
	}
	/**
	 * Check if staff member have assigned proformas / added as sale agent
	 * @param  mixed $staff_id staff id to check
	 * @return boolean
	 */
	function staff_has_assigned_proformas($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-proformas-' . $staff_id);
		
		if (is_numeric($cache)) {
			$result = $cache;
		} else {
			$result = total_rows(db_prefix() . 'proformas', ['sale_agent' => $staff_id]);
			$CI->app_object_cache->add('staff-total-assigned-proformas-' . $staff_id, $result);
		}
		
		return $result > 0 ? true : false;
	}
	
	/**
	 * Load proformas total templates
	 * This is the template where is showing the panels Outstanding Invoices, Paid Invoices and Past Due proformas
	 * @return string
	 */
	function load_proformas_total_template()
	{
		$CI = &get_instance();
		$CI->load->model('proformas_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['proformas_total_currencies'] = $CI->currencies_model->get();
		}
		
		$data['proformas_years'] = $CI->proformas_model->get_proformas_years();
		
		if (count($data['proformas_years']) >= 1
			&& !\app\services\utilities\Arr::inMultidimensional($data['proformas_years'], 'year', date('Y'))) {
			array_unshift($data['proformas_years'], ['year' => date('Y')]);
		}
		
		$data['total_result'] = $CI->proformas_model->get_proformas_total($_data);
		$data['_currency']    = $data['total_result']['currencyid'];
		
		$CI->load->view('admin/proformas/proformas_total_template', $data);
	}
	
	function get_proformas_where_sql_for_staff($staff_id)
	{
		$CI                                 = &get_instance();
		$has_permission_view_own            = has_permission('proformas', '', 'view_own');
		$allow_staff_view_proformas_assigned = get_option('allow_staff_view_proformas_assigned');
		$whereUser                          = '';
		if ($has_permission_view_own) {
			$whereUser = '((' . db_prefix() . 'proformas.addedfrom=' . $CI->db->escape_str($staff_id) . ' AND ' . db_prefix() . 'proformas.addedfrom IN (SELECT staff_id FROM ' . db_prefix() . 'staff_permissions WHERE feature = "proformas" AND capability="view_own"))';
			if ($allow_staff_view_proformas_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 proforma
	 * @param  mixed $id proforma id
	 * @param  mixed $staff_id
	 * @return boolean
	 */
	function user_can_view_proforma($id, $staff_id = false)
	{
		$CI = &get_instance();
		
		$staff_id = $staff_id ? $staff_id : get_staff_user_id();
		
		if (has_permission('proformas', $staff_id, 'view')) {
			return true;
		}
		
		$CI->db->select('id, addedfrom, sale_agent');
		$CI->db->from(db_prefix() . 'proformas');
		$CI->db->where('id', $id);
		$proforma = $CI->db->get()->row();
		
		if ((has_permission('proformas', $staff_id, 'view_own') && $proforma->addedfrom == $staff_id)
			|| ($proforma->sale_agent == $staff_id && get_option('allow_staff_view_proformas_assigned') == '1')) {
			return true;
		}
		
		return false;
	}
