<?php

if (!defined('BASEPATH'))
	exit('No direct script access allowed');

class Invoice extends Admin_Controller
{

	public function __construct()
	{
		parent::__construct();
		$this->load->model('invoice_model');
		$this->load->model('finance_report_model');
		$this->load->model('items_model');
		$this->load->library('gst');
		$this->load->library('sms');
	}

	public function invoice_state_report()
	{
		if (!$this->input->is_ajax_request()) {
			redirect('admin/dashboard');
		}
		$data = array();
		$pathonor_jonno['invoice_state_report_div'] = $this->load->view("admin/invoice/invo_data_2", $data, true);
		echo json_encode($pathonor_jonno);
		exit;
	}

	public function invo_data()
	{
		// cheeck its ajax request then redirect to admin/dashboard
		if (!$this->input->is_ajax_request()) {
			redirect('admin/dashboard');
		}
		$all_valid_invo_total = 0;
		$today_valid_invo_total = 0;
		$past_overdue = 0;
		$all_paid_amount = 0;
		$invoice_overdue_no = 0;
		$today = date('Y-m-d');
		$visible_invoices = $this->invoice_model->get_permission('tbl_invoices');

		if (!empty($visible_invoices)) {
			$financial_map = $this->invoice_model->get_invoice_financial_map($visible_invoices);
			$visible_invoice_ids = array();

			foreach ($visible_invoices as $invoice_row) {
				$invoice_id = (int) $invoice_row->invoices_id;
				$visible_invoice_ids[] = $invoice_id;

				$status = strtolower(trim((string) $invoice_row->status));
				if ($status === 'draft' || $status === 'cancelled') {
					continue;
				}

				$financial = isset($financial_map[$invoice_id]) ? $financial_map[$invoice_id] : array(
					'total' => 0,
					'due' => 0,
					'paid_amount' => 0,
					'status' => lang('not_paid'),
				);

				$all_valid_invo_total += (float) $financial['total'];
				$all_paid_amount += (float) $financial['paid_amount'];

				if ((string) $invoice_row->invoice_date === $today) {
					$today_valid_invo_total += (float) $financial['total'];
				}

				if (!empty($invoice_row->due_date) && $invoice_row->due_date < $today && (float) $financial['due'] > 0) {
					$invoice_overdue_no++;
					$past_overdue += (float) $financial['due'];
				}
			}

			$visible_invoice_ids = array_values(array_unique(array_filter($visible_invoice_ids)));
			if (!empty($visible_invoice_ids)) {
				$payment_today = $this->finance_report_model->sum_payment_amount(
					array('payment_date' => $today),
					array('invoices_id' => $visible_invoice_ids)
				);
			} else {
				$payment_today = 0;
			}
		} else {
			$payment_today = 0;
		}

		$res['client_outstanding'] = display_money($all_valid_invo_total - $all_paid_amount, default_currency());
		$res['total_invo_amount'] = $res['total_invoice_amount'] = display_money($all_valid_invo_total, default_currency());
		$res['today_invo_amount'] = display_money($today_valid_invo_total, default_currency());
		$res['paid_invo_amount'] = $res['total_receipts'] = display_money($all_paid_amount, default_currency());
		$res['payment_today'] = display_money($payment_today, default_currency());
		$res['past_overdue'] = display_money($past_overdue, default_currency());
		$res['invoice_overdue_no'] = $invoice_overdue_no;
		$data = array();
		//$res['state_report'] = $this->load->view('admin/invoice/invo_data', $data, TRUE);
		echo json_encode($res);
		exit();
	}

	public function createinvoice($action = NULL, $id = NULL, $item_id = NULL)
	{
		$data['page'] = lang('sales');

		if ($action == 'all_payments') {
			$data['sub_active'] = lang('payments_received');
		} else {
			$data['sub_active'] = lang('invoice');
		}
		if (!empty($item_id)) {
			$can_edit = $this->invoice_model->can_action('tbl_invoices', 'edit', array('invoices_id' => $id));

			if (!empty($can_edit)) {

				$data['item_info'] = $this->invoice_model->check_by(array('items_id' => $item_id), 'tbl_items');
			}
		}
		if (!empty($id) && $action != 'payments_details') {
			// get all invoice info by id
			$can_edit = $this->invoice_model->can_action('tbl_invoices', 'edit', array('invoices_id' => $id));

			if (!empty($can_edit)) {
				$data['invoice_info'] = $this->invoice_model->check_by(array('invoices_id' => $id), 'tbl_invoices');
				if (!empty($data['invoice_info']->client_id)) {
					$data['invoices_to_merge'] = $this->invoice_model->check_for_merge_invoice($data['invoice_info']->client_id, $id);
				}
			}
		}
		if ($action == 'create_invoice') {

			$data['active'] = 2;
		} else {
			$data['active'] = 1;
		}
		$client_id = '';
		$project_id = '';
		if (!empty($data['project_info'])) {
			$project_id = $data['project_info']->project_id ?? '';
			if (!empty($data['project_info']->client_id)) {
				$client_id = $data['project_info']->client_id;
			}
			if (!empty($data['project_info']->project_name)) {
				$data['project_label'] = $data['project_info']->project_name;
			}
		}
		if (!empty($data['invoice_info'])) {
			if (empty($client_id) && !empty($data['invoice_info']->client_id)) {
				$client_id = $data['invoice_info']->client_id;
			}
			if (empty($project_id) && !empty($data['invoice_info']->project_id)) {
				$project_id = $data['invoice_info']->project_id;
			}
		}
		if (!empty($client_id)) {
			$client_row = $this->db->select('name')->where('client_id', $client_id)->get('tbl_client')->row();
			$data['client_label'] = !empty($client_row->name) ? $client_row->name : '';
		}
		if (!empty($project_id) && empty($data['project_label'])) {
			$project_row = $this->db->select('project_name')->where('project_id', $project_id)->get('tbl_project')->row();
			$data['project_label'] = !empty($project_row->project_name) ? $project_row->project_name : '';
		}
		$data['client_id'] = $client_id;
		$data['project_id'] = $project_id;
		// get all client
		$this->invoice_model->_table_name = 'tbl_client';
		$this->invoice_model->_order_by = 'client_id';
		$data['all_client'] = $this->invoice_model->get();
		$data['warehouse_list'] = $this->db->where('status', 'published')->get('tbl_warehouse')->result();
		$data['tax_rates'] = $this->db->order_by('tax_rate_name', 'ASC')->get('tbl_tax_rates')->result();
		$data['default_currency_info'] = $this->invoice_model->check_by(array('code' => config_item('default_currency')), 'tbl_currencies');

		$data['agent_options'] = array('' => lang('select') . ' ' . lang('sales') . ' ' . lang('agent'));
		$agent_rows = $this->db
			->select('tbl_users.user_id, tbl_account_details.fullname')
			->from('tbl_users')
			->join('tbl_account_details', 'tbl_account_details.user_id = tbl_users.user_id', 'left')
			->where('tbl_users.role_id !=', 2)
			->order_by('tbl_users.sort_user', 'ASC')
			->get()
			->result();
		if (!empty($agent_rows)) {
			foreach ($agent_rows as $agent_row) {
				if (!empty($agent_row->fullname)) {
					$data['agent_options'][$agent_row->user_id] = $agent_row->fullname;
				}
			}
		}

		// get permission user
		$data['permission_user'] = $this->invoice_model->all_permission_user('13');
		$type = $this->uri->segment(5);
		if (empty($type)) {
			$type = '_' . date('Y');
		}
		$filterBy = null;
		if (!empty($type) && !is_numeric($type)) {
			$ex = explode('_', $type);
			if ($ex[0] == 'c' && !empty($ex[1])) {
				$data['client_id'] = (int) $ex[1];
				$client_row = $this->db->select('name')->where('client_id', $data['client_id'])->get('tbl_client')->row();
				$data['client_label'] = !empty($client_row->name) ? $client_row->name : '';
			} elseif ($ex[0] != 'c') {
				$filterBy = $type;
			}
		}

		if ($action == 'invoice_details') {
			$data['title'] = "Invoice Details"; //Page title
			$data['invoice_info'] = $this->invoice_model->check_by(array('invoices_id' => $id), 'tbl_invoices');
			if (!empty($data['invoice_info'])) {
				$data['client_info'] = $this->invoice_model->check_by(array('client_id' => $data['invoice_info']->client_id), 'tbl_client');
				$payment_status = $this->invoice_model->get_payment_status($id);
				if ($payment_status != lang('cancelled') && $payment_status != lang('fully_paid')) {
					$this->load->model('credit_note_model');
					$data['total_available_credit'] = $this->credit_note_model->get_available_credit_by_client($data['invoice_info']->client_id);
				}
				$lang = $this->invoice_model->all_files();
				foreach ($lang as $file => $altpath) {
					$shortfile = str_replace("_lang.php", "", $file);
					//CI will record your lang file is loaded, unset it and then you will able to load another
					//unset the lang file to allow the loading of another file
					if (isset($this->lang->is_loaded)) {
						$loaded = sizeof($this->lang->is_loaded);
						if ($loaded < 3) {
							for ($i = 3; $i <= $loaded; $i++) {
								unset($this->lang->is_loaded[$i]);
							}
						} else {
							for ($i = 0; $i <= $loaded; $i++) {
								unset($this->lang->is_loaded[$i]);
							}
						}
					}
					if (!empty($data['client_info']->language)) {
						$language = $data['client_info']->language;
					} else {
						$language = 'english';
					}
					$data['language_info'] = $this->lang->load($shortfile, $language, TRUE, TRUE, $altpath);
				}
				$subview = 'invoice_details';
				// get payment info by id
				$this->invoice_model->_table_name = 'tbl_payments';
				$this->invoice_model->_order_by = 'payments_id';
				$data['all_payments_history'] = $this->invoice_model->get_by(array('invoices_id' => $id), FALSE);
			} else {
				set_message('error', lang('no_data_found'));
				redirect('admin/invoice/manage_invoice');
			}
		} elseif ($action == 'payment' || $action == 'payment_history') {
			$data['title'] = lang($action); //Page title
			// get payment info by id
			$this->invoice_model->_table_name = 'tbl_payments';
			$this->invoice_model->_order_by = 'payments_id';
			$data['all_payments_history'] = $this->invoice_model->get_by(array('invoices_id' => $id), FALSE);

			$subview = $action;
		} elseif ($action == 'payments_details') {
			$data['title'] = "Payments Details"; //Page title
			$subview = 'payments_details';
			// get payment info by id
			$this->invoice_model->_table_name = 'tbl_payments';
			$this->invoice_model->_order_by = 'payments_id';
			$data['payments_info'] = $this->invoice_model->get_by(array('payments_id' => $id), TRUE);
			if (!empty($data['payments_info'])) {
				$invoice_info = $this->invoice_model->check_by(array('invoices_id' => $data['payments_info']->invoices_id), 'tbl_invoices');
				$default_currency = $this->invoice_model->check_by(array('code' => config_item('default_currency')), 'tbl_currencies');
				$currency = !empty($data['payments_info']->system_currency)
					? $this->invoice_model->check_by(array('code' => $data['payments_info']->system_currency), 'tbl_currencies')
					: $default_currency;
				if (empty($currency)) {
					$currency = $default_currency;
				}
				$data['page_title'] = !empty($data['payments_info']->trans_id) ? $data['payments_info']->trans_id : lang('payment_details');
				$data['page_description'] = display_date($data['payments_info']->payment_date) . ' • ' . display_money($data['payments_info']->amount, !empty($currency->symbol) ? $currency->symbol : default_currency());
				$data['header_badge_html'] = '<span class="inline-flex items-center rounded-full border border-emerald-200 bg-emerald-50 px-3 py-1 text-xs font-semibold text-emerald-700 dark:border-emerald-800 dark:bg-emerald-900/30 dark:text-emerald-300">' . html_escape(lang('payment')) . '</span>';
				$data['header_actions'] = array();
				$can_edit_payment = $this->invoice_model->can_action('tbl_payments', 'edit', array('payments_id' => $id));
				if (!empty($invoice_info) && !empty($can_edit_payment)) {
					$data['header_actions'][] = array(
						'label' => lang('edit'),
						'icon' => 'pencil',
						'href' => base_url('admin/invoice/all_payments/' . $data['payments_info']->payments_id),
						'style' => 'info',
					);
				}
				$data['header_actions'][] = array(
					'label' => lang('email') . ' ' . lang('receipt'),
					'icon' => 'mail',
					'href' => base_url('admin/invoice/send_payment/' . $data['payments_info']->payments_id . '/' . $data['payments_info']->amount),
					'style' => 'neutral',
				);
				$data['header_actions'][] = array(
					'label' => lang('print'),
					'icon' => 'printer',
					'href' => base_url('admin/invoice/payments_print/' . $data['payments_info']->payments_id),
					'style' => 'neutral',
					'attrs' => array(
						'target' => '_blank',
						'rel' => 'noopener noreferrer',
					),
				);
				$data['header_actions'][] = array(
					'label' => 'PDF',
					'icon' => 'download',
					'href' => base_url('admin/invoice/payments_pdf/' . $data['payments_info']->payments_id),
					'style' => 'primary',
				);

				$this->db
					->select('tbl_payments.payments_id, tbl_payments.trans_id, tbl_payments.amount, tbl_payments.created_date, tbl_payments.invoices_id, tbl_client.name as client_name')
					->from('tbl_payments')
					->join('tbl_client', 'tbl_client.client_id = tbl_payments.paid_by', 'left')
					->order_by('tbl_payments.payments_id', 'DESC')
					->limit(30);
				$payment_sidebar_items = $this->db->get()->result();
				$has_selected_payment = false;
				if (!empty($payment_sidebar_items)) {
					foreach ($payment_sidebar_items as $sidebar_payment) {
						if ((int) $sidebar_payment->payments_id === (int) $data['payments_info']->payments_id) {
							$has_selected_payment = true;
							break;
						}
					}
				}
				if (!$has_selected_payment) {
					$this->db
						->select('tbl_payments.payments_id, tbl_payments.trans_id, tbl_payments.amount, tbl_payments.created_date, tbl_payments.invoices_id, tbl_client.name as client_name')
						->from('tbl_payments')
						->join('tbl_client', 'tbl_client.client_id = tbl_payments.paid_by', 'left')
						->where('tbl_payments.payments_id', $data['payments_info']->payments_id);
					$selected_sidebar_payment = $this->db->get()->row();
					if (!empty($selected_sidebar_payment)) {
						array_unshift($payment_sidebar_items, $selected_sidebar_payment);
					}
				}
				$data['payment_sidebar_items'] = $payment_sidebar_items;
			}
		} elseif ($action == 'invoice_history') {
			$data['invoice_info'] = $this->invoice_model->check_by(array('invoices_id' => $id), 'tbl_invoices');
			$data['title'] = "Invoice History"; //Page title
			$subview = 'invoice_history';
		} elseif ($action == 'email_invoice') {
			$data['invoice_info'] = $this->invoice_model->check_by(array('invoices_id' => $id), 'tbl_invoices');
			$data['title'] = "Email Invoice"; //Page title
			$subview = 'email_invoice';
		} elseif ($action == 'send_reminder') {
			$data['invoice_info'] = $this->invoice_model->check_by(array('invoices_id' => $id), 'tbl_invoices');
			$data['title'] = "Send Remainder"; //Page title
			$subview = 'send_reminder';
		} elseif ($action == 'send_overdue') {
			$data['invoice_info'] = $this->invoice_model->check_by(array('invoices_id' => $id), 'tbl_invoices');
			$data['title'] = lang('send_invoice_overdue'); //Page title
			$subview = 'send_overdue';
		} elseif ($action == 'make_payment') {
			//$data['all_invoices'] = $this->invoice_model->get_permission('tbl_invoices');
			$data['title'] = lang('make_payment'); //Page title
			$subview = 'make_payment';
		} else {
			$data['title'] = "Create Invoice"; //Page title
			// $data['invoice_info'] = $this->invoice_model->check_by(array('invoices_id' => $id), 'tbl_invoices');
			// print('<pre>' . print_r($data['invoice_info'], true) . '</pre>');
			// exit;

			$subview = 'createinvoice';
		}
		$data['subview'] = $this->load->view('admin/invoice/' . $subview, $data, TRUE);
		$this->load->view('admin/_layout_main', $data); //page load
	}

	public function manage_invoice($action = NULL, $id = NULL, $item_id = NULL)
	{
		$data['page'] = lang('sales');
		$data['dataTables'] = true;
		if ($action == 'all_payments') {
			$data['sub_active'] = lang('payments_received');
		} else {
			$data['sub_active'] = lang('invoice');
		}
		if (!empty($item_id)) {
			$can_edit = $this->invoice_model->can_action('tbl_invoices', 'edit', array('invoices_id' => $id));

			if (!empty($can_edit)) {
				$data['item_info'] = $this->invoice_model->check_by(array('items_id' => $item_id), 'tbl_items');
			}
		}
		if (!empty($id) && $action != 'payments_details') {
			// get all invoice info by id
			$can_edit = $this->invoice_model->can_action('tbl_invoices', 'edit', array('invoices_id' => $id));

			if (!empty($can_edit)) {
				$data['invoice_info'] = join_data('tbl_invoices', '*', array('invoices_id' => $id), array('tbl_client' => 'tbl_client.client_id = tbl_invoices.client_id'));
				if (!empty($data['invoice_info']->client_id)) {
					$data['invoices_to_merge'] = $this->invoice_model->check_for_merge_invoice($data['invoice_info']->client_id, $id);
				}
			}
		}
		if ($action == 'create_invoice') {
			$data['active'] = 2;
		} else {
			$data['active'] = 1;
		}
		// get all client
		$this->invoice_model->_table_name = 'tbl_client';
		$this->invoice_model->_order_by = 'client_id';
		$data['all_client'] = $this->invoice_model->get();

		// get permission user
		$data['permission_user'] = $this->invoice_model->all_permission_user('13');
		$type = $this->uri->segment(5);
		if (empty($type)) {
			$type = '_' . date('Y');
		}
		$filterBy = null;
		if (!empty($type) && !is_numeric($type)) {
			$ex = explode('_', $type);
			if ($ex[0] == 'c' && !empty($ex[1])) {
				$data['client_id'] = (int) $ex[1];
				$client_row = $this->db->select('name')->where('client_id', $data['client_id'])->get('tbl_client')->row();
				$data['client_label'] = !empty($client_row->name) ? $client_row->name : '';
			} elseif ($ex[0] != 'c') {
				$filterBy = $type;
			}
		}

		if ($action == 'pdf_invoice') {
			redirect('admin/invoice/pdf_invoice/' . $id);
		} elseif ($action == 'invoice_details') {
			redirect('admin/invoice/invoice_details/' . $id);
		} elseif ($action == 'payment' || $action == 'payment_history') {
			$data['title'] = lang($action); //Page title
			$per_page = 15;
			$current_page = (int) $this->input->get('payment_page', true);
			$current_page = $current_page > 0 ? $current_page : 1;
			$total_rows = $this->invoice_model->count_invoice_payments($id);
			$total_pages = max(1, (int) ceil($total_rows / $per_page));
			if ($current_page > $total_pages) {
				$current_page = $total_pages;
			}
			$offset = ($current_page - 1) * $per_page;
			$data['all_payments_history'] = $this->invoice_model->get_invoice_payment_page($id, $per_page, $offset);
			$data['payment_history_page'] = $current_page;
			$data['payment_history_pages'] = $total_pages;
			$data['payment_history_total'] = $total_rows;
			$subview = $action;
		} elseif ($action == 'payments_details') {
			$data['title'] = "Payments Details"; //Page title
			$subview = 'payments_details';
			// get payment info by id
			$this->invoice_model->_table_name = 'tbl_payments';
			$this->invoice_model->_order_by = 'payments_id';
			$data['payments_info'] = $this->invoice_model->get_by(array('payments_id' => $id), TRUE);
			if (!empty($data['payments_info'])) {
				$invoice_info = $this->invoice_model->check_by(array('invoices_id' => $data['payments_info']->invoices_id), 'tbl_invoices');
				$default_currency = $this->invoice_model->check_by(array('code' => config_item('default_currency')), 'tbl_currencies');
				$currency = !empty($data['payments_info']->system_currency)
					? $this->invoice_model->check_by(array('code' => $data['payments_info']->system_currency), 'tbl_currencies')
					: $default_currency;
				if (empty($currency)) {
					$currency = $default_currency;
				}

				$invoice_ref = !empty($invoice_info->reference_no) ? $invoice_info->reference_no : '-';
				$data['page_title'] = !empty($data['payments_info']->trans_id) ? $data['payments_info']->trans_id : lang('payment_details');
				$data['page_description'] = lang('invoice') . ': ' . $invoice_ref . ' • ' . display_date($data['payments_info']->payment_date) . ' • ' . display_money($data['payments_info']->amount, !empty($currency->symbol) ? $currency->symbol : default_currency());
				$data['header_badge_html'] = '<span class="inline-flex items-center rounded-full border border-emerald-200 bg-emerald-50 px-3 py-1 text-xs font-semibold text-emerald-700 dark:border-emerald-800 dark:bg-emerald-900/30 dark:text-emerald-300">' . html_escape(lang('payment')) . '</span>';
				$data['header_actions'] = array();
				$can_edit_payment = $this->invoice_model->can_action('tbl_payments', 'edit', array('payments_id' => $id));
				if (!empty($invoice_info) && !empty($can_edit_payment)) {
					$data['header_actions'][] = array(
						'label' => lang('edit'),
						'icon' => 'pencil',
						'href' => base_url('admin/invoice/all_payments/' . $data['payments_info']->payments_id),
						'style' => 'info',
					);
				}
				$data['header_actions'][] = array(
					'label' => lang('email') . ' ' . lang('receipt'),
					'icon' => 'mail',
					'href' => base_url('admin/invoice/send_payment/' . $data['payments_info']->payments_id . '/' . $data['payments_info']->amount),
					'style' => 'neutral',
				);
				$data['header_actions'][] = array(
					'label' => lang('print') ?: 'Print',
					'icon' => 'printer',
					'href' => base_url('admin/invoice/payments_print/' . $data['payments_info']->payments_id),
					'style' => 'neutral',
					'attrs' => array(
						'target' => '_blank',
						'rel' => 'noopener noreferrer',
					),
				);
				$data['header_actions'][] = array(
					'label' => 'PDF',
					'icon' => 'download',
					'href' => base_url('admin/invoice/payments_pdf/' . $data['payments_info']->payments_id),
					'style' => 'primary',
				);

				$per_page = 15;
				$total_payments = (int) $this->db->count_all('tbl_payments');
				$total_pages = max(1, (int) ceil($total_payments / $per_page));
				$current_page = (int) $this->input->get('page', true);
				if ($current_page < 1) {
					$newer_count = (int) $this->db->where('payments_id >', $data['payments_info']->payments_id)->count_all_results('tbl_payments');
					$current_page = (int) floor($newer_count / $per_page) + 1;
				}
				if ($current_page > $total_pages) {
					$current_page = $total_pages;
				}
				$offset = ($current_page - 1) * $per_page;

				$this->db
					->select('tbl_payments.payments_id, tbl_payments.trans_id, tbl_payments.amount, tbl_payments.created_date, tbl_payments.invoices_id, tbl_client.name as client_name')
					->from('tbl_payments')
					->join('tbl_client', 'tbl_client.client_id = tbl_payments.paid_by', 'left')
					->order_by('tbl_payments.payments_id', 'DESC')
					->limit($per_page, $offset);
				$data['payment_sidebar_items'] = $this->db->get()->result();
				$data['payment_sidebar_page'] = $current_page;
				$data['payment_sidebar_pages'] = $total_pages;
				$data['payment_sidebar_total'] = $total_payments;
			}
		} elseif ($action == 'invoice_history') {
			$data['invoice_info'] = join_data('tbl_invoices', '*', array('invoices_id' => $id), array('tbl_client' => 'tbl_client.client_id = tbl_invoices.client_id'));
			$data['title'] = "Invoice History"; //Page title
			$per_page = 20;
			$current_page = (int) $this->input->get('history_page', true);
			$current_page = $current_page > 0 ? $current_page : 1;
			$total_rows = $this->invoice_model->count_invoice_activities($id);
			$total_pages = max(1, (int) ceil($total_rows / $per_page));
			if ($current_page > $total_pages) {
				$current_page = $total_pages;
			}
			$offset = ($current_page - 1) * $per_page;
			$data['activities_info'] = $this->invoice_model->get_invoice_activity_page($id, $per_page, $offset);
			$data['history_page'] = $current_page;
			$data['history_pages'] = $total_pages;
			$data['history_total'] = $total_rows;
			$subview = 'invoice_history';
		} elseif ($action == 'email_invoice') {
			$data['invoice_info'] = join_data('tbl_invoices', '*', array('invoices_id' => $id), array('tbl_client' => 'tbl_client.client_id = tbl_invoices.client_id'));
			$data['title'] = "Email Invoice"; //Page title
			$subview = 'email_invoice';
		} elseif ($action == 'send_reminder') {
			$data['invoice_info'] = join_data('tbl_invoices', '*', array('invoices_id' => $id), array('tbl_client' => 'tbl_client.client_id = tbl_invoices.client_id'));
			$data['title'] = "Send Remainder"; //Page title
			$subview = 'send_reminder';
		} elseif ($action == 'send_overdue') {
			$data['invoice_info'] = join_data('tbl_invoices', '*', array('invoices_id' => $id), array('tbl_client' => 'tbl_client.client_id = tbl_invoices.client_id'));
			$data['title'] = lang('send_invoice_overdue'); //Page title
			$subview = 'send_overdue';
		} elseif ($action == 'make_payment') {
			//$data['all_invoices'] = $this->invoice_model->get_permission('tbl_invoices');
			$data['title'] = lang('make_payment'); //Page title
			$subview = 'make_payment';
		} else {
			$data['title'] = "Manage Invoice"; //Page title
			$data['page_title'] = lang('invoice');
			$data['page_description'] = '';
			$data['datatable_preload'] = $this->capture_datatable_preload(function () use ($filterBy) {
				$this->invoiceList($filterBy);
			});
			$data['header_actions'] = array();
			$data['header_filter_extras_html'] = '';
			$data['header_actions_html'] = '';
			$invoiceFilter = $this->invoice_model->get_invoice_filter();
			
			$status_filters = array();
			$period_filters = array();
			$year_filters = array();
			if (!empty($invoiceFilter)) {
				foreach ($invoiceFilter as $filter) {
					$value = isset($filter['value']) ? $filter['value'] : '';
					if (strpos($value, '_') === 0 && is_numeric(substr($value, 1))) {
						$year_filters[] = $filter;
					} elseif (in_array($value, array('last_month', 'this_months'), true)) {
						$period_filters[] = $filter;
					} else {
						$status_filters[] = $filter;
					}
				}
			}
			$status_options = array('' => lang('all') . ' ' . lang('status'));
			foreach ($status_filters as $filter) {
				$status_options[$filter['value']] = $filter['name'];
			}
			$period_options = array('' => lang('all') . ' ' . lang('invoice_date'));
			foreach ($period_filters as $filter) {
				$period_options[$filter['value']] = $filter['name'];
			}
			$year_options = array('' => lang('all') . ' ' . lang('year'));
			foreach ($year_filters as $filter) {
				$year_options[$filter['value']] = $filter['name'];
			}
			$selected_status = array_key_exists($filterBy, $status_options) ? $filterBy : '';
			$selected_period = array_key_exists($filterBy, $period_options) ? $filterBy : '';
			$selected_year = array_key_exists($filterBy, $year_options) ? $filterBy : '';
			$header_year_options = array();
			foreach ($year_filters as $filter) {
				$header_year_options[$filter['value']] = $filter['name'];
			}
			$header_selected_year = $selected_year;
			if (empty($header_selected_year)) {
				$default_header_year = '_' . date('Y');
				if (array_key_exists($default_header_year, $header_year_options)) {
					$header_selected_year = $default_header_year;
				} elseif (!empty($header_year_options)) {
					$header_selected_year = array_key_first($header_year_options);
				}
			}
			$year_select_html = '';
			$current_cycle_label = lang('all');
			foreach (array($status_filters, $period_filters, $year_filters) as $filter_group) {
				foreach ($filter_group as $filter) {
					if ($filterBy === (isset($filter['value']) ? $filter['value'] : null)) {
						$current_cycle_label = isset($filter['name']) && $filter['name'] !== '' ? $filter['name'] : lang('all');
						break 2;
					}
				}
			}
			$invoice_header_filter_items = array(
				array(
					'label' => lang('all'),
					'active' => empty($filterBy),
					'attrs' => array(
						'data-invoice-filter-action' => '1',
						'data-invoice-filter' => '',
						'data-invoice-search' => '',
						'data-invoice-filter-label' => lang('all'),
					),
				),
			);
			foreach ($status_filters as $filter) {
				$invoice_header_filter_items[] = array(
					'label' => $filter['name'],
					'active' => $filterBy === $filter['value'],
					'attrs' => array(
						'data-invoice-filter-action' => '1',
						'data-invoice-filter' => $filter['value'],
						'data-invoice-search' => '',
						'data-invoice-filter-label' => $filter['name'],
					),
				);
			}
			if (!empty($period_filters)) {
				foreach ($period_filters as $index => $filter) {
					$invoice_header_filter_items[] = array(
						'label' => $filter['name'],
						'divider_before' => $index === 0,
						'active' => $filterBy === $filter['value'],
						'attrs' => array(
							'data-invoice-filter-action' => '1',
							'data-invoice-filter' => $filter['value'],
							'data-invoice-search' => '',
							'data-invoice-filter-label' => $filter['name'],
						),
					);
				}
			}
			if (!empty($year_filters)) {
				$year_filter_items = array(
					array(
						'label' => lang('all') . ' ' . lang('year'),
						'attrs' => array(
							'data-invoice-filter-action' => '1',
							'data-invoice-filter' => '',
							'data-invoice-search' => '',
							'data-invoice-filter-label' => lang('all') . ' ' . lang('year'),
						),
					),
				);
				foreach ($year_filters as $filter) {
					$year_filter_items[] = array(
						'label' => $filter['name'],
						'active' => $filterBy === $filter['value'],
						'attrs' => array(
							'data-invoice-filter-action' => '1',
							'data-invoice-filter' => $filter['value'],
							'data-invoice-search' => '',
							'data-invoice-filter-label' => $filter['name'],
						),
					);
				}
				$invoice_header_filter_items[] = array(
					'label' => lang('year'),
					'icon' => 'calendar-range',
					'divider_before' => true,
					'items' => $year_filter_items,
				);
			}
			$invoice_header_filter_items[] = array(
				'label' => lang('project'),
				'icon' => 'briefcase',
				'divider_before' => true,
				'items' => array(
					array('label' => lang('all') . ' ' . lang('project'), 'attrs' => array('data-invoice-filter-action' => '1', 'data-invoice-filter' => '', 'data-invoice-search' => 'by_project', 'data-invoice-filter-label' => lang('all') . ' ' . lang('project'))),
				),
				'lookup' => array(
					'endpoint' => base_url('admin/common/project_lookup'),
					'limit' => 12,
					'min_length' => 0,
					'action_attrs' => array('data-invoice-filter-action' => '1', 'data-invoice-search' => 'by_project'),
					'filter_attr' => 'data-invoice-filter',
					'label_attr' => 'data-invoice-filter-label',
					'label_prefix' => lang('project') . ': ',
					'placeholder' => lang('search') . ' ' . lang('project'),
					'cache_key' => 'invoice_project_lookup',
				),
			);
			$invoice_header_filter_items[] = array(
				'label' => lang('client'),
				'icon' => 'user',
				'items' => array(
					array('label' => lang('all') . ' ' . lang('client'), 'attrs' => array('data-invoice-filter-action' => '1', 'data-invoice-filter' => '', 'data-invoice-search' => 'by_client', 'data-invoice-filter-label' => lang('all') . ' ' . lang('client'))),
				),
				'lookup' => array(
					'endpoint' => base_url('admin/common/client_lookup'),
					'limit' => 12,
					'min_length' => 0,
					'action_attrs' => array('data-invoice-filter-action' => '1', 'data-invoice-search' => 'by_client'),
					'filter_attr' => 'data-invoice-filter',
					'label_attr' => 'data-invoice-filter-label',
					'label_prefix' => lang('client') . ': ',
					'placeholder' => lang('search') . ' ' . lang('client'),
					'cache_key' => 'invoice_client_lookup',
				),
			);
			$invoice_header_filter_items[] = array(
				'label' => lang('sales') . ' ' . lang('agent'),
				'icon' => 'user-check',
				'items' => array(
					array('label' => lang('all') . ' ' . lang('sales') . ' ' . lang('agent'), 'attrs' => array('data-invoice-filter-action' => '1', 'data-invoice-filter' => '', 'data-invoice-search' => 'by_agent', 'data-invoice-filter-label' => lang('all') . ' ' . lang('sales') . ' ' . lang('agent'))),
				),
				'lookup' => array(
					'endpoint' => base_url('admin/common/staff_lookup'),
					'limit' => 12,
					'min_length' => 0,
					'action_attrs' => array('data-invoice-filter-action' => '1', 'data-invoice-search' => 'by_agent'),
					'filter_attr' => 'data-invoice-filter',
					'label_attr' => 'data-invoice-filter-label',
					'label_prefix' => lang('sales') . ' ' . lang('agent') . ': ',
					'placeholder' => lang('search') . ' ' . lang('sales') . ' ' . lang('agent'),
					'cache_key' => 'invoice_staff_lookup',
				),
			);
			$data['header_filters'] = array(
				array(
					'label' => 'Filters',
					'icon' => 'sliders-horizontal',
					'selected_label' => $current_cycle_label,
					'attrs' => array('id' => 'invoice-header-filter'),
					'items' => $invoice_header_filter_items,
					),
				);
				$invoice_quick_state_hidden = config_item('invoice_state') == 'none';
				if ($invoice_quick_state_hidden) {
					$invoice_quick_state_title = lang('view_quick_state');
					$invoice_quick_state_url = 'show';
					$invoice_quick_state_icon = 'toggle-right';
					$invoice_quick_state_always_label = lang('quick_state') . ' ' . lang('always') . ': ' . lang('show');
				} else {
					$invoice_quick_state_title = lang('hide_quick_state');
					$invoice_quick_state_url = 'hide';
					$invoice_quick_state_icon = 'toggle-left';
					$invoice_quick_state_always_label = lang('quick_state') . ' ' . lang('always') . ': ' . lang('hide');
				}
				$data['header_filter_extras_html'] =
					$year_select_html .
					'<button type="button" id="quick_state" data-default-hidden="' . ($invoice_quick_state_hidden ? '1' : '0') . '"' .
					' title="' . html_escape($invoice_quick_state_title) . '" data-tooltip="' . html_escape($invoice_quick_state_title) . '" data-placement="top" aria-label="' . html_escape($invoice_quick_state_title) . '"' .
					' aria-controls="state_report" aria-expanded="' . ($invoice_quick_state_hidden ? 'false' : 'true') . '"' .
					' class="inline-flex h-8 w-8 items-center justify-center rounded-lg border border-border bg-white text-slate-700 shadow-sm transition hover:bg-slate-50 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200 dark:hover:bg-slate-800">' .
					'<i data-lucide="' . ($invoice_quick_state_hidden ? 'panel-top-open' : 'panel-top-close') . '" class="h-3.5 w-3.5"></i>' .
					'</button>' .
					'<a href="' . base_url('admin/dashboard/change_report/' . $invoice_quick_state_url . '/invoice') . '"' .
					' data-invoice-quick-state-always="1"' .
					' data-no-instant-nav="1"' .
					' title="' . html_escape($invoice_quick_state_always_label) . '" data-tooltip="' . html_escape($invoice_quick_state_always_label) . '" data-placement="top" aria-label="' . html_escape($invoice_quick_state_always_label) . '"' .
					' class="inline-flex h-8 w-8 items-center justify-center rounded-lg border border-amber-200 bg-amber-50 text-amber-700 shadow-sm transition hover:bg-amber-100 dark:border-amber-800/60 dark:bg-amber-900/30 dark:text-amber-300 dark:hover:bg-amber-900/40">' .
					'<i data-lucide="' . html_escape($invoice_quick_state_icon) . '" class="h-3.5 w-3.5"></i>' .
					'</a>';
				$subview = 'manage_invoice';
			}

		if (in_array($action, array('payment', 'payment_history', 'email_invoice', 'send_overdue', 'invoice_history', 'send_reminder'), true)) {
			$data['invoice_sidebar_html'] = $this->render_invoice_sidebar($action, $id);
		}
		
		$data['subview'] = $this->load->view('admin/invoice/' . $subview, $data, TRUE);
		$this->load->view('admin/_layout_main', $data); //page load
	}

	private function get_invoice_sidebar_payload($mode, $selected_id = 0)
	{
		$allowed_modes = array('payment', 'payment_history', 'email_invoice', 'send_overdue', 'invoice_history', 'send_reminder');
		if (!in_array($mode, $allowed_modes, true)) {
			$mode = 'payment';
		}

		$per_page = 12;
		$page = (int) $this->input->get('page', true);
		if ($page < 1) {
			$page = 1;
		}
		$search = trim((string) $this->input->get('q', true));
		$total = $this->invoice_model->count_invoice_sidebar($search);
		$total_pages = $total > 0 ? (int) ceil($total / $per_page) : 1;
		if ($page > $total_pages) {
			$page = $total_pages;
		}
		$offset = ($page - 1) * $per_page;

		return array(
			'sidebar_mode' => $mode,
			'selected_invoice_id' => (int) $selected_id,
			'sidebar_search' => $search,
			'sidebar_page' => $page,
			'sidebar_pages' => $total_pages,
			'sidebar_total' => $total,
			'sidebar_invoices' => $this->invoice_model->get_invoice_sidebar_page($per_page, $offset, $search),
			'sidebar_selected_invoice' => !empty($selected_id) ? $this->invoice_model->get_invoice_sidebar_invoice($selected_id) : null,
		);
	}

	private function render_invoice_sidebar($mode, $selected_id = 0)
	{
		return $this->load->view('admin/invoice/_invoice_sidebar', $this->get_invoice_sidebar_payload($mode, $selected_id), true);
	}

	public function invoice_sidebar($mode, $selected_id = 0)
	{
		echo $this->render_invoice_sidebar($mode, $selected_id);
	}

	public function invoice_details($id, $pdf = NULL)
	{
		$data['title'] = "Invoice"; //Page title
		$data['page_title'] = lang('invoice');
		$data['sales_info'] = join_data('tbl_invoices', '*', array('invoices_id' => $id), array('tbl_client' => 'tbl_client.client_id = tbl_invoices.client_id'));
		if (!empty($data['sales_info'])) {
			$url = base_url('frontend/view_invoice/') . url_encode($id);
			$data['qrcode'] = generate_qrcode($url);

			$payment_status = $this->invoice_model->get_payment_status($id);
			$data['sales_info']->ref_no = lang('invoice') . ' : ' . $data['sales_info']->reference_no;
			$data['sales_info']->start_date = lang('invoice_date') . ' : ' . display_date($data['sales_info']->invoice_date);
			// check overdue invoice
			if (safe_strtotime($data['sales_info']->due_date) < safe_strtotime(date('Y-m-d')) && $payment_status != lang('fully_paid') && $payment_status != lang('cancelled')) {
				// check overdue how many days from due_date
				$date1 = new DateTime($data['sales_info']->due_date);
				$date2 = new DateTime(date('Y-m-d'));
				$interval = $date1->diff($date2);
				$overdue_days = $interval->format('%a');
				$data['sales_info']->overdue_days = lang('invoice_overdue') . ' ' . lang('by') . ' ' . $overdue_days . ' ' . lang('days');
			}
			$data['sales_info']->end_date = lang('due_date') . ' : ' . display_date($data['sales_info']->due_date);
			if (!empty($data['sales_info']->user_id)) {
				$data['sales_info']->sales_agent = lang('sales') . ' ' . lang('agent') . ' : ' . fullname($data['sales_info']->user_id);
			}
			$text = null;
			$text = null;
			if ($payment_status == lang('fully_paid')) {
				$label = "success";
			} elseif ($payment_status == lang('draft')) {
				$label = "default";
				$text = lang('status_as_draft');
			} elseif ($payment_status == lang('cancelled')) {
				$label = "danger";
			} elseif ($payment_status == lang('partially_paid')) {
				$label = "warning";
			} elseif ($data['sales_info']->emailed == 'Yes') {
				$label = "info";
				$payment_status = lang('sent');
			} else {
				$label = "danger";
			}
			$data['sales_info']->status = lang('status') . ' :  <span class="label label-' . $label . '">' . lang($payment_status) . '</span>';
			if (!empty($text)) {
				$data['sales_info']->status .= '<br><p style="padding: 15px;margin-bottom: 20px;border: 1px solid transparent;border-radius: 4px;;background: color: #8a6d3b;background-color: #fcf8e3;border-color: #faebcc;">' . $text . '</p>';
			}
			$data['sales_info']->custom_field = '';
			$show_custom_fields = custom_form_label(9, $data['sales_info']->invoices_id);
			if (!empty($show_custom_fields)) {
				foreach ($show_custom_fields as $c_label => $v_fields) {
					if (!empty($v_fields)) {
						$data['sales_info']->custom_field .= $c_label . ' : ' . $v_fields . '<br>';
					}
				}
			}
			$data['all_items'] = $this->invoice_model->ordered_items_by_id($data['sales_info']->invoices_id);
			$data['sales_info']->sub_total = ($this->invoice_model->calculate_to('invoice_cost', $data['sales_info']->invoices_id));
			$data['sales_info']->discount = ($this->invoice_model->calculate_to('discount', $data['sales_info']->invoices_id));
			$data['sales_info']->total = ($this->invoice_model->calculate_to('total', $data['sales_info']->invoices_id));
			$data['paid_amount'] = $this->invoice_model->calculate_to('paid_amount', $data['sales_info']->invoices_id);
			$data['invoice_due'] = $this->invoice_model->calculate_to('invoice_due', $data['sales_info']->invoices_id);
			$data['payment_status'] = $payment_status;
			$data['page_title'] = 'INV-' . $data['sales_info']->reference_no;
			$data['page_description'] = display_date($data['sales_info']->invoice_date) . ' • ' . lang('due_date') . ': ' . display_date($data['sales_info']->due_date);
			$data['can_edit_invoice'] = $this->invoice_model->can_action('tbl_invoices', 'edit', array('invoices_id' => $data['sales_info']->invoices_id));
			$data['invoice_cost_total'] = $data['sales_info']->sub_total;
			$data['all_payment_info'] = get_result('tbl_payments', array('invoices_id' => $id));
			$data['payment_count'] = !empty($data['all_payment_info']) ? count($data['all_payment_info']) : 0;
			$data['pending_reminder_count'] = (int) $this->db
				->where(array('module' => 'invoice', 'module_id' => $data['sales_info']->invoices_id, 'notified' => 'No'))
				->count_all_results('tbl_reminders');
			$data['credit_used_count'] = (int) $this->db
				->where('invoices_id', $data['sales_info']->invoices_id)
				->count_all_results('tbl_credit_used');
			$data['total_available_credit'] = 0;
			if ($payment_status != lang('cancelled') && $payment_status != lang('fully_paid')) {
				$this->load->model('credit_note_model');
				$data['total_available_credit'] = $this->credit_note_model->get_available_credit_by_client($data['sales_info']->client_id);
			}
			$status_key = strtolower((string) $payment_status);
			$status_badges = array(
				strtolower(lang('fully_paid')) => 'bg-emerald-50 text-emerald-700 border-emerald-200',
				strtolower(lang('paid')) => 'bg-emerald-50 text-emerald-700 border-emerald-200',
				strtolower(lang('draft')) => 'bg-slate-100 text-slate-700 border-slate-200',
				strtolower(lang('cancelled')) => 'bg-rose-50 text-rose-700 border-rose-200',
				strtolower(lang('partially_paid')) => 'bg-amber-50 text-amber-700 border-amber-200',
				strtolower(lang('sent')) => 'bg-blue-50 text-blue-700 border-blue-200',
			);
			$status_class = isset($status_badges[$status_key]) ? $status_badges[$status_key] : 'bg-slate-100 text-slate-700 border-slate-200';
			$data['header_badge_html'] = '<span class="inline-flex items-center rounded-full border px-3 py-1 text-xs font-semibold ' . $status_class . '">' . html_escape($payment_status) . '</span>';
			$data['header_actions'] = array();
			$data['header_actions_html'] = '';
			$data['header_actions_html'] .= '<div class="flex flex-wrap items-center justify-end gap-2">';
			if (!empty($data['can_edit_invoice'])) {
				$data['header_actions_html'] .= btn_modal(
					'admin/invoice/insert_items/' . $data['sales_info']->invoices_id,
					lang('add_items'),
					lang('add_items'),
					'lg',
					'plus',
					array('class' => 'inline-flex items-center gap-2 rounded-xl border border-slate-800 bg-slate-800 px-4 py-2.5 text-sm font-semibold text-white shadow-sm transition-colors hover:bg-slate-700 dark:border-slate-700 dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-white')
				);
			}
			if (!empty($data['can_edit_invoice']) && !empty($data['invoice_cost_total'])) {
				$data['header_actions_html'] .= '<a href="' . base_url('admin/invoice/manage_invoice/payment/' . $data['sales_info']->invoices_id) . '" class="inline-flex items-center gap-2 rounded-xl border border-border bg-white px-4 py-2.5 text-sm font-semibold text-slate-700 shadow-sm transition-colors hover:bg-slate-50 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200 dark:hover:bg-slate-800"><i data-lucide="wallet-cards" class="h-4 w-4"></i><span>' . html_escape(lang('record_payment')) . '</span></a>';
			}
			if (!empty($data['can_edit_invoice'])) {
				$data['header_actions_html'] .= btn_modal(
					'admin/invoice/clone_invoice/' . $data['sales_info']->invoices_id,
					lang('clone'),
					lang('clone'),
					'md',
					'copy',
					array('class' => 'inline-flex items-center gap-2 rounded-xl border border-border bg-white px-4 py-2.5 text-sm font-semibold text-slate-700 hover:bg-slate-50 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200 dark:hover:bg-slate-800')
				);
			}
			if (!empty($data['invoice_cost_total'])) {
				$more_actions = '<div class="relative" data-dropdown style="position:relative;">';
				$more_actions .= '<button type="button" data-dropdown-toggle="invoice-header-actions" class="inline-flex h-11 items-center gap-2 rounded-xl border border-border bg-white px-4 text-sm font-semibold text-slate-700 shadow-sm transition-colors hover:bg-slate-50 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200 dark:hover:bg-slate-800" title="' . html_escape(lang('more_actions')) . '" aria-label="' . html_escape(lang('more_actions')) . '"><i data-lucide="more-horizontal" class="h-4 w-4"></i><span>' . html_escape(lang('more_actions')) . '</span></button>';
				$more_actions .= '<div id="invoice-header-actions" data-dropdown-menu class="hidden absolute right-0 mt-2 w-56 max-w-[calc(100vw-1rem)] max-h-[calc(100vh-6rem)] overflow-y-auto rounded-xl border border-border bg-card p-2 shadow-lg z-30">';
				$more_actions .= '<a href="' . base_url('admin/invoice/pdf_invoice/' . $data['sales_info']->invoices_id) . '" class="flex items-center gap-2 rounded-lg px-3 py-2 text-xs text-foreground transition-colors hover:bg-muted"><i data-lucide="download" class="h-3.5 w-3.5 text-blue-500"></i><span>' . html_escape(lang('pdf')) . '</span></a>';
				$more_actions .= '<a href="#" onclick="print_sales_details(\'sales_details\'); return false;" class="flex items-center gap-2 rounded-lg px-3 py-2 text-xs text-foreground transition-colors hover:bg-muted"><i data-lucide="printer" class="h-3.5 w-3.5 text-slate-500"></i><span>' . html_escape(lang('print')) . '</span></a>';
				$more_actions .= '<a href="' . base_url('admin/invoice/manage_invoice/email_invoice/' . $data['sales_info']->invoices_id) . '" class="flex items-center gap-2 rounded-lg px-3 py-2 text-xs text-foreground transition-colors hover:bg-muted"><i data-lucide="mail" class="h-3.5 w-3.5 text-emerald-500"></i><span>' . html_escape(lang('email_invoice')) . '</span></a>';
				$more_actions .= '<div class="my-2 border-t border-border"></div>';
				$more_actions .= '<a href="' . base_url('admin/invoice/manage_invoice/send_reminder/' . $data['sales_info']->invoices_id) . '" class="flex items-center gap-2 rounded-lg px-3 py-2 text-xs text-foreground transition-colors hover:bg-muted"><i data-lucide="bell" class="h-3.5 w-3.5 text-amber-500"></i><span>' . html_escape(lang('send_reminder')) . '</span></a>';
				$reminder_count = !empty($data['pending_reminder_count']) ? (int) $data['pending_reminder_count'] : 0;
				$reminder_badge = '';
				if (!empty($reminder_count)) {
					$reminder_badge = ' <span class="ml-1 inline-flex items-center justify-center rounded-full bg-amber-100 px-2 text-[10px] font-bold text-amber-700">' . $reminder_count . '</span>';
				}
				$more_actions .= '<a href="' . base_url('admin/invoice/reminder/invoice/' . $data['sales_info']->invoices_id) . '" class="flex items-center gap-2 rounded-lg px-3 py-2 text-xs text-foreground transition-colors hover:bg-muted"><i data-lucide="bell-ring" class="h-3.5 w-3.5 text-amber-500"></i><span>' . html_escape(lang('reminder')) . $reminder_badge . '</span></a>';
				if (!empty($data['total_available_credit'])) {
					$credit_badge = '';
					if (!empty($data['credit_used_count'])) {
						$credit_badge = ' <span class="ml-1 inline-flex items-center justify-center rounded-full bg-slate-200 px-2 text-[10px] font-bold text-slate-600">' . (int) $data['credit_used_count'] . '</span>';
					}
					$more_actions .= '<a href="' . base_url('admin/invoice/applied_credits/' . $data['sales_info']->invoices_id) . '" class="flex items-center gap-2 rounded-lg px-3 py-2 text-xs text-foreground transition-colors hover:bg-muted"><i data-lucide="badge-dollar-sign" class="h-3.5 w-3.5 text-slate-500"></i><span>' . html_escape(lang('applied_credits')) . $credit_badge . '</span></a>';
				}
				if (!empty($data['sales_info']->overdue_days)) {
					$more_actions .= '<a href="' . base_url('admin/invoice/manage_invoice/send_overdue/' . $data['sales_info']->invoices_id) . '" class="flex items-center gap-2 rounded-lg px-3 py-2 text-xs text-foreground transition-colors hover:bg-muted"><i data-lucide="clock-3" class="h-3.5 w-3.5 text-orange-500"></i><span>' . html_escape(lang('send_invoice_overdue')) . '</span></a>';
				}
				$more_actions .= '<div class="my-2 border-t border-border"></div>';
				if ($data['sales_info']->emailed != 'Yes') {
					$more_actions .= '<a href="' . base_url('admin/invoice/change_invoice_status/mark_as_sent/' . $data['sales_info']->invoices_id) . '" class="flex items-center gap-2 rounded-lg px-3 py-2 text-xs text-foreground transition-colors hover:bg-muted"><i data-lucide="send" class="h-3.5 w-3.5 text-sky-500"></i><span>' . html_escape(lang('mark_as_sent')) . '</span></a>';
				}
				if ($data['paid_amount'] <= 0) {
					if ($data['sales_info']->status != 'Cancelled') {
						$more_actions .= '<a href="' . base_url('admin/invoice/change_invoice_status/mark_as_cancelled/' . $data['sales_info']->invoices_id) . '" class="flex items-center gap-2 rounded-lg px-3 py-2 text-xs text-foreground transition-colors hover:bg-muted"><i data-lucide="ban" class="h-3.5 w-3.5 text-rose-500"></i><span>' . html_escape(lang('mark_as_cancelled')) . '</span></a>';
					} else {
						$more_actions .= '<a href="' . base_url('admin/invoice/change_invoice_status/unmark_as_cancelled/' . $data['sales_info']->invoices_id) . '" class="flex items-center gap-2 rounded-lg px-3 py-2 text-xs text-foreground transition-colors hover:bg-muted"><i data-lucide="undo-2" class="h-3.5 w-3.5 text-slate-500"></i><span>' . html_escape(lang('unmark_as_cancelled')) . '</span></a>';
					}
				}
				$more_actions .= '<a href="' . base_url('admin/invoice/manage_invoice/invoice_history/' . $data['sales_info']->invoices_id) . '" class="flex items-center gap-2 rounded-lg px-3 py-2 text-xs text-foreground transition-colors hover:bg-muted"><i data-lucide="history" class="h-3.5 w-3.5 text-slate-500"></i><span>' . html_escape(lang('invoice_history')) . '</span></a>';
				if (!empty($data['can_edit_invoice'])) {
					$more_actions .= '<div class="my-2 border-t border-border"></div>';
					$more_actions .= '<a href="' . base_url('admin/invoice/createinvoice/create_invoice/' . $data['sales_info']->invoices_id) . '" class="flex items-center gap-2 rounded-lg px-3 py-2 text-xs text-foreground transition-colors hover:bg-muted"><i data-lucide="pencil" class="h-3.5 w-3.5 text-slate-500"></i><span>' . html_escape(lang('edit_invoice')) . '</span></a>';
				}
				$more_actions .= '</div></div>';
				$data['header_actions_html'] .= $more_actions;
			}
			$data['header_actions_html'] .= '</div>';
			if (!empty($data['sales_info']->project_id)) {
				$data['project_info'] = $this->db
					->select('project_id, project_name')
					->where('project_id', $data['sales_info']->project_id)
					->get('tbl_project')
					->row();
			}
			$data['footer'] = config_item('invoice_footer');
		} else {
			set_message('error', lang('no_data_found'));
			redirect('admin/invoice/manage_invoice');
		}
		if (!empty($pdf)) {
			$this->common_model->sales_pdf($data, $pdf);
			return;
		}
		$data['invoice_pdf_print_html'] = $this->load->view('admin/common/sales_pdf', $data, TRUE);
		$data['subview'] = $this->load->view('admin/invoice/invoice_details', $data, TRUE);
		$this->load->view('admin/_layout_main', $data); //page load
	}

	public function delivery_note($id, $pdf = true)
	{
		$data['title'] = "Invoice"; //Page title
		$data['sales_info'] = join_data('tbl_invoices', '*', array('invoices_id' => $id), array('tbl_client' => 'tbl_client.client_id = tbl_invoices.client_id'));
		if (!empty($data['sales_info'])) {
			$url = base_url('frontend/view_invoice/') . url_encode($id);
			$data['qrcode'] = generate_qrcode($url);

			$payment_status = $this->invoice_model->get_payment_status($id);
			$data['sales_info']->ref_no = lang('invoice') . ' : ' . $data['sales_info']->reference_no;
			$data['sales_info']->start_date = lang('invoice_date') . ' : ' . display_date($data['sales_info']->invoice_date);
			// check overdue invoice
			if (safe_strtotime($data['sales_info']->due_date) < safe_strtotime(date('Y-m-d')) && $payment_status != lang('fully_paid') && $payment_status != lang('cancelled')) {
				// check overdue how many days from due_date
				$date1 = new DateTime($data['sales_info']->due_date);
				$date2 = new DateTime(date('Y-m-d'));
				$interval = $date1->diff($date2);
				$overdue_days = $interval->format('%a');
				$data['sales_info']->overdue_days = lang('invoice_overdue') . ' ' . lang('by') . ' ' . $overdue_days . ' ' . lang('days');
			}
			$data['sales_info']->end_date = lang('due_date') . ' : ' . display_date($data['sales_info']->due_date);
			if (!empty($data['sales_info']->user_id)) {
				$data['sales_info']->sales_agent = lang('sales') . ' ' . lang('agent') . ' : ' . fullname($data['sales_info']->user_id);
			}
			if ($payment_status == lang('fully_paid')) {
				$label = "success";
			} elseif ($payment_status == lang('draft')) {
				$label = "default";
				$text = lang('status_as_draft');
			} elseif ($payment_status == lang('cancelled')) {
				$label = "danger";
			} elseif ($payment_status == lang('partially_paid')) {
				$label = "warning";
			} elseif ($data['sales_info']->emailed == 'Yes') {
				$label = "info";
				$payment_status = lang('sent');
			} else {
				$label = "danger";
			}
			$data['sales_info']->status = lang('status') . ' :  <span class="label label-' . $label . '">' . lang($payment_status) . '</span>';
			if (!empty($text)) {
				$data['sales_info']->status .= '<br><p style="padding: 15px;margin-bottom: 20px;border: 1px solid transparent;border-radius: 4px;;background: color: #8a6d3b;background-color: #fcf8e3;border-color: #faebcc;">' . $text . '</p>';
			}
			$data['sales_info']->custom_field = '';
			$show_custom_fields = custom_form_label(9, $data['sales_info']->invoices_id);
			if (!empty($show_custom_fields)) {
				foreach ($show_custom_fields as $c_label => $v_fields) {
					if (!empty($v_fields)) {
						$data['sales_info']->custom_field .= $c_label . ' : ' . $v_fields . '<br>';
					}
				}
			}
			$data['all_items'] = $this->invoice_model->ordered_items_by_id($data['sales_info']->invoices_id);
			$data['sales_info']->sub_total = ($this->invoice_model->calculate_to('invoice_cost', $data['sales_info']->invoices_id));
			$data['sales_info']->discount = ($this->invoice_model->calculate_to('discount', $data['sales_info']->invoices_id));
			$data['sales_info']->total = ($this->invoice_model->calculate_to('total', $data['sales_info']->invoices_id));
			$data['paid_amount'] = $this->invoice_model->calculate_to('paid_amount', $data['sales_info']->invoices_id);
			$data['invoice_due'] = $this->invoice_model->calculate_to('invoice_due', $data['sales_info']->invoices_id);
			$data['payment_status'] = $payment_status;
			if ($payment_status != lang('cancelled') && $payment_status != lang('fully_paid')) {
				$this->load->model('credit_note_model');
				$data['total_available_credit'] = $this->credit_note_model->get_available_credit_by_client($data['sales_info']->client_id);
			}
			// get payment info by id
			$data['all_payment_info'] = get_result('tbl_payments', array('invoices_id' => $id));
			$data['footer'] = config_item('invoice_footer');
		} else {
			set_message('error', lang('no_data_found'));
			redirect('admin/invoice/manage_invoice');
		}
		if (!empty($pdf)) {
			$this->common_model->sales_pdf($data, $pdf, true);
		}
	}


	public
	function invoices_credit($invoices_id)
	{
		$data['invoice_info'] = get_row('tbl_invoices', array('invoices_id' => $invoices_id));		
		$payment_status = $this->invoice_model->get_payment_status($invoices_id);
		$this->load->model('credit_note_model');
		$total_available_credit = $this->credit_note_model->get_available_credit_by_client($data['invoice_info']->client_id);
		if ($payment_status != lang('cancelled') && $payment_status != lang('fully_paid') && !empty($total_available_credit)) {
			$data['all_open_credit'] = get_result('tbl_credit_note', array('client_id' => $data['invoice_info']->client_id));			
			$data['subview'] = $this->load->view('admin/credit_note/invoices_to_credits', $data, false);
		} else {
			$type = "error";
			$message = "No Record Found";
			set_message($type, $message);
			redirect('admin/credit_note');
		}
	}


	public
	function apply_invoices_credit($invoices_id)
	{
		$invoice_info = $this->invoice_model->check_by(array('invoices_id' => $invoices_id), 'tbl_invoices');
		if (empty($invoice_info)) {
			$this->respond_apply_credit('error', lang('no_data_found'), $invoices_id);
			return;
		}

		$invoice_amount = $this->input->post('amount', true);
		$added_into_payment = $this->input->post('added_into_payment', true);
		$this->load->model('credit_note_model');
		$error = array();
		$valid_rows = array();

		if ($invoice_amount) {
			foreach ($invoice_amount as $credit_note_id => $amount) {
				$amount = (float) $amount;
				if ($amount <= 0) {
					continue;
				}

				$credit_remaining = (float) $this->credit_note_model->credit_note_calculation('credit_remaining', $credit_note_id);
				$credit_info = $this->invoice_model->check_by(array('credit_note_id' => $credit_note_id), 'tbl_credit_note');
				if (empty($credit_info) || (int) $credit_info->client_id !== (int) $invoice_info->client_id) {
					$error[] = lang('no_data_found');
					continue;
				}

				if ($amount > $credit_remaining) {
					$error[] = 'Amount exceeds available credit.';
					continue;
				}

				$valid_rows[] = array(
					'amount' => $amount,
					'credit_note_id' => $credit_note_id,
					'added_into_payment' => $added_into_payment,
				);
			}
		}

		if (!empty($error)) {
			foreach ($error as $show) {
				set_message('error', $show);
			}
			$this->respond_apply_credit('error', reset($error), $invoices_id);
			return;
		} elseif (!empty($valid_rows)) {
			foreach ($valid_rows as $row) {
				$this->apply_credits($invoices_id, $row);
			}
			set_message('success', lang('credit_applied_to_invoices'));
			$this->respond_apply_credit('success', lang('credit_applied_to_invoices'), $invoices_id);
			return;
		} else {
			set_message('error', lang('no_data_found'));
			$this->respond_apply_credit('error', lang('no_data_found'), $invoices_id);
			return;
		}

		redirect('admin/invoice/manage_invoice/invoice_details/' . $invoices_id);
	}

	private function respond_apply_credit($status, $message, $invoices_id)
	{
		$url = 'admin/invoice/manage_invoice/invoice_details/' . $invoices_id;
		if ($this->input->is_ajax_request()) {
			$this->output
				->set_content_type('application/json')
				->set_output(json_encode(array(
					'status' => $status,
					'message' => $message,
					'url' => $status === 'success' ? $url : '',
					'reload_page' => $status === 'success',
				)));
			return;
		}

		redirect($url);
	}

	public function apply_credits($invoices_id, $input_post)
	{
		$data = array(
			'invoices_id' => $invoices_id,
			'credit_note_id' => $input_post['credit_note_id'],
			'user_id' => my_id(),
			'date' => date('Y-m-d'),
			'date_applied' => date('Y-m-d H:i'),
			'amount' => $input_post['amount'],
		);
		$this->invoice_model->_table_name = 'tbl_credit_used';
		$this->invoice_model->_primary_key = 'credit_used_id';
		$credit_used_id = $this->invoice_model->save($data);
		if (!empty($credit_used_id)) {
			if ($input_post['added_into_payment'] == 'on') {
				$input_post['invoices_id'] = $invoices_id;
				$input_post['credit_used_id'] = $credit_used_id;
				$this->added_into_payment($input_post);
			}
		}

		return true;
	}

	private function added_into_payment($input_post)
	{
		$this->load->model('credit_note_model');
		$this->load->helper('string_helper');
		$invoices_id = $input_post['invoices_id'];
		$paid_amount = $input_post['amount'];
		$due = $this->invoice_model->calculate_to('invoice_due', $invoices_id);
		$credit_notes = $this->db->where('credit_note_id', $input_post['credit_note_id'])->get('tbl_credit_note')->row();
		if ($paid_amount != 0) {
			$trans_id = random_string('nozero', 6);
			$inv_info = $this->invoice_model->check_by(array('invoices_id' => $invoices_id), 'tbl_invoices');
			$data = array(
				'invoices_id' => $invoices_id,
				'paid_by' => $inv_info->client_id,
				'payment_method' => config_item('default_payment_method'),
				'currency' => client_currency($inv_info->client_id),
				'amount' => $paid_amount,
				'payment_date' => date('Y-m-d'),
				'trans_id' => $trans_id,
				'notes' => 'This Payment from Credit notes <a href="' . base_url('admin/credit_note/index/credit_note_details/' . $input_post['credit_note_id']) . '">' . $credit_notes->reference_no . '</a>',
				'month_paid' => date("m"),
				'year_paid' => date("Y"),
			);
			$this->invoice_model->_table_name = 'tbl_payments';
			$this->invoice_model->_primary_key = 'payments_id';
			$payments_id = $this->invoice_model->save($data);

			$this->invoice_model->_table_name = 'tbl_credit_used';
			$this->invoice_model->_primary_key = 'credit_used_id';
			$cu_data['payments_id'] = $payments_id;
			$this->invoice_model->save($cu_data, $input_post['credit_used_id']);


			if ($paid_amount < $due) {
				$status = 'partially_paid';
			}
			if ($paid_amount == $due) {
				$status = 'Paid';
			}
			$invoice_data['status'] = $status;
			update('tbl_invoices', array('invoices_id' => $invoices_id), $invoice_data);

			$activity = array(
				'user' => $this->session->userdata('user_id'),
				'module' => 'invoice',
				'module_field_id' => $invoices_id,
				'activity' => ('activity_new_payment'),
				'icon' => 'fa-shopping-cart',
				'link' => 'admin/invoice/manage_invoice/invoice_details/' . $invoices_id,
				'value1' => display_money($paid_amount, client_currency($inv_info->client_id)),
				'value2' => $inv_info->reference_no,
			);
			$this->invoice_model->_table_name = 'tbl_activities';
			$this->invoice_model->_primary_key = 'activities_id';
			$this->invoice_model->save($activity);

			if (!empty($inv_info->user_id)) {
				$notifiedUsers = array($inv_info->user_id);
				foreach ($notifiedUsers as $users) {
					if ($users != $this->session->userdata('user_id')) {
						add_notification(array(
							'to_user_id' => $users,
							'description' => 'not_new_invoice_payment',
							'icon' => 'shopping-cart',
							'link' => 'admin/invoice/manage_invoice/invoice_details/' . $invoices_id,
							'value' => lang('invoice') . ' ' . $inv_info->reference_no . ' ' . lang('amount') . display_money($paid_amount, client_currency($inv_info->client_id)),
						));
					}
				}
				show_notification($notifiedUsers);
			}
            if ($this->input->post('save_into_account') == 'on') {
                $account_id = config_item('default_account');
                if (!empty($account_id)) {
                    if (!finance_guard_accounting_period(date('Y-m-d'), lang('invoice_payment'))) {
                        return;
                    }
                    $reference = lang('invoice') . ' ' . lang('reference_no') . ": <a href='" . base_url('admin/invoice/manage_invoice/invoice_details/' . $inv_info->invoices_id) . "' >" . $inv_info->reference_no . "</a> and " . lang('trans_id') . ": <a href='" . base_url('admin/invoice/manage_invoice/payments_details/' . $payments_id) . "'>" . $this->input->post('trans_id', true) . "</a>";
					// save into tbl_transaction
					$tr_data = array(
						'name' => lang('invoice_payment', lang('trans_id') . '# ' . $trans_id),
						'type' => 'Income',
						'amount' => $paid_amount,
						'credit' => $paid_amount,
						'date' => date('Y-m-d'),
						'paid_by' => $inv_info->client_id,
						'payment_methods_id' => config_item('default_payment_method'),
						'reference' => $trans_id,
						'notes' => lang('this_deposit_from_invoice_payment', $reference) . ' ' . 'from credit notes',
						'permission' => 'all',
					);

					$account_info = $this->invoice_model->check_by(array('account_id' => $account_id), 'tbl_accounts');
					if (!empty($account_info)) {
						$ac_data['balance'] = $account_info->balance + $tr_data['amount'];
						$this->invoice_model->_table_name = "tbl_accounts"; //table name
						$this->invoice_model->_primary_key = "account_id";
						$this->invoice_model->save($ac_data, $account_info->account_id);
						finance_sync_model()->sync_account_by_id($account_info->account_id);

						$aaccount_info = $this->invoice_model->check_by(array('account_id' => $account_id), 'tbl_accounts');

						$tr_data['total_balance'] = $aaccount_info->balance;
						$tr_data['account_id'] = $account_id;

						// save into tbl_transaction
						$this->invoice_model->_table_name = "tbl_transactions"; //table name
						$this->invoice_model->_primary_key = "transactions_id";
						$return_id = $this->invoice_model->save($tr_data);
						finance_sync_model()->sync_transaction_by_id($return_id);

						$deduct_account['account_id'] = $account_id;
						$this->invoice_model->_table_name = 'tbl_payments';
						$this->invoice_model->_primary_key = 'payments_id';
						$this->invoice_model->save($deduct_account, $payments_id);

						// save into activities
						$activities = array(
							'user' => $this->session->userdata('user_id'),
							'module' => 'transactions',
							'module_field_id' => $return_id,
							'activity' => 'activity_new_deposit',
							'icon' => 'fa-building-o',
							'link' => 'admin/transactions/view_details/' . $return_id,
							'value1' => $account_info->account_name,
							'value2' => $paid_amount,
						);
						// Update into tbl_project
						$this->invoice_model->_table_name = "tbl_activities"; //table name
						$this->invoice_model->_primary_key = "activities_id";
						$this->invoice_model->save($activities);
					}
				}
				if ($this->input->post('send_thank_you') == 'on') {
					$this->send_payment_email($invoices_id, $paid_amount); //send thank you email
				}

				if ($this->input->post('send_sms') == 'on') {
					$this->send_payment_sms($invoices_id, $payments_id); //send thank you email
				}
			}
		}
	}

	function send_payment_email($invoices_id, $paid_amount)
	{
		$inv_info = $this->invoice_model->check_by(array('invoices_id' => $invoices_id), 'tbl_invoices');
		$email_template = email_templates(array('email_group' => 'payment_email'), $inv_info->client_id);
		$message = $email_template->template_body;
		$subject = $email_template->subject;
		if (!empty($inv_info)) {
			$currency = $inv_info->currency;
			$reference = $inv_info->reference_no;

			$invoice_currency = str_replace("{INVOICE_CURRENCY}", $currency, $message);
			$reference = str_replace("{INVOICE_REF}", $reference, $invoice_currency);
			$amount = str_replace("{PAID_AMOUNT}", $paid_amount, $reference);
			$message = str_replace("{SITE_NAME}", config_item('company_name'), $amount);

			$data['message'] = $message;
			$message = $this->load->view('email_template', $data, TRUE);
			$client_info = $this->invoice_model->check_by(array('client_id' => $inv_info->client_id), 'tbl_client');

			// send notification to client
			if (!empty($client_info)) {
				$client_info = $this->invoice_model->check_by(array('client_id' => $client_info->client_id), 'tbl_client');
				if (!empty($client_info->primary_contact)) {
					$notifyUser = array($client_info->primary_contact);
				} else {
					$user_info = $this->invoice_model->check_by(array('company' => $client_info->client_id), 'tbl_account_details');
					if (!empty($user_info)) {
						$notifyUser = array($user_info->user_id);
					}
				}
			}
			if (!empty($notifyUser)) {
				foreach ($notifyUser as $v_user) {
					if ($v_user != $this->session->userdata('user_id')) {
						add_notification(array(
							'to_user_id' => $v_user,
							'icon' => 'shopping-cart',
							'description' => 'not_payment_received',
							'link' => 'client/invoice/manage_invoice/invoice_details/' . $invoices_id,
							'value' => lang('invoice') . ' ' . $inv_info->reference_no . ' ' . lang('amount') . display_money($paid_amount, $inv_info->currency),
						));
					}
				}
				show_notification($notifyUser);
			}

			$address = $client_info->email;

			$params['recipient'] = $address;

			$params['subject'] = '[ ' . config_item('company_name') . ' ]' . ' ' . $subject;
			$params['message'] = $message;
			$params['resourceed_file'] = '';

			$activity = array(
				'user' => my_id(),
				'module' => 'invoice',
				'module_field_id' => $invoices_id,
				'activity' => ('activity_send_payment'),
				'icon' => 'fa-shopping-cart',
				'link' => 'admin/invoice/manage_invoice/invoice_details/' . $invoices_id,
				'value1' => $reference,
				'value2' => $currency . ' ' . $amount,
			);
			$this->invoice_model->_table_name = 'tbl_activities';
			$this->invoice_model->_primary_key = 'activities_id';
			$this->invoice_model->save($activity);
			$this->invoice_model->send_email($params);
		} else {
			return true;
		}
	}

	public function send_payment_sms($invoices_id, $payments_id)
	{
		$inv_info = $this->invoice_model->check_by(array('invoices_id' => $invoices_id), 'tbl_invoices');
		$mobile = client_can_received_sms($inv_info->client_id);

		if (!empty($mobile)) {
			$merge_fields = [];
			$merge_fields = array_merge($merge_fields, merge_invoice_template($invoices_id));
			$merge_fields = array_merge($merge_fields, merge_invoice_template($invoices_id, 'payment', $payments_id));
			$merge_fields = array_merge($merge_fields, merge_invoice_template($invoices_id, 'client', $inv_info->client_id));
			$this->sms->send(SMS_PAYMENT_RECORDED, $mobile, $merge_fields);
		}
		return true;
	}

	public function applied_credits($invoices_id)
	{
		$data['title'] = lang('applied_credits');
		$data['all_credit_used'] = get_result('tbl_credit_used', array('invoices_id' => $invoices_id));
		$data['subview'] = $this->load->view('admin/invoice/applied_credits', $data, FALSE);
	}

	public function invoiceList($filterBy = null, $search_by = null)
	{
		if ($this->input->is_ajax_request()) {
			$where = array();
			$this->load->model('datatables');
			$this->datatables->table = 'tbl_invoices';
			$this->datatables->join_table = array('tbl_client');
			$this->datatables->join_where = array('tbl_invoices.client_id=tbl_client.client_id');
			$this->datatables->select = 'tbl_invoices.*,tbl_client.name';
			$this->datatables->column_order = array('reference_no', 'tbl_client.name', 'project_id', 'invoice_date', 'due_date', 'status', 'user_id', 'tags');
			$this->datatables->column_search = array('reference_no', 'invoice_date', 'due_date', 'tbl_client.name', 'status', 'tags');
			$this->datatables->order = array('invoices_id' => 'desc');
			if (empty($filterBy)) {
				$filterBy = '_' . date('Y');
			}
			if ($filterBy === 'unpaid') {
				$filterBy = 'not_paid';
			}
			if (!empty($filterBy) && !is_numeric($filterBy)) {
				$ex = explode('_', $filterBy);
				if ($ex[0] != 'c') {
					$filterBy = $filterBy;
				}
			}
			if (!empty($search_by)) {
				if ($search_by == 'by_project') {
					$where = array('tbl_invoices.project_id' => $filterBy);
				}
				if ($search_by == 'by_agent') {
					$where = array('tbl_invoices.user_id' => $filterBy);
				}
				if ($search_by == 'by_client') {
					$where = array('tbl_invoices.client_id' => $filterBy);
				}
				if ($search_by == 'by_client_draft') {
					$where = array('tbl_invoices.client_id' => $filterBy, 'status !=' => 'draft');
				}
				if ($search_by == 'by_client_recurring') {
					$where = array('tbl_invoices.client_id' => $filterBy, 'recurring' => 'Yes');
				}
			} else {
				if ($filterBy == 'recurring') {
					$where = array('recurring' => 'Yes');
				}
				if ($filterBy == 'paid') {
					$where = array(
						'__raw_where' => "LOWER(tbl_invoices.status) NOT IN ('draft','cancelled') AND COALESCE((SELECT SUM(tbl_payments.amount) FROM tbl_payments WHERE tbl_payments.invoices_id = tbl_invoices.invoices_id), 0) > 0 AND ((COALESCE((SELECT SUM(tbl_items.total_cost) FROM tbl_items WHERE tbl_items.invoices_id = tbl_invoices.invoices_id), 0) - COALESCE(tbl_invoices.discount_total, 0) + COALESCE(tbl_invoices.adjustment, 0) + COALESCE((SELECT SUM(tbl_items.item_tax_total) FROM tbl_items WHERE tbl_items.invoices_id = tbl_invoices.invoices_id), 0)) - COALESCE((SELECT SUM(tbl_payments.amount) FROM tbl_payments WHERE tbl_payments.invoices_id = tbl_invoices.invoices_id), 0)) <= 0"
					);
				} else if ($filterBy == 'not_paid') {
					$where = array(
						'__raw_where' => "LOWER(tbl_invoices.status) NOT IN ('draft','cancelled') AND COALESCE((SELECT SUM(tbl_payments.amount) FROM tbl_payments WHERE tbl_payments.invoices_id = tbl_invoices.invoices_id), 0) < 1"
					);
				} else if ($filterBy == 'draft') {
					$where = array('status' => 'draft');
				} else if ($filterBy == 'partially_paid') {
					$where = array(
						'__raw_where' => "LOWER(tbl_invoices.status) NOT IN ('draft','cancelled') AND COALESCE((SELECT SUM(tbl_payments.amount) FROM tbl_payments WHERE tbl_payments.invoices_id = tbl_invoices.invoices_id), 0) > 0 AND ((COALESCE((SELECT SUM(tbl_items.total_cost) FROM tbl_items WHERE tbl_items.invoices_id = tbl_invoices.invoices_id), 0) - COALESCE(tbl_invoices.discount_total, 0) + COALESCE(tbl_invoices.adjustment, 0) + COALESCE((SELECT SUM(tbl_items.item_tax_total) FROM tbl_items WHERE tbl_items.invoices_id = tbl_invoices.invoices_id), 0)) - COALESCE((SELECT SUM(tbl_payments.amount) FROM tbl_payments WHERE tbl_payments.invoices_id = tbl_invoices.invoices_id), 0)) > 0"
					);
				} else if ($filterBy == 'cancelled') {
					$where = array('status' => 'Cancelled');
				} else if ($filterBy == 'overdue') {
					$where = array(
						'__raw_where' => "LOWER(tbl_invoices.status) NOT IN ('draft','cancelled') AND tbl_invoices.due_date < CURDATE() AND ((COALESCE((SELECT SUM(tbl_items.total_cost) FROM tbl_items WHERE tbl_items.invoices_id = tbl_invoices.invoices_id), 0) - COALESCE(tbl_invoices.discount_total, 0) + COALESCE(tbl_invoices.adjustment, 0) + COALESCE((SELECT SUM(tbl_items.item_tax_total) FROM tbl_items WHERE tbl_items.invoices_id = tbl_invoices.invoices_id), 0)) - COALESCE((SELECT SUM(tbl_payments.amount) FROM tbl_payments WHERE tbl_payments.invoices_id = tbl_invoices.invoices_id), 0)) > 0"
					);
				} else if ($filterBy == 'last_month' || $filterBy == 'this_months') {
					if ($filterBy == 'last_month') {
						$month = date('Y-m', safe_strtotime('-1 months'));
					} else {
						$month = date('Y-m');
					}
					$where = array('invoice_month' => $month);
				} else if (strstr($filterBy, '_')) {
					$year = str_replace('_', '', $filterBy);
					$where = array('invoice_year' => $year);
				}
			}
			// get all invoice
			$fetch_data = $this->datatables->get_datatable_permission($where);
			$data = array();

			$edited = can_action('13', 'edited');
			$deleted = can_action('13', 'deleted');
			$status_tones = array(
				lang('fully_paid') => 'success',
				lang('draft') => 'neutral',
				lang('partially_paid') => 'warning',
				lang('sent') => 'primary',
				lang('not_paid') => 'danger',
				lang('cancelled') => 'neutral',
			);

			$project_names = array();
			$user_profiles = array();
			$project_ids = array();
			$user_ids = array();
			$custom_field_headers = custom_form_table(9, null);
			$custom_field_labels = !empty($custom_field_headers) ? array_keys($custom_field_headers) : array();
			foreach ($fetch_data as $invoice_row) {
				if (!empty($invoice_row->project_id)) {
					$project_ids[] = (int) $invoice_row->project_id;
				}
				if (!empty($invoice_row->user_id)) {
					$user_ids[] = (int) $invoice_row->user_id;
				}
			}
			$project_ids = array_values(array_unique(array_filter($project_ids)));
			$user_ids = array_values(array_unique(array_filter($user_ids)));

			if (!empty($project_ids)) {
				$project_rows = $this->db->select('project_id, project_name')->where_in('project_id', $project_ids)->get('tbl_project')->result();
				foreach ($project_rows as $project_row) {
					$project_names[$project_row->project_id] = $project_row->project_name;
				}
			}

			if (!empty($user_ids)) {
				$user_rows = $this->db
					->select('user_id, fullname, avatar')
					->where_in('user_id', $user_ids)
					->get('tbl_account_details')
					->result();
				foreach ($user_rows as $user_row) {
					$user_profiles[$user_row->user_id] = $user_row;
				}
			}

			$financial_map = $this->invoice_model->get_invoice_financial_map($fetch_data);

			foreach ($fetch_data as $_key => $v_invoices) {
				if (!empty($v_invoices)) {
					$currency = client_currency($v_invoices->client_id);
					$action = null;
					$can_edit = $this->invoice_model->can_action('tbl_invoices', 'edit', array('invoices_id' => $v_invoices->invoices_id));
					$can_delete = $this->invoice_model->can_action('tbl_invoices', 'delete', array('invoices_id' => $v_invoices->invoices_id));
					$invoice_financial = isset($financial_map[$v_invoices->invoices_id]) ? $financial_map[$v_invoices->invoices_id] : array(
						'total' => 0,
						'due' => 0,
						'status' => lang('not_paid'),
					);
					$payment_status = $invoice_financial['status'];
					if ($payment_status == lang('fully_paid')) {
						$invoice_status = lang('fully_paid');
					} elseif ($payment_status == lang('draft')) {
						$invoice_status = lang('draft');
					} elseif ($payment_status == lang('partially_paid')) {
						$invoice_status = lang('partially_paid');
					} elseif ($v_invoices->emailed == 'Yes') {
						$invoice_status = lang('sent');
					} else {
						$invoice_status = $payment_status;
					}
					$status_tone = isset($status_tones[$invoice_status]) ? $status_tones[$invoice_status] : 'danger';
					$is_overdue = (strtotime($v_invoices->due_date) < strtotime(date('Y-m-d')) && $payment_status != lang('fully_paid') && $payment_status != lang('cancelled'));
					$project_name = !empty($project_names[$v_invoices->project_id]) ? $project_names[$v_invoices->project_id] : '';
					$agent_profile = !empty($user_profiles[$v_invoices->user_id]) ? $user_profiles[$v_invoices->user_id] : null;
					$invoice_total = $invoice_financial['total'];
					$invoice_due = $invoice_financial['due'];

					$sub_array = array();
					if (!empty($deleted)) {
						$sub_array[] = '<label class="inline-flex h-4 w-4 items-center justify-center"><input type="checkbox" value="' . $v_invoices->invoices_id . '" class="js-invoice-row-check h-4 w-4 rounded border-border text-primary focus:ring-2 focus:ring-primary/20"></label>';
					}

					$invoice_meta = '<div class="leading-tight">';
					$invoice_meta .= '<a class="text-sm font-semibold text-slate-900 hover:text-blue-600 dark:text-white dark:hover:text-blue-300" href="' . base_url() . 'admin/invoice/manage_invoice/invoice_details/' . $v_invoices->invoices_id . '">' . html_escape($v_invoices->reference_no) . '</a>';
					$invoice_meta .= '<div class="text-xs text-slate-500 dark:text-slate-400">#' . (int) $v_invoices->invoices_id;
					if ($is_overdue) {
						$invoice_meta .= '<span class="ml-2 text-rose-500">' . lang('overdue') . '</span>';
					}
					$invoice_meta .= '</div></div>';
					$sub_array[] = $invoice_meta;

					$client_html = '<div class="leading-tight">';
					$client_html .= '<div class="text-sm font-medium text-slate-700 dark:text-slate-200">' . html_escape($v_invoices->name) . '</div>';
					if (!empty($v_invoices->client_id)) {
						$client_html .= '<div class="text-xs text-slate-400">#' . (int) $v_invoices->client_id . '</div>';
					}
					$client_html .= '</div>';
					$sub_array[] = $client_html;

					$sub_array[] = !empty($project_name) ? '<div class="text-sm text-slate-700 dark:text-slate-200">' . html_escape($project_name) . '</div>' : '<span class="text-xs text-slate-400">-</span>';
					$sub_array[] = '<div class="text-sm text-slate-700 dark:text-slate-200">' . display_date($v_invoices->invoice_date) . '</div>';
					$sub_array[] = '<div class="leading-tight"><div class="text-sm text-slate-700 dark:text-slate-200">' . display_date($v_invoices->due_date) . '</div>' . ($is_overdue ? '<div class="text-xs text-rose-500">' . lang('overdue') . '</div>' : '') . '</div>';
					$sub_array[] = '<div class="leading-tight"><div class="text-sm font-semibold text-slate-900 dark:text-white">' . display_money($invoice_total, $currency) . '</div><div class="text-xs text-slate-500 dark:text-slate-400">' . lang('due') . ': ' . display_money($invoice_due, $currency) . '</div></div>';
					$badge_class = 'border-slate-200 text-slate-600 bg-slate-50 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300';
					if ($status_tone === 'success') {
						$badge_class = 'border-emerald-200 text-emerald-600 bg-emerald-50 dark:border-emerald-900/50 dark:bg-emerald-900/30 dark:text-emerald-300';
					} elseif ($status_tone === 'warning') {
						$badge_class = 'border-amber-200 text-amber-600 bg-amber-50 dark:border-amber-900/50 dark:bg-amber-900/30 dark:text-amber-300';
					} elseif ($status_tone === 'primary') {
						$badge_class = 'border-indigo-200 text-indigo-600 bg-indigo-50 dark:border-indigo-900/50 dark:bg-indigo-900/30 dark:text-indigo-300';
					} elseif ($status_tone === 'danger') {
						$badge_class = 'border-rose-200 text-rose-600 bg-rose-50 dark:border-rose-900/50 dark:bg-rose-900/30 dark:text-rose-300';
					}
					$sub_array[] = '<span class="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold ' . $badge_class . '">' . html_escape($invoice_status) . '</span>';

					if (!empty($agent_profile)) {
						$avatar = !empty($agent_profile->avatar) ? $agent_profile->avatar : 'assets/img/user/default_avatar.jpg';
						$agent_name = !empty($agent_profile->fullname) ? $agent_profile->fullname : fullname($v_invoices->user_id);
						$agent_html = '<div class="flex items-center gap-2"><img src="' . base_url() . $avatar . '" alt="' . html_escape($agent_name) . '" class="h-7 w-7 rounded-full object-cover"><span class="text-sm text-slate-700 dark:text-slate-200">' . html_escape($agent_name) . '</span></div>';
					} elseif (!empty($v_invoices->user_id)) {
						$agent_html = '<span class="text-sm text-slate-700 dark:text-slate-200">' . html_escape(fullname($v_invoices->user_id)) . '</span>';
					} else {
						$agent_html = '<span class="text-xs text-slate-400">-</span>';
					}
					$sub_array[] = $agent_html;

					$custom_form_table = custom_form_table(9, $v_invoices->invoices_id);
					if (!empty($custom_field_labels)) {
						foreach ($custom_field_labels as $c_label) {
							$sub_array[] = isset($custom_form_table[$c_label]) ? $custom_form_table[$c_label] : '';
						}
					}
					$action = '<div class="flex items-center justify-end gap-2">';
					$action .= btn_view('admin/invoice/manage_invoice/invoice_details/' . $v_invoices->invoices_id);
					if (!empty($can_edit) && !empty($edited)) {
						$action .= btn_modal('admin/invoice/clone_invoice/' . $v_invoices->invoices_id, '', lang('clone_invoice'), 'md', 'copy', ['class' => 'inline-flex h-8 w-8 items-center justify-center rounded-lg border border-border bg-white text-slate-700 shadow-sm']);
						$action .= btn_edit('admin/invoice/createinvoice/create_invoice/' . $v_invoices->invoices_id);
					}
					if (!empty($can_delete) && !empty($deleted)) {
						$action .= ajax_anchor(base_url("admin/invoice/delete/delete_invoice/$v_invoices->invoices_id"), '', array("class" => "", "title" => lang('delete'), "data-fade-out-on-success" => "#table_" . $_key));
					}
					$action .= '<details class="relative inline-flex">
						<summary class="inline-flex h-8 w-8 cursor-pointer list-none items-center justify-center rounded-lg border border-border bg-white text-slate-500 shadow-sm transition hover:text-slate-900 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300">
							<i data-lucide="more-horizontal" class="h-4 w-4"></i>
						</summary>
						<ul class="absolute right-0 top-full z-50 mt-2 min-w-[180px] overflow-hidden rounded-lg border border-slate-200 bg-white py-1 text-xs shadow-lg dark:border-slate-700 dark:bg-slate-800">
							<li><a class="block px-3 py-2 text-slate-700 hover:bg-slate-50 dark:text-slate-200 dark:hover:bg-slate-700" href="' . base_url() . 'admin/invoice/manage_invoice/invoice_details/' . $v_invoices->invoices_id . '">' . lang('view') . '</a></li>
							<li><a class="block px-3 py-2 text-slate-700 hover:bg-slate-50 dark:text-slate-200 dark:hover:bg-slate-700" href="' . base_url() . 'admin/invoice/manage_invoice/email_invoice/' . $v_invoices->invoices_id . '">' . lang('send_email') . '</a></li>
							<li><a class="block px-3 py-2 text-slate-700 hover:bg-slate-50 dark:text-slate-200 dark:hover:bg-slate-700" href="' . base_url() . 'admin/invoice/manage_invoice/payment/' . $v_invoices->invoices_id . '">' . lang('add_payment') . '</a></li>
							<li><a class="block px-3 py-2 text-slate-700 hover:bg-slate-50 dark:text-slate-200 dark:hover:bg-slate-700" href="' . base_url() . 'admin/invoice/manage_invoice/send_reminder/' . $v_invoices->invoices_id . '">' . lang('send_reminder') . '</a></li>
							<li><a class="block px-3 py-2 text-slate-700 hover:bg-slate-50 dark:text-slate-200 dark:hover:bg-slate-700" href="' . base_url() . 'admin/invoice/manage_invoice/invoice_history/' . $v_invoices->invoices_id . '">' . lang('invoice_history') . '</a></li>
							<li><a class="block px-3 py-2 text-slate-700 hover:bg-slate-50 dark:text-slate-200 dark:hover:bg-slate-700" href="' . base_url() . 'admin/invoice/pdf_invoice/' . $v_invoices->invoices_id . '">' . lang('pdf') . '</a></li>
							<li><a class="block px-3 py-2 text-slate-700 hover:bg-slate-50 dark:text-slate-200 dark:hover:bg-slate-700" href="' . base_url() . 'admin/invoice/manage_invoice/send_overdue/' . $v_invoices->invoices_id . '">' . lang('send_overdue') . '</a></li>
						</ul>
					</details>';
					$action .= '</div>';
					$sub_array[] = $action;
					$data[] = $sub_array;
				}
			}
			render_table($data, $where);
		} else {
			redirect('admin/dashboard');
		}
	}

	public function recurringinvoiceList($filterBy = null, $search_by = null)
	{
		if ($this->input->is_ajax_request()) {
			$where = array('recurring' => 'Yes');
			$this->load->model('datatables');
			$this->datatables->table = 'tbl_invoices';
			$this->datatables->join_table = array('tbl_client');
			$this->datatables->join_where = array('tbl_invoices.client_id=tbl_client.client_id');
			$this->datatables->select = 'tbl_invoices.*,tbl_client.name';
			$this->datatables->column_order = array('reference_no', 'invoice_date', 'due_date', 'tbl_client.name', 'status', 'tags');
			$this->datatables->column_search = array('reference_no', 'invoice_date', 'due_date', 'tbl_client.name', 'status', 'tags');
			$this->datatables->order = array('invoices_id' => 'desc');

			if (empty($filterBy)) {
				$filterBy = '';
			}
			if (!empty($filterBy) && !is_numeric($filterBy)) {
				$ex = explode('_', $filterBy);
				if ($ex[0] != 'c') {
					$filterBy = $filterBy;
				}
			}
			if (!empty($search_by)) {
				if ($search_by == 'by_project') {
					$where['project_id'] = $filterBy;
				}
				if ($search_by == 'by_agent') {
					$where['user_id'] = $filterBy;
				}
				if ($search_by == 'by_client') {
					$where['tbl_invoices.client_id'] = $filterBy;
				}
			} else {
				if ($filterBy == 'paid') {
					$where['status'] = 'Paid';
				} else if ($filterBy == 'not_paid') {
					$where['status'] = 'Unpaid';
				} else if ($filterBy == 'draft') {
					$where['status'] = 'draft';
				} else if ($filterBy == 'partially_paid') {
					$where['status'] = 'partially_paid';
				} else if ($filterBy == 'cancelled') {
					$where['status'] = 'Cancelled';
				} else if ($filterBy == 'overdue') {
					$where['UNIX_TIMESTAMP(due_date) <'] = safe_strtotime(date('Y-m-d'));
					$where['status !='] = 'Paid';
				} else if ($filterBy == 'last_month' || $filterBy == 'this_months') {
					if ($filterBy == 'last_month') {
						$month = date('Y-m', safe_strtotime('-1 months'));
					} else {
						$month = date('Y-m');
					}
					$where['invoice_month'] = $month;
				} else if (strstr($filterBy, '_')) {
					$year = str_replace('_', '', $filterBy);
					$where['invoice_year'] = $year;
				}
			}

			// get all invoice
			$fetch_data = $this->datatables->get_datatable_permission($where);

			$data = array();

			$edited = can_action('13', 'edited');
			$deleted = can_action('13', 'deleted');
			$custom_field_headers = custom_form_table(9, null);
			$custom_field_labels = !empty($custom_field_headers) ? array_keys($custom_field_headers) : array();
			foreach ($fetch_data as $_key => $v_invoices) {
				if (!empty($v_invoices)) {
					$action = null;

					$can_edit = $this->invoice_model->can_action('tbl_invoices', 'edit', array('invoices_id' => $v_invoices->invoices_id));
					$can_delete = $this->invoice_model->can_action('tbl_invoices', 'delete', array('invoices_id' => $v_invoices->invoices_id));
					if ($this->invoice_model->get_payment_status($v_invoices->invoices_id) == lang('fully_paid')) {
						$invoice_status = lang('fully_paid');
						$status_class = 'bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-800';
					} elseif ($this->invoice_model->get_payment_status($v_invoices->invoices_id) == lang('draft')) {
						$invoice_status = lang('draft');
						$status_class = 'bg-slate-100 text-slate-700 border-slate-200 dark:bg-slate-800 dark:text-slate-300 dark:border-slate-700';
					} elseif ($this->invoice_model->get_payment_status($v_invoices->invoices_id) == lang('partially_paid')) {
						$invoice_status = lang('partially_paid');
						$status_class = 'bg-amber-50 text-amber-700 border-amber-200 dark:bg-amber-900/20 dark:text-amber-300 dark:border-amber-800';
					} elseif ($v_invoices->emailed == 'Yes') {
						$invoice_status = lang('sent');
						$status_class = 'bg-blue-50 text-blue-700 border-blue-200 dark:bg-blue-900/20 dark:text-blue-300 dark:border-blue-800';
					} else {
						$invoice_status = $this->invoice_model->get_payment_status($v_invoices->invoices_id);
						$status_class = 'bg-rose-50 text-rose-700 border-rose-200 dark:bg-rose-900/20 dark:text-rose-300 dark:border-rose-800';
					}

					$sub_array = array();
					$name = null;
					$name .= '<a class="text-blue-600 hover:text-blue-900 dark:text-blue-400 dark:hover:text-blue-300" href="' . base_url() . 'admin/invoice/manage_invoice/invoice_details/' . $v_invoices->invoices_id . '">' . $v_invoices->reference_no . '</a>';

					$sub_array[] = $name;
					$sub_array[] = display_date($v_invoices->invoice_date);
					$payment_status = $this->invoice_model->get_payment_status($v_invoices->invoices_id);
					$overdue = null;
					if (strtotime($v_invoices->due_date) < strtotime(date('Y-m-d')) && $payment_status != lang('fully_paid') && $payment_status != lang('cancelled')) {
						$overdue .= '<span class="ml-1 inline-flex items-center rounded-full border border-rose-200 bg-rose-50 px-2 py-0.5 text-xs font-semibold text-rose-700 dark:border-rose-800 dark:bg-rose-900/20 dark:text-rose-300">' . lang("overdue") . '</span>';
					}
					$sub_array[] = display_date($v_invoices->due_date) . ' ' . $overdue;
					$sub_array[] = '<span class="tags">' . client_name($v_invoices->client_id) . '</span>';
					$sub_array[] = display_money($this->invoice_model->calculate_to('invoice_due', $v_invoices->invoices_id), client_currency($v_invoices->client_id));
					$recurring = null;
					if ($v_invoices->recurring == 'Yes') {
						$recurring = '<span data-toggle="tooltip" data-placement="top" title="' . lang("recurring") . '" class="ml-1 inline-flex items-center rounded-full border border-blue-200 bg-blue-50 px-2 py-0.5 text-xs font-semibold text-blue-700 dark:border-blue-800 dark:bg-blue-900/20 dark:text-blue-300"><i data-lucide="repeat-2" class="h-3.5 w-3.5"></i></span>';
					}
					$sub_array[] = "<span class='inline-flex items-center rounded-full border px-2.5 py-1 text-xs font-semibold " . $status_class . "'>" . $invoice_status . "</span>" . ' ' . $recurring;
					$sub_array[] = get_tags($v_invoices->tags, true);
					$custom_form_table = custom_form_table(9, $v_invoices->invoices_id);
					if (!empty($custom_field_labels)) {
						foreach ($custom_field_labels as $c_label) {
							$sub_array[] = isset($custom_form_table[$c_label]) ? $custom_form_table[$c_label] : '';
						}
					}
					if (!empty($can_edit) && !empty($edited)) {
						$action .= btn_modal('admin/invoice/clone_invoice/' . $v_invoices->invoices_id, '', lang('clone_invoice'), 'md', 'copy', ['class' => 'inline-flex h-7 items-center gap-1 rounded-md border border-emerald-200 bg-emerald-50 px-2 py-1 text-xs font-semibold text-emerald-700 hover:bg-emerald-100 dark:border-emerald-800 dark:bg-emerald-900/20 dark:text-emerald-300 dark:hover:bg-emerald-900/40']);
						$action .= btn_edit('admin/invoice/createinvoice/create_invoice/' . $v_invoices->invoices_id) . ' ';
					}
					if (!empty($can_delete) && !empty($deleted)) {
						$action .= ajax_anchor(base_url("admin/invoice/delete/delete_invoice/$v_invoices->invoices_id"), '', array("class" => "inline-flex h-7 items-center rounded-md border border-rose-200 bg-rose-50 px-2 py-1 text-xs font-semibold text-rose-700 hover:bg-rose-100 dark:border-rose-800 dark:bg-rose-900/20 dark:text-rose-300 dark:hover:bg-rose-900/40", "title" => lang('delete'), "data-fade-out-on-success" => "#table_" . $_key)) . ' ';
					}
					$change_status = null;
					if (!empty($can_edit) && !empty($edited)) {
						$ch_url = base_url() . 'admin/invoice/';
						$change_status .= '<details class="relative inline-flex">
							<summary class="inline-flex cursor-pointer list-none items-center justify-center gap-1 rounded-md border border-slate-200 bg-white px-2 py-1 text-slate-500 shadow-sm transition-colors hover:bg-slate-50 hover:text-slate-900 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-gray-200 mb-1 h-7 text-xs">
                                <i data-lucide="settings" class="h-4 w-4"></i>' . lang('change') . '
	            			</summary>
							<ul class="absolute right-0 top-full z-50 mt-1 min-w-[170px] overflow-hidden rounded-lg border border-slate-200 bg-white py-1 text-xs shadow-lg dark:border-gray-700 dark:bg-gray-800">';
						$change_status .= '<li><a class="block px-3 py-2 text-slate-700 hover:bg-slate-50 dark:text-slate-300 dark:hover:bg-gray-700" href="' . $ch_url . 'manage_invoice/invoice_details/' . $v_invoices->invoices_id . '">' . lang('preview_invoice') . '</a></li>';
						$change_status .= '<li><a class="block px-3 py-2 text-slate-700 hover:bg-slate-50 dark:text-slate-300 dark:hover:bg-gray-700" href="' . $ch_url . 'manage_invoice/payment/' . $v_invoices->invoices_id . '">' . lang('pay_invoice') . '</a></li>';
						$change_status .= '<li><a class="block px-3 py-2 text-slate-700 hover:bg-slate-50 dark:text-slate-300 dark:hover:bg-gray-700" href="' . $ch_url . 'manage_invoice/email_invoice/' . $v_invoices->invoices_id . '">' . lang('email_invoice') . '</a></li>';
						$change_status .= '<li><a class="block px-3 py-2 text-slate-700 hover:bg-slate-50 dark:text-slate-300 dark:hover:bg-gray-700" href="' . $ch_url . 'manage_invoice/send_reminder/' . $v_invoices->invoices_id . '">' . lang('send_reminder') . '</a></li>';
						$change_status .= '<li><a class="block px-3 py-2 text-slate-700 hover:bg-slate-50 dark:text-slate-300 dark:hover:bg-gray-700" href="' . $ch_url . 'manage_invoice/send_overdue/' . $v_invoices->invoices_id . '">' . lang('send_invoice_overdue') . '</a></li>';
						$change_status .= '<li><a class="block px-3 py-2 text-slate-700 hover:bg-slate-50 dark:text-slate-300 dark:hover:bg-gray-700" href="' . $ch_url . 'manage_invoice/invoice_history/' . $v_invoices->invoices_id . '">' . lang('invoice_history') . '</a></li>';
						$change_status .= '<li><a class="block px-3 py-2 text-slate-700 hover:bg-slate-50 dark:text-slate-300 dark:hover:bg-gray-700" href="' . $ch_url . 'pdf_invoice/' . $v_invoices->invoices_id . '">' . lang('pdf') . '</a></li>';
						$change_status .= '</ul></details>';
						$action .= $change_status;
					}

					$sub_array[] = $action;
					$data[] = $sub_array;
				}
			}
			render_table($data, array('recurring' => 'Yes'));
		} else {
			redirect('admin/dashboard');
		}
	}

	public function paymentList($filterBy = null, $search_by = null)
	{
		if ($this->input->is_ajax_request()) {
			$this->load->model('datatables');
			$this->datatables->table = 'tbl_payments';
			$this->datatables->join_table = array('tbl_invoices', 'tbl_client', 'tbl_payment_methods');
			$this->datatables->join_where = array('tbl_payments.invoices_id=tbl_invoices.invoices_id', 'tbl_payments.paid_by=tbl_client.client_id', 'tbl_payment_methods.payment_methods_id=tbl_payments.payment_method');
			$this->datatables->column_order = array('tbl_payments.payment_date', 'tbl_invoices.invoice_date', 'tbl_invoices.reference_no', 'tbl_client.name', 'amount', 'tbl_invoices.date_saved', 'tbl_payment_methods.method_name');
			$this->datatables->column_search = array('tbl_payments.trans_id', 'tbl_payments.payment_date', 'tbl_invoices.invoice_date', 'tbl_invoices.reference_no', 'tbl_client.name', 'amount', 'tbl_invoices.date_saved', 'tbl_payment_methods.method_name', 'tbl_payments.payment_method');
			$this->datatables->order = array('payments_id' => 'desc');

			$where = array();
			if (!empty($search_by)) {
				if ($search_by == 'by_invoice') {
					$where = array('tbl_payments.invoices_id' => $filterBy);
				}
				if ($search_by == 'by_account') {
					$where = array('account_id' => $filterBy);
				}
				if ($search_by == 'by_client') {
					$where = array('tbl_payments.paid_by' => $filterBy);
				}
			} else {
				if ($filterBy == 'last_month' || $filterBy == 'this_months') {
					if ($filterBy == 'last_month') {
						$month = date('m', safe_strtotime('-1 months'));
						$year = date('Y', safe_strtotime('-1 months'));
					} else {
						$month = date('m');
						$year = date('Y');
					}
					$where = array('year_paid' => $year, 'month_paid' => $month);
				} else if ($filterBy == 'today') {
					$where = array('UNIX_TIMESTAMP(payment_date)' => safe_strtotime(date('Y-m-d')));
				} else if (!empty($filterBy) && strstr((string) $filterBy, '_')) {
					$year = str_replace('_', '', $filterBy);
					$where = array('year_paid' => $year);
				}
			}

			// get all invoice
			$fetch_data = $this->datatables->get_payment($filterBy, $search_by);
			$data = array();

			$edited = can_action('13', 'edited');
			$deleted = can_action('13', 'deleted');
			foreach ($fetch_data as $_key => $v_payments_info) {
				if (!empty($v_payments_info)) {
					if (!empty($v_payments_info->system_currency)) {
						$currency = $this->invoice_model->check_by(array('code' => $v_payments_info->system_currency), 'tbl_currencies');
					} else {
						$currency = $this->invoice_model->check_by(array('code' => config_item('default_currency')), 'tbl_currencies');
					}
					$action = null;
					$invoice_id = !empty($v_payments_info->invoices_id) ? (int) $v_payments_info->invoices_id : 0;
					$can_edit = $this->invoice_model->can_action('tbl_invoices', 'edit', array('invoices_id' => $invoice_id));
					$can_delete = $this->invoice_model->can_action('tbl_invoices', 'delete', array('invoices_id' => $invoice_id));
					$method_name = !empty($v_payments_info->method_name) ? $v_payments_info->method_name : $v_payments_info->payment_method;
					$sub_array = array();
					$name = null;
					$name .= '<a class="text-blue-600 hover:text-blue-900 dark:text-blue-400 dark:hover:text-blue-300" href="' . base_url() . 'admin/invoice/manage_invoice/payments_details/' . $v_payments_info->payments_id . '">' . display_date($v_payments_info->payment_date) . '</a>';

					$sub_array[] = $name;
					$sub_array[] = !empty($v_payments_info->invoice_date) ? display_date($v_payments_info->invoice_date) : '-';
					$sub_array[] = '<a class="text-blue-600 hover:text-blue-900 dark:text-blue-400 dark:hover:text-blue-300" href="' . base_url() . 'admin/invoice/manage_invoice/invoice_details/' . $invoice_id . '">' . (!empty($v_payments_info->reference_no) ? $v_payments_info->reference_no : '-') . '</a>';
					$sub_array[] = !empty($v_payments_info->name) ? $v_payments_info->name : lang('undefined_client');
					$sub_array[] = display_money($v_payments_info->amount, $currency->symbol);
					$sub_array[] = !empty($method_name) ? $method_name : '-';

					if (!empty($can_edit) && !empty($edited)) {
						$action .= btn_edit('admin/invoice/all_payments/' . $v_payments_info->payments_id) . ' ';
					}
					if (!empty($can_delete) && !empty($deleted)) {
						$action .= ajax_anchor(base_url("admin/invoice/delete/delete_payment/$v_payments_info->payments_id"), lang('delete'), array("class" => "", "title" => lang('delete'), "data-fade-out-on-success" => "#table_" . $_key)) . ' ';
					}
					$action .= btn_view('admin/invoice/manage_invoice/payments_details/' . $v_payments_info->payments_id) . ' ';
					$action .= btn_mail('admin/invoice/send_payment/' . $v_payments_info->payments_id . '/' . $v_payments_info->amount);

					$sub_array[] = $action;
					$data[] = $sub_array;
				}
			}

			render_table($data, $where);
		} else {
			redirect('admin/dashboard');
		}
	}

	public
	function make_payment()
	{
		$edited = can_action('13', 'edited');
		if (!empty($edited)) {
			$this->load->helper('string');
			$data['batch_client_options'] = array('' => lang('filter') . ' ' . lang('invoice') . ' ' . lang('by') . ' ' . lang('client'));
			$data['default_account_id'] = config_item('default_account');
			$data['payment_methods'] = $this->db->order_by('method_name', 'asc')->get('tbl_payment_methods')->result();
			$data['redirect_to'] = !empty($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : base_url('admin/invoice/manage_invoice');
			$client_id = (int) $this->input->get('client_id', true);
			$lock_client = !empty($client_id) && $this->input->get('lock_client', true) == '1';
			$page = (int) $this->input->get('page', true);
			$per_page = (int) $this->input->get('per_page', true);
			if ($page < 1) {
				$page = 1;
			}
			if (!in_array($per_page, array(25, 50, 100), true)) {
				$per_page = 25;
			}
			if ($this->input->get('reset', true) == '1') {
				$this->clear_batch_payment_draft();
			}

			$client_rows = $this->invoice_model->get_batch_payment_clients();
			if (!empty($client_rows)) {
				foreach ($client_rows as $client_row) {
					$label = !empty($client_row->client_name) ? $client_row->client_name : (lang('client') . ' #' . $client_row->client_id);
					$data['batch_client_options'][(string) $client_row->client_id] = $label . ' (' . (int) $client_row->unpaid_count . ')';
				}
			}

			$total_invoices = $this->invoice_model->count_batch_payment_invoices($client_id ?: null);
			$total_pages = $total_invoices > 0 ? (int) ceil($total_invoices / $per_page) : 1;
			if ($page > $total_pages) {
				$page = $total_pages;
			}
			$offset = ($page - 1) * $per_page;
			$draft = $this->get_batch_payment_draft();
			$data['batch_rows'] = array();
			$invoice_rows = $this->invoice_model->get_batch_payment_invoice_page($per_page, $offset, $client_id ?: null);
			foreach ((array) $invoice_rows as $invoice_row) {
				$invoice_id = (int) $invoice_row->invoices_id;
				$invoice_currency = get_sales_currency($invoice_row);
				$draft_row = !empty($draft[$invoice_id]) ? $draft[$invoice_id] : array();
				$data['batch_rows'][] = array(
					'invoices_id' => $invoice_id,
					'client_id' => (int) $invoice_row->client_id,
					'client_name' => !empty($invoice_row->client_name) ? $invoice_row->client_name : (lang('client') . ' #' . $invoice_row->client_id),
					'reference_no' => !empty($invoice_row->reference_no) ? $invoice_row->reference_no : ('INV-' . $invoice_id),
					'payment_date' => isset($draft_row['payment_date']) ? $draft_row['payment_date'] : date('Y-m-d'),
					'payment_methods_id' => isset($draft_row['payment_methods_id']) ? $draft_row['payment_methods_id'] : '',
					'trans_id' => isset($draft_row['trans_id']) ? $draft_row['trans_id'] : random_string('nozero', 6),
					'amount' => isset($draft_row['amount']) ? $draft_row['amount'] : '',
					'due_amount' => round((float) $invoice_row->due_amount, 2),
					'currency_symbol' => !empty($invoice_currency->symbol) ? $invoice_currency->symbol : client_currency($invoice_row->client_id),
				);
			}
			$data['batch_client_id'] = $client_id;
			$data['batch_lock_client'] = $lock_client;
			$data['batch_page'] = $page;
			$data['batch_per_page'] = $per_page;
			$data['batch_total_invoices'] = $total_invoices;
			$data['batch_total_pages'] = $total_pages;
			$data['batch_draft_total'] = $this->get_batch_payment_draft_total($draft);
			$data['modal_subview'] = $this->load->view('admin/invoice/make_payment', $data, FALSE);
		} else {
			set_message('error', lang('there_in_no_value'));
			if (empty($_SERVER['HTTP_REFERER'])) {
				redirect('admin/invoice/all_payments');
			} else {
				redirect($_SERVER['HTTP_REFERER']);
			}
		}
	}

	public function save_batch_payments()
	{
		$edited = can_action('13', 'edited');
		$is_ajax = $this->input->is_ajax_request();
		if (empty($edited)) {
			set_message('error', lang('there_in_no_value'));
			if ($is_ajax) {
				$this->invoice_json_response('error', lang('there_in_no_value'));
			}
			redirect('admin/invoice/manage_invoice');
		}

		$this->load->helper('string');
		$draft = $this->merge_batch_payment_draft_from_request();
		$redirect_to = $this->input->post('redirect_to', TRUE);
		$batch_client_id = (int) $this->input->post('batch_client_id', TRUE);
		$account_id = $this->input->post('account_id', TRUE);
		$skip_payment_email = $this->input->post('skip_payment_email', TRUE);
		$save_into_account = $this->input->post('save_into_account', TRUE);

		if (empty($redirect_to) || strpos($redirect_to, base_url()) !== 0) {
			$redirect_to = base_url('admin/invoice/manage_invoice/all_payments');
		}

		$processed = 0;
		$errors = array();

		foreach ($draft as $invoice_id => $draft_row) {
			$invoice_id = (int) $invoice_id;
			if (empty($invoice_id)) {
				continue;
			}

			$paid_amount = isset($draft_row['amount']) ? (float) $draft_row['amount'] : 0;
			if ($paid_amount <= 0) {
				continue;
			}

			$can_edit = $this->invoice_model->can_action('tbl_invoices', 'edit', array('invoices_id' => $invoice_id));
			if (empty($can_edit)) {
				$errors[] = lang('there_in_no_value');
				continue;
			}

			$due_amount = round((float) $this->invoice_model->calculate_to('invoice_due', $invoice_id), 2);
			$invoice_info = $this->invoice_model->check_by(array('invoices_id' => $invoice_id), 'tbl_invoices');
			$invoice_label = !empty($invoice_info->reference_no) ? $invoice_info->reference_no : ('#' . $invoice_id);
			if (!empty($batch_client_id) && (empty($invoice_info->client_id) || (int) $invoice_info->client_id !== $batch_client_id)) {
				$errors[] = $invoice_label . ': ' . lang('client') . ' mismatch';
				continue;
			}

			if ($due_amount <= 0) {
				continue;
			}

			if ($paid_amount > $due_amount) {
				$errors[] = $invoice_label . ': ' . lang('overpaid_amount');
				continue;
			}

			$payment_method = isset($draft_row['payment_methods_id']) ? trim($draft_row['payment_methods_id']) : '';
			if ($payment_method === '') {
				$errors[] = $invoice_label . ': Payment method is required';
				continue;
			}

			$payment_date = isset($draft_row['payment_date']) ? trim($draft_row['payment_date']) : '';
			if ($payment_date === '') {
				$payment_date = date('Y-m-d');
			}
			$trans_id = isset($draft_row['trans_id']) ? trim($draft_row['trans_id']) : '';
			if ($trans_id === '') {
				$trans_id = random_string('nozero', 6);
			}

			$this->record_invoice_payment($invoice_id, array(
				'paid_amount' => $paid_amount,
				'payment_date' => $payment_date,
				'payment_method' => $payment_method,
				'currency' => '',
				'trans_id' => $trans_id,
				'notes' => '',
				'save_into_account' => !empty($save_into_account),
				'account_id' => $account_id,
				'send_email' => empty($skip_payment_email),
				'send_sms' => false,
			));
			$processed++;
		}

		if (!empty($processed)) {
			set_message('success', $processed . ' payment(s) recorded successfully');
		}
		if (!empty($errors)) {
			foreach (array_slice($errors, 0, 5) as $error) {
				set_message('error', $error);
			}
		}
		if (empty($processed) && empty($errors)) {
			$errors[] = 'Enter an amount greater than 0 before applying payments.';
			set_message('error', $errors[0]);
		}
		$this->clear_batch_payment_draft();

		if ($is_ajax) {
			if (!empty($processed)) {
				$message = $processed . ' payment(s) recorded successfully';
				if (!empty($errors)) {
					$message .= '. Some rows were skipped: ' . implode('; ', array_slice($errors, 0, 3));
				}
				$this->invoice_json_response('success', $message, array('reload_page' => true));
			}
			$message = !empty($errors) ? implode('; ', array_slice($errors, 0, 3)) : lang('there_in_no_value');
			$this->invoice_json_response('error', $message);
		}

		redirect($redirect_to);
	}

	public function save_batch_payment_draft()
	{
		if (!$this->input->is_ajax_request()) {
			show_404();
		}

		$draft = $this->merge_batch_payment_draft_from_request();
		return $this->output
			->set_content_type('application/json')
			->set_output(json_encode(array(
				'status' => true,
				'draft_count' => count($draft),
				'draft_total' => $this->get_batch_payment_draft_total($draft),
			)));
	}

	private function batch_payment_draft_session_key()
	{
		return 'invoice_batch_payment_draft_' . (int) $this->session->userdata('user_id');
	}

	private function get_batch_payment_draft()
	{
		$draft = $this->session->userdata($this->batch_payment_draft_session_key());
		return is_array($draft) ? $draft : array();
	}

	private function set_batch_payment_draft(array $draft)
	{
		$this->session->set_userdata($this->batch_payment_draft_session_key(), $draft);
	}

	private function clear_batch_payment_draft()
	{
		$this->session->unset_userdata($this->batch_payment_draft_session_key());
	}

	private function merge_batch_payment_draft_from_request()
	{
		$draft = $this->get_batch_payment_draft();
		$invoice_ids = (array) $this->input->post('invoice_ids', TRUE);
		$payment_dates = (array) $this->input->post('payment_date', TRUE);
		$payment_methods = (array) $this->input->post('payment_methods_id', TRUE);
		$trans_ids = (array) $this->input->post('trans_id', TRUE);
		$amounts = (array) $this->input->post('amount', TRUE);

		foreach ($invoice_ids as $invoice_id) {
			$invoice_id = (int) $invoice_id;
			if (empty($invoice_id)) {
				continue;
			}
			$existing = !empty($draft[$invoice_id]) ? $draft[$invoice_id] : array();
			$draft[$invoice_id] = array(
				'payment_date' => isset($payment_dates[$invoice_id]) ? trim($payment_dates[$invoice_id]) : (isset($existing['payment_date']) ? $existing['payment_date'] : ''),
				'payment_methods_id' => isset($payment_methods[$invoice_id]) ? trim($payment_methods[$invoice_id]) : (isset($existing['payment_methods_id']) ? $existing['payment_methods_id'] : ''),
				'trans_id' => isset($trans_ids[$invoice_id]) ? trim($trans_ids[$invoice_id]) : (isset($existing['trans_id']) ? $existing['trans_id'] : ''),
				'amount' => isset($amounts[$invoice_id]) ? trim($amounts[$invoice_id]) : (isset($existing['amount']) ? $existing['amount'] : ''),
			);
		}

		$this->set_batch_payment_draft($draft);
		return $draft;
	}

	private function get_batch_payment_draft_total(array $draft)
	{
		$total = 0;
		foreach ($draft as $row) {
			$total += isset($row['amount']) ? (float) $row['amount'] : 0;
		}
		return $total;
	}

	private function record_invoice_payment($invoices_id, array $payload = array())
	{
		$inv_info = $this->invoice_model->check_by(array('invoices_id' => $invoices_id), 'tbl_invoices');
		if (empty($inv_info)) {
			return false;
		}

		$currency_row = $this->invoice_model->check_by(array('code' => $inv_info->currency), 'tbl_currencies');
		$display_currency = !empty($payload['currency']) ? $payload['currency'] : (!empty($currency_row->symbol) ? $currency_row->symbol : $inv_info->currency);
		$paid_amount = (float) $payload['paid_amount'];
		$payment_date = !empty($payload['payment_date']) ? $payload['payment_date'] : date('Y-m-d');
		$payment_method = isset($payload['payment_method']) ? $payload['payment_method'] : '';
		$trans_id = !empty($payload['trans_id']) ? $payload['trans_id'] : date('His') . $invoices_id;
		$notes = isset($payload['notes']) ? $payload['notes'] : '';
		$save_into_account = !empty($payload['save_into_account']);
		$account_id = !empty($payload['account_id']) ? $payload['account_id'] : config_item('default_account');
		$send_email = !empty($payload['send_email']);
		$send_sms = !empty($payload['send_sms']);

		$data = array(
			'invoices_id' => $invoices_id,
			'paid_by' => $inv_info->client_id,
			'payment_method' => $payment_method,
			'currency' => $display_currency,
			'amount' => $paid_amount,
			'payment_date' => $payment_date,
			'trans_id' => $trans_id,
			'notes' => $notes,
			'month_paid' => date("m", safe_strtotime($payment_date)),
			'year_paid' => date("Y", safe_strtotime($payment_date)),
		);

		$this->invoice_model->_table_name = 'tbl_payments';
		$this->invoice_model->_primary_key = 'payments_id';
		$payments_id = $this->invoice_model->save($data);

		$due_amount = round((float) $this->invoice_model->calculate_to('invoice_due', $invoices_id), 2);
		$invoice_data['status'] = ($due_amount == 0) ? 'Paid' : 'partially_paid';
		update('tbl_invoices', array('invoices_id' => $invoices_id), $invoice_data);

		$this->invoice_model->_table_name = 'tbl_award_points';
		$this->invoice_model->_primary_key = 'tbl_award_points_id ';

		$client_award_point = (!empty(config_item('client_award_ponint')) ? config_item('client_award_ponint') : 0);
		$client_purchese_price = (!empty(config_item('client_spent_amount')) ? config_item('client_spent_amount') : 0);
		$user_sales_price = (!empty(config_item('staff_spent_amount')) ? config_item('staff_spent_amount') : 0);
		$user_award_point = (!empty(config_item('staff_award_ponint')) ? config_item('staff_award_ponint') : 0);

		$client_point = 0;
		if ($client_award_point != 0 || $client_purchese_price != 0) {
			if ($paid_amount >= $client_purchese_price && !empty($client_purchese_price)) {
				$client_point = floor(($paid_amount / $client_purchese_price) * $client_award_point);
			}
		}

		$award_p['client_award_point'] = $client_point;
		$staff_point = 0;
		if ($client_award_point != 0 || $user_sales_price != 0) {
			if ($paid_amount >= $user_sales_price && !empty($user_sales_price)) {
				$staff_point = floor(($paid_amount / $user_sales_price) * $user_award_point);
			}
		}
		$award_p['user_award_point'] = $staff_point;
		$award_p['client_id'] = $inv_info->client_id;
		$award_p['user_id'] = my_id();
		$award_p['invoices_id'] = $invoices_id;
		$award_p['payment_status'] = $invoice_data['status'];
		$award_p['date'] = date('Y-m-d');
		$this->invoice_model->save($award_p);

		$activity = array(
			'user' => $this->session->userdata('user_id'),
			'module' => 'invoice',
			'module_field_id' => $invoices_id,
			'activity' => ('activity_new_payment'),
			'icon' => 'fa-shopping-cart',
			'link' => 'admin/invoice/manage_invoice/invoice_details/' . $invoices_id,
			'value1' => display_money($paid_amount, client_currency($inv_info->client_id)),
			'value2' => $inv_info->reference_no,
		);
		$this->invoice_model->_table_name = 'tbl_activities';
		$this->invoice_model->_primary_key = 'activities_id';
		$this->invoice_model->save($activity);

		if (!empty($inv_info->user_id)) {
			$notifiedUsers = array($inv_info->user_id);
			foreach ($notifiedUsers as $users) {
				if ($users != $this->session->userdata('user_id')) {
					add_notification(array(
						'to_user_id' => $users,
						'description' => 'not_new_invoice_payment',
						'icon' => 'shopping-cart',
						'link' => 'admin/invoice/manage_invoice/invoice_details/' . $invoices_id,
						'value' => lang('invoice') . ' ' . $inv_info->reference_no . ' ' . lang('amount') . display_money($paid_amount, $display_currency),
					));
				}
			}
			show_notification($notifiedUsers);
		}
		$this->refresh_project_finance_cache($invoices_id);

		if ($save_into_account && !empty($account_id)) {
			if (!finance_guard_accounting_period(date('Y-m-d', safe_strtotime($payment_date)), lang('invoice_payment'))) {
				return;
			}
			$reference = lang('invoice') . ' ' . lang('reference_no') . ": <a href='" . base_url('admin/invoice/manage_invoice/invoice_details/' . $inv_info->invoices_id) . "' >" . $inv_info->reference_no . "</a> and " . lang('trans_id') . ": <a href='" . base_url('admin/invoice/manage_invoice/payments_details/' . $payments_id) . "'>" . $trans_id . "</a>";
			$transaction_payment_method = is_numeric($payment_method) ? $payment_method : config_item('default_payment_method');
			$tr_data = array(
				'name' => lang('invoice_payment', lang('trans_id') . '# ' . $trans_id),
				'type' => 'Income',
				'amount' => $paid_amount,
				'credit' => $paid_amount,
				'date' => date('Y-m-d', safe_strtotime($payment_date)),
				'paid_by' => $inv_info->client_id,
				'payment_methods_id' => $transaction_payment_method,
				'reference' => $trans_id,
				'notes' => lang('this_deposit_from_invoice_payment', $reference),
				'permission' => 'all',
			);

			$account_info = $this->invoice_model->check_by(array('account_id' => $account_id), 'tbl_accounts');
			if (!empty($account_info)) {
				$ac_data['balance'] = $account_info->balance + $tr_data['amount'];
				$this->invoice_model->_table_name = "tbl_accounts";
				$this->invoice_model->_primary_key = "account_id";
				$this->invoice_model->save($ac_data, $account_info->account_id);
				finance_sync_model()->sync_account_by_id($account_info->account_id);

				$aaccount_info = $this->invoice_model->check_by(array('account_id' => $account_id), 'tbl_accounts');
				$tr_data['total_balance'] = $aaccount_info->balance;
				$tr_data['account_id'] = $account_id;

				$this->invoice_model->_table_name = "tbl_transactions";
				$this->invoice_model->_primary_key = "transactions_id";
				$return_id = $this->invoice_model->save($tr_data);
				finance_sync_model()->sync_transaction_by_id($return_id);

				$deduct_account['account_id'] = $account_id;
				$this->invoice_model->_table_name = 'tbl_payments';
				$this->invoice_model->_primary_key = 'payments_id';
				$this->invoice_model->save($deduct_account, $payments_id);

				$activities = array(
					'user' => $this->session->userdata('user_id'),
					'module' => 'transactions',
					'module_field_id' => $return_id,
					'activity' => 'activity_new_deposit',
					'icon' => 'fa-building-o',
					'link' => 'admin/transactions/view_details/' . $return_id,
					'value1' => $account_info->account_name,
					'value2' => $paid_amount,
				);
				$this->invoice_model->_table_name = "tbl_activities";
				$this->invoice_model->_primary_key = "activities_id";
				$this->invoice_model->save($activities);
			}
		}

		if ($send_email) {
			$this->send_payment_email($invoices_id, $paid_amount);
		}

		if ($send_sms) {
			$this->send_payment_sms($invoices_id, $payments_id);
		}
		$this->refresh_project_finance_cache($invoices_id);

		return array(
			'payments_id' => $payments_id,
			'status' => $invoice_data['status'],
		);
	}

	private function refresh_project_finance_cache($invoices_id)
	{
		$invoice_info = $this->invoice_model->check_by(array('invoices_id' => (int) $invoices_id), 'tbl_invoices');
		if (!empty($invoice_info) && !empty($invoice_info->project_id)) {
			finance_report_model()->refresh_project_finance_summary((int) $invoice_info->project_id);
		}
		if (!empty($invoice_info) && !empty($invoice_info->client_id)) {
			$this->clear_client_invoice_cache((int) $invoice_info->client_id);
		}
	}

	private function clear_client_invoice_cache($client_id)
	{
		$client_id = (int) $client_id;
		if (empty($client_id) || empty($this->cache) || !method_exists($this->cache, 'delete')) {
			return;
		}

		$this->cache->delete('client_tab_data_' . $client_id . '_invoices');
		$this->cache->delete('client_tab_data_' . $client_id . '_payments');
		$this->cache->delete('client_summary_' . $client_id);
		$this->cache->delete('client_details_tabs_' . $client_id . '_' . md5('segmented'));
		$this->cache->delete('client_details_tabs_' . $client_id . '_' . md5(''));
	}

	private function refresh_project_finance_cache_by_payment_id($payments_id)
	{
		$payment_info = $this->invoice_model->check_by(array('payments_id' => (int) $payments_id), 'tbl_payments');
		if (!empty($payment_info) && !empty($payment_info->invoices_id)) {
			$this->refresh_project_finance_cache((int) $payment_info->invoices_id);
		}
	}

	public
	function client_change_data($customer_id, $current_invoice = 'undefined')
	{
		if ($this->input->is_ajax_request()) {
			$data = array();
			$data['client_currency'] = $this->invoice_model->client_currency_symbol($customer_id);
			$_data['invoices_to_merge'] = $this->invoice_model->check_for_merge_invoice($customer_id, $current_invoice);
			$data['merge_info'] = $this->load->view('admin/invoice/merge_invoice', $_data, true);
			echo json_encode($data);
			exit();
		}
	}

	public
	function get_merge_data($id)
	{
		$invoice_items = $this->invoice_model->ordered_items_by_id($id);
		$i = 0;
		foreach ($invoice_items as $item) {
			$invoice_items[$i]->taxname = $this->invoice_model->get_invoice_item_taxes($item->items_id);
			//            $invoice_items[$i]->new_itmes_id = $item->saved_items_id;
			$invoice_items[$i]->qty = $item->quantity;
			$invoice_items[$i]->rate = $item->unit_cost;
			$i++;
		}
		echo json_encode($invoice_items);
		exit();
	}

	public
	function payments_pdf($id)
	{
		$data['title'] = "Payments PDF"; //Page title
		// get payment info by id
		$this->invoice_model->_table_name = 'tbl_payments';
		$this->invoice_model->_order_by = 'payments_id';
		$data['payments_info'] = $this->invoice_model->get_by(array('payments_id' => $id), TRUE);
		$this->load->helper('dompdf');
		$viewfile = $this->load->view('admin/invoice/payments_pdf', $data, TRUE);
		pdf_create($viewfile, slug_it('Payment  # ' . $data['payments_info']->trans_id));
	}

	public
	function payments_print($id)
	{
		$data['title'] = "Payment Receipt";
		$this->invoice_model->_table_name = 'tbl_payments';
		$this->invoice_model->_order_by = 'payments_id';
		$data['payments_info'] = $this->invoice_model->get_by(array('payments_id' => $id), TRUE);
		if (empty($data['payments_info'])) {
			show_404();
			return;
		}
		$data['print_mode'] = true;
		$this->load->view('admin/invoice/payments_pdf', $data);
	}

	public
	function pdf_invoice($id)
	{
		$preview = (string) $this->input->get('preview', true);
		if ($preview === '1') {
			$this->invoice_details($id, 'preview');
			return;
		}
		$this->invoice_details($id, true);
	}

	public
	function project_invoice($id)
	{
		$data['title'] = lang('project') . ' ' . lang('invoice'); //Page title
		$data['active'] = 2;
		$data['project_id'] = $id;
		$data['project_info'] = $this->invoice_model->check_by(array('project_id' => $id), 'tbl_project');
		// get all client
		$this->invoice_model->_table_name = 'tbl_client';
		$this->invoice_model->_order_by = 'client_id';
		$data['all_client'] = $this->invoice_model->get();
		// get permission user
		$data['permission_user'] = $this->invoice_model->all_permission_user('13');
		// get all invoice
		$data['all_invoices_info'] = $this->invoice_model->get_permission('tbl_invoices');
		$data['subview'] = $this->load->view('admin/invoice/manage_invoice', $data, TRUE);
		$this->load->view('admin/_layout_main', $data); //page load
	}

	public
	function all_payments($id = NULL)
	{
		if (!empty($id)) {
			$can_edit = $this->invoice_model->can_action('tbl_invoices', 'edit', array('invoices_id' => $id));
			if (!empty($can_edit)) {
				$payments_info = $this->invoice_model->check_by(array('payments_id' => $id), 'tbl_payments');
				$data['invoice_info'] = $this->invoice_model->check_by(array('invoices_id' => $payments_info->invoices_id), 'tbl_invoices');
			}
			$data['title'] = "Edit Payments"; //Page title
			$subview = 'edit_payments';
		} else {
			$data['title'] = "All Payments"; //Page title
			$data['page_title'] = lang('all_payments');
			$data['page_description'] = lang('payments') . ' ' . lang('list');
			$data['datatable_preload'] = $this->capture_datatable_preload(function () {
				$this->paymentList();
			});
			$data['header_actions'] = array();
			$data['header_actions_html'] = '';
			$data['header_filters'] = array();
			$subview = 'all_payments';
			$data['dataTables'] = true;
			$edited = can_action('13', 'edited');
			$deleted = can_action('13', 'deleted');
			$is_department_head = is_department_head();
			$can_filter = ($this->session->userdata('user_type') == 1 || !empty($is_department_head));
			if (!empty($edited) && !empty($deleted)) {
				$data['header_actions_html'] .= btn_modal(
					'admin/invoice/zipped/payment',
					lang('zip_payment'),
					lang('zip_payment'),
					'md',
					'archive',
					array('class' => 'inline-flex items-center gap-2 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-2.5 text-sm font-semibold text-emerald-700 shadow-sm transition-colors hover:bg-emerald-100 dark:border-emerald-900/60 dark:bg-emerald-950/40 dark:text-emerald-200 dark:hover:bg-emerald-950/60')
				);
				$data['header_actions_html'] .= btn_modal(
					'admin/invoice/make_payment',
					lang('batch') . ' ' . lang('payments'),
					'Add Payments',
					'xl',
					'credit-card',
					array('class' => 'inline-flex items-center gap-2 rounded-xl border border-violet-600 bg-violet-600 px-4 py-2.5 text-sm font-semibold text-white shadow-sm transition-colors hover:bg-violet-500 dark:border-violet-500 dark:bg-violet-500 dark:hover:bg-violet-400')
				);
			}
			if ($can_filter) {
				$payment_filter_items = array(
					array(
						'label' => lang('all'),
						'active' => true,
						'attrs' => array(
							'data-payment-filter-action' => '1',
							'data-payment-filter' => '',
							'data-payment-search' => '',
							'data-payment-filter-label' => lang('all'),
						),
					),
					array(
						'label' => lang('today'),
						'attrs' => array(
							'data-payment-filter-action' => '1',
							'data-payment-filter' => 'today',
							'data-payment-search' => '',
							'data-payment-filter-label' => lang('today'),
						),
					),
					array(
						'label' => lang('this_months'),
						'attrs' => array(
							'data-payment-filter-action' => '1',
							'data-payment-filter' => 'this_months',
							'data-payment-search' => '',
							'data-payment-filter-label' => lang('this_months'),
						),
					),
					array(
						'label' => lang('last_month'),
						'attrs' => array(
							'data-payment-filter-action' => '1',
							'data-payment-filter' => 'last_month',
							'data-payment-search' => '',
							'data-payment-filter-label' => lang('last_month'),
						),
					),
					array(
						'label' => lang('invoice'),
						'icon' => 'file-text',
						'divider_before' => true,
						'items' => array(
							array(
								'label' => lang('all') . ' ' . lang('invoice'),
								'attrs' => array(
									'data-payment-filter-action' => '1',
									'data-payment-filter' => '',
									'data-payment-search' => 'by_invoice',
									'data-payment-filter-label' => lang('all') . ' ' . lang('invoice'),
								),
							),
						),
						'lookup' => array(
							'endpoint' => base_url('admin/common/invoice_lookup'),
							'limit' => 12,
							'min_length' => 0,
							'action_attrs' => array('data-payment-filter-action' => '1', 'data-payment-search' => 'by_invoice'),
							'filter_attr' => 'data-payment-filter',
							'label_attr' => 'data-payment-filter-label',
							'label_prefix' => lang('invoice') . ': ',
							'placeholder' => lang('search') . ' ' . lang('invoice'),
							'cache_key' => 'payments_invoice_lookup',
						),
					),
					array(
						'label' => lang('account'),
						'icon' => 'wallet',
						'items' => array(
							array(
								'label' => lang('all') . ' ' . lang('account'),
								'attrs' => array(
									'data-payment-filter-action' => '1',
									'data-payment-filter' => '',
									'data-payment-search' => 'by_account',
									'data-payment-filter-label' => lang('all') . ' ' . lang('account'),
								),
							),
						),
						'lookup' => array(
							'endpoint' => base_url('admin/common/account_lookup'),
							'limit' => 12,
							'min_length' => 0,
							'action_attrs' => array('data-payment-filter-action' => '1', 'data-payment-search' => 'by_account'),
							'filter_attr' => 'data-payment-filter',
							'label_attr' => 'data-payment-filter-label',
							'label_prefix' => lang('account') . ': ',
							'placeholder' => lang('search') . ' ' . lang('account'),
							'cache_key' => 'payments_account_lookup',
						),
					),
					array(
						'label' => lang('client'),
						'icon' => 'user',
						'items' => array(
							array(
								'label' => lang('all') . ' ' . lang('client'),
								'attrs' => array(
									'data-payment-filter-action' => '1',
									'data-payment-filter' => '',
									'data-payment-search' => 'by_client',
									'data-payment-filter-label' => lang('all') . ' ' . lang('client'),
								),
							),
						),
						'lookup' => array(
							'endpoint' => base_url('admin/common/client_lookup'),
							'limit' => 12,
							'min_length' => 0,
							'action_attrs' => array('data-payment-filter-action' => '1', 'data-payment-search' => 'by_client'),
							'filter_attr' => 'data-payment-filter',
							'label_attr' => 'data-payment-filter-label',
							'label_prefix' => lang('client') . ': ',
							'placeholder' => lang('search') . ' ' . lang('client'),
							'cache_key' => 'payments_client_lookup',
						),
					),
				);
				$data['header_filters'] = array(
					array(
						'label' => 'Filters',
						'icon' => 'sliders-horizontal',
						'selected_label' => lang('all'),
						'attrs' => array('id' => 'payments-header-filter'),
						'items' => $payment_filter_items,
					),
				);
			}
		}
		$data['all_invoice_info'] = $this->invoice_model->get_permission('tbl_invoices');

		// get payment info by id

		if (!empty($id)) {
			$can_edit = $this->invoice_model->can_action('tbl_payments', 'edit', array('payments_id' => $id));
			if (!empty($can_edit)) {
				$this->invoice_model->_table_name = 'tbl_payments';
				$this->invoice_model->_order_by = 'payments_id';
				$data['payments_info'] = $this->invoice_model->get_by(array('payments_id' => $id), TRUE);
			} else {
				set_message('error', lang('no_permission_to_access'));
				if (empty($_SERVER['HTTP_REFERER'])) {
					redirect('admin/invoice/all_payments');
				} else {
					redirect($_SERVER['HTTP_REFERER']);
				}
			}
		}
		$data['subview'] = $this->load->view('admin/invoice/' . $subview, $data, TRUE);
		$this->load->view('admin/_layout_main', $data); //page load
	}

	public function payments_state_report()
	{
		$mdate = date('Y-m-d');
		$last_7_days = date('Y-m-d', safe_strtotime('today - 7 days'));
		$data['daily_series'] = $this->finance_report_model->get_payment_daily_series($last_7_days, $mdate);
		$pathonor_jonno['payments_state_report_div'] = $this->load->view("admin/invoice/payments_state_report", $data, true);
		echo json_encode($pathonor_jonno);
		exit;
	}

	public
	function save_invoice($id = NULL)
	{
		$created = can_action('13', 'created');
		$edited = can_action('13', 'edited');
		if (!empty($created) || !empty($edited) && !empty($id)) {
			$this->db->trans_begin();
			$stock_ok = true;
			$stock_error = lang('stock_update_failed');
			$existing_invoice_info = null;
			if (!empty($id)) {
				$existing_invoice_info = $this->invoice_model->check_by(array('invoices_id' => $id), 'tbl_invoices');
			}

			$data = $this->invoice_model->array_from_post(array('reference_no', 'client_id', 'project_id', 'warehouse_id', 'discount_type', 'tags', 'discount_percent', 'user_id', 'adjustment', 'discount_total', 'show_quantity_as'));
			$data['tags'] = normalize_and_sync_tags($data['tags']);
			if (empty($data['discount_type'])) {
				$data['discount_type'] = null;
			}
			$data['show_quantity_as'] = strtolower((string) $data['show_quantity_as']);
			if (!in_array($data['show_quantity_as'], array('qty', 'hours', 'qty_hours'), true)) {
				$data['show_quantity_as'] = 'qty';
			}
			if (empty($data['project_id'])) {
				$data['project_id'] = 0;
			}
			if (empty($data['warehouse_id'])) {
				$data['warehouse_id'] = 0;
			}
			if (empty($data['client_id'])) {
				$this->db->trans_rollback();
				set_message('error', lang('client') . ' is required');
				if (empty($_SERVER['HTTP_REFERER'])) {
					redirect('admin/invoice/createinvoice/create_invoice');
				} else {
					redirect($_SERVER['HTTP_REFERER']);
				}
			}

			$all_payment = get_result('tbl_online_payment');
			foreach ($all_payment as $payment) {
				$allow_gateway = 'allow_' . slug_it(strtolower($payment->gateway_name));
				$gateway_status = slug_it(strtolower($payment->gateway_name)) . '_status';
				if (config_item($gateway_status) == 'active') {
					$data[$allow_gateway] = ($this->input->post($allow_gateway) == 'Yes') ? 'Yes' : 'No';
				}
			}

			$data['client_visible'] = ($this->input->post('client_visible') == 'Yes') ? 'Yes' : 'No';
			$data['invoice_date'] = date('Y-m-d', safe_strtotime($this->input->post('invoice_date', TRUE)));
			if (empty($data['invoice_date'])) {
				$data['invoice_date'] = date('Y-m-d');
			}
			$data['invoice_year'] = date('Y', safe_strtotime($this->input->post('invoice_date', TRUE)));
			$data['invoice_month'] = date('Y-m', safe_strtotime($this->input->post('invoice_date', TRUE)));
			$data['due_date'] = date('Y-m-d', safe_strtotime($this->input->post('due_date', TRUE)));
			$pos = $this->input->post('pos', true);
			if (!empty($pos)) {
				$permission = 'everyone';
				$notes = 'Directly from purchase';
			} else {
				$permission = $this->input->post('permission', true);
				$notes = $this->input->post('notes');
			}
			$data['notes'] = $notes;
			$tax['tax_name'] = $this->input->post('total_tax_name', TRUE);
			$tax['total_tax'] = $this->input->post('total_tax', TRUE);
			$data['total_tax'] = json_encode($tax);
			$i_tax = 0;
			if (!empty($tax['total_tax'])) {
				foreach ($tax['total_tax'] as $v_tax) {
					$i_tax += $v_tax;
				}
			}
			$data['tax'] = $i_tax;

			$save_as_draft = $this->input->post('save_as_draft', TRUE);
			if (!empty($save_as_draft)) {
				$data['status'] = 'draft';
			}
			$Paid = $this->input->post('Paid', TRUE);
			if (!empty($Paid)) {
				$data['status'] = 'Paid';
			}
			$currency = $this->invoice_model->client_currency_symbol($data['client_id']);
			if (!empty($currency->code)) {
				$curren = $currency->code;
			} else {
				$curren = config_item('default_currency');
			}
			$data['currency'] = $curren;
			if (!empty($permission)) {
				if ($permission == 'everyone') {
					$assigned = 'all';
				} else {
					$assigned_to = $this->invoice_model->array_from_post(array('assigned_to'));
					if (!empty($assigned_to['assigned_to'])) {
						foreach ($assigned_to['assigned_to'] as $assign_user) {
							$assigned[$assign_user] = $this->input->post('action_' . $assign_user, true);
						}
					}
				}
				if (!empty($assigned)) {
					if ($assigned != 'all') {
						$assigned = json_encode($assigned);
					}
				} else {
					$assigned = 'all';
				}
				$data['permission'] = $assigned;
			} else {
				$this->db->trans_rollback();
				set_message('error', lang('assigned_to') . ' Field is required');
				if (empty($_SERVER['HTTP_REFERER'])) {
					redirect('admin/invoice/manage_invoice');
				} else {
					redirect($_SERVER['HTTP_REFERER']);
				}
			}
			// get all client
			$this->invoice_model->_table_name = 'tbl_invoices';
			$this->invoice_model->_primary_key = 'invoices_id';
			if (!empty($id)) {
				$invoice_id = $id;
				$can_edit = $this->invoice_model->can_action('tbl_invoices', 'edit', array('invoices_id' => $id));
				if (!empty($can_edit)) {
					$this->invoice_model->save($data, $id);
				} else {
					$this->db->trans_rollback();
					set_message('error', lang('there_in_no_value'));
					redirect('admin/invoice/manage_invoice');
				}
				$action = ('activity_invoice_updated');
				$description = 'not_invoice_updated';
				$msg = lang('invoice_updated');
			} else {
				$invoice_id = $this->invoice_model->save($data);
				$action = ('activity_invoice_created');
				$description = 'not_invoice_created';
				$msg = lang('invoice_created');
			}

			save_custom_field(9, $invoice_id);

			$recuring_frequency = $this->input->post('recuring_frequency', TRUE);
			if (!empty($recuring_frequency) && $recuring_frequency != 'none') {
				$recur_data = $this->invoice_model->array_from_post(array('recur_start_date', 'recur_end_date'));
				$recur_data['recuring_frequency'] = $recuring_frequency;
				$this->get_recuring_frequency($invoice_id, $recur_data); // set recurring
			} else {
				$update_recur = array(
					'recurring' => 'No',
					'recur_end_date' => date('Y-m-d'),
					'recur_next_date' => '0000-00-00'
				);
				$this->invoice_model->_table_name = 'tbl_invoices';
				$this->invoice_model->_primary_key = 'invoices_id';
				$this->invoice_model->save($update_recur, $invoice_id);
			}
			$qty_calculation = config_item('qty_calculation_from_items');
			// save items
			$invoices_to_merge = $this->input->post('invoices_to_merge', TRUE);
			$cancel_merged_invoices = $this->input->post('cancel_merged_invoices', TRUE);

			if (!empty($invoices_to_merge)) {
				foreach ($invoices_to_merge as $inv_id) {
					if (empty($cancel_merged_invoices)) {
						if (!empty($qty_calculation) && $qty_calculation == 'Yes') {
							$all_items_info = $this->db->where('invoices_id', $inv_id)->get('tbl_items')->result();
							if (!empty($all_items_info)) {
								foreach ($all_items_info as $v_items) {
									if (!$this->invoice_model->return_items($v_items->saved_items_id, $v_items->quantity, $data['warehouse_id'])) {
										$stock_ok = false;
										break;
									}
								}
							}
						}
						if (!$stock_ok) {
							break;
						}
						$this->db->where('invoices_id', $inv_id);
						$this->db->delete('tbl_invoices');

						$this->db->where('invoices_id', $inv_id);
						$this->db->delete('tbl_items');
					} else {
						$mdata = array('status' => 'Cancelled');
						$this->invoice_model->_table_name = 'tbl_invoices';
						$this->invoice_model->_primary_key = 'invoices_id';
						$this->invoice_model->save($mdata, $inv_id);
					}
				}
			}
			if (!$stock_ok) {
				$this->db->trans_rollback();
				set_message('error', $stock_error);
				redirect($_SERVER['HTTP_REFERER']);
			}

			$removed_items = $this->input->post('removed_items', TRUE);
			if (!empty($removed_items)) {
				foreach ($removed_items as $r_id) {
					$itemInfo = get_row('tbl_items', array('items_id' => $r_id));
					if ($r_id != 'undefined') {
						if (!empty($qty_calculation) && $qty_calculation == 'Yes' && !empty($itemInfo->saved_items_id)) {
							if (!$this->invoice_model->return_items($itemInfo->saved_items_id, $itemInfo->quantity, $data['warehouse_id'])) {
								$stock_ok = false;
								break;
							}
						}
						$this->db->where('items_id', $r_id);
						$this->db->delete('tbl_items');
					}
				}
			}
			if (!$stock_ok) {
				$this->db->trans_rollback();
				set_message('error', $stock_error);
				redirect($_SERVER['HTTP_REFERER']);
			}


			$itemsid = $this->input->post('items_id', TRUE);
			$items_data = $this->input->post('items', true);
			if (!empty($items_data)) {
				$index = 0;
				$total_price = 0;
				foreach ($items_data as $items) {
					unset($items['invoice_items_id']);
					unset($items['total_qty']);
					$items['invoices_id'] = $invoice_id;
					$tax = 0;
					if (!empty($items['taxname'])) {
						foreach ($items['taxname'] as $tax_name) {
							$tax_rate = explode("|", $tax_name);
							$tax += $tax_rate[1];
						}
						$items['item_tax_name'] = $items['taxname'];
						unset($items['taxname']);
						$items['item_tax_name'] = json_encode($items['item_tax_name']);
					}
					if (empty($items['saved_items_id']) || $items['saved_items_id'] == 'undefined') {
						$items['saved_items_id'] = 0;
					}

					$price = $items['quantity'] * $items['unit_cost'];
					$items['item_tax_total'] = ($price / 100 * $tax);
					$items['total_cost'] = $price;


					// get all client
					$this->invoice_model->_table_name = 'tbl_items';
					$this->invoice_model->_primary_key = 'items_id';
					$data['warehouse_id'] = $this->input->post('warehouse_id', true);

					if (!empty($items['items_id'])) {
						$items_id = $items['items_id'];
						if (!empty($qty_calculation) && $qty_calculation == 'Yes') {
							if (!$this->invoice_model->check_existing_qty($items_id, $items['quantity'], $data['warehouse_id'])) {
								$stock_ok = false;
								break;
							}
						}
						$this->invoice_model->save($items, $items_id);
					} else {
						if (!empty($qty_calculation) && $qty_calculation == 'Yes') {
							if (!empty($items['saved_items_id']) && $items['saved_items_id'] != 'undefined') {
								if (!$this->invoice_model->reduce_items($items['saved_items_id'], $items['quantity'], $data['warehouse_id'])) {
									$stock_ok = false;
									break;
								}
							}
						}
						$items_id = $this->invoice_model->save($items);
					}
					$thecount = $items['total_cost'];
					$total_price += $thecount;
					$index++;
				}
			}
			if (!$stock_ok || $this->db->trans_status() === FALSE) {
				$this->db->trans_rollback();
				set_message('error', $stock_error);
				redirect($_SERVER['HTTP_REFERER']);
			}
			$activity = array(
				'user' => $this->session->userdata('user_id'),
				'module' => 'invoice',
				'module_field_id' => $invoice_id,
				'activity' => $action,
				'icon' => 'fa-shopping-cart',
				'link' => 'admin/invoice/manage_invoice/invoice_details/' . $invoice_id,
				'value1' => $data['reference_no']
			);
			$this->invoice_model->_table_name = 'tbl_activities';
			$this->invoice_model->_primary_key = 'activities_id';
			$this->invoice_model->save($activity);
			$this->db->trans_commit();
			$this->refresh_project_finance_cache($invoice_id);
			$this->clear_client_invoice_cache($data['client_id']);
			if (!empty($existing_invoice_info) && !empty($existing_invoice_info->project_id) && (int) $existing_invoice_info->project_id !== (int) $data['project_id']) {
				finance_report_model()->refresh_project_finance_summary((int) $existing_invoice_info->project_id);
			}
			if (!empty($existing_invoice_info) && !empty($existing_invoice_info->client_id) && (int) $existing_invoice_info->client_id !== (int) $data['client_id']) {
				$this->clear_client_invoice_cache((int) $existing_invoice_info->client_id);
			}

			if (!empty($Paid)) {
				$this->get_payment($invoice_id, true);
			}
			// send notification to client
			if (!empty($data['client_id'])) {
				$client_info = $this->invoice_model->check_by(array('client_id' => $data['client_id']), 'tbl_client');
				if (!empty($client_info->primary_contact)) {
					$notifyUser = array($client_info->primary_contact);
				} else {
					$user_info = $this->invoice_model->check_by(array('company' => $data['client_id']), 'tbl_account_details');
					if (!empty($user_info)) {
						$notifyUser = array($user_info->user_id);
					}
				}
			}
			if (!empty($notifyUser)) {
				foreach ($notifyUser as $v_user) {
					if ($v_user != $this->session->userdata('user_id')) {
						add_notification(array(
							'to_user_id' => $v_user,
							'icon' => 'shopping-cart',
							'description' => $description,
							'link' => 'client/invoice/manage_invoice/invoice_details/' . $invoice_id,
							'value' => $data['reference_no'],
						));
					}
				}
				show_notification($notifyUser);
			}
			// messages for user
			$type = "success";
			$message = $msg;
			set_message($type, $message);
			redirect('admin/invoice/manage_invoice/invoice_details/' . $invoice_id);
		} else {
			redirect('admin/invoice/manage_invoice');
		}
	}

	function get_recuring_frequency($invoices_id, $recur_data)
	{
		$recur_days = $this->get_calculate_recurring_days($recur_data['recuring_frequency']);
		$due_date = $this->invoice_model->get_table_field('tbl_invoices', array('invoices_id' => $invoices_id), 'due_date');

		$next_date = date("Y-m-d", safe_strtotime($due_date . "+ " . $recur_days . " days"));

		if ($recur_data['recur_end_date'] == '') {
			$recur_end_date = '0000-00-00';
		} else {
			$recur_end_date = date('Y-m-d', safe_strtotime($recur_data['recur_end_date']));
		}
		$update_invoice = array(
			'recurring' => 'Yes',
			'recuring_frequency' => $recur_days,
			'recur_frequency' => $recur_data['recuring_frequency'],
			'recur_start_date' => date('Y-m-d', safe_strtotime($recur_data['recur_start_date'])),
			'recur_end_date' => $recur_end_date,
			'recur_next_date' => $next_date
		);
		$this->invoice_model->_table_name = 'tbl_invoices';
		$this->invoice_model->_primary_key = 'invoices_id';
		$this->invoice_model->save($update_invoice, $invoices_id);
		return TRUE;
	}

	function get_calculate_recurring_days($recuring_frequency)
	{
		switch ($recuring_frequency) {
			case '7D':
				return 7;
				break;
			case '1M':
				return 31;
				break;
			case '3M':
				return 90;
				break;
			case '6M':
				return 182;
				break;
			case '1Y':
				return 365;
				break;
		}
	}


	public
	function recurring_invoice($id = NULL)
	{
		$data['title'] = lang('recurring_invoice');
		$data['datatable'] = true;
		$data['header_actions'] = array(
			array(
				'label' => lang('invoices'),
				'icon' => 'receipt-text',
				'href' => base_url('admin/invoice/manage_invoice'),
				'style' => 'neutral',
			),
			array(
				'label' => lang('filters'),
				'icon' => 'funnel',
				'attrs' => array(
					'type' => 'button',
					'id' => 'recurringHeaderFilterToggle',
					'aria-expanded' => 'false',
					'aria-controls' => 'recurringFiltersShell',
				),
				'style' => 'neutral',
			),
		);
		if (can_action('51', 'created') || can_action('51', 'edited')) {
			array_splice($data['header_actions'], 1, 0, array(array(
				'label' => lang('create_invoice'),
				'icon' => 'plus',
				'href' => base_url('admin/invoice/createrecuringinvoice'),
				'style' => 'primary',
			)));
		}
		$data['header_filters'] = array();
		if (!empty($id)) {
			$data['invoice_info'] = join_data('tbl_invoices', '*', array('invoices_id' => $id), array('tbl_client' => 'tbl_client.client_id = tbl_invoices.client_id'));
			$data['active'] = 2;
		} else {
			$data['active'] = 1;
		}
		// get all client
		$this->invoice_model->_table_name = 'tbl_client';
		$this->invoice_model->_order_by = 'client_id';
		$data['all_client'] = $this->invoice_model->get();
		// get permission user
		$data['permission_user'] = $this->invoice_model->all_permission_user('51');

		// get all invoice
		$data['all_invoices_info'] = $this->invoice_model->get_permission('tbl_invoices');

		$data['subview'] = $this->load->view('admin/invoice/recurring_invoice', $data, TRUE);
		$this->load->view('admin/_layout_main', $data); //page load
	}

	public function createrecuringinvoice($id = null)
	{
		$data['title'] = lang('recurring_invoice');
		if (!empty($id)) {
			$data['invoice_info'] = join_data('tbl_invoices', '*', array('invoices_id' => $id), array('tbl_client' => 'tbl_client.client_id = tbl_invoices.client_id'));
			$data['active'] = 2;
		} else {
			$data['active'] = 1;
		}
		// get all client
		$this->invoice_model->_table_name = 'tbl_client';
		$this->invoice_model->_order_by = 'client_id';
		$data['all_client'] = $this->invoice_model->get();
		// get permission user
		$data['permission_user'] = $this->invoice_model->all_permission_user('51');

		// get all invoice
		$data['all_invoices_info'] = $this->invoice_model->get_permission('tbl_invoices');

		$data['subview'] = $this->load->view('admin/invoice/createrecuringinvoice', $data, TRUE);
		$this->load->view('admin/_layout_main', $data); //page load
	}

	public
	function stop_recurring($invoices_id)
	{
		$update_recur = array(
			'recurring' => 'No',
			'recur_end_date' => date('Y-m-d'),
			'recur_next_date' => '0000-00-00'
		);
		$this->invoice_model->_table_name = 'tbl_invoices';
		$this->invoice_model->_primary_key = 'invoices_id';
		$this->invoice_model->save($update_recur, $invoices_id);
		// Log Activity
		$activity = array(
			'user' => $this->session->userdata('user_id'),
			'module' => 'invoice',
			'module_field_id' => $invoices_id,
			'activity' => 'activity_recurring_stopped',
			'icon' => 'fa-shopping-cart',
			'link' => 'admin/invoice/manage_invoice/invoice_details/' . $invoices_id,
		);
		$this->invoice_model->_table_name = 'tbl_activities';
		$this->invoice_model->_primary_key = 'activities_id';
		$this->invoice_model->save($activity);
		// messages for user
		$type = "success";
		$message = lang('recurring_invoice_stopped');
		set_message($type, $message);
		redirect('admin/invoice/manage_invoice');
	}

	public
	function insert_items($invoices_id)
	{
		$edited = can_action('13', 'edited');
		$can_edit = $this->invoice_model->can_action('tbl_invoices', 'edit', array('invoices_id' => $invoices_id));
		if (!empty($can_edit) && !empty($edited)) {
			$data['invoices_id'] = $invoices_id;
			$data['modal_subview'] = $this->load->view('admin/invoice/_modal_insert_items', $data, FALSE);
		} else {
			set_message('error', lang('there_in_no_value'));
			redirect($_SERVER['HTTP_REFERER']);
		}
	}

	public
	function clone_invoice($invoices_id)
	{
		$edited = can_action('13', 'edited');
		$can_edit = $this->invoice_model->can_action('tbl_invoices', 'edit', array('invoices_id' => $invoices_id));
		if (!empty($can_edit) && !empty($edited)) {
			$data['invoice_info'] = $this->invoice_model->check_by(array('invoices_id' => $invoices_id), 'tbl_invoices');
			// get all client
			$this->invoice_model->_table_name = 'tbl_client';
			$this->invoice_model->_order_by = 'client_id';
			$data['all_client'] = $this->invoice_model->get();

			$data['modal_subview'] = $this->load->view('admin/invoice/_modal_clone_invoice', $data, FALSE);
		} else {
			set_message('error', lang('there_in_no_value'));
			if (empty($_SERVER['HTTP_REFERER'])) {
				redirect('admin/invoice/manage_invoice');
			} else {
				redirect($_SERVER['HTTP_REFERER']);
			}
		}
	}

	public
	function cloned_invoice($id)
	{
		$edited = can_action('13', 'edited');
		$can_edit = $this->invoice_model->can_action('tbl_invoices', 'edit', array('invoices_id' => $id));
		if (!empty($can_edit) && !empty($edited)) {
			$this->db->trans_begin();
			$stock_ok = true;
			$stock_error = lang('stock_update_failed');
			if (config_item('increment_invoice_number') == 'FALSE') {
				$this->load->helper('string');
				$reference_no = config_item('invoice_prefix') . ' ' . random_string('nozero', 6);
			} else {
				$reference_no = $this->invoice_model->generate_invoice_number();
			}
			$invoice_info = $this->invoice_model->check_by(array('invoices_id' => $id), 'tbl_invoices');

			// save into invoice table
			$new_invoice = array(
				'reference_no' => $reference_no,
				'recur_start_date' => $invoice_info->recur_start_date,
				'recur_end_date' => $invoice_info->recur_end_date,
				'client_id' => $this->input->post('client_id', true),
				'warehouse_id' => $invoice_info->warehouse_id,
				'project_id' => $invoice_info->project_id,
				'invoice_date' => $this->input->post('invoice_date', true),
				'invoice_year' => date('Y', safe_strtotime($this->input->post('invoice_date', true))),
				'invoice_month' => date('Y-m', safe_strtotime($this->input->post('invoice_date', true))),
				'due_date' => $this->input->post('due_date', true),
				'notes' => $invoice_info->notes,
				'tags' => $invoice_info->tags,
				'total_tax' => $invoice_info->total_tax,
				'tax' => $invoice_info->tax,
				'discount_type' => $invoice_info->discount_type,
				'discount_percent' => $invoice_info->discount_percent,
				'user_id' => $invoice_info->user_id,
				'adjustment' => $invoice_info->adjustment,
				'discount_total' => $invoice_info->discount_total,
				'show_quantity_as' => $invoice_info->show_quantity_as,
				'recurring' => $invoice_info->recurring,
				'recuring_frequency' => $invoice_info->recuring_frequency,
				'recur_frequency' => $invoice_info->recur_frequency,
				'recur_next_date' => $invoice_info->recur_next_date,
				'currency' => $invoice_info->currency,
				'status' => $invoice_info->status,
				'date_saved' => $invoice_info->date_saved,
				'emailed' => $invoice_info->emailed,
				'show_client' => $invoice_info->show_client,
				'viewed' => $invoice_info->viewed,
				'permission' => $invoice_info->permission,
			);
			$all_payment = get_result('tbl_online_payment');
			foreach ($all_payment as $payment) {
				$allow_gateway = 'allow_' . slug_it(strtolower($payment->gateway_name));
				$gateway_status = slug_it(strtolower($payment->gateway_name)) . '_status';
				if (config_item($gateway_status) == 'active') {
					$new_invoice[$allow_gateway] = ($invoice_info->$allow_gateway == 'Yes') ? 'Yes' : 'No';
				}
			}

			$this->invoice_model->_table_name = "tbl_invoices"; //table name
			$this->invoice_model->_primary_key = "invoices_id";
			$new_invoice_id = $this->invoice_model->save($new_invoice);

			$qty_calculation = config_item('qty_calculation_from_items');
			$invoice_items = $this->db->where('invoices_id', $id)->get('tbl_items')->result();
			if (!empty($invoice_items)) {
				foreach ($invoice_items as $new_item) {
					if (!empty($qty_calculation) && $qty_calculation == 'Yes' && !empty($new_item->saved_items_id)) {
						$this->ensure_invoice_clone_warehouse_stock($new_item->saved_items_id, $invoice_info->warehouse_id);
						if (!$this->invoice_model->reduce_items($new_item->saved_items_id, $new_item->quantity, $invoice_info->warehouse_id)) {
							$stock_ok = false;
							break;
						}
					}
					$items = array(
						'invoices_id' => $new_invoice_id,
						'saved_items_id' => $new_item->saved_items_id,
						'item_name' => $new_item->item_name,
						'item_desc' => $new_item->item_desc,
						'unit_cost' => $new_item->unit_cost,
						'quantity' => $new_item->quantity,
						'item_tax_rate' => $new_item->item_tax_rate,
						'item_tax_name' => $new_item->item_tax_name,
						'item_tax_total' => $new_item->item_tax_total,
						'total_cost' => $new_item->total_cost,
						'unit' => $new_item->unit,
						'order' => $new_item->order,
						'date_saved' => $new_item->date_saved,
					);
					$this->invoice_model->_table_name = "tbl_items"; //table name
					$this->invoice_model->_primary_key = "items_id";
					$this->invoice_model->save($items);
				}
			}
			if (!$stock_ok || $this->db->trans_status() === FALSE) {
				$this->db->trans_rollback();
				set_message('error', $stock_error);
				if ($this->input->is_ajax_request()) {
					echo json_encode(array("status" => 'error', 'message' => $stock_error));
					exit();
				}
				redirect($_SERVER['HTTP_REFERER']);
			}
			// save into activities
			$activities = array(
				'user' => $this->session->userdata('user_id'),
				'module' => 'invoice',
				'module_field_id' => $new_invoice_id,
				'activity' => ('activity_cloned_invoice'),
				'icon' => 'fa-shopping-cart',
				'link' => 'admin/invoice/manage_invoice/invoice_details/' . $new_invoice_id,
				'value1' => ' from ' . $invoice_info->reference_no . ' to ' . $reference_no,
			);
			// Update into tbl_project
			$this->invoice_model->_table_name = "tbl_activities"; //table name
			$this->invoice_model->_primary_key = "activities_id";
			$this->invoice_model->save($activities);
			$this->db->trans_commit();

			// messages for user
			$type = "success";
			$message = lang('invoice_created');
			set_message($type, $message);
			if ($this->input->is_ajax_request()) {
				echo json_encode(array(
					"status" => $type,
					'message' => $message,
					'url' => 'admin/invoice/manage_invoice/invoice_details/' . $new_invoice_id,
				));
				exit();
			}
		} else {
			if ($this->input->is_ajax_request()) {
				echo json_encode(array("status" => 'error', 'message' => lang('there_in_no_value')));
				exit();
			}
		}
	}

	private function ensure_invoice_clone_warehouse_stock($saved_items_id, $warehouse_id)
	{
		if (empty($saved_items_id) || empty($warehouse_id)) {
			return;
		}
		$exists = get_row('tbl_warehouses_products', array(
			'warehouse_id' => $warehouse_id,
			'product_id' => $saved_items_id,
		));
		if (!empty($exists)) {
			return;
		}
		$item_info = get_row('tbl_saved_items', array('saved_items_id' => $saved_items_id));
		$quantity = !empty($item_info->quantity) ? (float) $item_info->quantity : 0;
		if ($quantity <= 0) {
			return;
		}
		$this->db->insert('tbl_warehouses_products', array(
			'warehouse_id' => $warehouse_id,
			'product_id' => $saved_items_id,
			'quantity' => $quantity,
		));
	}

	private function invoice_json_response($type, $message, array $extra = array())
	{
		$payload = array_merge(array(
			'status' => $type,
			'message' => $message,
		), $extra);
		$this->output->set_content_type('application/json');
		echo json_encode($payload);
		exit();
	}

	private function normalize_saved_item_tax_ids($raw_tax)
	{
		if ($raw_tax === null || $raw_tax === '') {
			return array();
		}
		$decoded = is_string($raw_tax) ? json_decode($raw_tax, true) : $raw_tax;
		if (json_last_error() !== JSON_ERROR_NONE || $decoded === null) {
			$decoded = $raw_tax;
		}
		$ids = array();
		$walk = function ($value) use (&$walk, &$ids) {
			if (is_array($value)) {
				foreach (array('tax_rates_id', 'id', 'value') as $key) {
					if (isset($value[$key]) && is_numeric($value[$key])) {
						$ids[] = (int) $value[$key];
						return;
					}
				}
				foreach ($value as $child) {
					$walk($child);
				}
				return;
			}
			if (is_object($value)) {
				$walk((array) $value);
				return;
			}
			if (is_numeric($value)) {
				$ids[] = (int) $value;
			}
		};
		$walk($decoded);
		return array_values(array_unique(array_filter($ids)));
	}

	private function get_saved_item_tax_rows($raw_tax)
	{
		$tax_ids = $this->normalize_saved_item_tax_ids($raw_tax);
		if (empty($tax_ids)) {
			return array();
		}
		return $this->db->where_in('tax_rates_id', $tax_ids)->get('tbl_tax_rates')->result();
	}

	private function get_invoice_insert_existing_items($invoices_id, $items_info)
	{
		$existing_items = $this->db
			->where('invoices_id', $invoices_id)
			->where('saved_items_id', $items_info->saved_items_id)
			->order_by('items_id', 'ASC')
			->get('tbl_items')
			->result();
		if (!empty($existing_items)) {
			return $existing_items;
		}
		return $this->db
			->where('invoices_id', $invoices_id)
			->where('item_name', $items_info->item_name)
			->group_start()
			->where('saved_items_id', 0)
			->or_where('saved_items_id IS NULL', null, false)
			->group_end()
			->order_by('items_id', 'ASC')
			->get('tbl_items')
			->result();
	}

	public
	function add_insert_items($invoices_id)
	{
		$is_ajax = $this->input->is_ajax_request();
		$redirect_url = 'admin/invoice/manage_invoice/invoice_details/' . $invoices_id;
		$edited = can_action('13', 'edited');
		$can_edit = $this->invoice_model->can_action('tbl_invoices', 'edit', array('invoices_id' => $invoices_id));
		if (!empty($can_edit) && !empty($edited)) {
			$invoice_info = $this->invoice_model->check_by(array('invoices_id' => $invoices_id), 'tbl_invoices');
			if (empty($invoice_info)) {
				set_message('error', lang('there_in_no_value'));
				if ($is_ajax) {
					$this->invoice_json_response('error', lang('there_in_no_value'));
				}
				redirect('admin/invoice/manage_invoice');
			}
			$stock_ok = true;
			$stock_error = lang('stock_update_failed');
			$warehouse_id = !empty($invoice_info->warehouse_id) ? $invoice_info->warehouse_id : $this->session->userdata('warehouse_id');
			$qty_calculation = config_item('qty_calculation_from_items');
			$saved_items_id = $this->input->post('saved_items_id', TRUE);
			if (!empty($saved_items_id)) {
				$inserted_items = 0;
				$saved_items_id = array_values(array_unique(array_filter((array) $saved_items_id)));
				foreach ($saved_items_id as $v_items_id) {
					$items_info = $this->invoice_model->check_by(array('saved_items_id' => $v_items_id), 'tbl_saved_items');
					if (empty($items_info)) {
						continue;
					}

					if ($qty_calculation == 'Yes') {
						if (empty($warehouse_id) && config_item('require_warehouse_for_stock')) {
							$stock_ok = false;
							$stock_error = 'Please select a warehouse before adding stock items.';
							break;
						}
						$this->ensure_invoice_clone_warehouse_stock($items_info->saved_items_id, $warehouse_id);
						if (!$this->invoice_model->reduce_items($items_info->saved_items_id, 1, $warehouse_id)) {
							$stock_ok = false;
							break;
						}
					}

					$tax_info = $this->get_saved_item_tax_rows($items_info->tax_rates_id);
					$tax_name = array();
					$tax_total = 0;
					if (!empty($tax_info)) {
						foreach ($tax_info as $v_tax) {
							$tax_name[] = $v_tax->tax_rate_name . '|' . $v_tax->tax_rate_percent;
							$tax_total += ((float) $items_info->unit_cost / 100) * (float) $v_tax->tax_rate_percent;
						}
					}
					if (!empty($tax_name)) {
						$tax_name = $tax_name;
					} else {
						$tax_name = array();
					}

					$existing_items = $this->get_invoice_insert_existing_items($invoices_id, $items_info);
					$existing_quantity = 0;
					if (!empty($existing_items)) {
						foreach ($existing_items as $existing_item) {
							$existing_quantity += (float) $existing_item->quantity;
						}
					}
					$quantity = !empty($existing_items) ? ($existing_quantity + 1) : 1;
					$line_subtotal = (float) $items_info->unit_cost * $quantity;

					$data = array();
					$data['quantity'] = $quantity;
					$data['invoices_id'] = $invoices_id;
					$data['saved_items_id'] = $items_info->saved_items_id;
					$data['item_name'] = $items_info->item_name;
					$data['item_desc'] = $items_info->item_desc;
					$data['hsn_code'] = $items_info->hsn_code;
					$data['unit_cost'] = $items_info->unit_cost;
					$data['item_tax_rate'] = '0.00';
					$data['item_tax_name'] = json_encode($tax_name);
					$data['item_tax_total'] = $tax_total * $quantity;
					$data['total_cost'] = $line_subtotal;
					// get all client
					$this->invoice_model->_table_name = 'tbl_items';
					$this->invoice_model->_primary_key = 'items_id';
					if (!empty($existing_items)) {
						$items_id = $existing_items[0]->items_id;
						$this->invoice_model->save($data, $items_id);
						if (count($existing_items) > 1) {
							$duplicate_ids = array();
							foreach (array_slice($existing_items, 1) as $duplicate_item) {
								$duplicate_ids[] = $duplicate_item->items_id;
							}
							if (!empty($duplicate_ids)) {
								$this->db->where_in('items_id', $duplicate_ids)->delete('tbl_items');
							}
						}
						$action = 'activity_invoice_items_updated';
					} else {
						$items_id = $this->invoice_model->save($data);
						$action = 'activity_invoice_items_added';
					}
					$inserted_items++;

					$activity = array(
						'user' => $this->session->userdata('user_id'),
						'module' => 'invoice',
						'module_field_id' => $items_id,
						'activity' => $action,
						'icon' => 'fa-circle-o',
						'value1' => $items_info->item_name
					);
					$this->invoice_model->_table_name = 'tbl_activities';
					$this->invoice_model->_primary_key = 'activities_id';
					$this->invoice_model->save($activity);
				}
				if (!$stock_ok) {
					set_message('error', $stock_error);
					if ($is_ajax) {
						$this->invoice_json_response('error', $stock_error);
					}
					redirect($_SERVER['HTTP_REFERER']);
				}

				if ($inserted_items > 0) {
					$this->update_invoice_tax($saved_items_id, $invoices_id);
					$type = "success";
					$msg = lang('invoice_item_added');
				} else {
					$type = "error";
					$msg = lang('no_record_found') ?: 'No valid items were found.';
				}
			} else {
				$type = "error";
				$msg = 'Please select an item.';
			}
			$message = $msg;
			set_message($type, $message);
			if ($is_ajax) {
				$this->invoice_json_response($type, $message, $type === 'success' ? array('reload_page' => true) : array());
			}
			redirect($redirect_url);
		} else {
			set_message('error', lang('there_in_no_value'));
			if ($is_ajax) {
				$this->invoice_json_response('error', lang('there_in_no_value'));
			}
			if (empty($_SERVER['HTTP_REFERER'])) {
				redirect('admin/invoice/manage_invoice');
			} else {
				redirect($_SERVER['HTTP_REFERER']);
			}
		}
	}

	function update_invoice_tax($saved_items_id, $invoices_id)
	{
		$invoice_items = $this->db->where('invoices_id', $invoices_id)->get('tbl_items')->result();
		$results = array();
		if (!empty($invoice_items)) {
			foreach ($invoice_items as $item) {
				$item_tax_names = !empty($item->item_tax_name) ? json_decode($item->item_tax_name, true) : array();
				if (empty($item_tax_names) || !is_array($item_tax_names)) {
					continue;
				}
				foreach ($item_tax_names as $tax_name) {
					if (empty($tax_name) || strpos($tax_name, '|') === false) {
						continue;
					}
					$parts = explode('|', $tax_name);
					$tax_label = $parts[0] . '|' . (isset($parts[1]) ? $parts[1] : 0);
					$tax_amount = ((float) $item->unit_cost * (float) $item->quantity / 100) * (float) (isset($parts[1]) ? $parts[1] : 0);
					if (!isset($results[$tax_label])) {
						$results[$tax_label] = 0;
					}
					$results[$tax_label] += $tax_amount;
				}
			}
		}

		$invoice_data = array('tax' => 0, 'total_tax' => '');
		if (!empty($results)) {
			$structured_results = array('tax_name' => array(), 'total_tax' => array());
			foreach ($results as $key => $value) {
				$structured_results['tax_name'][] = $key;
				$structured_results['total_tax'][] = $value;
			}
			$invoice_data['tax'] = array_sum($structured_results['total_tax']);
			$invoice_data['total_tax'] = json_encode($structured_results);
		}

		$this->invoice_model->_table_name = 'tbl_invoices';
		$this->invoice_model->_primary_key = 'invoices_id';
		$this->invoice_model->save($invoice_data, $invoices_id);
		return true;
	}

	public
	function add_item($id = NULL)
	{
		$edited = can_action('13', 'edited');
		$data = $this->invoice_model->array_from_post(array('invoices_id', 'item_order'));
		$can_edit = $this->invoice_model->can_action('tbl_invoices', 'edit', array('invoices_id' => $data['invoices_id']));
		if (!empty($can_edit) && !empty($edited)) {
			$quantity = $this->input->post('quantity', TRUE);
			$array_data = $this->invoice_model->array_from_post(array('item_name', 'item_desc', 'item_tax_rate', 'unit_cost'));
			if (!empty($quantity)) {
				foreach ($quantity as $key => $value) {
					if (!empty($array_data['item_name'][$key])) {
						$data['quantity'] = $value;
						$data['item_name'] = $array_data['item_name'][$key];
						$data['item_desc'] = $array_data['item_desc'][$key];
						$data['unit_cost'] = $array_data['unit_cost'][$key];
						$data['item_tax_rate'] = $array_data['item_tax_rate'][$key];
						$sub_total = $data['unit_cost'] * $data['quantity'];

						$data['item_tax_total'] = ($data['item_tax_rate'] / 100) * $sub_total;
						$data['total_cost'] = $sub_total + $data['item_tax_total'];

						// get all client
						$this->invoice_model->_table_name = 'tbl_items';
						$this->invoice_model->_primary_key = 'items_id';
						if (!empty($id)) {
							$items_id = $id;
							$this->invoice_model->save($data, $id);
							$action = ('activity_invoice_items_updated');
							$msg = lang('invoice_item_updated');
						} else {
							$items_id = $this->invoice_model->save($data);
							$action = ('activity_invoice_items_added');
							$msg = lang('invoice_item_added');
						}
						$activity = array(
							'user' => $this->session->userdata('user_id'),
							'module' => 'invoice',
							'module_field_id' => $items_id,
							'activity' => $action,
							'icon' => 'fa-circle-o',
							'value1' => $data['item_name']
						);
						$this->invoice_model->_table_name = 'tbl_activities';
						$this->invoice_model->_primary_key = 'activities_id';
						$this->invoice_model->save($activity);
					}
				}
			}
			$this->refresh_project_finance_cache($data['invoices_id']);
			$type = "success";
			$message = $msg;
			set_message($type, $message);
			redirect('admin/invoice/manage_invoice/invoice_details/' . $data['invoices_id']);
		} else {
			set_message('error', lang('there_in_no_value'));
			if (empty($_SERVER['HTTP_REFERER'])) {
				redirect('admin/invoice/manage_invoice');
			} else {
				redirect($_SERVER['HTTP_REFERER']);
			}
		}
	}

	public
	function change_status($action, $id)
	{
		$edited = can_action('13', 'edited');
		$can_edit = $this->invoice_model->can_action('tbl_invoices', 'edit', array('invoices_id' => $id));
		if (!empty($can_edit) && !empty($edited)) {
			$where = array('invoices_id' => $id);
			if ($action == 'hide') {
				$data = array('show_client' => 'No');
			} else {
				$data = array('show_client' => 'Yes');
			}
			$this->invoice_model->set_action($where, $data, 'tbl_invoices');
			// messages for user
			$type = "success";
			$message = lang('invoice_status_changed', $action);
			set_message($type, $message);
			redirect('admin/invoice/manage_invoice/invoice_details/' . $id);
		} else {
			set_message('error', lang('there_in_no_value'));
			if (empty($_SERVER['HTTP_REFERER'])) {
				redirect('admin/invoice/manage_invoice');
			} else {
				redirect($_SERVER['HTTP_REFERER']);
			}
		}
	}

	public
	function delete($action, $invoices_id, $item_id = NULL)
	{
		$deleted = can_action('13', 'deleted');
		$can_delete = $this->invoice_model->can_action('tbl_invoices', 'delete', array('invoices_id' => $invoices_id));
		if (!empty($can_delete) && !empty($deleted)) {
			$invoices_info = $this->invoice_model->check_by(array('invoices_id' => $invoices_id), 'tbl_invoices');
			$payment_info = null;
			if ($action == 'delete_payment') {
				$payment_info = $this->invoice_model->check_by(array('payments_id' => $invoices_id), 'tbl_payments');
			}
			if (!empty($invoices_info->reference_no)) {
				$val = $invoices_info->reference_no;
			} else {
				$val = NULL;
			}
			$activity = array(
				'user' => $this->session->userdata('user_id'),
				'module' => 'invoice',
				'module_field_id' => $invoices_id,
				'activity' => ('activity_invoice' . $action),
				'icon' => 'fa-shopping-cart',
				'value1' => $val,

			);
			$this->invoice_model->_table_name = 'tbl_activities';
			$this->invoice_model->_primary_key = 'activities_id';
			$this->invoice_model->save($activity);

			if ($action == 'delete_item') {
				$this->invoice_model->_table_name = 'tbl_items';
				$this->invoice_model->_primary_key = 'items_id';
				$this->invoice_model->delete($item_id);
				if (!empty($invoices_info->project_id)) {
					finance_report_model()->refresh_project_finance_summary((int) $invoices_info->project_id);
				}
			} elseif ($action == 'delete_invoice') {
				if (!empty($invoices_info->client_id)) {
					$this->clear_client_invoice_cache((int) $invoices_info->client_id);
				}
				$this->invoice_model->_table_name = 'tbl_items';
				$this->invoice_model->delete_multiple(array('invoices_id' => $invoices_id));

				$this->invoice_model->_table_name = 'tbl_payments';
				$this->invoice_model->delete_multiple(array('invoices_id' => $invoices_id));

				$this->invoice_model->_table_name = 'tbl_reminders';
				$this->invoice_model->delete_multiple(array('module' => 'invoice', 'module_id' => $invoices_id));

				$this->invoice_model->_table_name = 'tbl_pinaction';
				$this->invoice_model->delete_multiple(array('module_name' => 'invoice', 'module_id' => $invoices_id));

				$this->invoice_model->_table_name = 'tbl_credit_used';
				$this->invoice_model->delete_multiple(array('invoices_id' => $invoices_id));

				$this->invoice_model->_table_name = 'tbl_invoices';
				$this->invoice_model->_primary_key = 'invoices_id';
				$this->invoice_model->delete($invoices_id);
				if (!empty($invoices_info->project_id)) {
					finance_report_model()->refresh_project_finance_summary((int) $invoices_info->project_id);
				}
			} elseif ($action == 'delete_payment') {
				$this->invoice_model->_table_name = 'tbl_payments';
				$this->invoice_model->_primary_key = 'payments_id';
				$this->invoice_model->delete($invoices_id);
				if (!empty($payment_info->invoices_id)) {
					$this->refresh_project_finance_cache((int) $payment_info->invoices_id);
				}
				if (!empty($payment_info->paid_by)) {
					$this->clear_client_invoice_cache((int) $payment_info->paid_by);
				}
			} elseif ($action == 'delete_applied_credits') {
				$credit_used = get_row('tbl_credit_used', array('credit_used_id' => $item_id));
				if (!empty($credit_used->payments_id) && $credit_used->payments_id != 0) {
					$credit_payment_info = $this->invoice_model->check_by(array('payments_id' => $credit_used->payments_id), 'tbl_payments');
					$this->invoice_model->_table_name = 'tbl_payments';
					$this->invoice_model->_primary_key = 'payments_id';
					$this->invoice_model->delete($credit_used->payments_id);
					if (!empty($credit_payment_info->invoices_id)) {
						$this->refresh_project_finance_cache((int) $credit_payment_info->invoices_id);
					}
					if (!empty($credit_payment_info->paid_by)) {
						$this->clear_client_invoice_cache((int) $credit_payment_info->paid_by);
					}
				}
				$this->invoice_model->_table_name = 'tbl_credit_used';
				$this->invoice_model->_primary_key = 'credit_used_id';
				$this->invoice_model->delete($item_id);
			}
			$type = "success";


			if ($action == 'delete_item') {
				$text = lang('invoice_item_deleted');
				//                set_message($type, $text);
				//                redirect('admin/invoice/manage_invoice/invoice_details/' . $invoices_id);
			} elseif ($action == 'delete_payment') {
				$text = lang('payment_deleted');
				//                set_message($type, $text);
				//                redirect('admin/invoice/manage_invoice/all_payments');
			} else {
				$text = lang('deleted_invoice');
				//                set_message($type, $text);
				//                redirect('admin/invoice/manage_invoice');
			}
			echo json_encode(array("status" => $type, 'message' => $text));
			exit();
		} else {
			echo json_encode(array("status" => 'error', 'message' => lang('there_in_no_value')));
			exit();
			//            set_message('error', lang('there_in_no_value'));
			//            redirect($_SERVER['HTTP_REFERER']);
		}
	}

	public function bulk_delete()
	{
		$selected_id = $this->input->post('ids', true);
		$deleted = can_action('13', 'deleted');
		$result = array();

		if (empty($deleted)) {
			echo json_encode(array("status" => 'error', 'message' => lang('there_in_no_value')));
			exit();
		}

		if (!empty($selected_id)) {
			foreach ($selected_id as $invoice_id) {
				$invoice_id = (int) $invoice_id;
				$can_delete = $this->invoice_model->can_action('tbl_invoices', 'delete', array('invoices_id' => $invoice_id));
				if (empty($can_delete)) {
					continue;
				}

				$invoice_info = $this->invoice_model->check_by(array('invoices_id' => $invoice_id), 'tbl_invoices');
				$activity = array(
					'user' => $this->session->userdata('user_id'),
					'module' => 'invoice',
					'module_field_id' => $invoice_id,
					'activity' => 'activity_invoicedelete_invoice',
					'icon' => 'fa-shopping-cart',
					'value1' => !empty($invoice_info->reference_no) ? $invoice_info->reference_no : NULL,
				);
				$this->invoice_model->_table_name = 'tbl_activities';
				$this->invoice_model->_primary_key = 'activities_id';
				$this->invoice_model->save($activity);

				$this->invoice_model->_table_name = 'tbl_items';
				$this->invoice_model->delete_multiple(array('invoices_id' => $invoice_id));

				$this->invoice_model->_table_name = 'tbl_payments';
				$this->invoice_model->delete_multiple(array('invoices_id' => $invoice_id));

				$this->invoice_model->_table_name = 'tbl_reminders';
				$this->invoice_model->delete_multiple(array('module' => 'invoice', 'module_id' => $invoice_id));

				$this->invoice_model->_table_name = 'tbl_pinaction';
				$this->invoice_model->delete_multiple(array('module_name' => 'invoice', 'module_id' => $invoice_id));

				$this->invoice_model->_table_name = 'tbl_credit_used';
				$this->invoice_model->delete_multiple(array('invoices_id' => $invoice_id));

				$this->invoice_model->_table_name = 'tbl_invoices';
				$this->invoice_model->_primary_key = 'invoices_id';
				$this->invoice_model->delete($invoice_id);
				if (!empty($invoice_info->client_id)) {
					$this->clear_client_invoice_cache((int) $invoice_info->client_id);
				}

				$result[] = $invoice_id;
			}

			echo json_encode(array("status" => 'success', 'message' => lang('deleted_invoice'), 'ids' => $result));
			exit();
		}

		echo json_encode(array("status" => 'error', 'message' => lang('you_need_select_to_delete')));
		exit();
	}

	public
	function get_payment($invoices_id, $pos = null)
	{
		$edited = can_action('13', 'edited');
		$can_edit = $this->invoice_model->can_action('tbl_invoices', 'edit', array('invoices_id' => $invoices_id));
		if (!empty($can_edit) && !empty($edited)) {
			$due = $this->invoice_model->calculate_to('invoice_due', $invoices_id);

			if (!empty($pos)) {
				$paid_amount = $due;
				$payment_date = date('Y-m-d H:i');
				$this->load->helper('string');
				$trans_id = random_string('nozero', 6);
				$notes = 'directly from POS';
				$save_into_account = 'on';
				$send_thank_you = 'on';
				$send_sms = 'on';
			} else {
				$paid_amount = $this->input->post('amount', TRUE);
				$payment_date = $this->input->post('payment_date', TRUE);
				$trans_id = $this->input->post('trans_id');
				$notes = $this->input->post('notes', true);
				$save_into_account = $this->input->post('save_into_account');
				$send_thank_you = $this->input->post('send_thank_you');
				$send_sms = $this->input->post('send_sms');
			}
			if ($paid_amount != 0) {
				if ($paid_amount > $due) {
					// messages for user
					$type = "error";
					$message = lang('overpaid_amount');
					set_message($type, $message);
					redirect('admin/invoice/manage_invoice/payment/' . $invoices_id);
				} else {
					$inv_info = $this->invoice_model->check_by(array('invoices_id' => $invoices_id), 'tbl_invoices');
					$currency = $this->invoice_model->check_by(array('code' => $inv_info->currency), 'tbl_currencies');
					$this->record_invoice_payment($invoices_id, array(
						'paid_amount' => $paid_amount,
						'payment_date' => $payment_date,
						'payment_method' => (!empty($pos) ? '-' : $this->input->post('payment_methods_id', TRUE)),
						'currency' => (!empty($pos) && !empty($currency->symbol) ? $currency->symbol : $this->input->post('currency', TRUE)),
						'trans_id' => $trans_id,
						'notes' => $notes,
						'save_into_account' => ($save_into_account == 'on'),
						'account_id' => $this->input->post('account_id', true),
						'send_email' => ($send_thank_you == 'on'),
						'send_sms' => ($send_sms == 'on'),
					));
				}
			}
			// messages for user
			$type = "success";
			$message = lang('generate_payment');
			set_message($type, $message);
			redirect('admin/invoice/manage_invoice/invoice_details/' . $invoices_id);
		} else {
			set_message('error', lang('there_in_no_value'));
			if (empty($_SERVER['HTTP_REFERER'])) {
				redirect('admin/invoice/all_payments');
			} else {
				redirect($_SERVER['HTTP_REFERER']);
			}
		}
	}

	public
	function update_payemnt($payments_id)
	{
		$data = array(
			'amount' => $this->input->post('amount', TRUE),
			'payment_method' => $this->input->post('payment_methods_id', TRUE),
			'payment_date' => date('Y-m-d', safe_strtotime($this->input->post('payment_date', TRUE))),
			'notes' => $this->input->post('notes', TRUE),
			'month_paid' => date("m", safe_strtotime($this->input->post('payment_date', TRUE))),
			'year_paid' => date("Y", safe_strtotime($this->input->post('payment_date', TRUE))),
		);
		$payments_info = $this->invoice_model->check_by(array('payments_id' => $payments_id), 'tbl_payments');
		if (empty($payments_info)) {
			$type = "error";
			$message = "No Record Found";
			set_message($type, $message);
			redirect('admin/invoice/all_payments');
		}
		if ($payments_info->amount != $data['amount']) {
			$activity = array(
				'user' => $this->session->userdata('user_id'),
				'module' => 'invoice',
				'module_field_id' => $payments_id,
				'activity' => ('activity_update_payment'),
				'icon' => 'fa-shopping-cart',
				'link' => 'admin/invoice/manage_invoice/payments_details/' . $payments_id,
				'value1' => $data['amount'],
				'value2' => $data['payment_date'],
			);
			$this->invoice_model->_table_name = 'tbl_activities';
			$this->invoice_model->_primary_key = 'activities_id';
			$this->invoice_model->save($activity);


			// send notification to client
			if (!empty($payments_info)) {
				$client_info = $this->invoice_model->check_by(array('client_id' => $payments_info->paid_by), 'tbl_client');
				if (!empty($client_info->primary_contact)) {
					$notifyUser = array($client_info->primary_contact);
				} else {
					$user_info = $this->invoice_model->check_by(array('company' => $client_info->client_id), 'tbl_account_details');
					if (!empty($user_info)) {
						$notifyUser = array($user_info->user_id);
					}
				}
			}
			if (!empty($notifyUser)) {
				foreach ($notifyUser as $v_user) {
					if ($v_user != $this->session->userdata('user_id')) {
						add_notification(array(
							'to_user_id' => $v_user,
							'icon' => 'shopping-cart',
							'description' => 'not_payment_update',
							'link' => 'client/invoice/manage_invoice/payments_details/' . $payments_id,
							'value' => lang('trans_id') . ' ' . $payments_info->trans_id . ' ' . lang('new') . ' ' . lang('amount') . ' ' . display_money($data['amount'], $payments_info->currency),
						));
					}
				}
				show_notification($notifyUser);
			}
		}

		$this->invoice_model->_table_name = 'tbl_payments';
		$this->invoice_model->_primary_key = 'payments_id';
		$this->invoice_model->save($data, $payments_id);
		$this->refresh_project_finance_cache_by_payment_id($payments_id);


		// messages for user
		$type = "success";
		$message = lang('generate_payment');
		set_message($type, $message);
		redirect('admin/invoice/all_payments');
	}

	public
	function send_payment($invoices_id, $paid_amount)
	{
		$this->send_payment_email($invoices_id, $paid_amount); //send email
		$type = "success";
		$message = lang('payment_information_send');
		set_message($type, $message);
		if (empty($_SERVER['HTTP_REFERER'])) {
			redirect('admin/invoice/all_payments');
		} else {
			redirect($_SERVER['HTTP_REFERER']);
		}
	}

	public
	function change_invoice_status($action, $id)
	{
		if ($action == 'mark_as_sent') {
			$data = array('emailed' => 'Yes', 'date_sent' => date("Y-m-d H:i:s", time()), 'status' => 'Unpaid');
		}
		if ($action == 'mark_as_cancelled') {
			$data = array('status' => 'Cancelled');
		}
		if ($action == 'unmark_as_cancelled') {
			$data = array('status' => 'Unpaid');
		}
		$this->invoice_model->_table_name = 'tbl_invoices';
		$this->invoice_model->_primary_key = 'invoices_id';
		$this->invoice_model->save($data, $id);

		// messages for user
		$type = "success";
		$imessage = lang('invoice_update');
		set_message($type, $imessage);
		redirect('admin/invoice/manage_invoice/invoice_details/' . $id);
	}

	public
	function send_invoice_email($invoice_id, $row = null)
	{
		if (!empty($row)) {
			$invoice_info = $this->invoice_model->check_by(array('invoices_id' => $invoice_id), 'tbl_invoices');
			$client_info = $this->invoice_model->check_by(array('client_id' => $invoice_info->client_id), 'tbl_client');
			if (!empty($client_info)) {
				$client = $client_info->name;
				$currency = $this->invoice_model->client_currency_symbol($client_info->client_id);
			} else {
				$client = '-';
				$currency = $this->invoice_model->check_by(array('code' => config_item('default_currency')), 'tbl_currencies');
			}

			$amount = $this->invoice_model->calculate_to('invoice_due', $invoice_info->invoices_id);
			$currency = $currency->code;
			$email_template = email_templates(array('email_group' => 'invoice_message'), $invoice_info->client_id);
			$message = $email_template->template_body;
			$ref = $invoice_info->reference_no;
			$subject = $email_template->subject;
			$due_date = $invoice_info->due_date;
		} else {
			$message = $this->input->post('message', TRUE);
			$ref = $this->input->post('ref', TRUE);
			$subject = $this->input->post('subject', TRUE);
			$client = $this->input->post('client_name', TRUE);
			$amount = $this->input->post('amount', true);
			$currency = $this->input->post('currency', TRUE);
			$due_date = $this->input->post('due_date', TRUE);
		}
		$message = (string) ($message ?? '');
		$client = (string) ($client ?? '');
		$ref = (string) ($ref ?? '');
		$subject = (string) ($subject ?? '');
		$amount = (string) ($amount ?? '');
		$currency = (string) ($currency ?? '');
		$due_date = (string) ($due_date ?? '');

		$client_name = str_replace("{CLIENT}", $client, $message);
		$Ref = str_replace("{REF}", $ref, $client_name);
		$Amount = str_replace("{AMOUNT}", $amount, $Ref);
		$Currency = str_replace("{CURRENCY}", $currency, $Amount);
		$Due_date = str_replace("{DUE_DATE}", $due_date, $Currency);
		$link = str_replace("{INVOICE_LINK}", base_url() . 'frontend/view_invoice/' . url_encode($invoice_id), $Due_date);
		$message = str_replace("{SITE_NAME}", config_item('company_name'), $link);

		$this->send_email_invoice($invoice_id, $message, $subject); // Email Invoice

		$data = array('status' => 'sent', 'emailed' => 'Yes', 'date_sent' => date("Y-m-d H:i:s", time()));

		$this->invoice_model->_table_name = 'tbl_invoices';
		$this->invoice_model->_primary_key = 'invoices_id';
		$this->invoice_model->save($data, $invoice_id);

		// Log Activity
		$activity = array(
			'user' => $this->session->userdata('user_id'),
			'module' => 'invoice',
			'module_field_id' => $invoice_id,
			'activity' => ('activity_invoice_sent'),
			'icon' => 'fa-shopping-cart',
			'link' => 'admin/invoice/manage_invoice/invoice_details/' . $invoice_id,
			'value1' => $ref,
			'value2' => $this->input->post('currency', TRUE) . ' ' . $this->input->post('amount'),
		);
		$this->invoice_model->_table_name = 'tbl_activities';
		$this->invoice_model->_primary_key = 'activities_id';
		$this->invoice_model->save($activity);
		// messages for user
		$type = "success";
		$imessage = lang('invoice_sent');
		set_message($type, $imessage);
		redirect('admin/invoice/manage_invoice/invoice_details/' . $invoice_id);
	}

	function send_email_invoice($invoice_id, $message, $subject)
	{
		$invoice_info = $this->invoice_model->check_by(array('invoices_id' => $invoice_id), 'tbl_invoices');
		$client_info = $this->invoice_model->check_by(array('client_id' => $invoice_info->client_id), 'tbl_client');

		$recipient = $client_info->email;

		$data['message'] = $message;

		$message = $this->load->view('email_template', $data, TRUE);
		$params = array(
			'recipient' => $recipient,
			'subject' => $subject,
			'message' => $message
		);
		$params['resourceed_file'] = 'uploads/' . slug_it(lang('invoice') . '_pdf_' . $invoice_info->reference_no) . '.pdf';
		$params['resourcement_url'] = base_url() . 'uploads/' . slug_it(lang('invoice') . '_pdf_' . $invoice_info->reference_no) . '.pdf';
		$this->attach_pdf($invoice_id);
		$this->invoice_model->send_email($params);

		$mobile = client_can_received_sms($invoice_info->client_id);
		if (!empty($mobile)) {
			$merge_fields = [];
			$merge_fields = array_merge($merge_fields, merge_invoice_template($invoice_id));
			$merge_fields = array_merge($merge_fields, merge_invoice_template($invoice_id, 'client', $invoice_info->client_id));
			$this->sms->send(SMS_INVOICE_REMINDER, $mobile, $merge_fields);
		}
		//Delete invoice in tmp folder
		if (is_file('uploads/' . slug_it(lang('invoice') . '_pdf_' . $invoice_info->reference_no) . '.pdf')) {
			unlink('uploads/' . slug_it(lang('invoice') . '_pdf_' . $invoice_info->reference_no) . '.pdf');
		}
		// send notification to client
		if (!empty($client_info->primary_contact)) {
			$notifyUser = array($client_info->primary_contact);
		} else {
			$user_info = $this->invoice_model->check_by(array('company' => $invoice_info->client_id), 'tbl_account_details');
			if (!empty($user_info)) {
				$notifyUser = array($user_info->user_id);
			}
		}
		if (!empty($notifyUser)) {
			foreach ($notifyUser as $v_user) {
				if ($v_user != $this->session->userdata('user_id')) {
					add_notification(array(
						'to_user_id' => $v_user,
						'icon' => 'shopping-cart',
						'description' => 'not_email_send_alert',
						'link' => 'client/invoice/manage_invoice/invoice_details/' . $invoice_id,
						'value' => lang('invoice') . ' ' . $invoice_info->reference_no,
					));
				}
			}
			show_notification($notifyUser);
		}
	}

	public
	function attach_pdf($id)
	{
		$this->invoice_details($id, 'attach');
	}

	function invoice_email($invoice_id)
	{
		$data['invoice_info'] = $this->invoice_model->check_by(array('invoices_id' => $invoice_id), 'tbl_invoices');
		$data['title'] = "Invoice PDF"; //Page title
		$message = $this->load->view('admin/invoice/invoice_pdf', $data, TRUE);

		$client_info = $this->invoice_model->check_by(array('client_id' => $data['invoice_info']->client_id), 'tbl_client');

		$recipient = $client_info->email;

		$data['message'] = $message;

		$message = $this->load->view('email_template', $data, TRUE);

		$params = array(
			'recipient' => $recipient,
			'subject' => '[ ' . config_item('company_name') . ' ]' . ' New Invoice' . ' ' . $data['invoice_info']->reference_no,
			'message' => $message
		);
		$params['resourceed_file'] = 'uploads/' . slug_it(lang('invoice') . '_' . $data['invoice_info']->reference_no) . '.pdf';
		$params['resourcement_url'] = base_url() . 'uploads/' . slug_it(lang('invoice') . '_' . $data['invoice_info']->reference_no) . '.pdf';

		$this->attach_pdf($invoice_id);

		$this->invoice_model->send_email($params);

		//Delete invoice in tmp folder
		if (is_file('uploads/' . slug_it(lang('invoice') . '_' . $data['invoice_info']->reference_no) . '.pdf')) {
			unlink('uploads/' . slug_it(lang('invoice') . '_' . $data['invoice_info']->reference_no) . '.pdf');
		}

		$data = array('emailed' => 'Yes', 'date_sent' => date("Y-m-d H:i:s", time()));

		$this->invoice_model->_table_name = 'tbl_invoices';
		$this->invoice_model->_primary_key = 'invoices_id';
		$invoice_id = $this->invoice_model->save($data, $invoice_id);

		$data['invoice_info'] = $this->invoice_model->check_by(array('invoices_id' => $invoice_id), 'tbl_invoices');
		// Log Activity
		$activity = array(
			'user' => $this->session->userdata('user_id'),
			'module' => 'invoice',
			'module_field_id' => $invoice_id,
			'activity' => ('activity_invoice_sent'),
			'icon' => 'fa-shopping-cart',
			'link' => 'admin/invoice/manage_invoice/invoice_details/' . $invoice_id,
			'value1' => $data['invoice_info']->reference_no,
		);

		$this->invoice_model->_table_name = 'tbl_activities';
		$this->invoice_model->_primary_key = 'activities_id';
		$this->invoice_model->save($activity);

		// send notification to client
		if (!empty($client_info->primary_contact)) {
			$notifyUser = array($client_info->primary_contact);
		} else {
			$user_info = $this->invoice_model->check_by(array('company' => $data['invoice_info']->client_id), 'tbl_account_details');
			if (!empty($user_info)) {
				$notifyUser = array($user_info->user_id);
			}
		}
		if (!empty($notifyUser)) {
			foreach ($notifyUser as $v_user) {
				if ($v_user != $this->session->userdata('user_id')) {
					add_notification(array(
						'to_user_id' => $v_user,
						'icon' => 'shopping-cart',
						'description' => 'not_email_send_alert',
						'link' => 'client/invoice/manage_invoice/invoice_details/' . $invoice_id,
						'value' => lang('invoice') . ' ' . $data['invoice_info']->reference_no,
					));
				}
			}
			show_notification($notifyUser);
		}
		// messages for user
		$type = "success";
		$imessage = lang('invoice_sent');
		set_message($type, $imessage);
		redirect('admin/invoice/manage_invoice/invoice_details/' . $invoice_id);
	}

	public
	function tax_rates($action = NULL, $id = NULL)
	{
		$edited = can_action('16', 'edited');
		$deleted = can_action('16', 'deleted');
		$data['page'] = lang('sales');
		$data['sub_active'] = lang('tax_rates');
		$data['datatable'] = true;
		if ($action == 'edit_tax_rates') {
			$data['active'] = 2;
			if (!empty($id)) {
				$can_edit = $this->invoice_model->can_action('tbl_tax_rates', 'edit', array('tax_rates_id' => $id));
				if (!empty($can_edit) && !empty($edited)) {
					$data['tax_rates_info'] = $this->invoice_model->check_by(array('tax_rates_id' => $id), 'tbl_tax_rates');
				}
			}
		} else {
			$data['active'] = 1;
		}
		if ($action == 'delete_tax_rates') {
			$can_delete = $this->invoice_model->can_action('tbl_tax_rates', 'delete', array('tax_rates_id' => $id));
			if (!empty($can_delete) && !empty($deleted)) {
				$tax_rates_info = $this->invoice_model->check_by(array('tax_rates_id' => $id), 'tbl_tax_rates');
				// Log Activity
				$activity = array(
					'user' => $this->session->userdata('user_id'),
					'module' => 'invoice',
					'module_field_id' => $id,
					'activity' => ('activity_taxt_rate_deleted'),
					'icon' => 'fa-shopping-cart',
					'value1' => $tax_rates_info->tax_rate_name,
				);
				$this->invoice_model->_table_name = 'tbl_activities';
				$this->invoice_model->_primary_key = 'activities_id';
				$this->invoice_model->save($activity);

				$this->invoice_model->_table_name = 'tbl_tax_rates';
				$this->invoice_model->_primary_key = 'tax_rates_id';
				$this->invoice_model->delete($id);
				// messages for user
				$type = "success";
				$message = lang('tax_deleted');
			} else {
				$type = "error";
				$message = lang('there_in_no_value');
			}
			echo json_encode(array("status" => $type, 'message' => $message));
			exit();
		} else {
			$data['title'] = "Tax Rates Info"; //Page title
			$data['page_title'] = lang('tax_rates');
			$data['page_description'] = lang('manage') . ' ' . lang('tax_rates');
			$data['header_actions'] = array();
			if (!empty(can_action('16', 'created')) || !empty(can_action('16', 'edited'))) {
				$data['header_actions'][] = array(
					'label' => lang('new') . ' ' . lang('tax_rates'),
					'icon' => 'plus',
					'href' => base_url('admin/invoice/createtax_rates'),
					'style' => 'primary',
				);
			}
			$data['header_filters'] = array();
			$subview = 'tax_rates';
			// get permission user
			$data['permission_user'] = $this->invoice_model->all_permission_user('16');
			// get all invoice
			$data['all_tax_rates'] = $this->invoice_model->get_permission('tbl_tax_rates');

			$data['subview'] = $this->load->view('admin/invoice/' . $subview, $data, TRUE);
			$this->load->view('admin/_layout_main', $data); //page load
		}
	}

	function createtax_rates($action = NULL, $id = NULL)
	{
		$edited = can_action('16', 'edited');
		$deleted = can_action('16', 'deleted');
		$data['page'] = lang('sales');
		$data['sub_active'] = lang('tax_rates');
		if ($action == 'edit_tax_rates') {
			$data['active'] = 2;
			if (!empty($id)) {
				$can_edit = $this->invoice_model->can_action('tbl_tax_rates', 'edit', array('tax_rates_id' => $id));
				if (!empty($can_edit) && !empty($edited)) {
					$data['tax_rates_info'] = $this->invoice_model->check_by(array('tax_rates_id' => $id), 'tbl_tax_rates');
				}
			}
		} else {
			$data['active'] = 1;
		}

		$data['title'] = "Tax Rates Info"; //Page title
		$data['page_title'] = !empty($id) ? lang('edit') . ' ' . lang('tax_rates') : lang('new') . ' ' . lang('tax_rates');
		$data['page_description'] = lang('manage') . ' ' . lang('tax_rates');
		$data['header_actions'] = array(
			array(
				'label' => lang('all') . ' ' . lang('tax_rates'),
				'icon' => 'arrow-left',
				'href' => base_url('admin/invoice/tax_rates'),
				'style' => 'neutral',
			),
		);
		$data['header_filters'] = array();
		$subview = 'createtax_rates';
		// get permission user
		$data['permission_user'] = $this->invoice_model->all_permission_user('16');
		// get all invoice
		$data['all_tax_rates'] = $this->invoice_model->get_permission('tbl_tax_rates');

		$data['subview'] = $this->load->view('admin/invoice/' . $subview, $data, TRUE);
		$this->load->view('admin/_layout_main', $data); //page load

	}

	public function taxList()
	{
		if ($this->input->is_ajax_request()) {
			$this->load->model('datatables');
			$this->datatables->table = 'tbl_tax_rates';
			$this->datatables->column_order = array('tax_rate_name', 'tax_rate_percent');
			$this->datatables->column_search = array('tax_rate_name', 'tax_rate_percent');
			$this->datatables->order = array('tax_rates_id' => 'desc');

			// get all invoice
			$fetch_data = $this->datatables->get_datatable_permission();

			$data = array();

			$edited = can_action('16', 'edited');
			$deleted = can_action('16', 'deleted');
			foreach ($fetch_data as $_key => $v_tax_rates) {

				$action = null;
				$can_delete = $this->invoice_model->can_action('tbl_tax_rates', 'delete', array('tax_rates_id' => $v_tax_rates->tax_rates_id));
				$can_edit = $this->invoice_model->can_action('tbl_tax_rates', 'edit', array('tax_rates_id' => $v_tax_rates->tax_rates_id));

				$sub_array = array();

				$sub_array[] = $v_tax_rates->tax_rate_name;
				$sub_array[] = $v_tax_rates->tax_rate_percent . '%';

				if (!empty($can_edit) && !empty($edited)) {
					$action .= btn_edit('admin/invoice/createtax_rates/edit_tax_rates/' . $v_tax_rates->tax_rates_id) . ' ';
				}
				if (!empty($can_delete) && !empty($deleted)) {
					$action .= ajax_anchor(base_url("admin/invoice/tax_rates/delete_tax_rates/$v_tax_rates->tax_rates_id"), '', array("class" => "btn btn-xs btn-danger", "title" => lang('delete'), "data-fade-out-on-success" => "#table_" . $_key)) . ' ';
				}

				$sub_array[] = $action;
				$data[] = $sub_array;
			}

			render_table($data);
		} else {
			redirect('admin/dashboard');
		}
	}

	public
	function save_tax_rate($id = NULL)
	{
		$data = $this->invoice_model->array_from_post(array('tax_rate_name', 'tax_rate_percent'));
		$permission = $this->input->post('permission', true);
		if (!empty($permission)) {
			if ($permission == 'everyone') {
				$assigned = 'all';
			} else {
				$assigned_to = $this->invoice_model->array_from_post(array('assigned_to'));
				if (!empty($assigned_to['assigned_to'])) {
					foreach ($assigned_to['assigned_to'] as $assign_user) {
						$assigned[$assign_user] = $this->input->post('action_' . $assign_user, true);
					}
				}
			}
			if (!empty($assigned)) {
				if ($assigned != 'all') {
					$assigned = json_encode($assigned);
				}
			} else {
				$assigned = 'all';
			}
			$data['permission'] = $assigned;
		} else {
			set_message('error', lang('assigned_to') . ' Field is required');
			if (empty($_SERVER['HTTP_REFERER'])) {
				redirect('admin/invoice/tax_rates');
			} else {
				redirect($_SERVER['HTTP_REFERER']);
			}
		}

		$this->invoice_model->_table_name = 'tbl_tax_rates';
		$this->invoice_model->_primary_key = 'tax_rates_id';
		$id = $this->invoice_model->save($data, $id);

		// Log Activity
		$activity = array(
			'user' => $this->session->userdata('user_id'),
			'module' => 'invoice',
			'module_field_id' => $id,
			'activity' => ('activity_taxt_rate_add'),
			'icon' => 'fa-shopping-cart',
			'value1' => $data['tax_rate_name'],
		);
		$this->invoice_model->_table_name = 'tbl_activities';
		$this->invoice_model->_primary_key = 'activities_id';
		$this->invoice_model->save($activity);

		// messages for user
		$type = "success";
		$message = lang('tax_added');
		set_message($type, $message);
		$save = $this->input->post('save', true);
		if ($save == 2) {
			redirect('admin/invoice/tax_rates/edit_tax_rates');
		} else {
			redirect('admin/invoice/tax_rates');
		}
	}

	public
	function zipped($module, $client_id = null, $id = null)
	{
		$this->load->helper('dompdf');
		$client_id = !empty($client_id) ? (int) $client_id : null;
		if ($module == 'estimate') {
			$this->load->model('estimates_model');
		} elseif ($module == 'proposal') {
			$this->load->model('proposal_model');
		} elseif ($module == 'credit_note') {
			$this->load->model('credit_note_model');
		}
		if ($this->input->post()) {
			if ($module == 'invoice') {
				$view = can_action('13', 'view');
				if (!$view) {
					access_denied('Zip Invoices');
				}

				$status = $this->input->post('invoice_status');
				$ex = explode('_', $status);
				if (!empty($ex)) {
					if (!empty($ex[1]) && is_numeric($ex[1])) {
						$ex = 'year';
					} else {
						$ex = 'no';
					}
				}

				$posted_client_id = (int) $this->input->post('client_id');
				if (!empty($posted_client_id)) {
					$client_id = $posted_client_id;
				}
				if (!empty($client_id)) {
					$client_info = $this->db->where('client_id', $client_id)->get('tbl_client')->row();
					$file_name = !empty($client_info->name) ? slug_it($client_info->name) : slug_it('client-' . $client_id);
				} else {
					$file_name = slug_it($status);
					$client_id = null;
				}

				if ($this->input->post('from_date') && $this->input->post('to_date') && $status != 'last_month' && $status != 'this_months' && $ex != 'year') {
					$from_date = $this->input->post('from_date', true);
					$to_date = $this->input->post('to_date', true);
					if (!empty($client_id)) {
						$this->db->where('client_id', $client_id);
					}
					$this->db->where('invoice_date BETWEEN "' . $from_date . '" AND "' . $to_date . '"');
					$all_invoice = $this->db->get('tbl_invoices')->result();
				} else {
					$from_date = null;
					$to_date = null;
					$all_invoice = $this->invoice_model->get_invoices($status, $client_id);
				}

				$this->load->helper('file');
				if (!is_really_writable(TEMP_FOLDER)) {
					show_error('uploads folder is not writable. You need to change the permissions to 755');
				}
				$dir = TEMP_FOLDER . $file_name;

				if (is_dir($dir)) {
					$this->delete_zip_temp_dir($dir);
				}
				if (empty($all_invoice)) {
					set_message('error', lang('no_record_available'));
					if (!empty($client_id)) {
						redirect('admin/client/details/' . $client_id . '/invoices');
					} else {
						redirect('admin/invoice/manage_invoice');
					}
				}

				mkdir($dir, 0777);
				foreach ($all_invoice as $v_invoice) {
					$data = $this->get_invoice_pdf_data($v_invoice->invoices_id);
					if (empty($data['sales_info'])) {
						continue;
					}
					$pdf_file = $this->load->view('admin/common/sales_pdf', $data, TRUE);
					$_temp_file_name = slug_it($data['sales_info']->reference_no);
					$file_name = $dir . strtoupper($_temp_file_name);
					if (!empty($client_info->name)) {
						$cl_name = slug_it($client_info->name);
					} else {
						$cl_name = slug_it($status);
					}
					$this->create_zip_pdf($pdf_file, slug_it($data['sales_info']->reference_no), $dir);
				}
			} else if ($module == 'estimate') {
				$view = can_action('14', 'view');
				if (!$view) {
					access_denied('Zip Estimate');
				}

				$status = $this->input->post('invoice_status', true);
				$ex = explode('_', $status);
				if (!empty($ex)) {
					if (!empty($ex[1]) && is_numeric($ex[1])) {
						$ex = 'year';
					} else {
						$ex = 'no';
					}
				}

				$client_id = $this->input->post('client_id', true);
				if (!empty($client_id)) {
					$client_info = $this->db->where('client_id', $client_id)->get('tbl_client')->row();
					$file_name = slug_it($client_info->name);
				} else {
					$file_name = lang($status);
					$client_id = null;
				}
				if ($this->input->post('from_date') && $this->input->post('to_date') && $status != 'last_month' && $status != 'this_months' && $ex != 'year') {
					$from_date = $this->input->post('from_date', true);
					$to_date = $this->input->post('to_date', true);
					if (!empty($client_id)) {
						$this->db->where('client_id', $client_id);
					}
					$this->db->where('estimate_date BETWEEN "' . $from_date . '" AND "' . $to_date . '"');
					$all_estimate = $this->db->get('tbl_estimates')->result();
				} else {
					$from_date = null;
					$to_date = null;
					$this->load->model('estimates_model');
					$all_estimate = $this->estimates_model->get_estimates($status, $client_id);
				}

				$this->load->helper('file');
				if (!is_really_writable(TEMP_FOLDER)) {
					show_error('uploads folder is not writable. You need to change the permissions to 755');
				}
				$dir = TEMP_FOLDER . $file_name;

				if (is_dir($dir)) {
					$this->delete_zip_temp_dir($dir);
				}
				if (empty($all_estimate)) {
					set_message('error', lang('no_record_available'));
					if (!empty($client_id)) {
						redirect('admin/client/details/' . $client_id . '/estimate');
					} else {
						redirect('admin/estimates');
					}
				}
				mkdir($dir, 0777);
				foreach ($all_estimate as $v_estimate) {
					$data['estimates_info'] = $v_estimate;
					$pdf_file = $this->load->view('admin/estimates/estimates_pdf', $data, TRUE);
					$_temp_file_name = slug_it($data['estimates_info']->reference_no);
					$file_name = $dir . strtoupper($_temp_file_name);
					if (!empty($client_info->name)) {
						$cl_name = slug_it($client_info->name);
					} else {
						$cl_name = slug_it($status);
					}
					$this->create_zip_pdf($pdf_file, slug_it($data['estimates_info']->reference_no), $dir);
				}
			} else if ($module == 'credit_note') {
				$view = can_action('14', 'view');
				if (!$view) {
					access_denied('Zip Credit Notes');
				}
				$status = $this->input->post('invoice_status', true);
				$ex = explode('_', $status);
				if (!empty($ex)) {
					if (!empty($ex[1]) && is_numeric($ex[1])) {
						$ex = 'year';
					} else {
						$ex = 'no';
					}
				}

				$client_id = $this->input->post('client_id', true);
				if (!empty($client_id)) {
					$client_info = $this->db->where('client_id', $client_id)->get('tbl_client')->row();
					$file_name = slug_it($client_info->name);
				} else {
					$file_name = lang($status);
					$client_id = null;
				}
				if ($this->input->post('from_date') && $this->input->post('to_date') && $status != 'last_month' && $status != 'this_months' && $ex != 'year') {
					$from_date = $this->input->post('from_date', true);
					$to_date = $this->input->post('to_date', true);
					if (!empty($client_id)) {
						$this->db->where('client_id', $client_id);
					}
					$this->db->where('credit_note_date BETWEEN "' . $from_date . '" AND "' . $to_date . '"');
					$all_credit_note = $this->db->get('tbl_credit_note')->result();
				} else {
					$from_date = null;
					$to_date = null;
					$this->load->model('credit_note_model');
					$all_credit_note = $this->credit_note_model->get_credit_notes($status, $client_id);
				}

				$this->load->helper('file');
				if (!is_really_writable(TEMP_FOLDER)) {
					show_error('uploads folder is not writable. You need to change the permissions to 755');
				}
				$dir = TEMP_FOLDER . $file_name;

				if (is_dir($dir)) {
					$this->delete_zip_temp_dir($dir);
				}
				if (empty($all_credit_note)) {
					set_message('error', lang('no_record_available'));
					if (!empty($client_id)) {
						redirect('admin/client/details/' . $client_id . '/credit_note');
					} else {
						redirect('admin/credit_note');
					}
				}
				mkdir($dir, 0777);
				foreach ($all_credit_note as $v_credit_note) {
					$data['credit_note_info'] = $v_credit_note;
					$pdf_file = $this->load->view('admin/credit_note/credit_note_pdf', $data, TRUE);
					$_temp_file_name = slug_it($data['credit_note_info']->reference_no);
					$file_name = $dir . strtoupper($_temp_file_name);
					if (!empty($client_info->name)) {
						$cl_name = slug_it($client_info->name);
					} else {
						$cl_name = slug_it($status);
					}
					$this->create_zip_pdf($pdf_file, slug_it($data['credit_note_info']->reference_no), $dir);
				}
			} else if ($module == 'proposal') {
				$view = can_action('140', 'view');
				if (!$view) {
					access_denied('Zip Proposal');
				}

				$status = $this->input->post('invoice_status', true);
				$ex = explode('_', $status);
				if (!empty($ex)) {
					if (!empty($ex[1]) && is_numeric($ex[1])) {
						$ex = 'year';
					} else {
						$ex = 'no';
					}
				}
				$client_id = $this->input->post('client_id', true);
				if (!empty($client_id)) {
					$client_info = $this->db->where('client_id', $client_id)->get('tbl_client')->row();
					$file_name = slug_it($client_info->name);
				} else {
					$file_name = slug_it($status);
					$client_id = null;
				}
				if ($this->input->post('from_date') && $this->input->post('to_date') && $status != 'last_month' && $status != 'this_months' && $ex != 'year') {
					$from_date = $this->input->post('from_date', true);
					$to_date = $this->input->post('to_date', true);
					if (!empty($client_id)) {
						$this->db->where('module', 'client');
						$this->db->where('module_id', $client_id);
					}
					$this->db->where('proposal_date BETWEEN "' . $from_date . '" AND "' . $to_date . '"');
					$all_proposal = $this->db->get('tbl_proposals')->result();
				} else {
					$from_date = null;
					$to_date = null;
					$this->load->model('proposal_model');
					$all_proposal = $this->proposal_model->get_proposals($status, $client_id);
				}

				$this->load->helper('file');
				if (!is_really_writable(TEMP_FOLDER)) {
					show_error('uploads folder is not writable. You need to change the permissions to 755');
				}
				$dir = TEMP_FOLDER . $file_name;
				if (is_dir($dir)) {
					$this->delete_zip_temp_dir($dir);
				}
				if (empty($all_proposal)) {
					set_message('error', lang('no_record_available'));
					if (!empty($client_id)) {
						redirect('admin/client/details/' . $client_id . '/proposal');
					} else {
						redirect('admin/proposals');
					}
				}
				mkdir($dir, 0777);
				foreach ($all_proposal as $v_proposal) {
					$data['proposals_info'] = $v_proposal;
					$pdf_file = $this->load->view('admin/proposals/proposals_pdf', $data, TRUE);
					$_temp_file_name = slug_it($data['proposals_info']->reference_no);
					$file_name = $dir . strtoupper($_temp_file_name);
					if (!empty($client_info->name)) {
						$cl_name = slug_it($client_info->name);
					} else {
						$cl_name = slug_it($status);
					}
					$this->create_zip_pdf($pdf_file, slug_it($data['proposals_info']->reference_no), $dir);
				}
			} else if ($module == 'payment') {
				$view = can_action('15', 'view');

				if (!$view) {
					access_denied('Zip Payment');
				}

				$status = $this->input->post('invoice_status', true);
				$ex = explode('_', $status);
				if (!empty($ex)) {
					if (!empty($ex[1]) && is_numeric($ex[1])) {
						$ex = 'year';
					} else {
						$ex = 'no';
					}
				}
				$client_id = $this->input->post('client_id', true);
				if (!empty($client_id)) {
					$client_info = $this->db->where('client_id', $client_id)->get('tbl_client')->row();
					$file_name = slug_it($client_info->name);
				} else {
					$file_name = slug_it($status);
					$client_id = null;
				}
				if ($this->input->post('from_date') && $this->input->post('to_date') && $status != 'last_month' && $status != 'this_months' && $ex != 'year') {
					$from_date = $this->input->post('from_date', true);
					$to_date = $this->input->post('to_date', true);
					if (!empty($client_id)) {
						$this->db->where('paid_by', $client_id);
					}
					$this->db->where('payment_date BETWEEN "' . $from_date . '" AND "' . $to_date . '"');
					$all_payments = $this->db->get('tbl_payments')->result();
				} else {
					$from_date = null;
					$to_date = null;
					$all_payments = $this->invoice_model->get_payments($status, $client_id);
				}
				$this->load->helper('file');
				if (!is_really_writable(TEMP_FOLDER)) {
					show_error('uploads folder is not writable. You need to change the permissions to 755');
				}
				$dir = TEMP_FOLDER . $file_name;

				if (is_dir($dir)) {
					$this->delete_zip_temp_dir($dir);
				}
				if (empty($all_payments)) {
					set_message('error', lang('no_record_available'));
					if (!empty($client_id)) {
						redirect('admin/client/details/' . $client_id . '/payment');
					} else {
						redirect('admin/invoice/all_payments');
					}
				}
				mkdir($dir, 0777);
				foreach ($all_payments as $v_payment) {
					$data['payments_info'] = $v_payment;
					$pdf_file = $this->load->view('admin/invoice/payments_pdf', $data, TRUE);
					$_temp_file_name = slug_it($data['payments_info']->trans_id);
					$file_name = $dir . strtoupper($_temp_file_name);
					if (!empty($client_info->name)) {
						$cl_name = slug_it($client_info->name);
					} else {
						$cl_name = slug_it($status);
					}
					$this->create_zip_pdf($pdf_file, slug_it($data['payments_info']->trans_id), $dir);
				}
			}

			$this->load->library('zip');
			// Read the invoices
			$this->zip->read_dir($dir, false);
			// Delete the temp directory for the client
			$this->delete_zip_temp_dir($dir);
			if (!empty($client_info->name)) {
				$cl_name = slug_it($client_info->name);
			} else {
				$cl_name = slug_it($status);
			}
			$this->zip->download($module . '-' . $cl_name . '.zip');
			$this->zip->clear_data();
		} else {
			$data['title'] = lang('zip_' . $module);
			$data['client_id'] = $client_id;
			$data['module'] = $module;
			$data['subview'] = $this->load->view('admin/invoice/zipped', $data, FALSE);
		}
	}

	private function get_invoice_pdf_data($id)
	{
		$data = array();
		$data['title'] = 'Invoice';
		$data['sales_info'] = join_data('tbl_invoices', '*', array('invoices_id' => $id), array('tbl_client' => 'tbl_client.client_id = tbl_invoices.client_id'));
		if (empty($data['sales_info'])) {
			return $data;
		}

		$url = base_url('frontend/view_invoice/') . url_encode($id);
		$data['qrcode'] = generate_qrcode($url);
		$payment_status = $this->invoice_model->get_payment_status($id);
		$data['sales_info']->ref_no = lang('invoice') . ' : ' . $data['sales_info']->reference_no;
		$data['sales_info']->start_date = lang('invoice_date') . ' : ' . display_date($data['sales_info']->invoice_date);
		$data['sales_info']->end_date = lang('due_date') . ' : ' . display_date($data['sales_info']->due_date);
		if (!empty($data['sales_info']->user_id)) {
			$data['sales_info']->sales_agent = lang('sales') . ' ' . lang('agent') . ' : ' . fullname($data['sales_info']->user_id);
		}
		if (safe_strtotime($data['sales_info']->due_date) < safe_strtotime(date('Y-m-d')) && $payment_status != lang('fully_paid') && $payment_status != lang('cancelled')) {
			$date1 = new DateTime($data['sales_info']->due_date);
			$date2 = new DateTime(date('Y-m-d'));
			$interval = $date1->diff($date2);
			$data['sales_info']->overdue_days = lang('invoice_overdue') . ' ' . lang('by') . ' ' . $interval->format('%a') . ' ' . lang('days');
		}
		$data['sales_info']->custom_field = '';
		$show_custom_fields = custom_form_label(9, $data['sales_info']->invoices_id);
		if (!empty($show_custom_fields)) {
			foreach ($show_custom_fields as $c_label => $v_fields) {
				if (!empty($v_fields)) {
					$data['sales_info']->custom_field .= $c_label . ' : ' . $v_fields . '<br>';
				}
			}
		}
		$data['all_items'] = $this->invoice_model->ordered_items_by_id($data['sales_info']->invoices_id);
		$data['sales_info']->sub_total = $this->invoice_model->calculate_to('invoice_cost', $data['sales_info']->invoices_id);
		$data['sales_info']->discount = $this->invoice_model->calculate_to('discount', $data['sales_info']->invoices_id);
		$data['sales_info']->total = $this->invoice_model->calculate_to('total', $data['sales_info']->invoices_id);
		$data['paid_amount'] = $this->invoice_model->calculate_to('paid_amount', $data['sales_info']->invoices_id);
		$data['invoice_due'] = $this->invoice_model->calculate_to('invoice_due', $data['sales_info']->invoices_id);
		$data['payment_status'] = $payment_status;
		return $data;
	}

	private function delete_zip_temp_dir($dir)
	{
		$dir = rtrim((string) $dir, '/\\');
		$temp_root = rtrim((string) TEMP_FOLDER, '/\\');
		if ($dir === '' || $temp_root === '' || strpos($dir, $temp_root) !== 0 || $dir === $temp_root) {
			return false;
		}
		$this->load->helper('file');
		delete_files($dir, true);
		return @rmdir($dir);
	}

	private function create_zip_pdf($html, $filename, $dir)
	{
		$uploads_root = realpath(FCPATH . 'uploads');
		$uploads_root = str_replace('\\', '/', rtrim(!empty($uploads_root) ? $uploads_root : FCPATH . 'uploads', '/\\'));
		$dir = str_replace('\\', '/', rtrim((string) $dir, '/\\'));
		if (strpos($dir, $uploads_root . '/') === 0) {
			$folder_name = substr($dir, strlen($uploads_root) + 1);
		} else {
			$folder_name = 'temp/' . basename($dir);
		}
		return pdf_create($html, $filename, 1, null, true, $folder_name);
	}

	public
	function reminder($module, $module_id, $id = null)
	{
		$data['title'] = lang('reminder') . ' ' . lang('list');
		if ($this->input->post()) {
			$r_data['date'] = $this->input->post('date', true);
			$r_data['module'] = $module;
			$r_data['module_id'] = $module_id;
			$r_data['user_id'] = $this->input->post('user_id', true) ?: my_id();
			$r_data['description'] = $this->input->post('description', true);
			$notify_by_email = $this->input->post('notify_by_email', true);
			if (empty($notify_by_email)) {
				$notify_by_email = 'No';
			} else {
				$notify_by_email = 'Yes';
			}
			$r_data['notify_by_email'] = $notify_by_email;
			$r_data['created_by'] = $this->session->userdata('user_id');
			$this->invoice_model->_table_name = 'tbl_reminders';
			$this->invoice_model->_primary_key = 'reminder_id';
			$this->invoice_model->save($r_data, $id);
			if ($module == 'client') {
				$url = 'admin/client/details/' . $module_id;
			} elseif ($module == 'invoice') {
				$url = 'admin/invoice/manage_invoice/invoice_details/' . $module_id;
			} elseif ($module == 'estimate') {
				$url = 'admin/estimates/create/estimates_details/' . $module_id;
			} elseif ($module == 'proposal') {
				$url = 'admin/proposals/createproposal/proposals_details/' . $module_id;
			} else if ($module == 'leads') {
				$url = 'admin/leads/leads_details/' . $module_id;
			} else {
				$url = '#';
			}
			// Log Activity
			$activity = array(
				'user' => $this->session->userdata('user_id'),
				'module' => $module,
				'module_field_id' => $module_id,
				'activity' => ('activity_added_reminder'),
				'icon' => 'fa-shopping-cart',
				'link' => $url,
				'value1' => $r_data['description'],
			);
			$this->invoice_model->_table_name = 'tbl_activities';
			$this->invoice_model->_primary_key = 'activities_id';
			$this->invoice_model->save($activity);

			$type = "success";
			$message = lang('update_reminder');
			set_message($type, $message);

			if ($this->input->is_ajax_request()) {
				echo json_encode(array(
					'status' => $type,
					'message' => $message,
					'url' => $url,
				));
				exit();
			}

			if ($module == 'invoice') {
				redirect('admin/invoice/manage_invoice/invoice_details/' . $module_id);
			} else if ($module == 'estimate') {
				redirect('admin/estimates/create/estimates_details/' . $module_id);
			} else if ($module == 'proposal') {
				redirect('admin/proposals/index/proposals_details/' . $module_id);
			} else if ($module == 'client') {
				redirect('admin/client/details/' . $module_id);
			} else if ($module == 'leads') {
				redirect('admin/leads/leads_details/' . $module_id);
			} else {
				if (empty($_SERVER['HTTP_REFERER'])) {
					redirect('admin/dashboard');
				} else {
					redirect($_SERVER['HTTP_REFERER']);
				}
			}
		} else {
			if (!empty($id)) {
				$data['active'] = 2;
				$data['reminder_info'] = $this->db->where('reminder_id', $id)->get('tbl_reminders')->row();
			} else {
				$data['active'] = 1;
			}
			$data['all_reminder'] = $this->db->where(array('module' => $module, 'module_id' => $module_id))->get('tbl_reminders')->result();

			$data['module_id'] = $module_id;
			$data['module'] = $module;
			$data['subview'] = $this->load->view('admin/invoice/reminder', $data, FALSE);
		}
	}

	public
	function delete_reminder($module, $module_id, $id = null)
	{
		$reminder_info = $this->db->where('reminder_id', $id)->get('tbl_reminders')->row();
		if (empty($reminder_info)) {
			echo json_encode(array("status" => 'error', 'message' => lang('no_data_found')));
			exit();
		}

		if ($module == 'client') {
			$url = 'admin/client/details/' . $module_id;
		} elseif ($module == 'invoice') {
			$url = 'admin/invoice/manage_invoice/invoice_details/' . $module_id;
		} elseif ($module == 'estimate') {
			$url = 'admin/estimates/create/estimates_details/' . $module_id;
		} elseif ($module == 'proposal') {
			$url = 'admin/proposals/index/proposals_details/' . $module_id;
		} else if ($module == 'leads') {
			$url = 'admin/leads/leads_details/' . $module_id;
		} else {
			$url = '#';
		}
		// Log Activity
		$activity = array(
			'user' => $this->session->userdata('user_id'),
			'module' => $module,
			'module_field_id' => $module_id,
			'activity' => ('activity_delete_reminder'),
			'icon' => 'fa-shopping-cart',
			'link' => $url,
			'value1' => $reminder_info->description,
		);
		$this->invoice_model->_table_name = 'tbl_activities';
		$this->invoice_model->_primary_key = 'activities_id';
		$this->invoice_model->save($activity);

		$this->invoice_model->_table_name = 'tbl_reminders';
		$this->invoice_model->_primary_key = 'reminder_id';
		$this->invoice_model->delete($id);

		echo json_encode(array("status" => 'success', 'message' => lang('delete_reminder')));
		exit();
	}

	public function pos_sales()
	{
		$data['title'] = lang('pos_sales');
		$data['page_title'] = lang('pos_sales');
		$data['page_description'] = 'Fast billing workspace for walk-in sales, cart checkout, and POS draft handling.';
		$data['header_actions_html'] = ''
			. '<button type="button" id="Preset" class="inline-flex items-center gap-2 rounded-xl border border-rose-200 bg-rose-50 px-4 py-2.5 text-sm font-semibold text-rose-700 transition hover:bg-rose-100 dark:border-rose-900/60 dark:bg-rose-900/20 dark:text-rose-300 dark:hover:bg-rose-900/35">'
			. '<i data-lucide="rotate-ccw" class="h-4 w-4"></i><span>' . lang('reset') . '</span></button>'
			. '<button type="submit" form="pos-sales-form" name="save_as_draft" value="1" class="inline-flex items-center gap-2 rounded-xl border border-amber-200 bg-amber-50 px-4 py-2.5 text-sm font-semibold text-amber-700 transition hover:bg-amber-100 dark:border-amber-900/60 dark:bg-amber-900/20 dark:text-amber-300 dark:hover:bg-amber-900/35">'
			. '<i data-lucide="file-clock" class="h-4 w-4"></i><span>' . lang('draft') . '</span></button>'
			. '<button type="submit" form="pos-sales-form" name="Paid" value="' . html_escape(lang('paid')) . '" class="inline-flex items-center gap-2 rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-2.5 text-sm font-semibold text-emerald-700 transition hover:bg-emerald-100 dark:border-emerald-900/60 dark:bg-emerald-900/20 dark:text-emerald-300 dark:hover:bg-emerald-900/35">'
			. '<i data-lucide="badge-dollar-sign" class="h-4 w-4"></i><span>' . lang('paid') . '</span></button>';
		$data['all_client'] = $this->items_model->select_data('tbl_client', 'client_id', 'name');
		$data['warehouseList'] = $this->items_model->select_data('tbl_warehouse', 'warehouse_id', 'warehouse_name', array('status' => 'published'));
		$data['permission_user'] = $this->items_model->all_permission_user('13');
		$data['subview'] = $this->load->view('admin/invoice/pos_sales', $data, TRUE);
		$this->load->view('admin/_layout_main', $data); //page load
	}

	public function client_awards()
	{
		$data['title'] = lang('award');
		$data['all_client'] = $this->items_model->select_data('tbl_client', 'tbl_client.client_id', 'name', '', ['tbl_award_points' => 'tbl_award_points.client_id = tbl_client.client_id']);
		$data['dataTables'] = true;
		$data['subview'] = $this->load->view('admin/invoice/client_award_list', $data, TRUE);
		$this->load->view('admin/_layout_main', $data); //page load
	}

	public function clientawardpointslist()
	{
		if ($this->input->is_ajax_request()) {
			$this->load->model('datatables');

			$this->datatables->table = 'tbl_award_points';
			$this->datatables->join_table = array('tbl_client');
			$this->datatables->join_where = array('tbl_client.client_id=tbl_award_points.client_id');
			$custom_field = custom_form_table_search(15);
			$action_array = array('award_points_id');
			$main_column = array('tbl_client.name', 'client_award_point');
			$result = array_merge($main_column, $custom_field, $action_array);
			$this->datatables->column_order = $result;
			$this->datatables->column_search = $result;
			$this->db->group_by('tbl_award_points.client_id');
			$this->datatables->order = array('award_points_id' => 'desc');

			$fetch_data = $this->datatables->get_datatable_permission();

			$data = array();
			foreach ($fetch_data as $_key => $v_rule) {
				$profile_info = $this->db->where('client_id', $v_rule->client_id)->get('tbl_client')->row();
				$clientpoint = $this->invoice_model->get_client_point_byid($v_rule->client_id);
				if (!empty($profile_info->name)) {
					$clientname = $profile_info->name;
				} else {
					$clientname = '-';
				}

				$action = null;
				$sub_array = array();

				$sub_array[] = $clientname;
				$sub_array[] = $clientpoint;

				$action .= ajax_anchor(base_url("admin/invoice/client_awards/delete_clientaward
				points/$v_rule->award_points_id"), '', array("class" => "btn btn-xs btn-danger", "title" => lang('delete'), "data-fade-out-on-success" => "#table_" . $_key)) . ' ';
				$sub_array[] = $action;
				$data[] = $sub_array;
			}

			render_table($data);
		} else {
			redirect('admin/dashboard');
		}
	}

	public function invoice_pdf()
	{
		$data['title'] = lang('invoice');
		$data['page_header'] = lang('invoice');
		$subview = $this->load->view('admin/common/sales_pdf_back', $data, true);
		// create pdf by dompdf
		$this->load->helper('dompdf');
		pdf_create($subview, lang('invoice'), 1, false, false, false, 'Partially Paid');

		//        $this->load->view('admin/_layout_main', $data); //page load
	}

	public function invoice_view()
	{
		$data['title'] = lang('invoice');
		$data['page_header'] = lang('invoice');
		$data['subview'] = $this->load->view('admin/common/invoice_view', $data, TRUE);
		$this->load->view('admin/_layout_main', $data); //page load
	}

	public function pos()
	{
		$data['title'] = lang('invoice');
		$data['subview'] = $this->load->view('admin/invoice/pos', $data, TRUE);
		$this->load->view('admin/_layout_main', $data); //page load
	}
}
