load->model('Projects_model'); return $this->Projects_model->get($id); break; case 'tasks': $this->load->model('Tasks_model'); return $this->Tasks_model->get($id); break; case 'staffs': $this->load->model('Staff_model'); return $this->Staff_model->get($id); break; case 'tickets': $this->load->model('Tickets_model'); return $this->Tickets_model->get($id); break; case 'leads': $this->load->model('Leads_model'); return $this->Leads_model->get($id); break; case 'clients': $this->load->model('Clients_model'); return $this->Clients_model->get($id); break; case 'contracts': $this->load->model('Contracts_model'); $original_data = $this->Contracts_model->get($id); // Process data based on whether it's a single contract or multiple if (is_numeric($id)) { // Single contract $data = $original_data; // Get custom fields $this->db->where('active', 1); $this->db->where('fieldto', 'contracts'); $fields = $this->db->get(db_prefix() . 'customfields')->result_array(); $customfields = []; foreach ($fields as $field) { $this->db->where('relid', $id); $this->db->where('fieldid', $field['id']); $this->db->where('fieldto', 'contracts'); $field_value = $this->db->get(db_prefix() . 'customfieldsvalues')->row(); // Add field value to array if (is_object($data)) { if (!property_exists($data, 'custom_fields_values')) { $data->custom_fields_values = []; } $data->custom_fields_values[] = [ 'field_id' => $field['id'], 'field_name' => $field['name'], 'value' => $field_value ? $field_value->value : '' ]; } else { if (!isset($data['custom_fields_values'])) { $data['custom_fields_values'] = []; } $data['custom_fields_values'][] = [ 'field_id' => $field['id'], 'field_name' => $field['name'], 'value' => $field_value ? $field_value->value : '' ]; } } } else { // Multiple contracts $data = []; // Get all custom fields $this->db->where('active', 1); $this->db->where('fieldto', 'contracts'); $all_fields = $this->db->get(db_prefix() . 'customfields')->result_array(); // Get all contract IDs $contract_ids = array_column($original_data, 'id'); // Get all custom field values for these contracts $this->db->where_in('relid', $contract_ids); $this->db->where('fieldto', 'contracts'); $all_values = $this->db->get(db_prefix() . 'customfieldsvalues')->result_array(); // Organize values by contract and field ID $organized_values = []; foreach ($all_values as $value) { $organized_values[$value['relid']][$value['fieldid']] = $value['value']; } // Process each contract foreach ($original_data as $contract) { $contract_id = $contract['id']; $contract_copy = $contract; // Add custom fields $contract_copy['custom_fields_values'] = []; foreach ($all_fields as $field) { $field_value = isset($organized_values[$contract_id][$field['id']]) ? $organized_values[$contract_id][$field['id']] : ''; $contract_copy['custom_fields_values'][] = [ 'field_id' => $field['id'], 'field_name' => $field['name'], 'value' => $field_value ]; } $data[] = $contract_copy; } } return $data; break; case 'invoices': $this->load->model('Invoices_model'); $data = $this->Invoices_model->get($id); if (!empty($data) && !empty($id)) { $data->items = $this->get_api_custom_data($data->items, 'items', '', true); } return $data; break; case 'estimates': $this->load->model('Estimates_model'); $data = $this->Estimates_model->get($id); if (!empty($data) && !empty($id)) { $data->items = $this->get_api_custom_data($data->items, 'items', '', true); } return $data; break; case 'departments': $this->load->model('Departments_model'); return $this->Departments_model->get($id); break; case 'payments': $this->load->model('Payments_model'); return $this->Payments_model->get($id); break; case 'roles': $this->load->model('Roles_model'); return $this->Roles_model->get($id); break; case 'proposals': $this->load->model('Proposals_model'); $data = $this->Proposals_model->get($id); if (!empty($data) && !empty($id)) { $data->items = $this->get_api_custom_data($data->items, 'items', '', true); } return $data; break; case 'knowledge': $this->load->model('Knowledge_base_model'); return $this->Knowledge_base_model->get($id); break; case 'goals': $this->load->model('Goals_model'); return $this->Goals_model->get($id); break; case 'currencies': $this->load->model('Currencies_model'); return $this->Currencies_model->get($id); break; case 'annex': $this->load->model('Annex_model'); return $this->Annex_model->get($id); break; case 'contacts': $this->load->model('Clients_model'); return $this->clients_model->get_contact($id); break; case 'all_contacts': $this->load->model('Clients_model'); return $this->clients_model->get_contacts($id); break; case 'invoices': $this->load->model('invoices_model'); return $this->invoices_model->get($id); break; case 'invoice_items': $this->load->model('invoice_items_model'); return $this->invoice_items_model->get($id); break; case 'milestones': return $this->get_milestones_api($id); break; case 'expenses': return $this->get_expenses_api($id); break; case 'creditnotes': $this->load->model('Credit_notes_model'); $data = $this->Credit_notes_model->get($id); if (!empty($data) && !empty($id)) { $data->items = $this->get_api_custom_data($data->items,"items", '', true); } return $data; break; case 'events': return $this->get_calendar_events($id); break; case 'subscriptions': return $this->get_subscription_events($id); break; case 'taskstimers': return $this->get_timesheets_events($id); break; default: return ''; break; } } public function value($value) { if ($value) { return $value; } return ''; } public function search($type, $key) { \modules\api\core\Apiinit::the_da_vinci_code('api'); return $this->get_relation_data_api($type, $key); } public function _search_tickets($q, $limit = 0, $api = false) { $fields = get_custom_fields('tickets'); $result = [ 'result' => [], 'type' => 'tickets', 'search_heading' => _l('support_tickets'), ]; if (is_staff_member() || (!is_staff_member() && 1 == get_option('access_tickets_to_none_staff_members')) || true == $api) { $is_admin = is_admin(); $where = ''; if (!$is_admin && 1 == get_option('staff_access_only_assigned_departments') && false == $api) { $this->load->model('departments_model'); $staff_deparments_ids = $this->departments_model->get_staff_departments(get_staff_user_id(), true); $departments_ids = []; if (0 == count($staff_deparments_ids)) { $departments = $this->departments_model->get(); foreach ($departments as $department) { array_push($departments_ids, $department['departmentid']); } } else { $departments_ids = $staff_deparments_ids; } if (count($departments_ids) > 0) { $where = 'department IN (SELECT departmentid FROM tblstaffdepartments WHERE departmentid IN ('.implode(',', $departments_ids).') AND staffid="'.get_staff_user_id().'")'; } } $this->db->select(); $this->db->from('tbltickets'); $this->db->join('tbldepartments', 'tbldepartments.departmentid = tbltickets.department'); $this->db->join('tblclients', 'tblclients.userid = tbltickets.userid', 'left'); $this->db->join('tblcontacts', 'tblcontacts.id = tbltickets.contactid', 'left'); if (!_startsWith($q, '#')) { $where_string = ''; foreach ($fields as $key => $value) { $this->db->join(db_prefix().'customfieldsvalues as ctable_'.$key.'', db_prefix().'tickets.ticketid = ctable_'.$key.'.relid and ctable_'.$key.'.fieldto="tickets" AND ctable_'.$key.'.fieldid='.$value['id'], 'LEFT'); $where_string .= ' OR ctable_'.$key.'.value LIKE "%'.$q.'%"'; } $this->db->where('( ticketid LIKE "'.$q.'%" OR subject LIKE "%'.$q.'%" OR message LIKE "%'.$q.'%" OR tblcontacts.email LIKE "%'.$q.'%" OR CONCAT(firstname, \' \', lastname) LIKE "%'.$q.'%" OR company LIKE "%'.$q.'%" OR vat LIKE "%'.$q.'%" OR tblcontacts.phonenumber LIKE "%'.$q.'%" OR tblclients.phonenumber LIKE "%'.$q.'%" OR city LIKE "%'.$q.'%" OR state LIKE "%'.$q.'%" OR address LIKE "%'.$q.'%" OR tbldepartments.name LIKE "%'.$q.'%" '.$where_string.' )'); if ('' != $where) { $this->db->where($where); } } else { $this->db->where('ticketid IN (SELECT rel_id FROM tbltags_in WHERE tag_id IN (SELECT id FROM tbltags WHERE name="'.strafter($q, '#').'") AND tbltags_in.rel_type=\'ticket\' GROUP BY rel_id HAVING COUNT(tag_id) = 1) '); } if (0 != $limit) { $this->db->limit($limit); } $this->db->order_by('ticketid', 'DESC'); $result['result'] = $this->db->get()->result_array(); } return $result; } public function _search_leads($q, $limit = 0, $where = [], $api = false) { $fields = get_custom_fields('leads'); $result = [ 'result' => [], 'type' => 'leads', 'search_heading' => _l('leads'), ]; $has_permission_view = has_permission('leads', '', 'view'); if (is_staff_member() || true == $api) { // Leads $this->db->select('tblleads.*'); $this->db->from('tblleads'); if (!$has_permission_view && false == $api) { $this->db->where('(assigned = '.get_staff_user_id().' OR addedfrom = '.get_staff_user_id().' OR is_public=1)'); } if (!_startsWith($q, '#')) { $where_string = ''; foreach ($fields as $key => $value) { $this->db->join(db_prefix().'customfieldsvalues as ctable_'.$key.'', db_prefix().'leads.id = ctable_'.$key.'.relid and ctable_'.$key.'.fieldto="leads" AND ctable_'.$key.'.fieldid='.$value['id'], 'LEFT'); $where_string .= ' OR ctable_'.$key.'.value LIKE "%'.$q.'%"'; } $this->db->where('(name LIKE "%'.$q.'%" OR title LIKE "%'.$q.'%" OR company LIKE "%'.$q.'%" OR zip LIKE "%'.$q.'%" OR city LIKE "%'.$q.'%" OR state LIKE "%'.$q.'%" OR address LIKE "%'.$q.'%" OR email LIKE "%'.$q.'%" OR phonenumber LIKE "%'.$q.'%" '.$where_string.' )'); } else { $this->db->where('id IN (SELECT rel_id FROM tbltags_in WHERE tag_id IN (SELECT id FROM tbltags WHERE name="'.strafter($q, '#').'") AND tbltags_in.rel_type=\'lead\' GROUP BY rel_id HAVING COUNT(tag_id) = 1) '); } $this->db->where('client_id < 1'); if (0 != $limit) { $this->db->limit($limit); } $this->db->order_by('name', 'ASC'); $result['result'] = $this->db->get()->result_array(); } return $result; } public function _search_invoices($q, $limit = 0, $where = [], $api = false) { $fields = get_custom_fields('invoice'); $result = [ 'result' => [], 'type' => 'invoices', 'search_heading' => _l('invoices'), ]; $has_permission_view_invoices = has_permission('invoices', '', 'view'); $has_permission_view_invoices_own = has_permission('invoices', '', 'view_own'); if ($has_permission_view_invoices || $has_permission_view_invoices_own || '1' == get_option('allow_staff_view_invoices_assigned') || true == $api) { if (is_numeric($q)) { $q = trim($q); $q = ltrim($q, '0'); } elseif (startsWith($q, get_option('invoice_prefix'))) { $q = strafter($q, get_option('invoice_prefix')); $q = trim($q); $q = ltrim($q, '0'); } $invoice_fields = prefixed_table_fields_array(db_prefix().'invoices'); $clients_fields = prefixed_table_fields_array(db_prefix().'clients'); // Invoices $this->db->select(implode(',', $invoice_fields).','.implode(',', $clients_fields).','.db_prefix().'invoices.id as invoiceid,'.get_sql_select_client_company()); $this->db->from(db_prefix().'invoices'); $this->db->join(db_prefix().'clients', db_prefix().'clients.userid = '.db_prefix().'invoices.clientid', 'left'); $this->db->join(db_prefix().'currencies', db_prefix().'currencies.id = '.db_prefix().'invoices.currency'); $this->db->join(db_prefix().'contacts', db_prefix().'contacts.userid = '.db_prefix().'clients.userid AND is_primary = 1', 'left'); if (!startsWith($q, '#')) { $where_string = ''; foreach ($fields as $key => $value) { $this->db->join(db_prefix().'customfieldsvalues as ctable_'.$key.'', db_prefix().'invoices.id = ctable_'.$key.'.relid and ctable_'.$key.'.fieldto="invoice" AND ctable_'.$key.'.fieldid='.$value['id'], 'LEFT'); $where_string .= ' OR ctable_'.$key.'.value LIKE "%'.$q.'%"'; } $this->db->where('('.db_prefix().'invoices.number LIKE "'.$this->db->escape_like_str($q).'" OR '.db_prefix().'clients.company LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'invoices.clientnote LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.vat LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.phonenumber LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.city LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.state LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.zip LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.address LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'invoices.adminnote LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR CONCAT(firstname,\' \',lastname) LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'invoices.billing_street LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'invoices.billing_city LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'invoices.billing_state LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'invoices.billing_zip LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'invoices.shipping_street LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'invoices.shipping_city LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'invoices.shipping_state LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'invoices.shipping_zip LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.billing_street LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.billing_city LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.billing_state LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.billing_zip LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.shipping_street LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.shipping_city LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.shipping_state LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.shipping_zip LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' '.$where_string.' )'); } else { $this->db->where(db_prefix().'invoices.id IN (SELECT rel_id FROM '.db_prefix().'taggables WHERE tag_id IN (SELECT id FROM '.db_prefix().'tags WHERE name="'.$this->db->escape_str(strafter($q, '#')).'") AND '.db_prefix().'taggables.rel_type=\'invoice\' GROUP BY rel_id HAVING COUNT(tag_id) = 1) '); } $this->db->order_by('number,YEAR(date)', 'desc'); if (0 != $limit) { $this->db->limit($limit); } $result['result'] = $this->db->get()->result_array(); } return $result; } public function _search_projects($q, $limit = 0, $where = false, $rel_type = null, $api = false) { $fields = get_custom_fields('projects'); $result = [ 'result' => [], 'type' => 'projects', 'search_heading' => _l('projects'), ]; $projects = has_permission('projects', '', 'view'); // Projects $this->db->select('tblprojects.*'); $this->db->from('tblprojects'); if (isset($rel_type) && 'lead' == $rel_type) { $this->db->join('tblleads', 'tblleads.id = tblprojects.clientid'); } else { $this->db->join('tblclients', 'tblclients.userid = tblprojects.clientid', 'LEFT'); $this->db->join('tblleads', 'tblleads.id = tblprojects.clientid', 'LEFT'); } if (!$projects && false == $api) { $this->db->where('tblprojects.id IN (SELECT project_id FROM tblprojectmembers WHERE staff_id='.get_staff_user_id().')'); } if (false != $where) { $this->db->where($where); } if (!_startsWith($q, '#')) { $where_string = ''; foreach ($fields as $key => $value) { $this->db->join(db_prefix().'customfieldsvalues as ctable_'.$key.'', db_prefix().'projects.id = ctable_'.$key.'.relid and ctable_'.$key.'.fieldto="projects" AND ctable_'.$key.'.fieldid='.$value['id'], 'LEFT'); $where_string .= ' OR ctable_'.$key.'.value LIKE "%'.$q.'%"'; } $this->db->where('(tblleads.company LIKE "%'.$q.'%" OR tblprojects.description LIKE "%'.$q.'%" OR tblprojects.name LIKE "%'.$q.'%" OR tblleads.phonenumber LIKE "%'.$q.'%" OR tblleads.city LIKE "%'.$q.'%" OR tblleads.zip LIKE "%'.$q.'%" OR tblleads.state LIKE "%'.$q.'%" OR tblleads.zip LIKE "%'.$q.'%" OR tblleads.address LIKE "%'.$q.'%" '.$where_string.' )'); } else { $this->db->where('id IN (SELECT rel_id FROM tbltags_in WHERE tag_id IN (SELECT id FROM tbltags WHERE name="'.strafter($q, '#').'") AND tbltags_in.rel_type=\'project\' GROUP BY rel_id HAVING COUNT(tag_id) = 1) '); } if (0 != $limit) { $this->db->limit($limit); } $this->db->order_by(db_prefix().'projects.name', 'ASC'); $result['result'] = $this->db->get()->result_array(); return $result; } public function _search_staff($q, $limit = 0, $api = false) { $result = [ 'result' => [], 'type' => 'staff', 'search_heading' => _l('staff_members'), ]; if (has_permission('staff', '', 'view') || true == $api) { // Staff $fields = get_custom_fields('staff'); $this->db->select('staff.*'); $this->db->from(db_prefix().'staff'); $this->db->like('firstname', $q); $this->db->or_like('lastname', $q); $this->db->or_like("CONCAT(firstname, ' ', lastname)", $q, false); $this->db->or_like('facebook', $q); $this->db->or_like('linkedin', $q); $this->db->or_like('phonenumber', $q); $this->db->or_like('email', $q); $this->db->or_like('skype', $q); foreach ($fields as $key => $value) { $this->db->join(db_prefix().'customfieldsvalues as ctable_'.$key.'', db_prefix().'staff.staffid = ctable_'.$key.'.relid and ctable_'.$key.'.fieldto="staff" AND ctable_'.$key.'.fieldid='.$value['id'], 'LEFT'); $this->db->or_like('ctable_'.$key.'.value', $q); } if (0 != $limit) { $this->db->limit($limit); } $this->db->order_by('firstname', 'ASC'); $result['result'] = $this->db->get()->result_array(); } return $result; } public function _search_tasks($q, $limit = 0, $api = false) { $result = [ 'result' => [], 'type' => 'tasks', 'search_heading' => _l('tasks'), ]; if (has_permission('tasks', '', 'view') || true == $api) { // task $fields = get_custom_fields('tasks'); $this->db->select(db_prefix().'tasks.*'); $this->db->from(db_prefix().'tasks'); $this->db->like('name', $q); $this->db->or_like(db_prefix().'tasks.id', $q); foreach ($fields as $key => $value) { $this->db->join(db_prefix().'customfieldsvalues as ctable_'.$key.'', db_prefix().'tasks.id = ctable_'.$key.'.relid and ctable_'.$key.'.fieldto="tasks" AND ctable_'.$key.'.fieldid='.$value['id'], 'LEFT'); $this->db->or_like('ctable_'.$key.'.value', $q); } if (0 != $limit) { $this->db->limit($limit); } $this->db->order_by('name', 'ASC'); $result['result'] = $this->db->get()->result_array(); } return $result; } public function get_user($id = '') { $this->db->select('*'); if ('' != $id) { $this->db->where('id', $id); } return $this->db->get(db_prefix() . 'user_api')->result_array(); } public function add_user($data) { $permissions = isset($data['permissions']) ? $data['permissions'] : []; unset($data['permissions']); $payload = [ 'user' => $data['user'], 'name' => $data['name'], ]; // Load Authorization Library or Load in autoload config file $this->load->library('Authorization_Token'); // generate a token $data['token'] = $this->authorization_token->generateToken($payload); $today = date('Y-m-d H:i:s'); $data['expiration_date'] = to_sql_date($data['expiration_date'], true); $data['permission_enable'] = 1; // Set default quota values $data['request_limit'] = 1000; $data['time_window'] = 3600; $data['burst_limit'] = 100; $data['quota_active'] = 1; $data['quota_created_at'] = date('Y-m-d H:i:s'); $data['quota_updated_at'] = date('Y-m-d H:i:s'); $this->db->insert(db_prefix() . 'user_api', $data); $insert_id = $this->db->insert_id(); if ($insert_id) { log_activity('New User Added [ID: '.$insert_id.', Name: '.$data['name'].']'); } $this->set_permissions($insert_id, $permissions); return $insert_id; } public function update_user($data, $id) { $permissions = isset($data['permissions']) ? $data['permissions'] : []; unset($data['permissions']); $data['expiration_date'] = to_sql_date($data['expiration_date'], true); $data['permission_enable'] = 1; $result = false; $this->db->where('id', $id); $this->db->update(db_prefix() . 'user_api', $data); if ($this->db->affected_rows() > 0) { log_activity('Ticket User Updated [ID: '.$id.' Name: '.$data['name'].']'); $result = true; } $this->set_permissions($id, $permissions); return $result; } public function delete_user($id) { $this->remove_permissions($id); $this->db->where('id', $id); $this->db->delete(db_prefix().'user_api'); if ($this->db->affected_rows() > 0) { log_activity('User Deleted [ID: '.$id.']'); return true; } return false; } public function check_token($token) { $this->db->where('token', $token); $user = $this->db->get(db_prefix() . 'user_api')->row(); if (isset($user)) { return true; } return false; } public function check_token_permission($token, $feature = '', $capability = '') { $this->db->where('token', $token); $user = $this->db->get(db_prefix() . 'user_api')->row(); if (isset($user)) { if ($user->permission_enable) { $this->db->where('api_id', $user->id); $this->db->where('feature', $feature); $this->db->where('capability', $capability); $permission = $this->db->get(db_prefix() . 'user_api_permissions')->row(); if (isset($permission)) { return true; } } else { return true; } } return false; } public function user_api_exists() { if ($this->input->is_ajax_request()) { if ($this->input->post()) { $lead_id = $this->input->post('lead_id'); $abbreviated_name = strtoupper($this->input->post('abbreviated_name')); if ('' != $lead_id) { $this->db->where('id', $lead_id); $_current_email = $this->db->get('tblleads')->row(); if ($_current_email->abbreviated_name == $abbreviated_name) { echo json_encode(true); die(); } } $result_lead = true; $result_client = true; $client_id = $this->input->post('client_id'); $this->db->where('abbreviated_name', $abbreviated_name); if ('' != $client_id) { $arr_id = []; $arr_id[] = $client_id; $this->db->where_not_in('client_id', $arr_id); } $total_rows = $this->db->count_all_results('tblleads'); if ($total_rows > 0) { $result_lead = false; } else { $result_lead = true; } $this->db->where('abbreviated_name', $abbreviated_name); if ('' != $client_id) { $arr_id = []; $arr_id[] = $client_id; $this->db->where_not_in('userid', $arr_id); } $total_rows = $this->db->count_all_results('tblclients'); if ($total_rows > 0) { $result_client = false; } else { $result_client = true; } if ($result_lead && $result_client) { echo json_encode(true); } else { echo json_encode(false); } die(); } } } public function get_relation_data_api($type, $search = '') { \modules\api\core\Apiinit::the_da_vinci_code('api'); $q = ''; if ('' != $search) { $q = $search; $q = trim(urldecode($q)); } $data = []; if ('customer' == $type || 'customers' == $type) { $where_clients = 'tblclients.active=1'; if ($q) { $where_clients .= ' AND ('; $where_clients .= 'company LIKE "%'.$q.'%" OR CONCAT(firstname, " ", lastname) LIKE "%'.$q.'%" OR email LIKE "%'.$q.'%"'; $fields = get_custom_fields('customers'); foreach ($fields as $key => $value) { $this->db->join(db_prefix().'customfieldsvalues as ctable_'.$key.'', db_prefix().'clients.userid = ctable_'.$key.'.relid and ctable_'.$key.'.fieldto="customers" AND ctable_'.$key.'.fieldid='.$value['id'], 'LEFT'); $where_clients .= ' OR ctable_'.$key.'.value LIKE "%'.$q.'%"'; } $where_clients .= ')'; } $this->load->model('clients_model'); $data = $this->clients_model->get('', $where_clients); } elseif ('contacts' == $type) { $where_clients = 'tblclients.active=1'; if ($q) { $where_clients .= ' AND ('; $where_clients .= ' company LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR CONCAT(firstname, " ", lastname) LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR email LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\''; $fields = get_custom_fields('contacts'); foreach ($fields as $key => $value) { $this->db->join(db_prefix().'customfieldsvalues as ctable_'.$key.'', db_prefix().'contacts.id = ctable_'.$key.'.relid and ctable_'.$key.'.fieldto="contacts" AND ctable_'.$key.'.fieldid='.$value['id'], 'LEFT'); $where_clients .= ' OR ctable_'.$key.'.value LIKE "%'.$q.'%"'; } $where_clients .= ') AND '.db_prefix().'clients.active = 1'; } $this->db->select('contacts.id AS id,clients.*,contacts.*'); $this->db->join(db_prefix().'clients', ''.db_prefix().'contacts.userid = '.db_prefix().'clients.userid', 'left'); $this->load->model('clients_model'); $data = $this->clients_model->get_contacts('', $where_clients); // echo $this->db->last_query(); } elseif ('ticket' == $type) { $search = $this->_search_tickets($q, 0, true); $data = $search['result']; } elseif ('lead' == $type || 'leads' == $type) { $search = $this->_search_leads($q, 0, ['junk' => 0,], true); $data = $search['result']; } elseif ('invoice' == $type || 'invoices' == $type) { $search = $this->_search_invoices($q, 0, [], true); $data = $search['result']; } elseif ('invoice_items' == $type) { $this->load->model('invoice_items_model'); $fields = get_custom_fields('items'); $this->db->select('rate, items.id, description as name, long_description as subtext'); $this->db->like('description', $q); $this->db->or_like('long_description', $q); foreach ($fields as $key => $value) { $this->db->join(db_prefix().'customfieldsvalues as ctable_'.$key.'', db_prefix().'items.id = ctable_'.$key.'.relid and ctable_'.$key.'.fieldto="items_pr" AND ctable_'.$key.'.fieldid='.$value['id'], 'LEFT'); $this->db->or_like('ctable_'.$key.'.value', $q); } $items = $this->db->get(db_prefix().'items')->result_array(); foreach ($items as $key => $item) { $items[$key]['subtext'] = strip_tags(mb_substr($item['subtext'], 0, 200)).'...'; $items[$key]['name'] = '('.app_format_number($item['rate']).') '.$item['name']; } $data = $items; } elseif ('project' == $type) { $where_projects = ''; if ($this->input->post('customer_id')) { $where_projects .= '(clientid='.$this->input->post('customer_id').' or clientid in (select id from tblleads where client_id='.$this->input->post('customer_id').') )'; } if ($this->input->post('rel_type')) { $where_projects .= ' and rel_type="'.$this->input->post('rel_type').'" '; } $search = $this->_search_projects($q, 0, $where_projects, $this->input->post('rel_type'), true); $data = $search['result']; } elseif ('staff' == $type) { $search = $this->_search_staff($q, 0, true); $data = $search['result']; } elseif ('tasks' == $type) { $search = $this->_search_tasks($q, 0, true); $data = $search['result']; } elseif ('payments' == $type) { $search = $this->_search_payment($q, 0, true); $data = $search['result']; } elseif ('proposals' == $type) { $search = $this->_search_proposals($q, 0, true); $data = $search['result']; } elseif ('estimates' == $type) { $search = $this->_search_estimates($q, 0, true); $data = $search['result']; } elseif ('expenses' == $type) { $search = $this->_search_expenses($q, 0, true); $data = $search['result']; } elseif ('creditnotes' == $type) { $search = $this->_search_credit_notes($q, 0, true); $data = $search['result']; } elseif ('milestones' == $type) { $where_milestones = ''; if ($q) { $where_milestones .= '(name LIKE "%'.$q.'%" OR id LIKE "%'.$q.'%")'; } $data = $this->get_milestones_api('', $where_milestones); } return $data; } public function get_milestones_api($id = '', $where = []) { $this->db->select('*, (SELECT COUNT(id) FROM '.db_prefix().'tasks WHERE milestone='.db_prefix().'milestones.id) as total_tasks, (SELECT COUNT(id) FROM '.db_prefix().'tasks WHERE rel_type="project" and milestone='.db_prefix().'milestones.id AND status=5) as total_finished_tasks'); if ('' != $id) { $this->db->where('id', $id); } if ((is_array($where) && count($where) > 0) || (is_string($where) && '' != $where)) { $this->db->where($where); } $this->db->order_by('milestone_order', 'ASC'); $milestones = $this->db->get(db_prefix().'milestones')->result_array(); return $milestones; } public function get_expenses_api($id, $where=[]) { $this->db->select('*,'.db_prefix().'expenses.id as id,'.db_prefix().'expenses_categories.name as category_name,'.db_prefix().'payment_modes.name as payment_mode_name,'.db_prefix().'taxes.name as tax_name, '.db_prefix().'taxes.taxrate as taxrate,'.db_prefix().'taxes_2.name as tax_name2, '.db_prefix().'taxes_2.taxrate as taxrate2, '.db_prefix().'expenses.id as expenseid,'.db_prefix().'expenses.addedfrom as addedfrom, recurring_from'); $this->db->from(db_prefix().'expenses'); $this->db->join(db_prefix().'clients', ''.db_prefix().'clients.userid = '.db_prefix().'expenses.clientid', 'left'); $this->db->join(db_prefix().'payment_modes', ''.db_prefix().'payment_modes.id = '.db_prefix().'expenses.paymentmode', 'left'); $this->db->join(db_prefix().'taxes', ''.db_prefix().'taxes.id = '.db_prefix().'expenses.tax', 'left'); $this->db->join(''.db_prefix().'taxes as '.db_prefix().'taxes_2', ''.db_prefix().'taxes_2.id = '.db_prefix().'expenses.tax2', 'left'); $this->db->join(db_prefix().'expenses_categories', ''.db_prefix().'expenses_categories.id = '.db_prefix().'expenses.category'); $this->db->where($where); if (is_numeric($id)) { $this->db->where(db_prefix().'expenses.id', $id); $expense = $this->db->get()->row(); if ($expense) { $expense->attachment = ''; $expense->filetype = ''; $expense->attachment_added_from = 0; $this->db->where('rel_id', $id); $this->db->where('rel_type', 'expense'); $file = $this->db->get(db_prefix().'files')->row(); if ($file) { $expense->attachment = $file->file_name; $expense->filetype = $file->filetype; $expense->attachment_added_from = $file->staffid; } $this->load->model('projects_model'); $expense->currency_data = get_currency($expense->currency); if (0 != $expense->project_id) { $expense->project_data = $this->projects_model->get($expense->project_id); } if (null === $expense->payment_mode_name) { // is online payment mode $this->load->model('payment_modes_model'); $payment_gateways = $this->payment_modes_model->get_payment_gateways(true); foreach ($payment_gateways as $gateway) { if ($expense->paymentmode == $gateway['id']) { $expense->payment_mode_name = $gateway['name']; } } } } return $expense; } $this->db->order_by('date', 'desc'); return $this->db->get()->result_array(); } public function get_api_custom_data($data, $custom_field_type, $id = '', $is_invoice_item = false) { $this->db->where('active', 1); $this->db->where('fieldto', $custom_field_type); $this->db->order_by('field_order', 'asc'); $fields = $this->db->get(db_prefix() . 'customfields')->result_array(); $customfields = []; // Converting empty/null id to string for comparison if ($id === null) { $id = ''; } // Check if data is an array or object $is_data_object = is_object($data); $is_data_array = is_array($data); // Processing multiple records (when id is empty and data is an array of items) if ($id === '' && $is_data_array && !isset($data['id'])) { foreach ($data as $data_key => $value) { // Initialize customfields array if ($is_data_object) { if (!isset($data->customfields)) { $data->customfields = []; } } else { if (!isset($data[$data_key]['customfields'])) { $data[$data_key]['customfields'] = []; } } $value_id = isset($value['id']) ? $value['id'] : ''; if ('customers' == $custom_field_type) { $value_id = $value['userid']; } if ('tickets' == $custom_field_type) { $value_id = $value['ticketid']; } if ('staff' == $custom_field_type) { $value_id = $value['staffid']; } foreach ($fields as $key => $field) { $customfields[$key] = [ 'label' => $field['name'], 'value' => '' ]; if ('items' == $custom_field_type && !$is_invoice_item) { $custom_field_type_for_value = 'items_pr'; $value_id = isset($value['itemid']) ? $value['itemid'] : $value['id']; } else { $custom_field_type_for_value = $custom_field_type; } $customfields[$key]['value'] = get_custom_field_value($value_id, $field['id'], $custom_field_type_for_value, false); } $data[$data_key]['customfields'] = $customfields; } } // Processing single record (when id is provided or data is a single item) else { // If no id was provided but data contains an id, use that if ($id === '' && ( ($is_data_array && isset($data['id'])) || ($is_data_object && isset($data->id)) )) { $id = $is_data_array ? $data['id'] : $data->id; } // Only process if we have an ID if ($id !== '') { foreach ($fields as $key => $field) { $customfields[$key] = [ 'label' => $field['name'], 'value' => '' ]; if ('items' == $custom_field_type && !$is_invoice_item) { $custom_field_type_for_value = 'items_pr'; } else { $custom_field_type_for_value = $custom_field_type; } $customfields[$key]['value'] = get_custom_field_value($id, $field['id'], $custom_field_type_for_value, false); } // Assign customfields to data based on its type if ($is_data_object) { $data->customfields = $customfields; } else { $data['customfields'] = $customfields; } } } return $data; } public function _search_payment($q, $limit = 0, $api = false) { $result = [ 'result' => [], 'type' => 'payments', 'search_heading' => _l('payments'), ]; if (has_permission('payments', '', 'view') || true == $api) { $this->db->select(db_prefix().'invoicepaymentrecords.*'); $this->db->from(db_prefix().'invoicepaymentrecords'); $this->db->join(db_prefix().'payment_modes', db_prefix().'payment_modes.id='.db_prefix().'invoicepaymentrecords.paymentmode', 'LEFT'); $this->db->like('name', $q); $this->db->or_like(db_prefix().'invoicepaymentrecords.paymentmode', $q); $this->db->or_like(db_prefix().'invoicepaymentrecords.amount', $q); if (0 != $limit) { $this->db->limit($limit); } $this->db->order_by('name', 'ASC'); $result['result'] = $this->db->get()->result_array(); } return $result; } public function payment_get($id='') { $this->db->select('*,'.db_prefix().'invoicepaymentrecords.id as paymentid'); $this->db->join(db_prefix().'payment_modes', db_prefix().'payment_modes.id = '.db_prefix().'invoicepaymentrecords.paymentmode', 'left'); $this->db->order_by(db_prefix().'invoicepaymentrecords.id', 'asc'); if (!empty($id)) { $this->db->where(db_prefix().'invoicepaymentrecords.id', $id); $payment = $this->db->get(db_prefix().'invoicepaymentrecords')->row(); } else { $payment = $this->db->get(db_prefix().'invoicepaymentrecords')->result(); } if (!$payment) { return false; } $this->load->model('payment_modes_model'); $payment_gateways = $this->payment_modes_model->get_payment_gateways(true); if (!empty($id)) { if (null === $payment->id) { foreach ($payment_gateways as $gateway) { if ($payment->paymentmode == $gateway['id']) { $payment->name = $gateway['name']; } } } } if (empty($id)) { foreach ($payment as $key => $pay) { if (null === $pay->id) { foreach ($payment_gateways as $gateway) { if ($pay->paymentmode == $gateway['id']) { $payment[$key]->name = $gateway['name']; } } } } } return $payment; } public function _search_proposals($q, $limit = 0, $api = false) { $fields = get_custom_fields('proposal'); $result = [ 'result' => [], 'type' => 'proposals', 'search_heading' => _l('proposals'), ]; $has_permission_view_proposals = has_permission('proposals', '', 'view'); $has_permission_view_proposals_own = has_permission('proposals', '', 'view_own'); if ($has_permission_view_proposals || $has_permission_view_proposals_own || '1' == get_option('allow_staff_view_proposals_assigned') || true == $api) { if (is_numeric($q)) { $q = trim($q); $q = ltrim($q, '0'); } elseif (startsWith($q, get_option('proposal_number_prefix'))) { $q = strafter($q, get_option('proposal_number_prefix')); $q = trim($q); $q = ltrim($q, '0'); } $where_string = ''; foreach ($fields as $key => $value) { $this->db->join(db_prefix().'customfieldsvalues as ctable_'.$key.'', db_prefix().'proposals.id = ctable_'.$key.'.relid and ctable_'.$key.'.fieldto="proposal" AND ctable_'.$key.'.fieldid='.$value['id'], 'LEFT'); $where_string .= ' OR ctable_'.$key.'.value LIKE "%'.$q.'%"'; } // Proposals $this->db->select('*,'.db_prefix().'proposals.id as id'); $this->db->from(db_prefix().'proposals'); $this->db->join(db_prefix().'currencies', db_prefix().'currencies.id = '.db_prefix().'proposals.currency'); $this->db->where('('.db_prefix().'proposals.id LIKE "'.$q.'%" OR '.db_prefix().'proposals.subject LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'proposals.content LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'proposals.proposal_to LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'proposals.zip LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'proposals.state LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'proposals.city LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'proposals.address LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'proposals.email LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'proposals.phone LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' '.$where_string.' )'); $this->db->order_by(db_prefix().'proposals.id', 'desc'); if (0 != $limit) { $this->db->limit($limit); } $result['result'] = $this->db->get()->result_array(); } return $result; } public function _search_estimates($q, $limit = 0, $api = false) { $fields = get_custom_fields('estimate'); $result = [ 'result' => [], 'type' => 'estimates', 'search_heading' => _l('estimates'), ]; $has_permission_view_estimates = has_permission('estimates', '', 'view'); $has_permission_view_estimates_own = has_permission('estimates', '', 'view_own'); if ($has_permission_view_estimates || $has_permission_view_estimates_own || '1' == get_option('allow_staff_view_estimates_assigned') || $api = true) { if (is_numeric($q)) { $q = trim($q); $q = ltrim($q, '0'); } elseif (startsWith($q, get_option('estimate_prefix'))) { $q = strafter($q, get_option('estimate_prefix')); $q = trim($q); $q = ltrim($q, '0'); } $where_string = ''; foreach ($fields as $key => $value) { $this->db->join(db_prefix().'customfieldsvalues as ctable_'.$key.'', db_prefix().'estimates.id = ctable_'.$key.'.relid and ctable_'.$key.'.fieldto="estimate" AND ctable_'.$key.'.fieldid='.$value['id'], 'LEFT'); $where_string .= ' OR ctable_'.$key.'.value LIKE "%'.$q.'%"'; } // Estimates $estimates_fields = prefixed_table_fields_array(db_prefix().'estimates'); $clients_fields = prefixed_table_fields_array(db_prefix().'clients'); $this->db->select(implode(',', $estimates_fields).','.implode(',', $clients_fields).','.db_prefix().'estimates.id as estimateid,'.get_sql_select_client_company()); $this->db->from(db_prefix().'estimates'); $this->db->join(db_prefix().'clients', db_prefix().'clients.userid = '.db_prefix().'estimates.clientid', 'left'); $this->db->join(db_prefix().'currencies', db_prefix().'currencies.id = '.db_prefix().'estimates.currency'); $this->db->join(db_prefix().'contacts', db_prefix().'contacts.userid = '.db_prefix().'clients.userid AND is_primary = 1', 'left'); $this->db->where('('.db_prefix().'estimates.number LIKE "'.$this->db->escape_like_str($q).'" OR '.db_prefix().'clients.company LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'estimates.clientnote LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.vat LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.phonenumber LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.city LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.state LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.zip LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR address LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'estimates.adminnote LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'estimates.billing_street LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'estimates.billing_city LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'estimates.billing_state LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'estimates.billing_zip LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'estimates.shipping_street LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'estimates.shipping_city LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'estimates.shipping_state LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'estimates.shipping_zip LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.billing_street LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.billing_city LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.billing_state LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.billing_zip LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.shipping_street LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.shipping_city LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.shipping_state LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.shipping_zip LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' '.$where_string.' )'); $this->db->order_by('number,YEAR(date)', 'desc'); if (0 != $limit) { $this->db->limit($limit); } $result['result'] = $this->db->get()->result_array(); } return $result; } public function _search_expenses($q, $limit = 0, $api=false) { $fields = get_custom_fields('expenses'); $result = [ 'result' => [], 'type' => 'expenses', 'search_heading' => _l('expenses'), ]; $has_permission_expenses_view = has_permission('expenses', '', 'view'); $has_permission_expenses_view_own = has_permission('expenses', '', 'view_own'); if ($has_permission_expenses_view || $has_permission_expenses_view_own || true == $api) { // Expenses $where_string = ''; foreach ($fields as $key => $value) { $this->db->join(db_prefix().'customfieldsvalues as ctable_'.$key.'', db_prefix().'expenses.id = ctable_'.$key.'.relid and ctable_'.$key.'.fieldto="expenses" AND ctable_'.$key.'.fieldid='.$value['id'], 'LEFT'); $where_string .= ' OR ctable_'.$key.'.value LIKE "%'.$q.'%"'; } $this->db->select('*,'.db_prefix().'expenses.amount as amount,'.db_prefix().'expenses_categories.name as category_name,'.db_prefix().'payment_modes.name as payment_mode_name,'.db_prefix().'taxes.name as tax_name, '.db_prefix().'expenses.id as expenseid,'.db_prefix().'currencies.name as currency_name'); $this->db->from(db_prefix().'expenses'); $this->db->join(db_prefix().'clients', db_prefix().'clients.userid = '.db_prefix().'expenses.clientid', 'left'); $this->db->join(db_prefix().'payment_modes', db_prefix().'payment_modes.id = '.db_prefix().'expenses.paymentmode', 'left'); $this->db->join(db_prefix().'taxes', db_prefix().'taxes.id = '.db_prefix().'expenses.tax', 'left'); $this->db->join(db_prefix().'expenses_categories', db_prefix().'expenses_categories.id = '.db_prefix().'expenses.category'); $this->db->join(db_prefix().'currencies', ''.db_prefix().'currencies.id = '.db_prefix().'expenses.currency', 'left'); $this->db->where('(company LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR paymentmode LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'payment_modes.name LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR vat LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR phonenumber LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR city LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR zip LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR address LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR state LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'expenses_categories.name LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'expenses.note LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'expenses.expense_name LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' '.$where_string.' )'); if (0 != $limit) { $this->db->limit($limit); } $this->db->order_by('date', 'DESC'); $result['result'] = $this->db->get()->result_array(); } return $result; } public function _search_credit_notes($q, $limit = 0, $api=false) { $fields = get_custom_fields('credit_note'); $result = [ 'result' => [], 'type' => 'credit_note', 'search_heading' => _l('credit_notes'), ]; $has_permission_view_credit_notes = has_permission('credit_notes', '', 'view'); $has_permission_view_credit_notes_own = has_permission('credit_notes', '', 'view_own'); if ($has_permission_view_credit_notes || $has_permission_view_credit_notes_own || true == $api) { if (is_numeric($q)) { $q = trim($q); $q = ltrim($q, '0'); } elseif (startsWith($q, get_option('credit_note_prefix'))) { $q = strafter($q, get_option('credit_note_prefix')); $q = trim($q); $q = ltrim($q, '0'); } $where_string = ''; foreach ($fields as $key => $value) { $this->db->join(db_prefix().'customfieldsvalues as ctable_'.$key.'', db_prefix().'creditnotes.id = ctable_'.$key.'.relid and ctable_'.$key.'.fieldto="credit_note" AND ctable_'.$key.'.fieldid='.$value['id'], 'LEFT'); $where_string .= ' OR ctable_'.$key.'.value LIKE "%'.$q.'%"'; } $credit_note_fields = prefixed_table_fields_array(db_prefix().'creditnotes'); $clients_fields = prefixed_table_fields_array(db_prefix().'clients'); // Invoices $this->db->select(implode(',', $credit_note_fields).','.implode(',', $clients_fields).','.db_prefix().'creditnotes.id as credit_note_id,'.get_sql_select_client_company()); $this->db->from(db_prefix().'creditnotes'); $this->db->join(db_prefix().'clients', db_prefix().'clients.userid = '.db_prefix().'creditnotes.clientid', 'left'); $this->db->join(db_prefix().'currencies', db_prefix().'currencies.id = '.db_prefix().'creditnotes.currency'); $this->db->join(db_prefix().'contacts', db_prefix().'contacts.userid = '.db_prefix().'clients.userid AND is_primary = 1', 'left'); $this->db->where('( '.db_prefix().'creditnotes.number LIKE "'.$this->db->escape_like_str($q).'" OR '.db_prefix().'clients.company LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'creditnotes.clientnote LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.vat LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.phonenumber LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.city LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.state LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.zip LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.address LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'creditnotes.adminnote LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR CONCAT(firstname,\' \',lastname) LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR CONCAT(lastname,\' \',firstname) LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'creditnotes.billing_street LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'creditnotes.billing_city LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'creditnotes.billing_state LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'creditnotes.billing_zip LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'creditnotes.shipping_street LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'creditnotes.shipping_city LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'creditnotes.shipping_state LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'creditnotes.shipping_zip LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.billing_street LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.billing_city LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.billing_state LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.billing_zip LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.shipping_street LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.shipping_city LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.shipping_state LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' OR '.db_prefix().'clients.shipping_zip LIKE "%'.$this->db->escape_like_str($q).'%" ESCAPE \'!\' '.$where_string.' )'); $this->db->order_by('number', 'desc'); if (0 != $limit) { $this->db->limit($limit); } $result['result'] = $this->db->get()->result_array(); } return $result; } private function total_refunds_by_credit_note($id) { return sum_from_table(db_prefix().'creditnote_refunds', [ 'field' => 'amount', 'where' => ['credit_note_id' => $id], ]); } private function total_credits_used_by_credit_note($id) { return sum_from_table(db_prefix().'credits', [ 'field' => 'amount', 'where' => ['credit_id' => $id], ]); } public function get_permissions($id = '', $feature = '', $capability = '') { $this->db->select('*'); if ('' != $id) { $this->db->where('api_id', $id); if ('' != $feature) { $this->db->where('feature', $feature); } if ('' != $capability) { $this->db->where('capability', $capability); } return $this->db->get(db_prefix() . 'user_api_permissions')->result_array(); } return []; } public function set_permissions($id, $permissions) { if ('' != $id) { if ($permissions) { foreach ($permissions as $feauture => $capabilities) { foreach ($capabilities as $capability) { if (!$this->get_permissions($id, $feauture, $capability)) { $this->add_permissions($id, $feauture, $capability); } } $feature_permissions = $this->get_permissions($id, $feauture); foreach ($feature_permissions as $feature_permission) { if (!in_array($feature_permission['capability'], array_values($capabilities))) { $this->remove_permissions($id, $feauture, $feature_permission['capability']); } } } } $api_permissions = $this->get_permissions($id); foreach ($api_permissions as $permission) { $permission_exist = true; if (isset($permissions[$permission['feature']])) { $permission_exist = false; foreach ($permissions[$permission['feature']] as $capability) { if ($capability == $permission['capability']) { $permission_exist = true; } } } else { $permission_exist = false; } if (!$permission_exist) { $this->remove_permissions($id, $permission['feature'], $permission['capability']); } } } } public function add_permissions($id = '', $feature = '', $capability = '') { $permissions = []; if ('' != $id) { if ('' != $feature) { $api_permissions = get_available_api_permissions(); foreach ($api_permissions as $api_feature => $api_permission) { if ($api_feature == $feature) { foreach ($api_permission['capabilities'] as $api_capability => $name) { if ('' != $capability) { if ($api_capability == $capability) { $permissions[] = [ 'api_id' => $id, 'feature' => $feature, 'capability' => $api_capability, ]; } } else { $permissions[] = [ 'api_id' => $id, 'feature' => $feature, 'capability' => $api_capability, ]; } } } } } } foreach ($permissions as $permission) { $this->db->insert(db_prefix() . 'user_api_permissions', $permission); if ($this->db->affected_rows() > 0) { log_activity('New API Permssion Added [API ID: ' . $permission['api_id'] . ', Feature: ' . $permission['feature'] . ', Capability: ' . $permission['capability'] . ']'); } } } public function remove_permissions($id = '', $feature = '', $capability = '') { if ('' != $id) { $this->db->where('api_id', $id); if ('' != $feature) { $this->db->where('feature', $feature); } if ('' != $capability) { $this->db->where('capability', $capability); } $this->db->delete(db_prefix() . 'user_api_permissions'); if ($this->db->affected_rows() > 0) { log_activity('API Permssion Deleted [API ID: ' . $id . ', Feature: ' . $feature . ', Capability: ' . $capability . ']'); return true; } } return false; } public function get_calendar_events($id ='') { $this->db->select('*'); $this->db->from(db_prefix().'events'); if($id >0){ $this->db->where('eventid', $id); } return $this->db->get()->result_array(); } /** * Add new event * @param array $data event $_POST data */ public function event($data) { $data['start'] = to_sql_date($data['start'], true); if ($data['end'] == '') { unset($data['end']); } else { $data['end'] = to_sql_date($data['end'], true); } $data['description'] = nl2br($data['description']); if (isset($data['eventid'])) { $this->db->where('eventid', $data['eventid']); $event = $this->db->get(db_prefix() . 'events')->row(); if (!$event) { return false; } if ($event->isstartnotified == 1) { if ($data['start'] > $event->start) { $data['isstartnotified'] = 0; } } $data = hooks()->apply_filters('event_update_data', $data, $data['eventid']); $this->db->where('eventid', $data['eventid']); $this->db->update(db_prefix() . 'events', $data); if ($this->db->affected_rows() > 0) { return true; } return false; } $data = hooks()->apply_filters('event_create_data', $data); $this->db->insert(db_prefix() . 'events', $data); $insert_id = $this->db->insert_id(); if ($insert_id) { return true; } return false; } // get subscription table data public function get_subscription_events($id ='') { $this->db->select('*'); $this->db->from(db_prefix().'subscriptions'); if($id >0){ $this->db->where('id', $id); } return $this->db->get()->result_array(); } // insert subscription data public function subscription($data){ $data = [ 'name' => $this->input->post('name'), 'description' => $this->input->post('description'), 'description_in_item' => $this->input->post('description_in_item'), 'clientid ' => $this->input->post('clientid'), 'date' => $this->input->post('date'), 'terms' => $this->input->post('terms'), 'currency' => $this->input->post('currency'), 'tax_id' => $this->input->post('tax_id'), 'stripe_tax_id' => $this->input->post('stripe_tax_id'), 'tax_id_2' => $this->input->post('tax_id_2'), 'stripe_tax_id_2' => $this->input->post('stripe_tax_id_2'), 'stripe_plan_id' => $this->input->post('stripe_plan_id'), 'next_billing_cycle' => $this->input->post('next_billing_cycle'), 'ends_at' => $this->input->post('ends_at'), 'status' => $this->input->post('status'), 'quantity' => $this->input->post('quantity'), 'project_id' => $this->input->post('project_id'), 'hash' => $this->input->post('hash'), 'created' => $this->input->post('created'), 'created_from' => $this->input->post('created_from'), 'date_subscribed' => $this->input->post('date_subscribed'), 'in_test_environment' => $this->input->post('in_test_environment'), 'last_sent_at' => $this->input->post('last_sent_at'), ]; $this->db->insert(db_prefix() . 'subscriptions', $data); $insert_id = $this->db->insert_id(); if ($insert_id) { return true; } return false; } // update subscriptions data public function subscriptions($data) { if (isset($data['id'])){ $this->db->where('id', $data['id']); $event = $this->db->get(db_prefix() . 'subscriptions')->row(); if (!$event){ return false; } $data = hooks()->apply_filters('event_update_data', $data, $data['id']); $this->db->where('id', $data['id']); $this->db->update(db_prefix() . 'subscriptions', $data); if ($this->db->affected_rows() > 0){ return true; } return false; } } /** * Delete Subscriptions Data * @param mixed $id id * @return boolean */ public function delete_subscription($id) { $this->db->where('id', $id); $this->db->delete(db_prefix() . 'subscriptions'); if ($this->db->affected_rows() > 0) { log_activity('subscription Deleted [' . $id . ']'); return true; } return false; } // get timesheets data public function get_timesheets_events($id ='') { $this->db->select('*'); $this->db->from(db_prefix().'taskstimers'); if($id >0){ $this->db->where('id', $id); } return $this->db->get()->result_array(); } // insert Timesheets data public function timesheets($data){ $data = [ 'task_id' => $this->input->post('task_id'), 'start_time' => $this->input->post('start_time'), 'end_time' => $this->input->post('end_time'), 'staff_id' => $this->input->post('staff_id'), 'hourly_rate' => $this->input->post('hourly_rate'), 'note' => $this->input->post('note') ]; $this->db->insert(db_prefix() . 'taskstimers', $data); $insert_id = $this->db->insert_id(); if ($insert_id) { return true; } return false; } // update timesheets data public function timesheetUpdate($data) { if (isset($data['id'])){ $this->db->where('id', $data['id']); $event = $this->db->get(db_prefix() . 'taskstimers')->row(); if (!$event){ return false; } $data = hooks()->apply_filters('event_update_data', $data, $data['id']); $this->db->where('id', $data['id']); $this->db->update(db_prefix() . 'taskstimers', $data); if ($this->db->affected_rows() > 0){ return true; } return false; } } /** * Delete Timesheets data * @param mixed $id id * @return boolean */ public function timesheetDelete($id) { $this->db->where('id', $id); $this->db->delete(db_prefix() . 'taskstimers'); if ($this->db->affected_rows() > 0) { log_activity('Event Deleted [' . $id . ']'); return true; } return false; } public function get_all_api_keys() { $this->db->select('token as api_key'); $this->db->from(db_prefix() . 'user_api'); $this->db->where('quota_active', 1); return $this->db->get()->result_array(); } // ==================== QUOTA MANAGEMENT METHODS ==================== /** * Check if API key has exceeded quota * * @param string $api_key * @param string $endpoint * @return bool */ public function check_quota($api_key, $endpoint = '') { $quota_settings = $this->get_quota_settings($api_key); if (!$quota_settings) { return true; // No quota restrictions } $current_usage = $this->get_current_usage($api_key, $endpoint, $quota_settings['time_window']); return $current_usage < $quota_settings['request_limit']; } /** * Get quota settings for API key * * @param string $api_key * @return array|null */ public function get_quota_settings($api_key) { $this->db->select('*'); $this->db->from(db_prefix() . 'user_api'); $this->db->where('token', $api_key); $this->db->where('quota_active', 1); $result = $this->db->get()->row_array(); if (!$result) { // Return default quota settings return [ 'request_limit' => 1000, 'time_window' => 3600, 'burst_limit' => 100, 'quota_active' => 1 ]; } return $result; } /** * Get current usage for API key * * @param string $api_key * @param string $endpoint * @param int $time_window * @return int */ public function get_current_usage($api_key, $endpoint = '', $time_window = 3600) { if ($time_window) { $time_start = time() - $time_window; } $this->db->select('COUNT(*) as usage_count'); $this->db->from(db_prefix() . 'api_usage_logs'); $this->db->where('api_key', $api_key); if ($time_window) { $this->db->where('timestamp >=', $time_start); } if (!empty($endpoint)) { $this->db->where('endpoint', $endpoint); } $result = $this->db->get()->row(); return $result ? $result->usage_count : 0; } /** * Log API usage * * @param string $api_key * @param string $endpoint * @param int $response_code * @param float $response_time * @return bool */ public function log_usage($api_key, $endpoint, $response_code, $response_time = 0) { // Get user_api_id from api_key $user_api = $this->get_user_api_by_token($api_key); if (!$user_api) { return false; } $data = [ 'user_api_id' => $user_api['id'], 'api_key' => $api_key, 'endpoint' => $endpoint, 'response_code' => $response_code, 'response_time' => $response_time, 'timestamp' => time(), 'ip_address' => $this->input->ip_address(), 'user_agent' => $this->input->user_agent() ]; return $this->db->insert(db_prefix() . 'api_usage_logs', $data); } /** * Update quota settings for API key * * @param array $data * @return bool */ public function update_quota($data) { // Get user_api record by token $user_api = $this->get_user_api_by_token($data['api_key']); if (!$user_api) { return false; } $quota_data = [ 'request_limit' => $data['request_limit'], 'time_window' => $data['time_window'], 'burst_limit' => $data['burst_limit'] ?? 0, 'quota_active' => $data['quota_active'] ?? 1, 'quota_updated_at' => date('Y-m-d H:i:s') ]; $this->db->where('id', $user_api['id']); return $this->db->update(db_prefix() . 'user_api', $quota_data); } /** * Get quota by user ID * * @param int $id * @return array|null */ public function get_quota_by_id($id) { $this->db->select('*'); $this->db->from(db_prefix() . 'user_api'); $this->db->where('id', $id); return $this->db->get()->row_array(); } /** * Get all quota settings * * @return array */ public function get_all_quotas() { $this->db->select('*'); $this->db->from(db_prefix() . 'user_api'); $this->db->where('quota_active', 1); $this->db->order_by('quota_created_at', 'DESC'); return $this->db->get()->result_array(); } /** * Get quota statistics * * @param string $api_key * @param int $days * @return array */ public function get_quota_stats($api_key, $days = 30) { $time_start = time() - ($days * 24 * 60 * 60); $this->db->select(' DATE(FROM_UNIXTIME(timestamp)) as date, COUNT(*) as request_count, AVG(response_time) as avg_response_time, SUM(CASE WHEN response_code >= 400 THEN 1 ELSE 0 END) as error_count '); $this->db->from(db_prefix() . 'api_usage_logs'); $this->db->where('api_key', $api_key); $this->db->where('timestamp >=', $time_start); $this->db->group_by('DATE(FROM_UNIXTIME(timestamp))'); $this->db->order_by('date', 'ASC'); return $this->db->get()->result_array(); } /** * Get top endpoints by usage * * @param string $api_key * @param int $limit * @return array */ public function get_top_endpoints($api_key, $limit = 10) { $this->db->select(' endpoint, COUNT(*) as request_count, SUM(CASE WHEN response_code >= 200 AND response_code < 400 THEN 1 ELSE 0 END) as success_count, SUM(CASE WHEN response_code >= 400 THEN 1 ELSE 0 END) as error_count, AVG(response_time) as avg_response_time '); $this->db->from(db_prefix() . 'api_usage_logs'); $this->db->where('api_key', $api_key); $this->db->group_by('endpoint'); $this->db->order_by('request_count', 'DESC'); $this->db->limit($limit); $results = $this->db->get()->result_array(); // Round avg_response_time for each endpoint foreach ($results as &$result) { $result['avg_response_time'] = round($result['avg_response_time'] ?: 0, 2); } return $results; } /** * Get quota usage summary * * @param string $api_key * @return array */ public function get_quota_summary($api_key) { $quota_settings = $this->get_quota_settings($api_key); if (!$quota_settings) { return null; } $current_usage = $this->get_current_usage($api_key, '', $quota_settings['time_window']); // Get total requests, success and error counts $this->db->select(' COUNT(*) as total_requests, SUM(CASE WHEN response_code >= 200 AND response_code < 400 THEN 1 ELSE 0 END) as success_requests, SUM(CASE WHEN response_code >= 400 THEN 1 ELSE 0 END) as error_requests, AVG(response_time) as avg_response_time '); $this->db->from(db_prefix() . 'api_usage_logs'); $this->db->where('api_key', $api_key); if ($quota_settings['time_window']) { $time_start = time() - $quota_settings['time_window']; $this->db->where('timestamp >=', $time_start); } $stats = $this->db->get()->row_array(); return [ 'total_requests' => $stats['total_requests'] ?: 0, 'success_requests' => $stats['success_requests'] ?: 0, 'error_requests' => $stats['error_requests'] ?: 0, 'avg_response_time' => round($stats['avg_response_time'] ?: 0, 2), 'quota_settings' => $quota_settings, 'current_usage' => $current_usage, 'remaining_requests' => max(0, $quota_settings['request_limit'] - $current_usage), 'usage_percentage' => ($current_usage / $quota_settings['request_limit']) * 100, 'reset_time' => time() + $quota_settings['time_window'] ]; } /** * Check burst limit * * @param string $api_key * @return bool */ public function check_burst_limit($api_key) { $quota_settings = $this->get_quota_settings($api_key); if (!$quota_settings || $quota_settings['burst_limit'] <= 0) { return true; } $burst_window = 60; // 1 minute burst window $current_burst = $this->get_current_usage($api_key, '', $burst_window); return $current_burst < $quota_settings['burst_limit']; } /** * Clean old usage logs * * @param int $days * @return bool */ public function clean_old_logs($days = 90) { $time_cutoff = time() - ($days * 24 * 60 * 60); $this->db->where('timestamp <', $time_cutoff); return $this->db->delete(db_prefix() . 'api_usage_logs'); } /** * Get user_api record by token * * @param string $token * @return array|null */ private function get_user_api_by_token($token) { $this->db->select('*'); $this->db->from(db_prefix() . 'user_api'); $this->db->where('token', $token); return $this->db->get()->row_array(); } }