chore: initial commit
This commit is contained in:
210
api/models/Api_metrics_model.php
Normal file
210
api/models/Api_metrics_model.php
Normal file
@@ -0,0 +1,210 @@
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Api_metrics_model extends App_Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get API usage statistics
|
||||
*/
|
||||
public function get_usage_stats($api_key = null, $start_date = null, $end_date = null)
|
||||
{
|
||||
$this->db->select('
|
||||
COUNT(*) as total_requests,
|
||||
AVG(response_time) as avg_response_time,
|
||||
MAX(response_time) as max_response_time,
|
||||
MIN(response_time) as min_response_time,
|
||||
COUNT(CASE WHEN response_code >= 200 AND response_code < 300 THEN 1 END) as success_requests,
|
||||
COUNT(CASE WHEN response_code >= 400 THEN 1 END) as error_requests,
|
||||
COUNT(CASE WHEN response_code >= 500 THEN 1 END) as server_errors
|
||||
');
|
||||
|
||||
$this->db->from(db_prefix() . 'api_usage_logs');
|
||||
|
||||
if ($api_key) {
|
||||
$this->db->where('api_key', $api_key);
|
||||
}
|
||||
|
||||
if ($start_date) {
|
||||
$this->db->where('timestamp >=', strtotime(date('Y-m-d 00:00:00', strtotime($start_date))));
|
||||
}
|
||||
|
||||
if ($end_date) {
|
||||
$this->db->where('timestamp <=', strtotime(date('Y-m-d 23:59:59', strtotime($end_date))));
|
||||
}
|
||||
|
||||
return $this->db->get()->row();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get endpoint usage statistics
|
||||
*/
|
||||
public function get_endpoint_stats($api_key = null, $start_date = null, $end_date = null, $limit = 10)
|
||||
{
|
||||
$this->db->select('
|
||||
endpoint,
|
||||
COUNT(*) as request_count,
|
||||
AVG(response_time) as avg_response_time,
|
||||
COUNT(CASE WHEN response_code >= 200 AND response_code < 300 THEN 1 END) as success_count,
|
||||
COUNT(CASE WHEN response_code >= 400 THEN 1 END) as error_count
|
||||
');
|
||||
|
||||
$this->db->from(db_prefix() . 'api_usage_logs');
|
||||
|
||||
if ($api_key) {
|
||||
$this->db->where('api_key', $api_key);
|
||||
}
|
||||
|
||||
if ($start_date) {
|
||||
$this->db->where('timestamp >=', strtotime(date('Y-m-d 00:00:00', strtotime($start_date))));
|
||||
}
|
||||
|
||||
if ($end_date) {
|
||||
$this->db->where('timestamp <=', strtotime(date('Y-m-d 23:59:59', strtotime($end_date))));
|
||||
}
|
||||
|
||||
$this->db->group_by('endpoint');
|
||||
$this->db->order_by('request_count', 'DESC');
|
||||
$this->db->limit($limit);
|
||||
|
||||
return $this->db->get()->result();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get hourly usage data for charts
|
||||
*/
|
||||
public function get_hourly_usage($api_key = null, $start_date = null, $end_date = null)
|
||||
{
|
||||
$this->db->select('
|
||||
FROM_UNIXTIME(timestamp, "%Y-%m-%d %H:00:00") as hour,
|
||||
COUNT(*) as request_count,
|
||||
AVG(response_time) as avg_response_time
|
||||
');
|
||||
|
||||
$this->db->from(db_prefix() . 'api_usage_logs');
|
||||
|
||||
if ($api_key) {
|
||||
$this->db->where('api_key', $api_key);
|
||||
}
|
||||
|
||||
if ($start_date) {
|
||||
$this->db->where('timestamp >=', strtotime(date('Y-m-d 00:00:00', strtotime($start_date))));
|
||||
}
|
||||
|
||||
if ($end_date) {
|
||||
$this->db->where('timestamp <=', strtotime(date('Y-m-d 23:59:59', strtotime($end_date))));
|
||||
}
|
||||
|
||||
$this->db->group_by('hour');
|
||||
$this->db->order_by('hour', 'ASC');
|
||||
|
||||
return $this->db->get()->result();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get daily usage data for charts
|
||||
*/
|
||||
public function get_daily_usage($api_key = null, $start_date = null, $end_date = null)
|
||||
{
|
||||
$this->db->select('
|
||||
FROM_UNIXTIME(timestamp, "%Y-%m-%d") as day,
|
||||
COUNT(*) as request_count,
|
||||
AVG(response_time) as avg_response_time
|
||||
');
|
||||
|
||||
$this->db->from(db_prefix() . 'api_usage_logs');
|
||||
|
||||
if ($api_key) {
|
||||
$this->db->where('api_key', $api_key);
|
||||
}
|
||||
|
||||
if ($start_date) {
|
||||
$this->db->where('timestamp >=', strtotime(date('Y-m-d 00:00:00', strtotime($start_date))));
|
||||
}
|
||||
|
||||
if ($end_date) {
|
||||
$this->db->where('timestamp <=', strtotime(date('Y-m-d 23:59:59', strtotime($end_date))));
|
||||
}
|
||||
|
||||
$this->db->group_by('day');
|
||||
$this->db->order_by('day', 'ASC');
|
||||
|
||||
return $this->db->get()->result();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get response code distribution
|
||||
*/
|
||||
public function get_response_code_distribution($api_key = null, $start_date = null, $end_date = null)
|
||||
{
|
||||
$this->db->select('
|
||||
response_code,
|
||||
COUNT(*) as count
|
||||
');
|
||||
|
||||
$this->db->from(db_prefix() . 'api_usage_logs');
|
||||
|
||||
if ($api_key) {
|
||||
$this->db->where('api_key', $api_key);
|
||||
}
|
||||
|
||||
if ($start_date) {
|
||||
$this->db->where('timestamp >=', strtotime(date('Y-m-d 00:00:00', strtotime($start_date))));
|
||||
}
|
||||
|
||||
if ($end_date) {
|
||||
$this->db->where('timestamp <=', strtotime(date('Y-m-d 23:59:59', strtotime($end_date))));
|
||||
}
|
||||
|
||||
$this->db->group_by('response_code');
|
||||
$this->db->order_by('count', 'DESC');
|
||||
|
||||
return $this->db->get()->result();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get API key usage summary
|
||||
*/
|
||||
public function get_api_key_summary($start_date = null, $end_date = null)
|
||||
{
|
||||
$this->db->select('
|
||||
api_key,
|
||||
COUNT(*) as total_requests,
|
||||
AVG(response_time) as avg_response_time,
|
||||
COUNT(CASE WHEN response_code >= 200 AND response_code < 300 THEN 1 END) as success_requests,
|
||||
COUNT(CASE WHEN response_code >= 400 THEN 1 END) as error_requests
|
||||
');
|
||||
|
||||
$this->db->from(db_prefix() . 'api_usage_logs');
|
||||
|
||||
if ($start_date) {
|
||||
$this->db->where('timestamp >=', strtotime(date('Y-m-d 00:00:00', strtotime($start_date))));
|
||||
}
|
||||
|
||||
if ($end_date) {
|
||||
$this->db->where('timestamp <=', strtotime(date('Y-m-d 23:59:59', strtotime($end_date))));
|
||||
}
|
||||
|
||||
$this->db->group_by('api_key');
|
||||
$this->db->order_by('total_requests', 'DESC');
|
||||
|
||||
return $this->db->get()->result();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean old logs (older than specified days)
|
||||
*/
|
||||
public function clean_old_logs($days = 30)
|
||||
{
|
||||
$cutoff_timestamp = time() - ($days * 24 * 60 * 60);
|
||||
$this->db->where('timestamp <', $cutoff_timestamp);
|
||||
$this->db->delete(db_prefix() . 'api_usage_logs');
|
||||
|
||||
return $this->db->affected_rows();
|
||||
}
|
||||
}
|
||||
2085
api/models/Api_model.php
Normal file
2085
api/models/Api_model.php
Normal file
File diff suppressed because it is too large
Load Diff
521
api/models/Authentication_model.php
Normal file
521
api/models/Authentication_model.php
Normal file
@@ -0,0 +1,521 @@
|
||||
<?php
|
||||
|
||||
use BaconQrCode\Renderer\Image\ImagickImageBackEnd;
|
||||
use BaconQrCode\Renderer\ImageRenderer;
|
||||
use BaconQrCode\Renderer\RendererStyle\RendererStyle;
|
||||
use BaconQrCode\Writer;
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Authentication_model extends App_Model {
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->load->config('api');
|
||||
|
||||
$this->load->model('user_autologin');
|
||||
$this->autologin();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string Email address for login
|
||||
* @param string User Password
|
||||
* @param boolean Set cookies for user if remember me is checked
|
||||
* @param boolean Is Staff Or Client
|
||||
* @return boolean if not redirect url found, if found redirect to the url
|
||||
*/
|
||||
public function login($email, $password, $remember, $staff, $playground = false) {
|
||||
if ((!empty($email)) and (!empty($password))) {
|
||||
$table = db_prefix() . ($playground ? 'playground_' : '') . 'contacts';
|
||||
$_id = 'id';
|
||||
if ($staff == true) {
|
||||
$table = db_prefix() . ($playground ? 'playground_' : '') . 'staff';
|
||||
$_id = 'staffid';
|
||||
}
|
||||
$this->db->where('email', $email);
|
||||
$user = $this->db->get($table)->row();
|
||||
if ($user) {
|
||||
// Email is okey lets check the password now
|
||||
if (!$user->password || !app_hasher()->CheckPassword($password, $user->password)) {
|
||||
hooks()->do_action('failed_login_attempt', ['user' => $user, 'is_staff_member' => $staff, ]);
|
||||
log_activity('Failed Login Attempt [Email: ' . $email . ', Is Staff Member: ' . ($staff == true ? 'Yes' : 'No') . ', IP: ' . $this->input->ip_address() . ']');
|
||||
// Password failed, return
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
hooks()->do_action('non_existent_user_login_attempt', ['email' => $email, 'is_staff_member' => $staff, ]);
|
||||
log_activity('Non Existing User Tried to Login [Email: ' . $email . ', Is Staff Member: ' . ($staff == true ? 'Yes' : 'No') . ', IP: ' . $this->input->ip_address() . ']');
|
||||
return false;
|
||||
}
|
||||
if ($user->active == 0) {
|
||||
hooks()->do_action('inactive_user_login_attempt', ['user' => $user, 'is_staff_member' => $staff, ]);
|
||||
log_activity('Inactive User Tried to Login [Email: ' . $email . ', Is Staff Member: ' . ($staff == true ? 'Yes' : 'No') . ', IP: ' . $this->input->ip_address() . ']');
|
||||
return ['memberinactive' => true, ];
|
||||
}
|
||||
$twoFactorAuth = false;
|
||||
if ($staff == true) {
|
||||
$twoFactorAuth = $user->two_factor_auth_enabled == 0 ? false : true;
|
||||
if (!$twoFactorAuth) {
|
||||
hooks()->do_action('before_staff_login', ['email' => $email, 'userid' => $user->$_id, ]);
|
||||
$user_data = ['staff_user_id' => $user->$_id, 'staff_logged_in' => true, ];
|
||||
} else {
|
||||
$user_data = [];
|
||||
$user_data['tfa_staffid'] = $user->staffid;
|
||||
if ($remember) {
|
||||
$user_data['tfa_remember'] = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hooks()->do_action('before_client_login', ['email' => $email, 'userid' => $user->userid, 'contact_user_id' => $user->$_id, ]);
|
||||
$user_data = ['client_user_id' => $user->userid, 'contact_user_id' => $user->$_id, 'client_logged_in' => true, ];
|
||||
}
|
||||
$this->session->set_userdata($user_data);
|
||||
if (!$twoFactorAuth) {
|
||||
if ($remember) {
|
||||
$this->create_autologin($user->$_id, $staff);
|
||||
}
|
||||
$this->update_login_info($user->$_id, $staff);
|
||||
} else {
|
||||
return ['two_factor_auth' => true, 'user' => $user];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boolean If Client or Staff
|
||||
* @return none
|
||||
*/
|
||||
public function logout($staff = true, $playground = false) {
|
||||
$this->delete_autologin($staff, $playground);
|
||||
if (is_client_logged_in()) {
|
||||
hooks()->do_action('before_contact_logout', get_client_user_id());
|
||||
$this->session->unset_userdata('client_user_id');
|
||||
$this->session->unset_userdata('client_logged_in');
|
||||
} else {
|
||||
hooks()->do_action('before_staff_logout', get_staff_user_id());
|
||||
$this->session->unset_userdata('staff_user_id');
|
||||
$this->session->unset_userdata('staff_logged_in');
|
||||
}
|
||||
$this->session->sess_destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer ID to create autologin
|
||||
* @param boolean Is Client or Staff
|
||||
* @return boolean
|
||||
*/
|
||||
private function create_autologin($user_id, $staff, $playground = false) {
|
||||
$this->load->helper('cookie');
|
||||
$key = substr(md5(uniqid(rand() . get_cookie($this->config->item('sess_cookie_name')))), 0, 16);
|
||||
$this->user_autologin->delete($user_id, $key, $staff, $playground);
|
||||
if ($this->user_autologin->set($user_id, md5($key), $staff, $playground)) {
|
||||
set_cookie([
|
||||
'name' => 'autologin',
|
||||
'value' => serialize(['user_id' => $user_id, 'key' => $key, ]),
|
||||
'expire' => 60 * 60 * 24 * 31 * 2, // 2 months
|
||||
]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boolean Is Client or Staff
|
||||
* @return none
|
||||
*/
|
||||
private function delete_autologin($staff, $playground = false) {
|
||||
$this->load->helper('cookie');
|
||||
if ($cookie = get_cookie('autologin', true)) {
|
||||
$data = unserialize($cookie);
|
||||
$this->user_autologin->delete($data['user_id'], md5($data['key']), $staff, $playground);
|
||||
delete_cookie('autologin', 'aal');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
* Check if autologin found
|
||||
*/
|
||||
public function autologin($playground = false) {
|
||||
if (!is_logged_in()) {
|
||||
$this->load->helper('cookie');
|
||||
if ($cookie = get_cookie('autologin', true)) {
|
||||
$data = unserialize($cookie);
|
||||
if (isset($data['key']) and isset($data['user_id'])) {
|
||||
if (!is_null($user = $this->user_autologin->get($data['user_id'], md5($data['key']), $playground))) {
|
||||
// Login user
|
||||
if ($user->staff == 1) {
|
||||
$user_data = ['staff_user_id' => $user->id, 'staff_logged_in' => true, ];
|
||||
} else {
|
||||
// Get the customer id
|
||||
$this->db->select('userid');
|
||||
$this->db->where('id', $user->id);
|
||||
$contact = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'contacts')->row();
|
||||
$user_data = ['client_user_id' => $contact->userid, 'contact_user_id' => $user->id, 'client_logged_in' => true, ];
|
||||
}
|
||||
$this->session->set_userdata($user_data);
|
||||
// Renew users cookie to prevent it from expiring
|
||||
set_cookie(['name' => 'autologin', 'value' => $cookie, 'expire' => 60 * 60 * 24 * 31 * 2, // 2 months
|
||||
]);
|
||||
$this->update_login_info($user->id, $user->staff, $playground);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer ID
|
||||
* @param boolean Is Client or Staff
|
||||
* @return none
|
||||
* Update login info on autologin
|
||||
*/
|
||||
private function update_login_info($user_id, $staff, $playground = false) {
|
||||
$table = db_prefix() . ($playground ? 'playground_' : '') . 'contacts';
|
||||
$_id = 'id';
|
||||
if ($staff == true) {
|
||||
$table = db_prefix() . ($playground ? 'playground_' : '') . 'staff';
|
||||
$_id = 'staffid';
|
||||
}
|
||||
$this->db->set('last_ip', $this->input->ip_address());
|
||||
$this->db->set('last_login', date('Y-m-d H:i:s'));
|
||||
$this->db->where($_id, $user_id);
|
||||
$this->db->update($table);
|
||||
log_activity('User Successfully Logged In [User Id: ' . $user_id . ', Is Staff Member: ' . ($staff == true ? 'Yes' : 'No') . ', IP: ' . $this->input->ip_address() . ']');
|
||||
}
|
||||
|
||||
/**
|
||||
* Send set password email for contacts
|
||||
* @param string $email
|
||||
*/
|
||||
public function set_password_email($email, $playground = false) {
|
||||
$this->db->where('email', $email);
|
||||
$user = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'contacts')->row();
|
||||
if ($user) {
|
||||
if ($user->active == 0) {
|
||||
return ['memberinactive' => true, ];
|
||||
}
|
||||
$new_pass_key = app_generate_hash();
|
||||
$this->db->where('id', $user->id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'contacts', ['new_pass_key' => $new_pass_key, 'new_pass_key_requested' => date('Y-m-d H:i:s'), ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$data['new_pass_key'] = $new_pass_key;
|
||||
$data['userid'] = $user->id;
|
||||
$data['email'] = $email;
|
||||
$sent = send_mail_template('customer_contact_set_password', $user, $data);
|
||||
if ($sent) {
|
||||
hooks()->do_action('set_password_email_sent', ['is_staff_member' => false, 'user' => $user]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string Email from the user
|
||||
* @param Is Client or Staff
|
||||
* @return boolean
|
||||
* Generate new password key for the user to reset the password.
|
||||
*/
|
||||
public function forgot_password($email, $staff = false, $playground = false) {
|
||||
$table = db_prefix() . ($playground ? 'playground_' : '') . 'contacts';
|
||||
$_id = 'id';
|
||||
if ($staff == true) {
|
||||
$table = db_prefix() . ($playground ? 'playground_' : '') . 'staff';
|
||||
$_id = 'staffid';
|
||||
}
|
||||
$this->db->where('email', $email);
|
||||
$user = $this->db->get($table)->row();
|
||||
if ($user) {
|
||||
if ($user->active == 0) {
|
||||
log_activity('Inactive User Tried Password Reset [Email: ' . $email . ', Is Staff Member: ' . ($staff == true ? 'Yes' : 'No') . ', IP: ' . $this->input->ip_address() . ']');
|
||||
return ['memberinactive' => true, ];
|
||||
}
|
||||
$new_pass_key = app_generate_hash();
|
||||
$this->db->where($_id, $user->$_id);
|
||||
$this->db->update($table, ['new_pass_key' => $new_pass_key, 'new_pass_key_requested' => date('Y-m-d H:i:s'), ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$data['new_pass_key'] = $new_pass_key;
|
||||
$data['staff'] = $staff;
|
||||
$data['userid'] = $user->$_id;
|
||||
$merge_fields = [];
|
||||
if ($staff == false) {
|
||||
$sent = send_mail_template('customer_contact_forgot_password', $user->email, $user->userid, $user->$_id, $data);
|
||||
} else {
|
||||
$sent = send_mail_template('staff_forgot_password', $user->email, $user->$_id, $data);
|
||||
}
|
||||
if ($sent) {
|
||||
log_activity('Password Reset Email sent [Email: ' . $email . ', Is Staff Member: ' . ($staff == true ? 'Yes' : 'No') . ', IP: ' . $this->input->ip_address() . ']');
|
||||
hooks()->do_action('forgot_password_email_sent', ['is_staff_member' => $staff, 'user' => $user]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
log_activity('Non Existing User Tried Password Reset [Email: ' . $email . ', Is Staff Member: ' . ($staff == true ? 'Yes' : 'No') . ', IP: ' . $this->input->ip_address() . ']');
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user password from forgot password feature or set password
|
||||
* @param boolean $staff is staff or contact
|
||||
* @param mixed $userid
|
||||
* @param string $new_pass_key the password generate key
|
||||
* @param string $password new password
|
||||
*/
|
||||
public function set_password($staff, $userid, $new_pass_key, $password, $playground = false) {
|
||||
if (!$this->can_set_password($staff, $userid, $new_pass_key, $playground)) {
|
||||
return ['expired' => true, ];
|
||||
}
|
||||
$password = app_hash_password($password);
|
||||
$table = db_prefix() . ($playground ? 'playground_' : '') . 'contacts';
|
||||
$_id = 'id';
|
||||
if ($staff == true) {
|
||||
$table = db_prefix() . ($playground ? 'playground_' : '') . 'staff';
|
||||
$_id = 'staffid';
|
||||
}
|
||||
$this->db->where($_id, $userid);
|
||||
$this->db->where('new_pass_key', $new_pass_key);
|
||||
$this->db->update($table, ['password' => $password, ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('User Set Password [User ID: ' . $userid . ', Is Staff Member: ' . ($staff == true ? 'Yes' : 'No') . ', IP: ' . $this->input->ip_address() . ']');
|
||||
$this->db->set('new_pass_key', null);
|
||||
$this->db->set('new_pass_key_requested', null);
|
||||
$this->db->set('last_password_change', date('Y-m-d H:i:s'));
|
||||
$this->db->where($_id, $userid);
|
||||
$this->db->where('new_pass_key', $new_pass_key);
|
||||
$this->db->update($table);
|
||||
return true;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boolean Is Client or Staff
|
||||
* @param integer ID
|
||||
* @param string
|
||||
* @param string
|
||||
* @return boolean
|
||||
* User reset password after successful validation of the key
|
||||
*/
|
||||
public function reset_password($staff, $userid, $new_pass_key, $password, $playground = false) {
|
||||
if (!$this->can_reset_password($staff, $userid, $new_pass_key, $playground)) {
|
||||
return ['expired' => true, ];
|
||||
}
|
||||
$password = app_hash_password($password);
|
||||
$table = db_prefix() . ($playground ? 'playground_' : '') . 'contacts';
|
||||
$_id = 'id';
|
||||
if ($staff == true) {
|
||||
$table = db_prefix() . ($playground ? 'playground_' : '') . 'staff';
|
||||
$_id = 'staffid';
|
||||
}
|
||||
$this->db->where($_id, $userid);
|
||||
$this->db->where('new_pass_key', $new_pass_key);
|
||||
$this->db->update($table, ['password' => $password, ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('User Reseted Password [User ID: ' . $userid . ', Is Staff Member: ' . ($staff == true ? 'Yes' : 'No') . ', IP: ' . $this->input->ip_address() . ']');
|
||||
$this->db->set('new_pass_key', null);
|
||||
$this->db->set('new_pass_key_requested', null);
|
||||
$this->db->set('last_password_change', date('Y-m-d H:i:s'));
|
||||
$this->db->where($_id, $userid);
|
||||
$this->db->where('new_pass_key', $new_pass_key);
|
||||
$this->db->update($table);
|
||||
$this->db->where($_id, $userid);
|
||||
$user = $this->db->get($table)->row();
|
||||
if ($staff == false) {
|
||||
$sent = send_mail_template('customer_contact_password_resetted', $user->email, $user->userid, $user->$_id);
|
||||
} else {
|
||||
$sent = send_mail_template('staff_password_resetted', $user->email, $user->$_id);
|
||||
}
|
||||
if ($sent) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer Is Client or Staff
|
||||
* @param integer ID
|
||||
* @param string Password reset key
|
||||
* @return boolean
|
||||
* Check if the key is not expired or not exists in database
|
||||
*/
|
||||
public function can_reset_password($staff, $userid, $new_pass_key, $playground = false) {
|
||||
$table = db_prefix() . ($playground ? 'playground_' : '') . 'contacts';
|
||||
$_id = 'id';
|
||||
if ($staff == true) {
|
||||
$table = db_prefix() . ($playground ? 'playground_' : '') . 'staff';
|
||||
$_id = 'staffid';
|
||||
}
|
||||
$this->db->where($_id, $userid);
|
||||
$this->db->where('new_pass_key', $new_pass_key);
|
||||
$user = $this->db->get($table)->row();
|
||||
if ($user) {
|
||||
$timestamp_now_minus_1_hour = time() - (60 * 60);
|
||||
$new_pass_key_requested = strtotime($user->new_pass_key_requested);
|
||||
if ($timestamp_now_minus_1_hour > $new_pass_key_requested) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer Is Client or Staff
|
||||
* @param integer ID
|
||||
* @param string Password reset key
|
||||
* @return boolean
|
||||
* Check if the key is not expired or not exists in database
|
||||
*/
|
||||
public function can_set_password($staff, $userid, $new_pass_key, $playground = false) {
|
||||
$table = db_prefix() . ($playground ? 'playground_' : '') . 'contacts';
|
||||
$_id = 'id';
|
||||
if ($staff == true) {
|
||||
$table = db_prefix() . ($playground ? 'playground_' : '') . 'staff';
|
||||
$_id = 'staffid';
|
||||
}
|
||||
$this->db->where($_id, $userid);
|
||||
$this->db->where('new_pass_key', $new_pass_key);
|
||||
$user = $this->db->get($table)->row();
|
||||
if ($user) {
|
||||
$timestamp_now_minus_48_hour = time() - (3600 * 48);
|
||||
$new_pass_key_requested = strtotime($user->new_pass_key_requested);
|
||||
if ($timestamp_now_minus_48_hour > $new_pass_key_requested) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user from database by 2 factor authentication code
|
||||
* @param string $code authentication code to search for
|
||||
* @return object
|
||||
*/
|
||||
public function get_user_by_two_factor_auth_code($code, $playground = false) {
|
||||
$this->db->where('two_factor_auth_code', $code);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'staff')->row();
|
||||
}
|
||||
|
||||
/**
|
||||
* Login user via two factor authentication
|
||||
* @param object $user user object
|
||||
* @return boolean
|
||||
*/
|
||||
public function two_factor_auth_login($user, $playground = false) {
|
||||
hooks()->do_action('before_staff_login', ['email' => $user->email, 'userid' => $user->staffid, ]);
|
||||
$this->session->set_userdata(['staff_user_id' => $user->staffid, 'staff_logged_in' => true, ]);
|
||||
$remember = null;
|
||||
if ($this->session->has_userdata('tfa_remember')) {
|
||||
$remember = true;
|
||||
$this->session->unset_userdata('tfa_remember');
|
||||
}
|
||||
if ($remember) {
|
||||
$this->create_autologin($user->staffid, true);
|
||||
}
|
||||
$this->update_login_info($user->staffid, true, $playground);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if 2 factor authentication code sent to email is valid for usage
|
||||
* @param string $code auth code
|
||||
* @param string $email email of staff login in
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_two_factor_code_valid($code, $email, $playground = false) {
|
||||
$this->db->select('two_factor_auth_code_requested');
|
||||
$this->db->where('two_factor_auth_code', $code);
|
||||
$this->db->where('email', $email);
|
||||
$user = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'staff')->row();
|
||||
// Code not exists because no user is found
|
||||
if (!$user) {
|
||||
return false;
|
||||
}
|
||||
$timestamp_minus_1_hour = time() - (60 * 60);
|
||||
$new_code_key_requested = strtotime($user->two_factor_auth_code_requested);
|
||||
// The code is older then 1 hour and its not valid
|
||||
if ($timestamp_minus_1_hour > $new_code_key_requested) {
|
||||
return false;
|
||||
}
|
||||
// Code is valid
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears 2 factor authentication code in database
|
||||
* @param mixed $id
|
||||
* @return boolean
|
||||
*/
|
||||
public function clear_two_factor_auth_code($id, $playground = false) {
|
||||
$this->db->where('staffid', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'staff', ['two_factor_auth_code' => null, ]);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set 2 factor authentication code for staff member
|
||||
* @param mixed $id staff id
|
||||
*/
|
||||
public function set_two_factor_auth_code($id, $playground = false) {
|
||||
$code = generate_two_factor_auth_key();
|
||||
$code.= $id;
|
||||
$this->db->where('staffid', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'staff', ['two_factor_auth_code' => $code, 'two_factor_auth_code_requested' => date('Y-m-d H:i:s'), ]);
|
||||
return $code;
|
||||
}
|
||||
|
||||
public function get_qr($System_name, $playground = false) {
|
||||
$staff = get_staff(get_staff_user_id());
|
||||
$google2fa = new PragmaRX\Google2FA\Google2FA();
|
||||
$secret = $google2fa->generateSecretKey();
|
||||
$g2faUrl = $google2fa->getQRCodeUrl($System_name, $staff->email, $secret);
|
||||
$writer = new Writer(new ImageRenderer(new RendererStyle(200), new ImagickImageBackEnd()));
|
||||
return ['qrURL' => base64_encode($writer->writeString($g2faUrl)), 'secret' => $secret];
|
||||
}
|
||||
|
||||
public function set_google_two_factor($secret, $playground = false) {
|
||||
$id = get_staff_user_id();
|
||||
$secret = $this->encrypt($secret);
|
||||
$this->db->where('staffid', $id);
|
||||
$success = $this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'staff', ['two_factor_auth_enabled' => 2, 'google_auth_secret' => $secret, ]);
|
||||
if ($success) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function is_google_two_factor_code_valid($code, $secret = null, $playground = false) {
|
||||
$g = new PragmaRX\Google2FA\Google2FA();
|
||||
if (!is_null($secret)) {
|
||||
return $g->verifyKey($secret, $code, 0);
|
||||
}
|
||||
$staffid = $this->session->userdata('tfa_staffid');
|
||||
$this->db->select('google_auth_secret')->where('staffid', $staffid);
|
||||
if ($staff = $this->db->get(($playground ? 'playground_' : '') . 'staff')->row()) {
|
||||
return $g->verifyKey($this->decrypt($staff->google_auth_secret), $code, 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function encrypt($string) {
|
||||
$this->load->library('encryption');
|
||||
return $this->encryption->encrypt($string);
|
||||
}
|
||||
|
||||
public function decrypt($string) {
|
||||
$this->load->library('encryption');
|
||||
return $this->encryption->decrypt($string);
|
||||
}
|
||||
}
|
||||
72
api/models/Calendar_model.php
Normal file
72
api/models/Calendar_model.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
use app\services\utilities\Arr;
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Calendar_model extends App_Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function get_events($id = '', $playground = false)
|
||||
{
|
||||
$this->db->select('*');
|
||||
$this->db->from(db_prefix() . ($playground ? 'playground_' : '') . '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, $playground = false)
|
||||
{
|
||||
$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() . ($playground ? 'playground_' : '') . '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() . ($playground ? 'playground_' : '') . '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() . ($playground ? 'playground_' : '') . 'events', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
|
||||
if ($insert_id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
146
api/models/Client_groups_model.php
Normal file
146
api/models/Client_groups_model.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Client_groups_model extends App_Model {
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new customer group
|
||||
* @param array $data $_POST data
|
||||
*/
|
||||
public function add($data, $playground = false) {
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'customers_groups', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
log_activity('New Customer Group Created [ID:' . $insert_id . ', Name:' . $data['name'] . ']');
|
||||
return $insert_id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get customer groups where customer belongs
|
||||
* @param mixed $id customer id
|
||||
* @return array
|
||||
*/
|
||||
public function get_customer_groups($id, $playground = false) {
|
||||
$this->db->where('customer_id', $id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'customer_groups')->result_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all customer groups
|
||||
* @param string $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_groups($id = '', $playground = false) {
|
||||
if (is_numeric($id)) {
|
||||
$this->db->where('id', $id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'customers_groups')->row();
|
||||
}
|
||||
$this->db->order_by('name', 'asc');
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'customers_groups')->result_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit customer group
|
||||
* @param array $data $_POST data
|
||||
* @return boolean
|
||||
*/
|
||||
public function edit($data, $playground = false) {
|
||||
$this->db->where('id', $data['id']);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'customers_groups', ['name' => $data['name'], ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Customer Group Updated [ID:' . $data['id'] . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete customer group
|
||||
* @param mixed $id group id
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete($id, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'customers_groups');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$this->db->where('groupid', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'customer_groups');
|
||||
hooks()->do_action('customer_group_deleted', $id);
|
||||
log_activity('Customer Group Deleted [ID:' . $id . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update/sync customer groups where belongs
|
||||
* @param mixed $id customer id
|
||||
* @param mixed $groups_in
|
||||
* @return boolean
|
||||
*/
|
||||
public function sync_customer_groups($id, $groups_in, $playground = false) {
|
||||
if ($groups_in == false) {
|
||||
unset($groups_in);
|
||||
}
|
||||
$affectedRows = 0;
|
||||
$customer_groups = $this->get_customer_groups($id);
|
||||
if (sizeof($customer_groups) > 0) {
|
||||
foreach ($customer_groups as $customer_group) {
|
||||
if (isset($groups_in)) {
|
||||
if (!in_array($customer_group['groupid'], $groups_in)) {
|
||||
$this->db->where('customer_id', $id);
|
||||
$this->db->where('id', $customer_group['id']);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'customer_groups');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$affectedRows++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->db->where('customer_id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'customer_groups');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$affectedRows++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($groups_in)) {
|
||||
foreach ($groups_in as $group) {
|
||||
$this->db->where('customer_id', $id);
|
||||
$this->db->where('groupid', $group);
|
||||
$_exists = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'customer_groups')->row();
|
||||
if (!$_exists) {
|
||||
if (empty($group)) {
|
||||
continue;
|
||||
}
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'customer_groups', ['customer_id' => $id, 'groupid' => $group, ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$affectedRows++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (isset($groups_in)) {
|
||||
foreach ($groups_in as $group) {
|
||||
if (empty($group)) {
|
||||
continue;
|
||||
}
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'customer_groups', ['customer_id' => $id, 'groupid' => $group, ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$affectedRows++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($affectedRows > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
86
api/models/Client_vault_entries_model.php
Normal file
86
api/models/Client_vault_entries_model.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Client_vault_entries_model extends App_Model {
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get single vault entry
|
||||
* @param mixed $id vault entry id
|
||||
* @return object
|
||||
*/
|
||||
public function get($id, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'vault')->row();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get customer vault entries
|
||||
* @param mixed $customer_id
|
||||
* @param array $where additional wher
|
||||
* @return array
|
||||
*/
|
||||
public function get_by_customer_id($customer_id, $where = [], $playground = false) {
|
||||
$this->db->where('customer_id', $customer_id);
|
||||
$this->db->order_by('date_created', 'desc');
|
||||
$this->db->where($where);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'vault')->result_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new vault entry
|
||||
* @param array $data $_POST data
|
||||
* @param mixed $customer_id customer id
|
||||
* @return boolean
|
||||
*/
|
||||
public function create($data, $customer_id, $playground = false) {
|
||||
$data['date_created'] = date('Y-m-d H:i:s');
|
||||
$data['customer_id'] = $customer_id;
|
||||
$data['share_in_projects'] = isset($data['share_in_projects']) ? 1 : 0;
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'vault', $data);
|
||||
log_activity('Vault Entry Created [Customer ID: ' . $customer_id . ']');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update vault entry
|
||||
* @param mixed $id vault entry id
|
||||
* @param array $data $_POST data
|
||||
* @return boolean
|
||||
*/
|
||||
public function update($id, $data, $playground = false) {
|
||||
$vault = $this->get($id, $playground);
|
||||
$last_updated_from = $data['last_updated_from'];
|
||||
unset($data['last_updated_from']);
|
||||
$data['share_in_projects'] = isset($data['share_in_projects']) ? 1 : 0;
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'vault', $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . 'vault', ['last_updated' => date('Y-m-d H:i:s'), 'last_updated_from' => $last_updated_from]);
|
||||
log_activity('Vault Entry Updated [Customer ID: ' . $vault->customer_id . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete vault entry
|
||||
* @param mixed $id entry id
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete($id, $playground = false) {
|
||||
$vault = $this->get($id, $playground);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'vault');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Vault Entry Deleted [Customer ID: ' . $vault->customer_id . ']');
|
||||
hooks()->do_action('customer_vault_entry_deleted', ['vault_id' => $id, 'customer_id' => $vault->customer_id]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
1360
api/models/Clients_model.php
Normal file
1360
api/models/Clients_model.php
Normal file
File diff suppressed because it is too large
Load Diff
128
api/models/Contract_types_model.php
Normal file
128
api/models/Contract_types_model.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Contract_types_model extends App_Model {
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new contract type
|
||||
* @param mixed $data All $_POST data
|
||||
*/
|
||||
public function add($data, $playground = false) {
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'contracts_types', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
log_activity('New Contract Type Added [' . $data['name'] . ']');
|
||||
return $insert_id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit contract type
|
||||
* @param mixed $data All $_POST data
|
||||
* @param mixed $id Contract type id
|
||||
*/
|
||||
public function update($data, $id, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'contracts_types', $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Contract Type Updated [' . $data['name'] . ', ID:' . $id . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer ID (optional)
|
||||
* @return mixed
|
||||
* Get contract type object based on passed id if not passed id return array of all types
|
||||
*/
|
||||
public function get($id = '', $playground = false) {
|
||||
if (is_numeric($id)) {
|
||||
$this->db->where('id', $id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'contracts_types')->row();
|
||||
}
|
||||
$types = $this->app_object_cache->get(($playground ? 'playground_' : '') . 'contract-types');
|
||||
if (!$types && !is_array($types)) {
|
||||
$types = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'contracts_types')->result_array();
|
||||
$this->app_object_cache->add(($playground ? 'playground_' : '') . 'contract-types', $types);
|
||||
}
|
||||
return $types;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer ID
|
||||
* @return mixed
|
||||
* Delete contract type from database, if used return array with key referenced
|
||||
*/
|
||||
public function delete($id, $playground = false) {
|
||||
if (is_reference_in_table('contract_type', db_prefix() . ($playground ? 'playground_' : '') . 'contracts', $id)) {
|
||||
return ['referenced' => true, ];
|
||||
}
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'contracts_types');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Contract Deleted [' . $id . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contract types data for chart
|
||||
* @return array
|
||||
*/
|
||||
public function get_chart_data($playground = false) {
|
||||
$labels = [];
|
||||
$totals = [];
|
||||
$types = $this->get();
|
||||
foreach ($types as $type) {
|
||||
$total_rows_where = ['contract_type' => $type['id'], 'trash' => 0, ];
|
||||
if (is_client_logged_in()) {
|
||||
$total_rows_where['client'] = get_client_user_id();
|
||||
$total_rows_where['not_visible_to_client'] = 0;
|
||||
} else {
|
||||
if (staff_cant('view', 'contracts')) {
|
||||
$total_rows_where['addedfrom'] = get_staff_user_id();
|
||||
}
|
||||
}
|
||||
$total_rows = total_rows(db_prefix() . ($playground ? 'playground_' : '') . 'contracts', $total_rows_where);
|
||||
if ($total_rows == 0 && is_client_logged_in()) {
|
||||
continue;
|
||||
}
|
||||
array_push($labels, $type['name']);
|
||||
array_push($totals, $total_rows);
|
||||
}
|
||||
$chart = ['labels' => $labels, 'datasets' => [['label' => _l('contract_summary_by_type'), 'backgroundColor' => 'rgba(3,169,244,0.2)', 'borderColor' => '#03a9f4', 'borderWidth' => 1, 'data' => $totals, ], ], ];
|
||||
return $chart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contract types values for chart
|
||||
* @return array
|
||||
*/
|
||||
public function get_values_chart_data($playground = false) {
|
||||
$labels = [];
|
||||
$totals = [];
|
||||
$types = $this->get();
|
||||
foreach ($types as $type) {
|
||||
array_push($labels, $type['name']);
|
||||
$where = ['where' => ['contract_type' => $type['id'], 'trash' => 0, ], 'field' => 'contract_value', ];
|
||||
if (staff_cant('view', 'contracts')) {
|
||||
$where['where']['addedfrom'] = get_staff_user_id();
|
||||
}
|
||||
$total = sum_from_table(db_prefix() . ($playground ? 'playground_' : '') . 'contracts', $where);
|
||||
if ($total == null) {
|
||||
$total = 0;
|
||||
}
|
||||
array_push($totals, $total);
|
||||
}
|
||||
$chart = ['labels' => $labels, 'datasets' => [['label' => _l('contract_summary_by_type_value'), 'backgroundColor' => 'rgba(37,155,35,0.2)', 'borderColor' => '#84c529', 'tension' => false, 'borderWidth' => 1, 'data' => $totals, ], ], ];
|
||||
return $chart;
|
||||
}
|
||||
}
|
||||
697
api/models/Contracts_model.php
Normal file
697
api/models/Contracts_model.php
Normal file
@@ -0,0 +1,697 @@
|
||||
<?php
|
||||
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Contracts_model extends App_Model {
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->load->model('contract_types_model');
|
||||
$this->load->model('clients_model');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contract/s
|
||||
* @param mixed $id contract id
|
||||
* @param array $where perform where
|
||||
* @param boolean $for_editor if for editor is false will replace the field if not will not replace
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($id = '', $where = [], $for_editor = false, $playground = false) {
|
||||
$this->db->select('*,' . db_prefix() . ($playground ? 'playground_' : '') . 'contracts_types.name as type_name,' . db_prefix() . ($playground ? 'playground_' : '') . 'contracts.id as id, ' . db_prefix() . ($playground ? 'playground_' : '') . 'contracts.addedfrom');
|
||||
$this->db->where($where);
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'contracts_types', '' . db_prefix() . ($playground ? 'playground_' : '') . 'contracts_types.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'contracts.contract_type', 'left');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'clients', '' . db_prefix() . ($playground ? 'playground_' : '') . 'clients.userid = ' . db_prefix() . ($playground ? 'playground_' : '') . 'contracts.client');
|
||||
if (is_numeric($id)) {
|
||||
$this->db->where(db_prefix() . ($playground ? 'playground_' : '') . 'contracts.id', $id);
|
||||
$contract = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'contracts')->row();
|
||||
if ($contract) {
|
||||
$merge_fields = $this->get_merge_fields($contract, $playground);
|
||||
$contract->attachments = $this->get_contract_attachments('', $contract->id, $playground);
|
||||
if ($contract->content !== null && $for_editor == false) {
|
||||
foreach ($merge_fields as $key => $val) {
|
||||
if (stripos($contract->content, $key) !== false) {
|
||||
$contract->content = str_ireplace($key, $val, $contract->content);
|
||||
} else {
|
||||
$contract->content = str_ireplace($key, '', $contract->content);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $contract;
|
||||
}
|
||||
$contracts = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'contracts')->result_array();
|
||||
$i = 0;
|
||||
foreach ($contracts as $contract) {
|
||||
$contracts[$i]['attachments'] = $this->get_contract_attachments('', $contract['id'], $playground);
|
||||
$i++;
|
||||
}
|
||||
return $contracts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select unique contracts years
|
||||
* @return array
|
||||
*/
|
||||
public function get_contracts_years($playground = false) {
|
||||
return $this->db->query('SELECT DISTINCT(YEAR(datestart)) as year FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'contracts')->result_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer ID
|
||||
* @return object
|
||||
* Retrieve contract attachments from database
|
||||
*/
|
||||
public function get_contract_attachments($attachment_id = '', $id = '', $playground = false) {
|
||||
if (is_numeric($attachment_id)) {
|
||||
$this->db->where('id', $attachment_id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'files')->row();
|
||||
}
|
||||
$this->db->order_by('dateadded', 'desc');
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->where('rel_type', 'contract');
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'files')->result_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $_POST data
|
||||
* @return integer Insert ID
|
||||
* Add new contract
|
||||
*/
|
||||
public function add($data, $playground = false) {
|
||||
$data['dateadded'] = date('Y-m-d H:i:s');
|
||||
$data['addedfrom'] = get_staff_user_id();
|
||||
$data['datestart'] = to_sql_date($data['datestart']);
|
||||
unset($data['attachment']);
|
||||
if ($data['dateend'] == '') {
|
||||
unset($data['dateend']);
|
||||
} else {
|
||||
$data['dateend'] = to_sql_date($data['dateend']);
|
||||
}
|
||||
if (isset($data['trash']) && ($data['trash'] == 1 || $data['trash'] === 'on')) {
|
||||
$data['trash'] = 1;
|
||||
} else {
|
||||
$data['trash'] = 0;
|
||||
}
|
||||
if (isset($data['not_visible_to_client']) && ($data['not_visible_to_client'] == 1 || $data['not_visible_to_client'] === 'on')) {
|
||||
$data['not_visible_to_client'] = 1;
|
||||
} else {
|
||||
$data['not_visible_to_client'] = 0;
|
||||
}
|
||||
if (isset($data['custom_fields'])) {
|
||||
$custom_fields = $data['custom_fields'];
|
||||
unset($data['custom_fields']);
|
||||
}
|
||||
$data['hash'] = app_generate_hash();
|
||||
$data = hooks()->apply_filters('before_contract_added', $data);
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'contracts', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
if (isset($custom_fields)) {
|
||||
$this->load->model('custom_fields_model');
|
||||
$this->custom_fields_model->handle_custom_fields_post($insert_id, $custom_fields, false, $playground);
|
||||
}
|
||||
hooks()->do_action('after_contract_added', $insert_id);
|
||||
log_activity('New Contract Added [' . $data['subject'] . ']');
|
||||
return $insert_id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $_POST data
|
||||
* @param integer Contract ID
|
||||
* @return boolean
|
||||
*/
|
||||
public function update($data, $id, $playground = false) {
|
||||
$affectedRows = 0;
|
||||
$contract = $this->db->where('id', $id)->get(($playground ? 'playground_' : '') . 'contracts')->row();
|
||||
if (isset($data['datestart'])) {
|
||||
$data['datestart'] = to_sql_date($data['datestart']);
|
||||
}
|
||||
if (isset($data['dateend'])) {
|
||||
$data['dateend'] = $data['dateend'] == '' ? null : to_sql_date($data['dateend']);
|
||||
}
|
||||
if (isset($data['dateend']) && $data['dateend'] !== $contract->dateend) {
|
||||
$data['isexpirynotified'] = 0;
|
||||
}
|
||||
if ($data['dateend'] !== $contract) {
|
||||
if (isset($data['trash'])) {
|
||||
$data['trash'] = 1;
|
||||
} else {
|
||||
$data['trash'] = 0;
|
||||
}
|
||||
}
|
||||
if (isset($data['not_visible_to_client'])) {
|
||||
$data['not_visible_to_client'] = 1;
|
||||
} else {
|
||||
$data['not_visible_to_client'] = 0;
|
||||
}
|
||||
$data = hooks()->apply_filters('before_contract_updated', $data, $id);
|
||||
if (isset($data['custom_fields'])) {
|
||||
$custom_fields = $data['custom_fields'];
|
||||
$this->load->model('custom_fields_model');
|
||||
if ($this->custom_fields_model->handle_custom_fields_post($id, $custom_fields, false, $playground)) {
|
||||
$affectedRows++;
|
||||
}
|
||||
unset($data['custom_fields']);
|
||||
}
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'contracts', $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
hooks()->do_action('after_contract_updated', $id);
|
||||
log_activity('Contract Updated [' . $data['subject'] . ']');
|
||||
return true;
|
||||
}
|
||||
return $affectedRows > 0;
|
||||
}
|
||||
|
||||
public function add_signature($id, $playground = false): bool {
|
||||
$contract = $this->get($id, [], true, $playground);
|
||||
if ($contract) {
|
||||
$content = override_merge_fields($this->get_merge_fields($contract), $contract->content);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'contracts', array_merge(get_acceptance_info_array(), ['signed' => 1, 'content' => $content]));
|
||||
// Notify contract creator that customer signed the contract
|
||||
send_contract_signed_notification_to_staff($id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function clear_signature($id, $playground = false): bool {
|
||||
$this->db->select('signature');
|
||||
$this->db->where('id', $id);
|
||||
$contract = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'contracts')->row();
|
||||
if ($contract) {
|
||||
$contractData = $this->get($id, [], true, $playground);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'contracts', array_merge(get_acceptance_info_array(true), ['signed' => 0, 'content' => restore_merge_fields($contractData->content) ]));
|
||||
if (!empty($contract->signature)) {
|
||||
$this->load->model('misc_model');
|
||||
unlink($this->misc_model->get_upload_path_by_type('contract', $playground) . $id . '/' . $contract->signature);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add contract comment
|
||||
* @param mixed $data $_POST comment data
|
||||
* @param boolean $client is request coming from the client side
|
||||
*/
|
||||
public function add_comment($data, $client = false, $playground = false) {
|
||||
if (is_staff_logged_in()) {
|
||||
$client = false;
|
||||
}
|
||||
if (isset($data['action'])) {
|
||||
unset($data['action']);
|
||||
}
|
||||
$data['dateadded'] = date('Y-m-d H:i:s');
|
||||
if ($client == false) {
|
||||
$data['staffid'] = get_staff_user_id();
|
||||
}
|
||||
$data['content'] = nl2br($data['content']);
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'contract_comments', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
$contract = $this->get($data['contract_id'], [], false, $playground);
|
||||
if (($contract->not_visible_to_client == '1' || $contract->trash == '1') && $client == false) {
|
||||
return true;
|
||||
}
|
||||
if ($client == true) {
|
||||
// Get creator
|
||||
$this->db->select('staffid, email, phonenumber');
|
||||
$this->db->where('staffid', $contract->addedfrom);
|
||||
$staff_contract = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'staff')->result_array();
|
||||
$notifiedUsers = [];
|
||||
foreach ($staff_contract as $member) {
|
||||
$notified = add_notification(['description' => 'not_contract_comment_from_client', 'touserid' => $member['staffid'], 'fromcompany' => 1, 'fromuserid' => 0, 'link' => 'contracts/contract/' . $data['contract_id'], 'additional_data' => serialize([$contract->subject, ]), ]);
|
||||
if ($notified) {
|
||||
array_push($notifiedUsers, $member['staffid']);
|
||||
}
|
||||
$template = mail_template('contract_comment_to_staff', $contract, $member);
|
||||
$merge_fields = $template->get_merge_fields();
|
||||
$template->send();
|
||||
// Send email/sms to admin that client commented
|
||||
$this->app_sms->trigger(SMS_TRIGGER_CONTRACT_NEW_COMMENT_TO_STAFF, $member['phonenumber'], $merge_fields);
|
||||
}
|
||||
pusher_trigger_notification($notifiedUsers);
|
||||
} else {
|
||||
$contacts = $this->clients_model->get_contacts($contract->client, ['active' => 1, 'contract_emails' => 1]);
|
||||
foreach ($contacts as $contact) {
|
||||
$template = mail_template('contract_comment_to_customer', $contract, $contact);
|
||||
$merge_fields = $template->get_merge_fields();
|
||||
$template->send();
|
||||
$this->app_sms->trigger(SMS_TRIGGER_CONTRACT_NEW_COMMENT_TO_CUSTOMER, $contact['phonenumber'], $merge_fields);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function edit_comment($data, $id, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'contract_comments', ['content' => nl2br($data['content']), ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contract comments
|
||||
* @param mixed $id contract id
|
||||
* @return array
|
||||
*/
|
||||
public function get_comments($id, $playground = false) {
|
||||
$this->db->where('contract_id', $id);
|
||||
$this->db->order_by('dateadded', 'ASC');
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'contract_comments')->result_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contract single comment
|
||||
* @param mixed $id comment id
|
||||
* @return object
|
||||
*/
|
||||
public function get_comment($id, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'contract_comments')->row();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove contract comment
|
||||
* @param mixed $id comment id
|
||||
* @return boolean
|
||||
*/
|
||||
public function remove_comment($id, $playground = false) {
|
||||
$comment = $this->get_comment($id);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'contract_comments');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Contract Comment Removed [Contract ID:' . $comment->contract_id . ', Comment Content: ' . $comment->content . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function copy($id, $playground = false) {
|
||||
$contract = $this->get($id, [], true, $playground);
|
||||
$fields = $this->db->list_fields(db_prefix() . ($playground ? 'playground_' : '') . 'contracts');
|
||||
$newContactData = [];
|
||||
$contract->content = restore_merge_fields($contract->content);
|
||||
foreach ($fields as $field) {
|
||||
if (isset($contract->$field)) {
|
||||
$newContactData[$field] = $contract->$field;
|
||||
}
|
||||
}
|
||||
unset($newContactData['id']);
|
||||
$newContactData['trash'] = 0;
|
||||
$newContactData['isexpirynotified'] = 0;
|
||||
$newContactData['signed'] = 0;
|
||||
$newContactData['marked_as_signed'] = 0;
|
||||
$newContactData['signature'] = null;
|
||||
$newContactData = array_merge($newContactData, get_acceptance_info_array(true));
|
||||
if ($contract->dateend) {
|
||||
$dStart = new DateTime($contract->datestart);
|
||||
$dEnd = new DateTime($contract->dateend);
|
||||
$dDiff = $dStart->diff($dEnd);
|
||||
$newContactData['dateend'] = _d(date('Y-m-d', strtotime(date('Y-m-d', strtotime('+' . $dDiff->days . 'DAY')))));
|
||||
} else {
|
||||
$newContactData['dateend'] = '';
|
||||
}
|
||||
$newId = $this->add($newContactData);
|
||||
if ($newId) {
|
||||
$this->load->model('custom_fields_model');
|
||||
$custom_fields = $this->custom_fields_model->get_custom_fields('contracts', [], false, $playgroun);
|
||||
foreach ($custom_fields as $field) {
|
||||
$value = $this->custom_fields_model->get_custom_field_value($id, $field['id'], 'contracts', false, $playground);
|
||||
if ($value != '') {
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues', ['relid' => $newId, 'fieldid' => $field['id'], 'fieldto' => 'contracts', 'value' => $value, ]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $newId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer ID
|
||||
* @return boolean
|
||||
* Delete contract, also attachment will be removed if any found
|
||||
*/
|
||||
public function delete($id, $playground = false) {
|
||||
hooks()->do_action('before_contract_deleted', $id);
|
||||
$this->clear_signature($id);
|
||||
$contract = $this->get($id, [], false, $playground);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'contracts');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$this->db->where('contract_id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'contract_comments');
|
||||
// Delete the custom field values
|
||||
$this->db->where('relid', $id);
|
||||
$this->db->where('fieldto', 'contracts');
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues');
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->where('rel_type', 'contract');
|
||||
$attachments = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'files')->result_array();
|
||||
foreach ($attachments as $attachment) {
|
||||
$this->delete_contract_attachment($attachment['id'], $playground);
|
||||
}
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->where('rel_type', 'contract');
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'notes');
|
||||
$this->db->where('contractid', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'contract_renewals');
|
||||
// Get related tasks
|
||||
$this->db->where('rel_type', 'contract');
|
||||
$this->db->where('rel_id', $id);
|
||||
$tasks = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'tasks')->result_array();
|
||||
$this->load->model('tasks_model');
|
||||
foreach ($tasks as $task) {
|
||||
$this->tasks_model->delete_task($task['id'], true, $playground);
|
||||
}
|
||||
$this->load->model('misc_model');
|
||||
$this->misc_model->delete_tracked_emails($id, 'contract', $playgroun);
|
||||
log_activity('Contract Deleted [' . $id . ']');
|
||||
hooks()->do_action('after_contract_deleted', $id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the contract as signed manually
|
||||
*
|
||||
* @param int $id contract id
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function mark_as_signed($id, $playground = false) {
|
||||
$contract = $this->get($id, [], true, $playground);
|
||||
if (!is_object($contract)) {
|
||||
return false;
|
||||
}
|
||||
$content = override_merge_fields($this->get_merge_fields($contract), $contract->content);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'contracts', ['marked_as_signed' => 1, 'content' => $content, ]);
|
||||
return $this->db->affected_rows() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmark the contract as signed manually
|
||||
*
|
||||
* @param int $id contract id
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function unmark_as_signed($id, $playground = false) {
|
||||
$contract = $this->get($id, [], true, $playground);
|
||||
if (!is_object($contract)) {
|
||||
return false;
|
||||
}
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'contracts', ['marked_as_signed' => 0, 'content' => restore_merge_fields($contract->content), ]);
|
||||
return $this->db->affected_rows() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that send contract to customer
|
||||
* @param mixed $id contract id
|
||||
* @param boolean $attachpdf to attach pdf or not
|
||||
* @param string $cc Email CC
|
||||
* @return boolean
|
||||
*/
|
||||
public function send_contract_to_client($id, $attachpdf = true, $cc = '', $playground = false) {
|
||||
$contract = $this->get($id, [], false, $playground);
|
||||
if ($attachpdf) {
|
||||
set_mailing_constant();
|
||||
$pdf = contract_pdf($contract);
|
||||
$attach = $pdf->Output(slug_it($contract->subject) . '.pdf', 'S');
|
||||
}
|
||||
$sent_to = $this->input->post('sent_to');
|
||||
$sent = false;
|
||||
if (is_array($sent_to)) {
|
||||
$i = 0;
|
||||
foreach ($sent_to as $contact_id) {
|
||||
if ($contact_id != '') {
|
||||
$contact = $this->clients_model->get_contact($contact_id, ['active' => 1], [], $playground);
|
||||
// Send cc only for the first contact
|
||||
if (!empty($cc) && $i > 0) {
|
||||
$cc = '';
|
||||
}
|
||||
$template = mail_template('contract_send_to_customer', $contract, $contact, $cc);
|
||||
if ($attachpdf) {
|
||||
$template->add_attachment(['attachment' => $attach, 'filename' => slug_it($contract->subject) . '.pdf', 'type' => 'application/pdf', ]);
|
||||
}
|
||||
if ($template->send()) {
|
||||
$sent = true;
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if ($sent) {
|
||||
$contactsSent = [];
|
||||
if (!empty($contract->contacts_sent_to)) {
|
||||
$sentTo = json_decode($contract->contacts_sent_to, true);
|
||||
$cc = array_unique(array_merge(is_array($sentTo['cc']) ? $sentTo['cc'] : explode(',', $sentTo['cc']), explode(',', $cc)));
|
||||
$contactsSent = $sentTo['contact_ids'];
|
||||
}
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'contracts', ['last_sent_at' => date('c'), 'contacts_sent_to' => json_encode(['contact_ids' => array_unique(array_merge($contactsSent, $sent_to)), 'cc' => is_array($cc) ? join(',', $cc) : $cc, ]), ]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete contract attachment
|
||||
* @param mixed $attachment_id
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete_contract_attachment($attachment_id, $playground = false) {
|
||||
$deleted = false;
|
||||
$attachment = $this->get_contract_attachments($attachment_id, $playground);
|
||||
$this->load->model('misc_model');
|
||||
if ($attachment) {
|
||||
if (empty($attachment->external)) {
|
||||
unlink($this->misc_model->get_upload_path_by_type('contract', $playground) . $attachment->rel_id . '/' . $attachment->file_name);
|
||||
}
|
||||
$this->db->where('id', $attachment->id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'files');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$deleted = true;
|
||||
log_activity('Contract Attachment Deleted [ContractID: ' . $attachment->rel_id . ']');
|
||||
}
|
||||
if (is_dir($this->misc_model->get_upload_path_by_type('contract', $playground) . $attachment->rel_id)) {
|
||||
// Check if no attachments left, so we can delete the folder also
|
||||
$other_attachments = list_files($this->misc_model->get_upload_path_by_type('contract', $playground) . $attachment->rel_id);
|
||||
if (count($other_attachments) == 0) {
|
||||
// okey only index.html so we can delete the folder also
|
||||
delete_dir($this->misc_model->get_upload_path_by_type('contract', $playground) . $attachment->rel_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renew contract
|
||||
* @param mixed $data All $_POST data
|
||||
* @return mixed
|
||||
*/
|
||||
public function renew($data, $playground = false) {
|
||||
$keepSignature = isset($data['renew_keep_signature']);
|
||||
if ($keepSignature) {
|
||||
unset($data['renew_keep_signature']);
|
||||
}
|
||||
$contract = $this->get($data['contractid'], [], false, $playground);
|
||||
if ($keepSignature) {
|
||||
$data['new_value'] = $contract->contract_value;
|
||||
}
|
||||
$data['new_start_date'] = to_sql_date($data['new_start_date']);
|
||||
$data['new_end_date'] = to_sql_date($data['new_end_date']);
|
||||
$data['date_renewed'] = date('Y-m-d H:i:s');
|
||||
$this->load->model('staff_model');
|
||||
$data['renewed_by'] = $this->staff_model->get_staff_full_name(get_staff_user_id());
|
||||
$data['renewed_by_staff_id'] = get_staff_user_id();
|
||||
if (!is_date($data['new_end_date'])) {
|
||||
unset($data['new_end_date']);
|
||||
}
|
||||
// get the original contract so we can check if is expiry notified on delete the expiry to revert
|
||||
$_contract = $this->get($data['contractid'], [], false, $playground);
|
||||
$data['is_on_old_expiry_notified'] = $_contract->isexpirynotified;
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'contract_renewals', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
$this->db->where('id', $data['contractid']);
|
||||
$_data = ['datestart' => $data['new_start_date'], 'contract_value' => $data['new_value'], 'isexpirynotified' => 0, ];
|
||||
if (isset($data['new_end_date'])) {
|
||||
$_data['dateend'] = $data['new_end_date'];
|
||||
}
|
||||
if (!$keepSignature) {
|
||||
$_data = array_merge($_data, get_acceptance_info_array(true));
|
||||
$_data['signed'] = 0;
|
||||
if (!empty($_contract->signature)) {
|
||||
$this->load->model('misc_model');
|
||||
unlink($this->misc_model->get_upload_path_by_type('contract', $playground) . $data['contractid'] . '/' . $_contract->signature);
|
||||
}
|
||||
}
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'contracts', $_data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Contract Renewed [ID: ' . $data['contractid'] . ']');
|
||||
return true;
|
||||
}
|
||||
// delete the previous entry
|
||||
$this->db->where('id', $insert_id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'contract_renewals');
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete contract renewal
|
||||
* @param mixed $id renewal id
|
||||
* @param mixed $contractid contract id
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete_renewal($id, $contractid, $playground = false) {
|
||||
// check if this renewal is last so we can revert back the old values, if is not last we wont do anything
|
||||
$this->db->select('id')->from(db_prefix() . ($playground ? 'playground_' : '') . 'contract_renewals')->where('contractid', $contractid)->order_by('id', 'desc')->limit(1);
|
||||
$query = $this->db->get();
|
||||
$last_contract_renewal = $query->row()->id;
|
||||
$is_last = false;
|
||||
if ($last_contract_renewal == $id) {
|
||||
$is_last = true;
|
||||
$this->db->where('id', $id);
|
||||
$original_renewal = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'contract_renewals')->row();
|
||||
}
|
||||
$contract = $this->get($id, [], false, $playground);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'contract_renewals');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
if (!is_null($contract->short_link)) {
|
||||
app_archive_short_link($contract->short_link);
|
||||
}
|
||||
if ($is_last == true) {
|
||||
$this->db->where('id', $contractid);
|
||||
$data = ['datestart' => $original_renewal->old_start_date, 'contract_value' => $original_renewal->old_value, 'isexpirynotified' => $original_renewal->is_on_old_expiry_notified, ];
|
||||
if ($original_renewal->old_end_date != '0000-00-00') {
|
||||
$data['dateend'] = $original_renewal->old_end_date;
|
||||
}
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'contracts', $data);
|
||||
}
|
||||
log_activity('Contract Renewed [RenewalID: ' . $id . ', ContractID: ' . $contractid . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contracts about to expired in the given days
|
||||
*
|
||||
* @param integer|null $staffId
|
||||
* @param integer $days
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_contracts_about_to_expire($staffId = null, $days = 7, $playground = false) {
|
||||
$diff1 = date('Y-m-d', strtotime('-' . $days . ' days'));
|
||||
$diff2 = date('Y-m-d', strtotime('+' . $days . ' days'));
|
||||
if ($staffId && !staff_can('view', 'contracts', $staffId)) {
|
||||
$this->db->where('addedfrom', $staffId);
|
||||
}
|
||||
$this->db->select('id,subject,client,datestart,dateend');
|
||||
$this->db->where('dateend IS NOT NULL');
|
||||
$this->db->where('trash', 0);
|
||||
$this->db->where('dateend >=', $diff1);
|
||||
$this->db->where('dateend <=', $diff2);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'contracts')->result_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contract renewals
|
||||
* @param mixed $id contract id
|
||||
* @return array
|
||||
*/
|
||||
public function get_contract_renewal_history($id, $playground = false) {
|
||||
$this->db->where('contractid', $id);
|
||||
$this->db->order_by('date_renewed', 'asc');
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'contract_renewals')->result_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer ID (optional)
|
||||
* @return mixed
|
||||
* Get contract type object based on passed id if not passed id return array of all types
|
||||
*/
|
||||
public function get_contract_types($id = '', $playground = false) {
|
||||
return $this->contract_types_model->get($id, $playground);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer ID
|
||||
* @return mixed
|
||||
* Delete contract type from database, if used return array with key referenced
|
||||
*/
|
||||
public function delete_contract_type($id, $playground = false) {
|
||||
return $this->contract_types_model->delete($id, $playground);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new contract type
|
||||
* @param mixed $data All $_POST data
|
||||
*/
|
||||
public function add_contract_type($data, $playground = false) {
|
||||
return $this->contract_types_model->add($data, $playground);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit contract type
|
||||
* @param mixed $data All $_POST data
|
||||
* @param mixed $id Contract type id
|
||||
*/
|
||||
public function update_contract_type($data, $id, $playground = false) {
|
||||
return $this->contract_types_model->update($data, $id, $playground);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contract types data for chart
|
||||
* @return array
|
||||
*/
|
||||
public function get_contracts_types_chart_data($playground = false) {
|
||||
return $this->contract_types_model->get_chart_data($playground);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contract types values for chart
|
||||
* @return array
|
||||
*/
|
||||
public function get_contracts_types_values_chart_data($playground = false) {
|
||||
return $this->contract_types_model->get_values_chart_data($playground);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $contract
|
||||
* @return array<string, string> i.e. ['{merge_field}' => 'value']
|
||||
*/
|
||||
public function get_merge_fields(object $contract): array {
|
||||
$this->load->library('merge_fields/client_merge_fields');
|
||||
$this->load->library('merge_fields/contract_merge_fields');
|
||||
$this->load->library('merge_fields/other_merge_fields');
|
||||
|
||||
$merge_fields = [];
|
||||
$merge_fields = array_merge($merge_fields, $this->contract_merge_fields->format($contract->id));
|
||||
$merge_fields = array_merge($merge_fields, $this->client_merge_fields->format($contract->client));
|
||||
$merge_fields = array_merge($merge_fields, $this->other_merge_fields->format());
|
||||
return $merge_fields;
|
||||
}
|
||||
}
|
||||
731
api/models/Credit_notes_model.php
Normal file
731
api/models/Credit_notes_model.php
Normal file
@@ -0,0 +1,731 @@
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Credit_notes_model extends App_Model {
|
||||
private $shipping_fields = ['shipping_street', 'shipping_city', 'shipping_city', 'shipping_state', 'shipping_zip', 'shipping_country'];
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->load->model('invoices_model');
|
||||
}
|
||||
|
||||
public function get_statuses() {
|
||||
return hooks()->apply_filters('before_get_credit_notes_statuses', [['id' => 1, 'color' => '#03a9f4', 'name' => _l('credit_note_status_open'), 'order' => 1, 'filter_default' => true, ], ['id' => 2, 'color' => '#84c529', 'name' => _l('credit_note_status_closed'), 'order' => 2, 'filter_default' => true, ], ['id' => 3, 'color' => '#777', 'name' => _l('credit_note_status_void'), 'order' => 3, 'filter_default' => false, ], ]);
|
||||
}
|
||||
|
||||
public function get_available_creditable_invoices($credit_note_id, $playground = false) {
|
||||
$has_permission_view = staff_can('view', 'invoices');
|
||||
$invoices_statuses_available_for_credits = invoices_statuses_available_for_credits();
|
||||
$this->db->select('clientid');
|
||||
$this->db->where('id', $credit_note_id);
|
||||
$credit_note = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes')->row();
|
||||
$this->db->select('' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.id as id, status, total, date, ' . db_prefix() . ($playground ? 'playground_' : '') . 'currencies.name as currency_name');
|
||||
$this->db->where('clientid', $credit_note->clientid);
|
||||
$this->db->where('status IN (' . implode(', ', $invoices_statuses_available_for_credits) . ')');
|
||||
if (!$has_permission_view) {
|
||||
$this->db->where('addedfrom', get_staff_user_id());
|
||||
}
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'currencies', '' . db_prefix() . ($playground ? 'playground_' : '') . 'currencies.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.currency');
|
||||
$invoices = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'invoices')->result_array();
|
||||
foreach ($invoices as $key => $invoice) {
|
||||
$invoices[$key]['total_left_to_pay'] = get_invoice_total_left_to_pay($invoice['id'], $invoice['total']);
|
||||
}
|
||||
return $invoices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send credit note to client
|
||||
* @param mixed $id credit note id
|
||||
* @param string $template email template to sent
|
||||
* @param boolean $attachpdf attach credit note pdf or not
|
||||
* @return boolean
|
||||
*/
|
||||
public function send_credit_note_to_client($id, $attachpdf = true, $cc = '', $manually = false, $playground = false) {
|
||||
$credit_note = $this->get($id);
|
||||
$number = format_credit_note_number($credit_note->id);
|
||||
$sent = false;
|
||||
$sent_to = $this->input->post('sent_to');
|
||||
$this->load->model('clients_model');
|
||||
if ($manually === true) {
|
||||
$sent_to = [];
|
||||
$contacts = $this->clients_model->get_contacts($credit_note->clientid, ['active' => 1, 'credit_note_emails' => 1]);
|
||||
foreach ($contacts as $contact) {
|
||||
array_push($sent_to, $contact['id']);
|
||||
}
|
||||
}
|
||||
if (is_array($sent_to) && count($sent_to) > 0) {
|
||||
if ($attachpdf) {
|
||||
set_mailing_constant();
|
||||
$pdf = credit_note_pdf($credit_note);
|
||||
$attach = $pdf->Output($number . '.pdf', 'S');
|
||||
}
|
||||
$i = 0;
|
||||
foreach ($sent_to as $contact_id) {
|
||||
if ($contact_id != '') {
|
||||
if (!empty($cc) && $i > 0) {
|
||||
$cc = '';
|
||||
}
|
||||
$contact = $this->clients_model->get_contact($contact_id, ['active' => 1], [], $playground);
|
||||
$template = mail_template('credit_note_send_to_customer', $credit_note, $contact, $cc);
|
||||
if ($attachpdf) {
|
||||
$template->add_attachment(['attachment' => $attach, 'filename' => str_replace('/', '-', $number . '.pdf'), 'type' => 'application/pdf', ]);
|
||||
}
|
||||
if ($template->send()) {
|
||||
$sent = true;
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if ($sent) {
|
||||
hooks()->do_action('credit_note_sent', $id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get credit note/s
|
||||
* @param mixed $id credit note id
|
||||
* @param array $where perform where
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($id = '', $where = [], $playground = false) {
|
||||
$this->db->select('*,' . db_prefix() . ($playground ? 'playground_' : '') . 'currencies.id as currencyid, ' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes.id as id, ' . db_prefix() . ($playground ? 'playground_' : '') . 'currencies.name as currency_name');
|
||||
$this->db->from(db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'currencies', '' . db_prefix() . ($playground ? 'playground_' : '') . 'currencies.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes.currency', 'left');
|
||||
$this->db->where($where);
|
||||
$this->load->model('clients_model');
|
||||
if (is_numeric($id)) {
|
||||
$this->db->where(db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes.id', $id);
|
||||
$credit_note = $this->db->get()->row();
|
||||
if ($credit_note) {
|
||||
$credit_note->refunds = $this->get_refunds($id, $playground);
|
||||
$credit_note->total_refunds = $this->total_refunds_by_credit_note($id, $playground);
|
||||
$credit_note->applied_credits = $this->get_applied_credits($id, $playground);
|
||||
$credit_note->remaining_credits = $this->total_remaining_credits_by_credit_note($id, $playground);
|
||||
$credit_note->credits_used = $this->total_credits_used_by_credit_note($id, $playground);
|
||||
$this->load->model('invoice_items_model');
|
||||
$credit_note->items = $this->invoice_items_model->get_items_by_type('credit_note', $id, $playground);
|
||||
$credit_note->client = $this->clients_model->get($credit_note->clientid, $playground);
|
||||
if (!$credit_note->client) {
|
||||
$credit_note->client = new stdClass();
|
||||
$credit_note->client->company = $credit_note->deleted_customer_name;
|
||||
}
|
||||
$credit_note->attachments = $this->get_attachments($id, $playground);
|
||||
}
|
||||
return $credit_note;
|
||||
}
|
||||
$this->db->order_by('number,YEAR(date)', 'desc');
|
||||
return $this->db->get()->result_array();
|
||||
}
|
||||
|
||||
public function add($data, $playground = false) {
|
||||
$save_and_send = isset($data['save_and_send']);
|
||||
$data['prefix'] = get_option('credit_note_prefix', $playground);
|
||||
$data['number_format'] = get_option('credit_note_number_format', $playground);
|
||||
$data['datecreated'] = date('Y-m-d H:i:s');
|
||||
$data['addedfrom'] = get_staff_user_id();
|
||||
$items = [];
|
||||
if (isset($data['newitems'])) {
|
||||
$items = $data['newitems'];
|
||||
unset($data['newitems']);
|
||||
}
|
||||
if (isset($data['custom_fields'])) {
|
||||
$custom_fields = $data['custom_fields'];
|
||||
unset($data['custom_fields']);
|
||||
}
|
||||
$data = $this->map_shipping_columns($data, $playground);
|
||||
$hook = hooks()->apply_filters('before_create_credit_note', ['data' => $data, 'items' => $items]);
|
||||
$data = $hook['data'];
|
||||
$items = $hook['items'];
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
$this->save_formatted_number($insert_id, $playground);
|
||||
// Update next credit note number in settings
|
||||
$this->db->where('name', 'next_credit_note_number');
|
||||
$this->db->set('value', 'value+1', false);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'options');
|
||||
if (isset($custom_fields)) {
|
||||
$this->load->model('custom_fields_model');
|
||||
$this->custom_fields_model->handle_custom_fields_post($insert_id, $custom_fields, false, $playground);
|
||||
}
|
||||
$this->load->model('invoice_items_model');
|
||||
foreach ($items as $key => $item) {
|
||||
if ($itemid = $this->invoice_items_model->add_new_sales_item_post($item, $insert_id, 'credit_note', $playground)) {
|
||||
$this->invoice_items_model->_maybe_insert_post_item_tax($itemid, $item, $insert_id, 'credit_note', $playground);
|
||||
}
|
||||
}
|
||||
update_sales_total_tax_column($insert_id, 'credit_note', db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes');
|
||||
log_activity('Credit Note Created [ID: ' . $insert_id . ']');
|
||||
hooks()->do_action('after_create_credit_note', $insert_id);
|
||||
if ($save_and_send === true) {
|
||||
$this->send_credit_note_to_client($insert_id, true, '', true, $playground);
|
||||
}
|
||||
return $insert_id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update proposal
|
||||
* @param mixed $data $_POST data
|
||||
* @param mixed $id proposal id
|
||||
* @return boolean
|
||||
*/
|
||||
public function update($data, $id, $playground = false) {
|
||||
$affectedRows = 0;
|
||||
$save_and_send = isset($data['save_and_send']);
|
||||
$items = [];
|
||||
if (isset($data['items'])) {
|
||||
$items = $data['items'];
|
||||
unset($data['items']);
|
||||
}
|
||||
$newitems = [];
|
||||
if (isset($data['newitems'])) {
|
||||
$newitems = $data['newitems'];
|
||||
unset($data['newitems']);
|
||||
}
|
||||
if (isset($data['custom_fields'])) {
|
||||
$custom_fields = $data['custom_fields'];
|
||||
$this->load->model('custom_fields_model');
|
||||
if ($this->custom_fields_model->handle_custom_fields_post($id, $custom_fields, false, $playground)) {
|
||||
$affectedRows++;
|
||||
}
|
||||
unset($data['custom_fields']);
|
||||
}
|
||||
$data = $this->map_shipping_columns($data, $playground);
|
||||
$hook = hooks()->apply_filters('before_update_credit_note', ['data' => $data, 'items' => $items, 'newitems' => $newitems, 'removed_items' => isset($data['removed_items']) ? $data['removed_items'] : [], ], $id);
|
||||
$data = $hook['data'];
|
||||
$items = $hook['items'];
|
||||
$newitems = $hook['newitems'];
|
||||
$data['removed_items'] = $hook['removed_items'];
|
||||
// Delete items checked to be removed from database
|
||||
foreach ($data['removed_items'] as $remove_item_id) {
|
||||
if (handle_removed_sales_item_post($remove_item_id, 'credit_note', $playground)) {
|
||||
$affectedRows++;
|
||||
}
|
||||
}
|
||||
unset($data['removed_items']);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes', $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$this->save_formatted_number($id, $playground);
|
||||
$affectedRows++;
|
||||
}
|
||||
$this->load->model('custom_fields_model');
|
||||
$this->load->model('invoice_items_model');
|
||||
foreach ($items as $key => $item) {
|
||||
if (update_sales_item_post($item['itemid'], $item, $playground)) {
|
||||
$affectedRows++;
|
||||
}
|
||||
if (isset($item['custom_fields'])) {
|
||||
if ($this->custom_fields_model->handle_custom_fields_post($item['itemid'], $item['custom_fields'], false, $playground)) {
|
||||
$affectedRows++;
|
||||
}
|
||||
}
|
||||
if (!isset($item['taxname']) || (isset($item['taxname']) && count($item['taxname']) == 0)) {
|
||||
if (delete_taxes_from_item($item['itemid'], 'credit_note', $playground)) {
|
||||
$affectedRows++;
|
||||
}
|
||||
} else {
|
||||
$item_taxes = get_credit_note_item_taxes($item['itemid'], $playground);
|
||||
$_item_taxes_names = [];
|
||||
foreach ($item_taxes as $_item_tax) {
|
||||
array_push($_item_taxes_names, $_item_tax['taxname']);
|
||||
}
|
||||
$i = 0;
|
||||
foreach ($_item_taxes_names as $_item_tax) {
|
||||
if (!in_array($_item_tax, $item['taxname'])) {
|
||||
$this->db->where('id', $item_taxes[$i]['id'])->delete(db_prefix() . ($playground ? 'playground_' : '') . 'item_tax');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$affectedRows++;
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
if ($this->invoice_items_model->_maybe_insert_post_item_tax($item['itemid'], $item, $id, 'credit_note', $playground)) {
|
||||
$affectedRows++;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($newitems as $key => $item) {
|
||||
if ($new_item_added = $this->invoice_items_model->add_new_sales_item_post($item, $id, 'credit_note', $playground)) {
|
||||
$this->invoice_items_model->_maybe_insert_post_item_tax($new_item_added, $item, $id, 'credit_note', $playground);
|
||||
$affectedRows++;
|
||||
}
|
||||
}
|
||||
if ($save_and_send === true) {
|
||||
$this->send_credit_note_to_client($id, true, '', true, $playground);
|
||||
}
|
||||
if ($affectedRows > 0) {
|
||||
$this->update_credit_note_status($id, $playground);
|
||||
update_sales_total_tax_column($id, 'credit_note', db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes');
|
||||
}
|
||||
if ($affectedRows > 0) {
|
||||
log_activity('Credit Note Updated [ID:' . $id . ']');
|
||||
hooks()->do_action('after_update_credit_note', $id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete credit note attachment
|
||||
* @param mixed $id attachmentid
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete_attachment($id, $playground = false) {
|
||||
$this->load->model('misc_model');
|
||||
$attachment = $this->misc_model->get_file($id, $playground);
|
||||
$deleted = false;
|
||||
if ($attachment) {
|
||||
if (empty($attachment->external)) {
|
||||
unlink($this->misc_model->get_upload_path_by_type('credit_note', $playground) . $attachment->rel_id . '/' . $attachment->file_name);
|
||||
}
|
||||
$this->db->where('id', $attachment->id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'files');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$deleted = true;
|
||||
log_activity('Credit Note Attachment Deleted [Credite Note: ' . format_credit_note_number($attachment->rel_id) . ']');
|
||||
}
|
||||
if (is_dir($this->misc_model->get_upload_path_by_type('credit_note', $playground) . $attachment->rel_id)) {
|
||||
// Check if no attachments left, so we can delete the folder also
|
||||
$other_attachments = list_files($this->misc_model->get_upload_path_by_type('credit_note', $playground) . $attachment->rel_id);
|
||||
if (count($other_attachments) == 0) {
|
||||
// okey only index.html so we can delete the folder also
|
||||
delete_dir($this->misc_model->get_upload_path_by_type('credit_note', $playground) . $attachment->rel_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
public function get_attachments($credit_note_id, $playground = false) {
|
||||
$this->db->where('rel_id', $credit_note_id);
|
||||
$this->db->where('rel_type', 'credit_note');
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'files')->result_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete credit note
|
||||
* @param mixed $id credit note id
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete($id, $simpleDelete = false, $playground = false) {
|
||||
hooks()->do_action('before_credit_note_deleted', $id);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$current_credit_note_number = get_option('next_credit_note_number');
|
||||
if ($current_credit_note_number > 1 && $simpleDelete == false && is_last_credit_note($id)) {
|
||||
// Decrement next credit note number
|
||||
$this->db->where('name', 'next_credit_note_number');
|
||||
$this->db->set('value', 'value-1', false);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'options');
|
||||
}
|
||||
$this->load->model('misc_model');
|
||||
$this->misc_model->delete_tracked_emails($id, 'credit_note', $playground);
|
||||
// Delete the custom field values
|
||||
$this->db->where('relid IN (SELECT id from ' . db_prefix() . ($playground ? 'playground_' : '') . 'itemable WHERE rel_type="credit_note" AND rel_id="' . $this->db->escape_str($id) . '")');
|
||||
$this->db->where('fieldto', 'items');
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues');
|
||||
$this->db->where('relid', $id);
|
||||
$this->db->where('fieldto', 'credit_note');
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues');
|
||||
$this->db->where('credit_id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'credits');
|
||||
$this->db->where('credit_note_id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'creditnote_refunds');
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->where('rel_type', 'credit_note');
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'itemable');
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->where('rel_type', 'credit_note');
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'item_tax');
|
||||
$attachments = $this->get_attachments($id, $playground);
|
||||
foreach ($attachments as $attachment) {
|
||||
$this->delete_attachment($attachment['id'], $playground);
|
||||
}
|
||||
$this->db->where('rel_type', 'credit_note');
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'reminders');
|
||||
hooks()->do_action('after_credit_note_deleted', $id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function mark($id, $status, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes', ['status' => $status]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
hooks()->do_action('credit_note_status_changed', $id, ['status' => $status]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function total_remaining_credits_by_customer($customer_id, $playground = false) {
|
||||
$has_permission_view = staff_can('view', 'credit_notes');
|
||||
$this->db->select('total,id');
|
||||
$this->db->where('clientid', $customer_id);
|
||||
$this->db->where('status', 1);
|
||||
if (!$has_permission_view) {
|
||||
$this->db->where('addedfrom', get_staff_user_id());
|
||||
}
|
||||
$credits = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes')->result_array();
|
||||
$total = $this->calc_remaining_credits($credits, $playground);
|
||||
return $total;
|
||||
}
|
||||
|
||||
public function total_remaining_credits_by_credit_note($credit_note_id, $playground = false) {
|
||||
$this->db->select('total,id');
|
||||
$this->db->where('id', $credit_note_id);
|
||||
$credits = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes')->result_array();
|
||||
$total = $this->calc_remaining_credits($credits, $playground);
|
||||
return $total;
|
||||
}
|
||||
|
||||
private function calc_remaining_credits($credits, $playground = false) {
|
||||
$total = 0;
|
||||
$credits_ids = [];
|
||||
$bcadd = function_exists('bcadd');
|
||||
foreach ($credits as $credit) {
|
||||
if ($bcadd) {
|
||||
$total = bcadd($total, $credit['total'], get_decimal_places());
|
||||
} else {
|
||||
$total+= $credit['total'];
|
||||
}
|
||||
array_push($credits_ids, $credit['id']);
|
||||
}
|
||||
if (count($credits_ids) > 0) {
|
||||
$this->db->where('credit_id IN (' . implode(', ', $credits_ids) . ')');
|
||||
$applied_credits = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'credits')->result_array();
|
||||
$bcsub = function_exists('bcsub');
|
||||
foreach ($applied_credits as $credit) {
|
||||
if ($bcsub) {
|
||||
$total = bcsub($total, $credit['amount'], get_decimal_places());
|
||||
} else {
|
||||
$total-= $credit['amount'];
|
||||
}
|
||||
}
|
||||
foreach ($credits_ids as $credit_note_id) {
|
||||
$total_refunds_by_credit_note = $this->total_refunds_by_credit_note($credit_note_id, $playground) ? : 0;
|
||||
if ($bcsub) {
|
||||
$total = bcsub($total, $total_refunds_by_credit_note, get_decimal_places());
|
||||
} else {
|
||||
$total-= $total_refunds_by_credit_note;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $total;
|
||||
}
|
||||
|
||||
public function delete_applied_credit($id, $credit_id, $invoice_id, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'credits');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$this->update_credit_note_status($credit_id, $playground);
|
||||
update_invoice_status($invoice_id, $playground);
|
||||
}
|
||||
}
|
||||
|
||||
public function credit_note_from_invoice($invoice_id, $playground = false) {
|
||||
$_invoice = $this->invoices_model->get($invoice_id, $playground);
|
||||
$new_credit_note_data = [];
|
||||
$new_credit_note_data['clientid'] = $_invoice->clientid;
|
||||
$new_credit_note_data['number'] = get_option('next_credit_note_number');
|
||||
$new_credit_note_data['date'] = _d(date('Y-m-d'));
|
||||
$new_credit_note_data['show_quantity_as'] = $_invoice->show_quantity_as;
|
||||
$new_credit_note_data['currency'] = $_invoice->currency;
|
||||
$new_credit_note_data['subtotal'] = $_invoice->subtotal;
|
||||
$new_credit_note_data['total'] = $_invoice->total;
|
||||
$new_credit_note_data['adminnote'] = $_invoice->adminnote;
|
||||
$new_credit_note_data['adjustment'] = $_invoice->adjustment;
|
||||
$new_credit_note_data['discount_percent'] = $_invoice->discount_percent;
|
||||
$new_credit_note_data['discount_total'] = $_invoice->discount_total;
|
||||
$new_credit_note_data['discount_type'] = $_invoice->discount_type;
|
||||
$new_credit_note_data['billing_street'] = clear_textarea_breaks($_invoice->billing_street);
|
||||
$new_credit_note_data['billing_city'] = $_invoice->billing_city;
|
||||
$new_credit_note_data['billing_state'] = $_invoice->billing_state;
|
||||
$new_credit_note_data['billing_zip'] = $_invoice->billing_zip;
|
||||
$new_credit_note_data['billing_country'] = $_invoice->billing_country;
|
||||
$new_credit_note_data['shipping_street'] = clear_textarea_breaks($_invoice->shipping_street);
|
||||
$new_credit_note_data['shipping_city'] = $_invoice->shipping_city;
|
||||
$new_credit_note_data['shipping_state'] = $_invoice->shipping_state;
|
||||
$new_credit_note_data['shipping_zip'] = $_invoice->shipping_zip;
|
||||
$new_credit_note_data['shipping_country'] = $_invoice->shipping_country;
|
||||
$new_credit_note_data['reference_no'] = format_invoice_number($_invoice->id);
|
||||
if ($_invoice->include_shipping == 1) {
|
||||
$new_credit_note_data['include_shipping'] = $_invoice->include_shipping;
|
||||
}
|
||||
$new_credit_note_data['show_shipping_on_credit_note'] = $_invoice->show_shipping_on_invoice;
|
||||
$new_credit_note_data['clientnote'] = get_option('predefined_clientnote_credit_note');
|
||||
$new_credit_note_data['terms'] = get_option('predefined_terms_credit_note');
|
||||
$new_credit_note_data['adminnote'] = '';
|
||||
$new_credit_note_data['newitems'] = [];
|
||||
$this->load->model('custom_fields_items');
|
||||
$custom_fields_items = $this->custom_fields_model->get_custom_fields('items', [], false, $playground);
|
||||
$key = 1;
|
||||
foreach ($_invoice->items as $item) {
|
||||
$new_credit_note_data['newitems'][$key]['description'] = $item['description'];
|
||||
$new_credit_note_data['newitems'][$key]['long_description'] = clear_textarea_breaks($item['long_description']);
|
||||
$new_credit_note_data['newitems'][$key]['qty'] = $item['qty'];
|
||||
$new_credit_note_data['newitems'][$key]['unit'] = $item['unit'];
|
||||
$new_credit_note_data['newitems'][$key]['taxname'] = [];
|
||||
$taxes = get_invoice_item_taxes($item['id']);
|
||||
foreach ($taxes as $tax) {
|
||||
// tax name is in format TAX1|10.00
|
||||
array_push($new_credit_note_data['newitems'][$key]['taxname'], $tax['taxname']);
|
||||
}
|
||||
$new_credit_note_data['newitems'][$key]['rate'] = $item['rate'];
|
||||
$new_credit_note_data['newitems'][$key]['order'] = $item['item_order'];
|
||||
foreach ($custom_fields_items as $cf) {
|
||||
$new_credit_note_data['newitems'][$key]['custom_fields']['items'][$cf['id']] = $this->custom_fields_model->get_custom_field_value($item['id'], $cf['id'], 'items', false, $playground);
|
||||
if (!defined('COPY_CUSTOM_FIELDS_LIKE_HANDLE_POST')) {
|
||||
define('COPY_CUSTOM_FIELDS_LIKE_HANDLE_POST', true);
|
||||
}
|
||||
}
|
||||
$key++;
|
||||
}
|
||||
$id = $this->add($new_credit_note_data);
|
||||
if ($id) {
|
||||
if ($_invoice->status != Invoices_model::STATUS_PAID) {
|
||||
if ($_invoice->status == Invoices_model::STATUS_DRAFT) {
|
||||
$this->invoices_model->change_invoice_number_when_status_draft($invoice_id, $playground);
|
||||
}
|
||||
if ($this->apply_credits($id, ['invoice_id' => $invoice_id, 'amount' => $_invoice->total_left_to_pay])) {
|
||||
update_invoice_status($invoice_id, true);
|
||||
}
|
||||
$this->invoices_model->save_formatted_number($invoice_id, $playground);
|
||||
}
|
||||
$invoiceNumber = format_invoice_number($_invoice->id);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(($playground ? 'playground_' : '') . 'creditnotes', ['reference_no' => $invoiceNumber]);
|
||||
log_activity('Created Credit Note From Invoice [Invoice: ' . $invoiceNumber . ', Credit Note: ' . format_credit_note_number($id) . ']');
|
||||
hooks()->do_action('created_credit_note_from_invoice', ['invoice_id' => $invoice_id, 'credit_note_id' => $id]);
|
||||
return $id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function create_refund($id, $data, $playground = false) {
|
||||
if ($data['amount'] == 0) {
|
||||
return false;
|
||||
}
|
||||
$data['note'] = trim($data['note']);
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'creditnote_refunds', ['created_at' => date('Y-m-d H:i:s'), 'credit_note_id' => $id, 'staff_id' => $data['staff_id'], 'refunded_on' => $data['refunded_on'], 'payment_mode' => $data['payment_mode'], 'amount' => $data['amount'], 'note' => nl2br($data['note']), ]);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
$this->update_credit_note_status($id, $playground);
|
||||
hooks()->do_action('credit_note_refund_created', ['data' => $data, 'credit_note_id' => $id]);
|
||||
}
|
||||
return $insert_id;
|
||||
}
|
||||
|
||||
public function edit_refund($id, $data, $playground = false) {
|
||||
if ($data['amount'] == 0) {
|
||||
return false;
|
||||
}
|
||||
$refund = $this->get_refund($id, $playground);
|
||||
$data['note'] = trim($data['note']);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'creditnote_refunds', ['refunded_on' => $data['refunded_on'], 'payment_mode' => $data['payment_mode'], 'amount' => $data['amount'], 'note' => nl2br($data['note']), ]);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$this->update_credit_note_status($refund->credit_note_id, $playground);
|
||||
hooks()->do_action('credit_note_refund_updated', ['data' => $data, 'refund_id' => $refund->credit_note_id]);
|
||||
}
|
||||
return $insert_id;
|
||||
}
|
||||
|
||||
public function get_refund($id, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'creditnote_refunds')->row();
|
||||
}
|
||||
|
||||
public function get_refunds($credit_note_id, $playground = false) {
|
||||
$this->db->select(prefixed_table_fields_array(db_prefix() . ($playground ? 'playground_' : '') . 'creditnote_refunds', true) . ',' . db_prefix() . ($playground ? 'playground_' : '') . 'payment_modes.id as payment_mode_id, ' . db_prefix() . ($playground ? 'playground_' : '') . 'payment_modes.name as payment_mode_name');
|
||||
$this->db->where('credit_note_id', $credit_note_id);
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'payment_modes', db_prefix() . ($playground ? 'playground_' : '') . 'payment_modes.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnote_refunds.payment_mode', 'left');
|
||||
$this->db->order_by('refunded_on', 'desc');
|
||||
$refunds = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'creditnote_refunds')->result_array();
|
||||
$this->load->model('payment_modes_model');
|
||||
$payment_gateways = $this->payment_modes_model->get_payment_gateways(true, $playground);
|
||||
$i = 0;
|
||||
foreach ($refunds as $refund) {
|
||||
if (is_null($refund['payment_mode_id'])) {
|
||||
foreach ($payment_gateways as $gateway) {
|
||||
if ($refund['payment_mode'] == $gateway['id']) {
|
||||
$refunds[$i]['payment_mode_id'] = $gateway['id'];
|
||||
$refunds[$i]['payment_mode_name'] = $gateway['name'];
|
||||
}
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
return $refunds;
|
||||
}
|
||||
|
||||
public function delete_refund($refund_id, $credit_note_id, $playground = false) {
|
||||
$this->db->where('id', $refund_id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'creditnote_refunds');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$this->update_credit_note_status($credit_note_id, $playground);
|
||||
hooks()->do_action('credit_note_refund_deleted', ['refund_id' => $refund_id, 'credit_note_id' => $credit_note_id]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function total_refunds_by_credit_note($id, $playground = false) {
|
||||
return sum_from_table(db_prefix() . ($playground ? 'playground_' : '') . 'creditnote_refunds', ['field' => 'amount', 'where' => ['credit_note_id' => $id], ]);
|
||||
}
|
||||
|
||||
public function apply_credits($id, $data, $playground = false) {
|
||||
if ($data['amount'] == 0) {
|
||||
return false;
|
||||
}
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'credits', ['invoice_id' => $data['invoice_id'], 'credit_id' => $id, 'staff_id' => get_staff_user_id(), 'date' => date('Y-m-d'), 'date_applied' => date('Y-m-d H:i:s'), 'amount' => $data['amount'], ]);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
$this->update_credit_note_status($id, $playground);
|
||||
$invoice = $this->db->select('id,status')->where('id', $data['invoice_id'])->get(db_prefix() . ($playground ? 'playground_' : '') . 'invoices')->row();
|
||||
if ($invoice->status == Invoices_model::STATUS_DRAFT) {
|
||||
// update invoice number for invoice with draft - V2.7.2
|
||||
$this->invoices_model->change_invoice_number_when_status_draft($invoice->id, $playground);
|
||||
$this->invoices_model->save_formatted_number($invoice->id, $playground);
|
||||
}
|
||||
$this->db->select(db_prefix() . ($playground ? 'playground_' : '') . 'currencies.name as currency_name');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'currencies', '' . db_prefix() . ($playground ? 'playground_' : '') . 'currencies.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.currency');
|
||||
$this->db->where(db_prefix() . ($playground ? 'playground_' : '') . 'invoices.id', $data['invoice_id']);
|
||||
$invoice = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'invoices')->row();
|
||||
$inv_number = format_invoice_number($data['invoice_id']);
|
||||
$credit_note_number = format_credit_note_number($id);
|
||||
$this->invoices_model->log_invoice_activity($data['invoice_id'], 'invoice_activity_applied_credits', false, serialize([app_format_money($data['amount'], $invoice->currency_name), $credit_note_number, ]), $playground);
|
||||
hooks()->do_action('credits_applied', ['data' => $data, 'credit_note_id' => $id]);
|
||||
log_activity('Credit Applied to Invoice [ Invoice: ' . $inv_number . ', Credit: ' . $credit_note_number . ' ]');
|
||||
}
|
||||
return $insert_id;
|
||||
}
|
||||
|
||||
private function total_credits_used_by_credit_note($id, $playground = false) {
|
||||
return sum_from_table(db_prefix() . ($playground ? 'playground_' : '') . 'credits', ['field' => 'amount', 'where' => ['credit_id' => $id], ]);
|
||||
}
|
||||
|
||||
public function update_credit_note_status($id, $playground = false) {
|
||||
$total_refunds_by_credit_note = $this->total_refunds_by_credit_note($id, $playground);
|
||||
$total_credits_used = $this->total_credits_used_by_credit_note($id, $playground);
|
||||
$status = 1;
|
||||
// sum from table returns null if nothing found
|
||||
if ($total_credits_used || $total_refunds_by_credit_note) {
|
||||
$compare = $total_credits_used + $total_refunds_by_credit_note;
|
||||
$this->db->select('total');
|
||||
$this->db->where('id', $id);
|
||||
$credit = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes')->row();
|
||||
if ($credit) {
|
||||
if (function_exists('bccomp')) {
|
||||
if (bccomp($credit->total, $compare, get_decimal_places()) === 0) {
|
||||
$status = 2;
|
||||
}
|
||||
} else {
|
||||
if ($credit->total == $compare) {
|
||||
$status = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes', ['status' => $status]);
|
||||
return $this->db->affected_rows() > 0 ? true : false;
|
||||
}
|
||||
|
||||
public function get_open_credits($customer_id, $playground = false) {
|
||||
$has_permission_view = staff_can('view', 'credit_notes');
|
||||
$this->db->where('status', 1);
|
||||
$this->db->where('clientid', $customer_id);
|
||||
if (!$has_permission_view) {
|
||||
$this->db->where('addedfrom', get_staff_user_id());
|
||||
}
|
||||
$credits = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes')->result_array();
|
||||
foreach ($credits as $key => $credit) {
|
||||
$credits[$key]['available_credits'] = $this->calculate_available_credits($credit['id'], $credit['total'], $playground);
|
||||
}
|
||||
return $credits;
|
||||
}
|
||||
|
||||
public function get_applied_invoice_credits($invoice_id, $playground = false) {
|
||||
$this->db->order_by('date', 'desc');
|
||||
$this->db->where('invoice_id', $invoice_id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'credits')->result_array();
|
||||
}
|
||||
|
||||
public function get_applied_credits($credit_id, $playground = false) {
|
||||
$this->db->where('credit_id', $credit_id);
|
||||
$this->db->order_by('date', 'desc');
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'credits')->result_array();
|
||||
}
|
||||
|
||||
private function calculate_available_credits($credit_id, $credit_amount = false, $playground = false) {
|
||||
if ($credit_amount === false) {
|
||||
$this->db->select('total')->from(db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes')->where('id', $credit_id);
|
||||
$credit_amount = $this->db->get()->row()->total;
|
||||
}
|
||||
$available_total = $credit_amount;
|
||||
$bcsub = function_exists('bcsub');
|
||||
$applied_credits = $this->get_applied_credits($credit_id, $playground);
|
||||
foreach ($applied_credits as $credit) {
|
||||
if ($bcsub) {
|
||||
$available_total = bcsub($available_total, $credit['amount'], get_decimal_places());
|
||||
} else {
|
||||
$available_total-= $credit['amount'];
|
||||
}
|
||||
}
|
||||
$total_refunds = $this->total_refunds_by_credit_note($credit_id, $playground);
|
||||
if ($total_refunds) {
|
||||
if ($bcsub) {
|
||||
$available_total = bcsub($available_total, $total_refunds, get_decimal_places());
|
||||
} else {
|
||||
$available_total-= $total_refunds;
|
||||
}
|
||||
}
|
||||
return $available_total;
|
||||
}
|
||||
|
||||
public function save_formatted_number($id, $playground = false) {
|
||||
$formattedNumber = format_credit_note_number($id);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(($playground ? 'playground_' : '') . 'creditnotes', ['formatted_number' => $formattedNumber]);
|
||||
}
|
||||
|
||||
public function get_credits_years($playground = false) {
|
||||
return $this->db->query('SELECT DISTINCT(YEAR(date)) as year FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes ORDER BY year DESC')->result_array();
|
||||
}
|
||||
|
||||
private function map_shipping_columns($data, $playground = false) {
|
||||
if (!isset($data['include_shipping'])) {
|
||||
foreach ($this->shipping_fields as $_s_field) {
|
||||
if (isset($data[$_s_field])) {
|
||||
$data[$_s_field] = null;
|
||||
}
|
||||
}
|
||||
$data['show_shipping_on_credit_note'] = 1;
|
||||
$data['include_shipping'] = 0;
|
||||
} else {
|
||||
$data['include_shipping'] = 1;
|
||||
// set by default for the next time to be checked
|
||||
if (isset($data['show_shipping_on_credit_note']) && ($data['show_shipping_on_credit_note'] == 1 || $data['show_shipping_on_credit_note'] == 'on')) {
|
||||
$data['show_shipping_on_credit_note'] = 1;
|
||||
} else {
|
||||
$data['show_shipping_on_credit_note'] = 0;
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
165
api/models/Currencies_model.php
Normal file
165
api/models/Currencies_model.php
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Currencies_model extends App_Model {
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer ID (optional)
|
||||
* @return mixed
|
||||
* Get currency object based on passed id if not passed id return array of all currencies
|
||||
*/
|
||||
public function get($id = false, $playground = false) {
|
||||
if (is_numeric($id)) {
|
||||
$this->db->where('id', $id);
|
||||
$currency = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'currencies')->row();
|
||||
$this->app_object_cache->set('currency-' . $currency->name, $currency);
|
||||
return $currency;
|
||||
}
|
||||
$currencies = $this->app_object_cache->get('currencies-data');
|
||||
if (!$currencies && !is_array($currencies)) {
|
||||
$currencies = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'currencies')->result_array();
|
||||
$this->app_object_cache->add('currencies-data', $currencies);
|
||||
}
|
||||
return $currencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get currency by name/iso code
|
||||
* @since 2.3.2
|
||||
* @param string $name currency name/iso code
|
||||
* @return object
|
||||
*/
|
||||
public function get_by_name($name, $playground = false) {
|
||||
$currency = $this->app_object_cache->get('currency-' . $name);
|
||||
if (!$currency && !is_object($currency)) {
|
||||
$this->db->where('name', $name);
|
||||
$currency = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'currencies')->row();
|
||||
$this->app_object_cache->add('currency-' . $name, $currency);
|
||||
}
|
||||
return $currency;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $_POST data
|
||||
* @return boolean
|
||||
*/
|
||||
public function add($data, $playground = false) {
|
||||
unset($data['currencyid']);
|
||||
$data['name'] = strtoupper($data['name']);
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'currencies', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
log_activity('New Currency Added [ID: ' . $data['name'] . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $_POST data
|
||||
* @return boolean
|
||||
* Update currency values
|
||||
*/
|
||||
public function edit($data, $playground = false) {
|
||||
$currencyid = $data['currencyid'];
|
||||
unset($data['currencyid']);
|
||||
$data['name'] = strtoupper($data['name']);
|
||||
$this->db->where('id', $currencyid);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'currencies', $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Currency Updated [' . $data['name'] . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer ID
|
||||
* @return mixed
|
||||
* Delete currency from database, if used return array with key referenced
|
||||
*/
|
||||
public function delete($id, $playground = false) {
|
||||
foreach ($this->app->get_tables_with_currency($playground) as $tt) {
|
||||
if (is_reference_in_table($tt['field'], $tt['table'], $id)) {
|
||||
return ['referenced' => true, ];
|
||||
}
|
||||
}
|
||||
$currency = $this->get($id);
|
||||
if ($currency->isdefault == 1) {
|
||||
return ['is_default' => true, ];
|
||||
}
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'currencies');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$this->load->dbforge();
|
||||
$columns = $this->db->list_fields(db_prefix() . ($playground ? 'playground_' : '') . 'items');
|
||||
foreach ($columns as $column) {
|
||||
if ($column == 'rate_currency_' . $id) {
|
||||
$this->dbforge->drop_column('items', 'rate_currency_' . $id);
|
||||
}
|
||||
}
|
||||
log_activity('Currency Deleted [' . $id . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer ID
|
||||
* @return boolean
|
||||
* Make currency your base currency for better using reports if found invoices with more then 1 currency
|
||||
*/
|
||||
public function make_base_currency($id, $playground = false) {
|
||||
$base = $this->get_base_currency($playground);
|
||||
foreach ($this->app->get_tables_with_currency($playground) as $tt) {
|
||||
if (is_reference_in_table($tt['field'], $tt['table'], $base->id)) {
|
||||
return ['has_transactions_currency' => true, ];
|
||||
}
|
||||
}
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'currencies', ['isdefault' => 1, ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$this->db->where('id !=', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'currencies', ['isdefault' => 0, ]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object
|
||||
* Get base currency
|
||||
*/
|
||||
public function get_base_currency($playground = false) {
|
||||
$this->db->where('isdefault', 1);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'currencies')->row();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer ID
|
||||
* @return string
|
||||
* Get the symbol from the currency
|
||||
*/
|
||||
public function get_currency_symbol($id, $playground = false) {
|
||||
if (!is_numeric($id)) {
|
||||
$id = $this->get_base_currency($playground)->id;
|
||||
}
|
||||
$currencies = $this->app_object_cache->get('currencies-data');
|
||||
if ($currencies) {
|
||||
foreach ($currencies as $currency) {
|
||||
if ($id == $currency['id']) {
|
||||
return $currency['symbol'];
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->db->select('symbol');
|
||||
$this->db->from(db_prefix() . ($playground ? 'playground_' : '') . 'currencies');
|
||||
$this->db->where('id', $id);
|
||||
return $this->db->get()->row()->symbol;
|
||||
}
|
||||
}
|
||||
567
api/models/Custom_fields_model.php
Normal file
567
api/models/Custom_fields_model.php
Normal file
@@ -0,0 +1,567 @@
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Custom_fields_model extends App_Model {
|
||||
private $pdf_fields = ['estimate', 'invoice', 'credit_note', 'items'];
|
||||
private $client_portal_fields = ['customers', 'estimate', 'invoice', 'proposal', 'contracts', 'tasks', 'projects', 'contacts', 'tickets', 'company', 'credit_note'];
|
||||
private $client_editable_fields = ['customers', 'contacts', 'tasks'];
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer (optional)
|
||||
* @return object
|
||||
* Get single custom field
|
||||
*/
|
||||
public function get($id = false, $playground = false) {
|
||||
if (is_numeric($id)) {
|
||||
$this->db->where('id', $id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'customfields')->row();
|
||||
}
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'customfields')->result_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new custom field
|
||||
* @param mixed $data All $_POST data
|
||||
* @return boolean
|
||||
*/
|
||||
public function add($data, $playground = false) {
|
||||
if (isset($data['disabled'])) {
|
||||
$data['active'] = 0;
|
||||
unset($data['disabled']);
|
||||
} else {
|
||||
$data['active'] = 1;
|
||||
}
|
||||
if (isset($data['show_on_pdf'])) {
|
||||
if (in_array($data['fieldto'], $this->pdf_fields)) {
|
||||
$data['show_on_pdf'] = 1;
|
||||
} else {
|
||||
$data['show_on_pdf'] = 0;
|
||||
}
|
||||
} else {
|
||||
$data['show_on_pdf'] = 0;
|
||||
}
|
||||
if (isset($data['required'])) {
|
||||
$data['required'] = 1;
|
||||
} else {
|
||||
$data['required'] = 0;
|
||||
}
|
||||
if (isset($data['disalow_client_to_edit'])) {
|
||||
$data['disalow_client_to_edit'] = 1;
|
||||
} else {
|
||||
$data['disalow_client_to_edit'] = 0;
|
||||
}
|
||||
if (isset($data['show_on_table'])) {
|
||||
$data['show_on_table'] = 1;
|
||||
} else {
|
||||
$data['show_on_table'] = 0;
|
||||
}
|
||||
if (isset($data['only_admin'])) {
|
||||
$data['only_admin'] = 1;
|
||||
} else {
|
||||
$data['only_admin'] = 0;
|
||||
}
|
||||
if (isset($data['show_on_client_portal'])) {
|
||||
if (in_array($data['fieldto'], $this->client_portal_fields)) {
|
||||
$data['show_on_client_portal'] = 1;
|
||||
} else {
|
||||
$data['show_on_client_portal'] = 0;
|
||||
}
|
||||
} else {
|
||||
$data['show_on_client_portal'] = 0;
|
||||
}
|
||||
if ($data['field_order'] == '') {
|
||||
$data['field_order'] = 0;
|
||||
}
|
||||
$data['slug'] = slug_it($data['fieldto'] . '_' . $data['name'], ['separator' => '_', ]);
|
||||
$slugs_total = total_rows(db_prefix() . ($playground ? 'playground_' : '') . 'customfields', ['slug' => $data['slug']]);
|
||||
if ($slugs_total > 0) {
|
||||
$data['slug'].= '_' . ($slugs_total + 1);
|
||||
}
|
||||
if ($data['fieldto'] == 'company') {
|
||||
$data['show_on_pdf'] = 1;
|
||||
$data['show_on_client_portal'] = 1;
|
||||
$data['show_on_table'] = 1;
|
||||
$data['only_admin'] = 0;
|
||||
$data['disalow_client_to_edit'] = 0;
|
||||
} else if ($data['fieldto'] == 'items') {
|
||||
$data['show_on_pdf'] = 1;
|
||||
$data['show_on_client_portal'] = 1;
|
||||
$data['show_on_table'] = 1;
|
||||
$data['only_admin'] = 0;
|
||||
$data['disalow_client_to_edit'] = 0;
|
||||
}
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'customfields', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
log_activity('New Custom Field Added [' . $data['name'] . ']');
|
||||
return $insert_id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update custom field
|
||||
* @param mixed $data All $_POST data
|
||||
* @return boolean
|
||||
*/
|
||||
public function update($data, $id, $playground = false) {
|
||||
$original_field = $this->get($id, $playground);
|
||||
if (isset($data['disabled'])) {
|
||||
$data['active'] = 0;
|
||||
unset($data['disabled']);
|
||||
} else {
|
||||
$data['active'] = 1;
|
||||
}
|
||||
if (isset($data['disalow_client_to_edit'])) {
|
||||
$data['disalow_client_to_edit'] = 1;
|
||||
} else {
|
||||
$data['disalow_client_to_edit'] = 0;
|
||||
}
|
||||
if (isset($data['only_admin'])) {
|
||||
$data['only_admin'] = 1;
|
||||
} else {
|
||||
$data['only_admin'] = 0;
|
||||
}
|
||||
if (isset($data['required'])) {
|
||||
$data['required'] = 1;
|
||||
} else {
|
||||
$data['required'] = 0;
|
||||
}
|
||||
if (isset($data['show_on_pdf'])) {
|
||||
if (in_array($data['fieldto'], $this->pdf_fields)) {
|
||||
$data['show_on_pdf'] = 1;
|
||||
} else {
|
||||
$data['show_on_pdf'] = 0;
|
||||
}
|
||||
} else {
|
||||
$data['show_on_pdf'] = 0;
|
||||
}
|
||||
if ($data['field_order'] == '') {
|
||||
$data['field_order'] = 0;
|
||||
}
|
||||
if (isset($data['show_on_client_portal'])) {
|
||||
if (in_array($data['fieldto'], $this->client_portal_fields)) {
|
||||
$data['show_on_client_portal'] = 1;
|
||||
} else {
|
||||
$data['show_on_client_portal'] = 0;
|
||||
}
|
||||
} else {
|
||||
$data['show_on_client_portal'] = 0;
|
||||
}
|
||||
if (isset($data['show_on_table'])) {
|
||||
$data['show_on_table'] = 1;
|
||||
} else {
|
||||
$data['show_on_table'] = 0;
|
||||
}
|
||||
if (!isset($data['display_inline'])) {
|
||||
$data['display_inline'] = 0;
|
||||
}
|
||||
if (!isset($data['show_on_ticket_form'])) {
|
||||
$data['show_on_ticket_form'] = 0;
|
||||
}
|
||||
if ($data['fieldto'] == 'company') {
|
||||
$data['show_on_pdf'] = 1;
|
||||
$data['show_on_client_portal'] = 1;
|
||||
$data['show_on_table'] = 1;
|
||||
$data['only_admin'] = 0;
|
||||
$data['disalow_client_to_edit'] = 0;
|
||||
} else if ($data['fieldto'] == 'items') {
|
||||
$data['show_on_pdf'] = 1;
|
||||
$data['show_on_client_portal'] = 1;
|
||||
$data['show_on_table'] = 1;
|
||||
$data['only_admin'] = 0;
|
||||
$data['disalow_client_to_edit'] = 0;
|
||||
}
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'customfields', $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Custom Field Updated [' . $data['name'] . ']');
|
||||
if ($data['type'] == 'checkbox' || $data['type'] == 'select' || $data['type'] == 'multiselect') {
|
||||
if (trim($data['options']) != trim($original_field->options)) {
|
||||
$options_now = explode(',', $data['options']);
|
||||
foreach ($options_now as $key => $val) {
|
||||
$options_now[$key] = trim($val);
|
||||
}
|
||||
$options_before = explode(',', $original_field->options);
|
||||
foreach ($options_before as $key => $val) {
|
||||
$options_before[$key] = trim($val);
|
||||
}
|
||||
$removed_options_in_use = [];
|
||||
foreach ($options_before as $option) {
|
||||
if (!in_array($option, $options_now) && total_rows(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues', ['fieldid' => $id, 'value' => $option, ])) {
|
||||
array_push($removed_options_in_use, $option);
|
||||
}
|
||||
}
|
||||
if (count($removed_options_in_use) > 0) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'customfields', ['options' => implode(',', $options_now) . ',' . implode(',', $removed_options_in_use), ]);
|
||||
return ['cant_change_option_custom_field' => true, ];
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer
|
||||
* @return boolean
|
||||
* Delete Custom fields
|
||||
* All values for this custom field will be deleted from database
|
||||
*/
|
||||
public function delete($id, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'customfields');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
// Delete the values
|
||||
$this->db->where('fieldid', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues');
|
||||
log_activity('Custom Field Deleted [' . $id . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function get_custom_data($data, $custom_field_type, $id = '', $is_invoice_item = false, $playground = 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() . ($playground ? 'playground_' : '') . 'customfields')->result_array();
|
||||
$customfields = [];
|
||||
if ('' === $id) {
|
||||
foreach ($data as $data_key => $value) {
|
||||
$data[$data_key]['customfields'] = [];
|
||||
$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] = new StdClass();
|
||||
$customfields[$key]->label = $field['name'];
|
||||
if ('items' == $custom_field_type && !$is_invoice_item) {
|
||||
$custom_field_type = 'items_pr';
|
||||
$value_id = $value['itemid'] ?? $value['id'];
|
||||
}
|
||||
$customfields[$key]->value = $this->custom_fields_model->get_custom_field_value($value_id, $field['id'], $custom_field_type, false, $playground);
|
||||
}
|
||||
$data[$data_key]['customfields'] = $customfields;
|
||||
}
|
||||
}
|
||||
if ('' !== $id && is_numeric($id)) {
|
||||
$data->customfields = new StdClass();
|
||||
foreach ($fields as $key => $field) {
|
||||
$customfields[$key] = new StdClass();
|
||||
$customfields[$key]->label = $field['name'];
|
||||
if ('items' == $custom_field_type && !$is_invoice_item) {
|
||||
$custom_field_type = 'items_pr';
|
||||
}
|
||||
$customfields[$key]->value = $this->custom_fields_model->get_custom_field_value($id, $field['id'], $custom_field_type, false, $playground);
|
||||
}
|
||||
$data->customfields = $customfields;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change custom field status / active / inactive
|
||||
* @param mixed $id customfield id
|
||||
* @param integer $status active or inactive
|
||||
*/
|
||||
public function change_custom_field_status($id, $status, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'customfields', ['active' => $status, ]);
|
||||
log_activity('Custom Field Status Changed [FieldID: ' . $id . ' - Active: ' . $status . ']');
|
||||
}
|
||||
|
||||
public function get_relation_data_api($type, $search = '', $playground = false)
|
||||
{
|
||||
$q = '';
|
||||
if ('' != $search) {
|
||||
$q = $search;
|
||||
$q = trim(urldecode($q));
|
||||
}
|
||||
$this->load->model('clients_model');
|
||||
$this->load->model('misc_model');
|
||||
$this->load->model('payment_modes_model');
|
||||
$data = [];
|
||||
if ('customer' == $type || 'customers' == $type) {
|
||||
$where_clients = db_prefix() . ($playground ? 'playground_' : '') . 'clients.active=1';
|
||||
|
||||
if ($q) {
|
||||
$where_clients .= ' AND (';
|
||||
$where_clients .= 'company LIKE "%'.$q.'%" OR CONCAT(firstname, " ", lastname) LIKE "%'.$q.'%" OR email LIKE "%'.$q.'%"';
|
||||
|
||||
$fields = $this->get_custom_fields('customers', [], false, $playground);
|
||||
foreach ($fields as $key => $value) {
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues as ctable_'.$key.'', db_prefix() . ($playground ? 'playground_' : '') . '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 .= ')';
|
||||
}
|
||||
$data = $this->clients_model->get('', $where_clients);
|
||||
} else if ('contacts' == $type) {
|
||||
$where_clients = db_prefix() . ($playground ? 'playground_' : '') . 'clients.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 = $this->get_custom_fields('contacts', [], false, $playground);
|
||||
foreach ($fields as $key => $value) {
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues as ctable_'.$key.'', db_prefix() . ($playground ? 'playground_' : '') . '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() . ($playground ? 'playground_' : '') . 'clients.active = 1';
|
||||
}
|
||||
|
||||
$this->db->select('contacts.id AS id,clients.*,contacts.*');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'clients', ''.db_prefix() . ($playground ? 'playground_' : '') . 'contacts.userid = '.db_prefix() . ($playground ? 'playground_' : '') . 'clients.userid', 'left');
|
||||
|
||||
$data = $this->clients_model->get_contacts('', $where_clients, [], $playground);
|
||||
// echo $this->db->last_query();
|
||||
} else if ('ticket' == $type) {
|
||||
$search = $this->_search_tickets($q, 0, true, $playground);
|
||||
$data = $search['result'];
|
||||
} else if ('lead' == $type || 'leads' == $type) {
|
||||
$search = $this->_search_leads($q, 0, ['junk' => 0,], true, $playground);
|
||||
$data = $search['result'];
|
||||
} else if ('invoice' == $type || 'invoices' == $type) {
|
||||
$search = $this->_search_invoices($q, 0, [], true, $playground);
|
||||
$data = $search['result'];
|
||||
} else if ('invoice_items' == $type) {
|
||||
$fields = $this->get_custom_fields('items', [], false, $playground);
|
||||
$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() . ($playground ? 'playground_' : '') . 'customfieldsvalues as ctable_'.$key.'', db_prefix() . ($playground ? 'playground_' : '') . '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() . ($playground ? 'playground_' : '') . '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;
|
||||
} else if ('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->misc_model->search_projects($q, 0, $where_projects, $this->input->post('rel_type'), $playground);
|
||||
$data = $search['result'];
|
||||
} else if ('staff' == $type) {
|
||||
$search = $this->misc_model->search_staff($q, 0, $playground);
|
||||
$data = $search['result'];
|
||||
} else if ('tasks' == $type) {
|
||||
$search = $this->misc_model->search_tasks($q, 0, $playground);
|
||||
$data = $search['result'];
|
||||
} else if ('payments' == $type) {
|
||||
$search = $this->payment_modes_model->search($q, 0, $playground);
|
||||
$data = $search['result'];
|
||||
} else if ('proposals' == $type) {
|
||||
$search = $this->misc_model->search_proposals($q, 0, $playground);
|
||||
$data = $search['result'];
|
||||
} else if ('estimates' == $type) {
|
||||
$search = $this->misc_model->search_estimates($q, 0, $playground);
|
||||
$data = $search['result'];
|
||||
} else if ('expenses' == $type) {
|
||||
$search = $this->misc_model->search_expenses($q, 0, $playground);
|
||||
$data = $search['result'];
|
||||
} else if ('creditnotes' == $type) {
|
||||
$search = $this->misc_model->search_credit_notes($q, 0, $playground);
|
||||
$data = $search['result'];
|
||||
} else if ('milestones' == $type) {
|
||||
$where_milestones = '';
|
||||
if ($q) {
|
||||
$where_milestones .= '(name LIKE "%'.$q.'%" OR id LIKE "%'.$q.'%")';
|
||||
}
|
||||
$data = $this->misc_model->get_milestones('', $where_milestones, $playground);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for custom fields, update on $_POST
|
||||
* @param mixed $rel_id the main ID from the table
|
||||
* @param array $custom_fields all custom fields with id and values
|
||||
* @return boolean
|
||||
*/
|
||||
public function handle_custom_fields_post($rel_id, $custom_fields, $is_cf_items = false, $playground = false)
|
||||
{
|
||||
$affectedRows = 0;
|
||||
|
||||
foreach ($custom_fields as $key => $fields) {
|
||||
foreach ($fields as $field_id => $field_value) {
|
||||
$this->db->where('relid', $rel_id);
|
||||
$this->db->where('fieldid', $field_id);
|
||||
$this->db->where('fieldto', ($is_cf_items ? 'items_pr' : $key));
|
||||
$row = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues')->row();
|
||||
if (!is_array($field_value)) {
|
||||
$field_value = trim($field_value);
|
||||
}
|
||||
// Make necessary checkings for fields
|
||||
if (!defined('COPY_CUSTOM_FIELDS_LIKE_HANDLE_POST')) {
|
||||
$this->db->where('id', $field_id);
|
||||
$field_checker = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'customfields')->row();
|
||||
if ($field_checker->type == 'date_picker') {
|
||||
$field_value = to_sql_date($field_value);
|
||||
} else if ($field_checker->type == 'date_picker_time') {
|
||||
$field_value = to_sql_date($field_value, true);
|
||||
} else if ($field_checker->type == 'textarea') {
|
||||
$field_value = nl2br($field_value);
|
||||
} else if ($field_checker->type == 'checkbox' || $field_checker->type == 'multiselect') {
|
||||
if ($field_checker->disalow_client_to_edit == 1 && is_client_logged_in()) {
|
||||
continue;
|
||||
}
|
||||
if (is_array($field_value)) {
|
||||
$v = 0;
|
||||
foreach ($field_value as $chk) {
|
||||
if ($chk == 'cfk_hidden') {
|
||||
unset($field_value[$v]);
|
||||
}
|
||||
$v++;
|
||||
}
|
||||
$field_value = implode(', ', $field_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($row) {
|
||||
$this->db->where('id', $row->id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues', [
|
||||
'value' => $field_value,
|
||||
]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$affectedRows++;
|
||||
}
|
||||
} else {
|
||||
if ($field_value != '') {
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues', [
|
||||
'relid' => $rel_id,
|
||||
'fieldid' => $field_id,
|
||||
'fieldto' => $is_cf_items ? 'items_pr' : $key,
|
||||
'value' => $field_value,
|
||||
]);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
$affectedRows++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($affectedRows > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom fields
|
||||
* @param string $field_to
|
||||
* @param array $where
|
||||
* @param boolean $exclude_only_admin
|
||||
* @return array
|
||||
*/
|
||||
public function get_custom_fields($field_to, $where = [], $exclude_only_admin = false, $playground = false)
|
||||
{
|
||||
$is_admin = is_admin();
|
||||
|
||||
$this->db->where('fieldto', $field_to);
|
||||
if ((is_array($where) && count($where) > 0) || (!is_array($where) && $where != '')) {
|
||||
$this->db->where($where);
|
||||
}
|
||||
if (!$is_admin || $exclude_only_admin == true) {
|
||||
$this->db->where('only_admin', 0);
|
||||
}
|
||||
$this->db->where('active', 1);
|
||||
$this->db->order_by('field_order', 'asc');
|
||||
$results = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'customfields')->result_array();
|
||||
foreach ($results as $key => $result) {
|
||||
$results[$key]['name'] = _maybe_translate_custom_field_name(e($result['name']), $result['slug']);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom field value
|
||||
* @param mixed $rel_id the main ID from the table, e.q. the customer id, invoice id
|
||||
* @param mixed $field_id_or_slug field id, the custom field ID or custom field slug
|
||||
* @param string $field_to belongs to e.q leads, customers, staff
|
||||
* @param string $format format date values
|
||||
* @return string
|
||||
*/
|
||||
public function get_custom_field_value($rel_id, $field_id_or_slug, $field_to, $format = true, $playground = false)
|
||||
{
|
||||
$this->db->select(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues.value,' . db_prefix() . ($playground ? 'playground_' : '') . 'customfields.type');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'customfields', db_prefix() . ($playground ? 'playground_' : '') . 'customfields.id=' . db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues.fieldid');
|
||||
$this->db->where(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues.relid', $rel_id);
|
||||
if (is_numeric($field_id_or_slug)) {
|
||||
$this->db->where(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues.fieldid', $field_id_or_slug);
|
||||
} else {
|
||||
$this->db->where(db_prefix() . ($playground ? 'playground_' : '') . 'customfields.slug', $field_id_or_slug);
|
||||
}
|
||||
$this->db->where(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues.fieldto', $field_to);
|
||||
$row = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues')->row();
|
||||
|
||||
$result = '';
|
||||
if ($row) {
|
||||
$result = $row->value;
|
||||
if ($format == true) {
|
||||
if ($row->type == 'date_picker') {
|
||||
$result = _d($result);
|
||||
} elseif ($row->type == 'date_picker_time') {
|
||||
$result = _dt($result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return field where Shown on PDF is allowed
|
||||
* @return array
|
||||
*/
|
||||
public function get_pdf_allowed_fields() {
|
||||
return $this->pdf_fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return fields where Show on customer portal is allowed
|
||||
* @return array
|
||||
*/
|
||||
public function get_client_portal_allowed_fields() {
|
||||
return $this->client_portal_fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return fields where are editable in customers area
|
||||
* @return array
|
||||
*/
|
||||
public function get_client_editable_fields() {
|
||||
return $this->client_editable_fields;
|
||||
}
|
||||
}
|
||||
166
api/models/Departments_model.php
Normal file
166
api/models/Departments_model.php
Normal file
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Departments_model extends App_Model {
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer ID (optional)
|
||||
* @param boolean (optional)
|
||||
* @return mixed
|
||||
* Get department object based on passed id if not passed id return array of all departments
|
||||
* Second parameter is to check if the request is coming from clientarea, so if any departments are hidden from client to exclude
|
||||
*/
|
||||
public function get($id = false, $clientarea = false, $playground = false) {
|
||||
if ($clientarea == true) {
|
||||
$this->db->where('hidefromclient', 0);
|
||||
}
|
||||
if (is_numeric($id)) {
|
||||
$this->db->where('departmentid', $id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'departments')->row();
|
||||
}
|
||||
$departments = $this->app_object_cache->get('departments');
|
||||
if (!$departments && !is_array($departments)) {
|
||||
$departments = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'departments')->result_array();
|
||||
$this->app_object_cache->add('departments', $departments);
|
||||
}
|
||||
return $departments;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $_POST data
|
||||
* @return integer
|
||||
* Add new department
|
||||
*/
|
||||
public function add($data, $playground = false) {
|
||||
if (isset($data['hidefromclient'])) {
|
||||
$data['hidefromclient'] = 1;
|
||||
} else {
|
||||
$data['hidefromclient'] = 0;
|
||||
}
|
||||
if (!empty($data['password'])) {
|
||||
$data['password'] = $this->encryption->encrypt($data['password']);
|
||||
}
|
||||
if (!isset($data['encryption'])) {
|
||||
$data['encryption'] = '';
|
||||
}
|
||||
if (!isset($data['delete_after_import'])) {
|
||||
$data['delete_after_import'] = 0;
|
||||
} else {
|
||||
$data['delete_after_import'] = 1;
|
||||
}
|
||||
$data = hooks()->apply_filters('before_department_added', $data);
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'departments', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
hooks()->do_action('after_department_added', $insert_id);
|
||||
log_activity('New Department Added [' . $data['name'] . ', ID: ' . $insert_id . ']');
|
||||
}
|
||||
return $insert_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $_POST data
|
||||
* @param integer ID
|
||||
* @return boolean
|
||||
* Update department to database
|
||||
*/
|
||||
public function update($data, $id, $playground = false) {
|
||||
$dep_original = $this->get($id);
|
||||
if (!$dep_original) {
|
||||
return false;
|
||||
}
|
||||
if (!isset($data['encryption'])) {
|
||||
$data['encryption'] = '';
|
||||
}
|
||||
if (!isset($data['delete_after_import'])) {
|
||||
$data['delete_after_import'] = 0;
|
||||
} else {
|
||||
$data['delete_after_import'] = 1;
|
||||
}
|
||||
if ($data['email'] == '') {
|
||||
$data['email'] = null;
|
||||
}
|
||||
if (isset($data['hidefromclient'])) {
|
||||
$data['hidefromclient'] = 1;
|
||||
} else {
|
||||
$data['hidefromclient'] = 0;
|
||||
}
|
||||
// Check if not empty $data['password']
|
||||
// Get original
|
||||
// Decrypt original
|
||||
// Compare with $data['password']
|
||||
// If equal unset
|
||||
// If not encrypt and save
|
||||
if (!empty($data['password'])) {
|
||||
$or_decrypted = $this->encryption->decrypt($dep_original->password);
|
||||
if ($or_decrypted == $data['password']) {
|
||||
unset($data['password']);
|
||||
} else {
|
||||
$data['password'] = $this->encryption->encrypt($data['password']);
|
||||
}
|
||||
}
|
||||
$data = hooks()->apply_filters('before_department_updated', $data, $id);
|
||||
$this->db->where('departmentid', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'departments', $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Department Updated [Name: ' . $data['name'] . ', ID: ' . $id . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer ID
|
||||
* @return mixed
|
||||
* Delete department from database, if used return array with key referenced
|
||||
*/
|
||||
public function delete($id, $playground = false) {
|
||||
$current = $this->get($id);
|
||||
if (is_reference_in_table('department', db_prefix() . ($playground ? 'playground_' : '') . 'tickets', $id)) {
|
||||
return ['referenced' => true, ];
|
||||
}
|
||||
hooks()->do_action('before_delete_department', $id);
|
||||
$this->db->where('departmentid', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'departments');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Department Deleted [ID: ' . $id . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer ID (option)
|
||||
* @param boolean (optional)
|
||||
* @return mixed
|
||||
* Get departments where staff belongs
|
||||
* If $onlyids passed return only departmentsID (simple array) if not returns array of all departments
|
||||
*/
|
||||
public function get_staff_departments($userid = false, $onlyids = false, $playground = false) {
|
||||
if ($userid == false) {
|
||||
$userid = get_staff_user_id();
|
||||
}
|
||||
if ($onlyids == false) {
|
||||
$this->db->select();
|
||||
} else {
|
||||
$this->db->select(db_prefix() . ($playground ? 'playground_' : '') . 'staff_departments.departmentid');
|
||||
}
|
||||
$this->db->from(db_prefix() . ($playground ? 'playground_' : '') . 'staff_departments');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'departments', db_prefix() . ($playground ? 'playground_' : '') . 'staff_departments.departmentid = ' . db_prefix() . ($playground ? 'playground_' : '') . 'departments.departmentid', 'left');
|
||||
$this->db->where('staffid', $userid);
|
||||
$departments = $this->db->get()->result_array();
|
||||
if ($onlyids == true) {
|
||||
$departmentsid = [];
|
||||
foreach ($departments as $department) {
|
||||
array_push($departmentsid, $department['departmentid']);
|
||||
}
|
||||
return $departmentsid;
|
||||
}
|
||||
return $departments;
|
||||
}
|
||||
}
|
||||
38
api/models/Email_schedule_model.php
Normal file
38
api/models/Email_schedule_model.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Email_schedule_model extends App_Model {
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function create($rel_id, $rel_type, $data, $playground = false) {
|
||||
$contacts = $data['contacts'];
|
||||
if (is_array($contacts)) {
|
||||
$contacts = implode(',', $contacts);
|
||||
}
|
||||
$this->db->insert(($playground ? 'playground_' : '') . 'scheduled_emails', ['rel_type' => $rel_type, 'rel_id' => $rel_id, 'scheduled_at' => $data['scheduled_at'], 'contacts' => $contacts, 'cc' => $data['cc'], 'attach_pdf' => $data['attach_pdf'], 'template' => $data['template'], ]);
|
||||
}
|
||||
|
||||
public function update($id, $data, $playground = false) {
|
||||
if (is_array($data['contacts'])) {
|
||||
$data['contacts'] = implode(',', $data['contacts']);
|
||||
}
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(($playground ? 'playground_' : '') . 'scheduled_emails', $data);
|
||||
return $this->db->affected_rows() > 0;
|
||||
}
|
||||
|
||||
public function getById($id, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
return $this->db->get(($playground ? 'playground_' : '') . 'scheduled_emails')->row();
|
||||
}
|
||||
|
||||
public function get($rel_id, $rel_type, $playground = false) {
|
||||
$this->db->where('rel_id', $rel_id);
|
||||
$this->db->where('rel_type', $rel_type);
|
||||
return $this->db->get(($playground ? 'playground_' : '') . 'scheduled_emails')->row();
|
||||
}
|
||||
}
|
||||
380
api/models/Estimate_request_model.php
Normal file
380
api/models/Estimate_request_model.php
Normal file
@@ -0,0 +1,380 @@
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Estimate_request_model extends App_Model {
|
||||
public const STATUS_PROCESSING = 2;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function update_request_assigned($data, $playground = false) {
|
||||
$this->db->select('assigned');
|
||||
$this->db->where('id', $data['requestid']);
|
||||
$_old_assigned = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_requests')->row();
|
||||
$this->db->where('id', $data['requestid']);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_requests', ['assigned' => $data['assigned'], ]);
|
||||
$this->db->select('assigned');
|
||||
$this->db->where('id', $data['requestid']);
|
||||
$_current_assigned = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_requests')->row();
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
if ($_current_assigned != $_old_assigned && $_old_assigned != '') {
|
||||
hooks()->do_action('estimate_request_assigned_changed', ['estimate_request_id' => $data['requestid'], 'old_staff' => $_old_assigned, 'new_staff' => $_current_assigned, ]);
|
||||
$this->load->model('staff_model');
|
||||
log_activity(sprintf('Estimate Request Assigned to %s', $this->staff_model->get_staff_full_name($_current_assigned->assigned, $playground)) . ' [ID: ' . $data['requestid'] . ']');
|
||||
}
|
||||
if ($_current_assigned == $_old_assigned) {
|
||||
return false;
|
||||
}
|
||||
$this->assigned_member_notification($data['requestid'], $_current_assigned->assigned, $playground);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function update_request_status($data, $playground = false) {
|
||||
$this->db->select('status');
|
||||
$this->db->where('id', $data['requestid']);
|
||||
$_old = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_requests')->row();
|
||||
$old_status = '';
|
||||
if ($_old) {
|
||||
$old_status = $this->get_status($_old->status, $playground);
|
||||
if ($old_status) {
|
||||
$old_status = $old_status->name;
|
||||
}
|
||||
}
|
||||
$affectedRows = 0;
|
||||
$current_status = $this->get_status($data['status'], $playground)->name;
|
||||
$this->db->where('id', $data['requestid']);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_requests', ['status' => $data['status'], ]);
|
||||
$_log_message = '';
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$affectedRows++;
|
||||
if ($current_status != $old_status && $old_status != '') {
|
||||
$_log_message = 'not_estimate_request_activity_status_updated';
|
||||
$this->load->model('staff_model');
|
||||
$additional_data = serialize([$this->staff_model->get_staff_full_name('', $playground), $old_status, $current_status, ]);
|
||||
hooks()->do_action('estimate_request_status_changed', ['estimate_request_id' => $data['requestid'], 'old_status' => $old_status, 'new_status' => $current_status, ]);
|
||||
}
|
||||
}
|
||||
if ($affectedRows > 0) {
|
||||
if ($_log_message == '') {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get estimate_request
|
||||
*
|
||||
* @param string $id Optional - estimate_requestid
|
||||
* @param mixed $where
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($id = '', $where = [], $playground = false) {
|
||||
$this->db->select('*,' . db_prefix() . ($playground ? 'playground_' : '') . 'estimate_requests.id,' . db_prefix() . ($playground ? 'playground_' : '') . 'estimate_request_status.name as status_name');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_request_status', db_prefix() . ($playground ? 'playground_' : '') . 'estimate_request_status.id=' . db_prefix() . ($playground ? 'playground_' : '') . 'estimate_requests.status', 'left');
|
||||
$this->db->where($where);
|
||||
if (is_numeric($id)) {
|
||||
$this->db->where(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_requests.id', $id);
|
||||
$request = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_requests')->row();
|
||||
if ($request) {
|
||||
if ($request->from_form_id != 0) {
|
||||
$request->form_data = $this->get_form(['id' => $request->from_form_id, ], $playground);
|
||||
}
|
||||
$request->attachments = $this->get_estimate_request_attachments($id, $playground);
|
||||
}
|
||||
return $request;
|
||||
}
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_requests')->result_array();
|
||||
}
|
||||
|
||||
public function get_forms($playground = false) {
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_request_forms')->result_array();
|
||||
}
|
||||
|
||||
public function get_form($where, $playground = false) {
|
||||
$this->db->where($where);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_request_forms')->row();
|
||||
}
|
||||
|
||||
public function add_form($data) {
|
||||
$data = $this->_do_estimate_request_form_responsibles($data);
|
||||
$data['success_submit_msg'] = nl2br($data['success_submit_msg']);
|
||||
$data['form_key'] = app_generate_hash();
|
||||
$data['dateadded'] = date('Y-m-d H:i:s');
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_request_forms', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
log_activity('New Estimate Request Form Added [' . $data['name'] . ']');
|
||||
return $insert_id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function update_form($id, $data, $playground = false) {
|
||||
$data = $this->_do_estimate_request_form_responsibles($data, $playground);
|
||||
$data['success_submit_msg'] = nl2br($data['success_submit_msg']);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_request_forms', $data);
|
||||
return $this->db->affected_rows() > 0 ? true : false;
|
||||
}
|
||||
|
||||
public function delete_form($id, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_request_forms');
|
||||
$this->db->where('from_form_id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_requests', ['from_form_id' => 0, ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Estimate Request Form Deleted [' . $id . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private function _do_estimate_request_form_responsibles($data, $playground = false) {
|
||||
if (isset($data['notify_request_submitted'])) {
|
||||
$data['notify_request_submitted'] = 1;
|
||||
} else {
|
||||
$data['notify_request_submitted'] = 0;
|
||||
}
|
||||
if ($data['responsible'] == '') {
|
||||
$data['responsible'] = 0;
|
||||
}
|
||||
if ($data['notify_request_submitted'] != 0) {
|
||||
if ($data['notify_type'] == 'specific_staff') {
|
||||
if (isset($data['notify_ids_staff'])) {
|
||||
$data['notify_ids'] = serialize($data['notify_ids_staff']);
|
||||
unset($data['notify_ids_staff']);
|
||||
} else {
|
||||
$data['notify_ids'] = serialize([]);
|
||||
unset($data['notify_ids_staff']);
|
||||
}
|
||||
if (isset($data['notify_ids_roles'])) {
|
||||
unset($data['notify_ids_roles']);
|
||||
}
|
||||
} else {
|
||||
if (isset($data['notify_ids_roles'])) {
|
||||
$data['notify_ids'] = serialize($data['notify_ids_roles']);
|
||||
unset($data['notify_ids_roles']);
|
||||
} else {
|
||||
$data['notify_ids'] = serialize([]);
|
||||
unset($data['notify_ids_roles']);
|
||||
}
|
||||
if (isset($data['notify_ids_staff'])) {
|
||||
unset($data['notify_ids_staff']);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$data['notify_ids'] = serialize([]);
|
||||
$data['notify_type'] = null;
|
||||
if (isset($data['notify_ids_staff'])) {
|
||||
unset($data['notify_ids_staff']);
|
||||
}
|
||||
if (isset($data['notify_ids_roles'])) {
|
||||
unset($data['notify_ids_roles']);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete estimate request from database and all connections
|
||||
*
|
||||
* @param mixed $id estimate request id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete($id, $playground = false) {
|
||||
$affectedRows = 0;
|
||||
hooks()->do_action('before_estimate_request_deleted', $id);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_requests');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$this->load->model('staff_model');
|
||||
log_activity('Estimate Request Deleted [Deleted by: ' . $this->staff_model->get_staff_full_name('', $playground) . ', ID: ' . $id . ']');
|
||||
$attachments = $this->get_estimate_request_attachments($id, $playground);
|
||||
foreach ($attachments as $attachment) {
|
||||
$this->delete_estimate_request_attachment($attachment['id'], $playground);
|
||||
}
|
||||
// Delete the tags
|
||||
$this->db->where('rel_type', 'estimate_request');
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'taggables');
|
||||
$affectedRows++;
|
||||
}
|
||||
return $affectedRows > 0;
|
||||
}
|
||||
|
||||
// Statuses
|
||||
|
||||
/**
|
||||
* Get estimate_request statuses
|
||||
*
|
||||
* @param mixed $id status id
|
||||
* @param mixed $where
|
||||
*
|
||||
* @return mixed object if id passed else array
|
||||
*/
|
||||
public function get_status($id = '', $where = [], $playground = false) {
|
||||
$this->db->where($where);
|
||||
if (is_numeric($id)) {
|
||||
$this->db->where('id', $id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_request_status')->row();
|
||||
}
|
||||
$statuses = $this->app_object_cache->get('estimate-request-all-statuses');
|
||||
if (!$statuses) {
|
||||
$this->db->order_by('statusorder', 'asc');
|
||||
$statuses = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_request_status')->result_array();
|
||||
$this->app_object_cache->add('estimate-request-all-statuses', $statuses);
|
||||
}
|
||||
return $statuses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new estimate_request status
|
||||
*
|
||||
* @param array $data estimate_request status data
|
||||
*/
|
||||
public function add_status($data, $playground = false) {
|
||||
if (isset($data['color']) && $data['color'] == '') {
|
||||
$data['color'] = hooks()->apply_filters('default_estimate_request_status_color', '#757575');
|
||||
}
|
||||
if (!isset($data['statusorder'])) {
|
||||
$data['statusorder'] = total_rows(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_request_status') + 1;
|
||||
}
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_request_status', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
log_activity('New Estimate Request Status Added [StatusID: ' . $insert_id . ', Name: ' . $data['name'] . ']');
|
||||
return $insert_id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update statuses
|
||||
*
|
||||
* @param mixed $data
|
||||
* @param mixed $id
|
||||
*/
|
||||
public function update_status($data, $id, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_request_status', $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Estimate Request Status Updated [StatusID: ' . $id . ', Name: ' . $data['name'] . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete estimate_request status from database
|
||||
*
|
||||
* @param mixed $id status id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete_status($id, $playground = false) {
|
||||
$current = $this->get_status($id, $playground);
|
||||
// Check if is already using in table
|
||||
if (is_reference_in_table('status', db_prefix() . ($playground ? 'playground_' : '') . 'estimate_requests', $id)) {
|
||||
return ['referenced' => true, ];
|
||||
}
|
||||
if ($current->flag != '') {
|
||||
return ['flag' => true, ];
|
||||
}
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_request_status');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Estimate Request Status Deleted [StatusID: ' . $id . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get estimate_request attachments
|
||||
*
|
||||
* @param mixed $id estimate_request id
|
||||
* @param mixed $attachment_id
|
||||
* @param mixed $where
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since Version 1.0.4
|
||||
*/
|
||||
public function get_estimate_request_attachments($id = '', $attachment_id = '', $where = [], $playground = false) {
|
||||
$this->db->where($where);
|
||||
$idIsHash = !is_numeric($attachment_id) && strlen($attachment_id) == 32;
|
||||
if (is_numeric($attachment_id) || $idIsHash) {
|
||||
$this->db->where($idIsHash ? 'attachment_key' : 'id', $attachment_id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'files')->row();
|
||||
}
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->where('rel_type', 'estimate_request');
|
||||
$this->db->order_by('dateadded', 'DESC');
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'files')->result_array();
|
||||
}
|
||||
|
||||
public function add_attachment_to_database($estimate_request_id, $attachment, $external = false, $playground = false) {
|
||||
$this->load->model('misc_model');
|
||||
$this->misc_model->add_attachment_to_database($estimate_request_id, 'estimate_request', $attachment, $external, $playground);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete estimate_request attachment
|
||||
*
|
||||
* @param mixed $id attachment id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete_estimate_request_attachment($id, $playground = false) {
|
||||
$attachment = $this->get_estimate_request_attachments('', $id, $playground);
|
||||
$deleted = false;
|
||||
$this->load->model('misc_model');
|
||||
if ($attachment) {
|
||||
if (empty($attachment->external)) {
|
||||
unlink($this->misc_model->get_upload_path_by_type('estimate_request', $playground) . $attachment->rel_id . '/' . $attachment->file_name);
|
||||
}
|
||||
$this->db->where('id', $attachment->id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'files');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$deleted = true;
|
||||
log_activity('Estima Request Attachment Deleted [ID: ' . $attachment->rel_id . ']');
|
||||
}
|
||||
if (is_dir($this->misc_model->get_upload_path_by_type('estimate_request') . $attachment->rel_id)) {
|
||||
// Check if no attachments left, so we can delete the folder also
|
||||
$other_attachments = list_files($this->misc_model->get_upload_path_by_type('estimate_request', $playground) . $attachment->rel_id);
|
||||
if (count($other_attachments) == 0) {
|
||||
// okey only index.html so we can delete the folder also
|
||||
delete_dir($this->misc_model->get_upload_path_by_type('estimate_request', $playground) . $attachment->rel_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
public function assigned_member_notification($estimate_request_id, $assigned, $playground = false) {
|
||||
if ((!empty($assigned) && $assigned != 0)) {
|
||||
$notified = add_notification(['description' => 'estimate_request_assigned_to_staff', 'touserid' => $assigned, 'additional_data' => serialize([]), 'link' => 'estimate_request/view/' . $estimate_request_id, ], $playground);
|
||||
if ($notified) {
|
||||
pusher_trigger_notification([$assigned]);
|
||||
}
|
||||
$this->db->select('email');
|
||||
$this->db->where('staffid', $assigned);
|
||||
$email = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'staff')->row()->email;
|
||||
send_mail_template('estimate_request_assigned', $estimate_request_id, $email);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function get_status_by_flag($flag, $playground = false) {
|
||||
$this->db->where('flag', $flag);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_request_status')->row();
|
||||
}
|
||||
}
|
||||
1054
api/models/Estimates_model.php
Normal file
1054
api/models/Estimates_model.php
Normal file
File diff suppressed because it is too large
Load Diff
658
api/models/Expenses_model.php
Normal file
658
api/models/Expenses_model.php
Normal file
@@ -0,0 +1,658 @@
|
||||
<?php
|
||||
|
||||
use app\services\utilities\Arr;
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Expenses_model extends App_Model {
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->load->model('clients_model');
|
||||
$this->load->model('currencies_model');
|
||||
$this->load->model('invoices_model');
|
||||
$this->load->model('payment_modes_model');
|
||||
$this->load->model('projects_model');
|
||||
$this->load->model('tasks_model');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get expense(s)
|
||||
* @param mixed $id Optional expense id
|
||||
* @return mixed object or array
|
||||
*/
|
||||
public function get($id = '', $where = [], $playground = false) {
|
||||
$this->db->select('*,' . db_prefix() . ($playground ? 'playground_' : '') . 'expenses.id as id,' . db_prefix() . ($playground ? 'playground_' : '') . 'expenses_categories.name as category_name,' . db_prefix() . ($playground ? 'playground_' : '') . 'payment_modes.name as payment_mode_name,' . db_prefix() . ($playground ? 'playground_' : '') . 'taxes.name as tax_name, ' . db_prefix() . ($playground ? 'playground_' : '') . 'taxes.taxrate as taxrate,' . db_prefix() . ($playground ? 'playground_' : '') . 'taxes_2.name as tax_name2, ' . db_prefix() . ($playground ? 'playground_' : '') . 'taxes_2.taxrate as taxrate2, ' . db_prefix() . ($playground ? 'playground_' : '') . 'expenses.id as expenseid,' . db_prefix() . ($playground ? 'playground_' : '') . 'expenses.addedfrom as addedfrom, recurring_from');
|
||||
$this->db->from(db_prefix() . ($playground ? 'playground_' : '') . 'expenses');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'clients', '' . db_prefix() . ($playground ? 'playground_' : '') . 'clients.userid = ' . db_prefix() . ($playground ? 'playground_' : '') . 'expenses.clientid', 'left');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'payment_modes', '' . db_prefix() . ($playground ? 'playground_' : '') . 'payment_modes.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'expenses.paymentmode', 'left');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'taxes', '' . db_prefix() . ($playground ? 'playground_' : '') . 'taxes.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'expenses.tax', 'left');
|
||||
$this->db->join('' . db_prefix() . ($playground ? 'playground_' : '') . 'taxes as ' . db_prefix() . ($playground ? 'playground_' : '') . 'taxes_2', '' . db_prefix() . ($playground ? 'playground_' : '') . 'taxes_2.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'expenses.tax2', 'left');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'expenses_categories', '' . db_prefix() . ($playground ? 'playground_' : '') . 'expenses_categories.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'expenses.category');
|
||||
$this->db->where($where);
|
||||
if (is_numeric($id)) {
|
||||
$this->db->where(db_prefix() . ($playground ? 'playground_' : '') . '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() . ($playground ? 'playground_' : '') . 'files')->row();
|
||||
if ($file) {
|
||||
$expense->attachment = $file->file_name;
|
||||
$expense->filetype = $file->filetype;
|
||||
$expense->attachment_added_from = $file->staffid;
|
||||
}
|
||||
$expense->currency_data = $this->projects_model->get_currency($expense->currency, $playground);
|
||||
if ($expense->project_id) {
|
||||
$expense->project_data = $this->projects_model->get($expense->project_id, $playground);
|
||||
}
|
||||
if (is_null($expense->payment_mode_name)) {
|
||||
// is online payment mode
|
||||
$payment_gateways = $this->payment_modes_model->get_payment_gateways(true, $playground);
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new expense
|
||||
* @param mixed $data All $_POST data
|
||||
* @return mixed
|
||||
*/
|
||||
public function add($data, $playground = false) {
|
||||
$data['date'] = to_sql_date($data['date']);
|
||||
$data['note'] = nl2br($data['note']);
|
||||
if (isset($data['billable'])) {
|
||||
$data['billable'] = 1;
|
||||
} else {
|
||||
$data['billable'] = 0;
|
||||
}
|
||||
if (isset($data['create_invoice_billable'])) {
|
||||
$data['create_invoice_billable'] = 1;
|
||||
} else {
|
||||
$data['create_invoice_billable'] = 0;
|
||||
}
|
||||
if (isset($data['custom_fields'])) {
|
||||
$custom_fields = $data['custom_fields'];
|
||||
unset($data['custom_fields']);
|
||||
}
|
||||
if (isset($data['send_invoice_to_customer'])) {
|
||||
$data['send_invoice_to_customer'] = 1;
|
||||
} else {
|
||||
$data['send_invoice_to_customer'] = 0;
|
||||
}
|
||||
if (isset($data['repeat_every']) && $data['repeat_every'] != '') {
|
||||
$data['recurring'] = 1;
|
||||
if ($data['repeat_every'] == 'custom') {
|
||||
$data['repeat_every'] = $data['repeat_every_custom'];
|
||||
$data['recurring_type'] = $data['repeat_type_custom'];
|
||||
$data['custom_recurring'] = 1;
|
||||
} else {
|
||||
$_temp = explode('-', $data['repeat_every']);
|
||||
$data['recurring_type'] = $_temp[1];
|
||||
$data['repeat_every'] = $_temp[0];
|
||||
$data['custom_recurring'] = 0;
|
||||
}
|
||||
} else {
|
||||
$data['recurring'] = 0;
|
||||
}
|
||||
unset($data['repeat_type_custom']);
|
||||
unset($data['repeat_every_custom']);
|
||||
if ((isset($data['project_id']) && $data['project_id'] == '') || !isset($data['project_id'])) {
|
||||
$data['project_id'] = 0;
|
||||
}
|
||||
$data['addedfrom'] = get_staff_user_id();
|
||||
$data['dateadded'] = date('Y-m-d H:i:s');
|
||||
$data = hooks()->apply_filters('before_expense_added', $data);
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'expenses', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
if (isset($custom_fields)) {
|
||||
$this->load->model('custom_fields_model');
|
||||
$this->custom_fields_model->handle_custom_fields_post($insert_id, $custom_fields, false, $playground);
|
||||
}
|
||||
if (isset($data['project_id']) && !empty($data['project_id'])) {
|
||||
$project_settings = $this->projects_model->get_project_settings($data['project_id'], $playground);
|
||||
$visible_activity = 0;
|
||||
foreach ($project_settings as $s) {
|
||||
if ($s['name'] == 'view_finance_overview') {
|
||||
if ($s['value'] == 1) {
|
||||
$visible_activity = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$expense = $this->get($insert_id);
|
||||
$activity_additional_data = $expense->name;
|
||||
$this->projects_model->log_activity($data['project_id'], 'project_activity_recorded_expense', $activity_additional_data, $visible_activity, $playground);
|
||||
}
|
||||
hooks()->do_action('after_expense_added', $insert_id);
|
||||
log_activity('New Expense Added [' . $insert_id . ']');
|
||||
return $insert_id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function get_child_expenses($id, $playground = false) {
|
||||
$this->db->select('id');
|
||||
$this->db->where('recurring_from', $id);
|
||||
$expenses = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'expenses')->result_array();
|
||||
$_expenses = [];
|
||||
foreach ($expenses as $expense) {
|
||||
$_expenses[] = $this->get($expense['id'], $playground);
|
||||
}
|
||||
return $_expenses;
|
||||
}
|
||||
|
||||
public function get_expenses_total($data, $playground = false) {
|
||||
$base_currency = $this->currencies_model->get_base_currency($playground, $playground)->id;
|
||||
$base = true;
|
||||
$currency_switcher = false;
|
||||
if (isset($data['currency'])) {
|
||||
$currencyid = $data['currency'];
|
||||
$currency_switcher = true;
|
||||
} else if (isset($data['customer_id']) && $data['customer_id'] != '') {
|
||||
$currencyid = $this->clients_model->get_customer_default_currency($data['customer_id'], $playground);
|
||||
if ($currencyid == 0) {
|
||||
$currencyid = $base_currency;
|
||||
} else {
|
||||
if (total_rows(db_prefix() . ($playground ? 'playground_' : '') . 'expenses', ['currency' => $base_currency, 'clientid' => $data['customer_id'], ])) {
|
||||
$currency_switcher = true;
|
||||
}
|
||||
}
|
||||
} else if (isset($data['project_id']) && $data['project_id'] != '') {
|
||||
$currencyid = $this->projects_model->get_currency($data['project_id'], $playground)->id;
|
||||
} else {
|
||||
$currencyid = $base_currency;
|
||||
if (total_rows(db_prefix() . ($playground ? 'playground_' : '') . 'expenses', ['currency !=' => $base_currency, ])) {
|
||||
$currency_switcher = true;
|
||||
}
|
||||
}
|
||||
$currency = $this->projects_model->get_currency($currencyid, $playground);
|
||||
$has_permission_view = staff_can('view', 'expenses');
|
||||
$_result = [];
|
||||
for ($i = 1;$i <= 5;$i++) {
|
||||
$this->db->select('amount,tax,tax2,invoiceid');
|
||||
$this->db->where('currency', $currencyid);
|
||||
if (isset($data['years']) && count($data['years']) > 0) {
|
||||
$this->db->where('YEAR(date) IN (' . implode(', ', array_map(function ($year) {
|
||||
return get_instance()->db->escape_str($year);
|
||||
}, $data['years'])) . ')');
|
||||
} else {
|
||||
$this->db->where('YEAR(date) = ' . date('Y'));
|
||||
}
|
||||
if (isset($data['customer_id']) && $data['customer_id'] != '') {
|
||||
$this->db->where('clientid', $data['customer_id']);
|
||||
}
|
||||
if (isset($data['project_id']) && $data['project_id'] != '') {
|
||||
$this->db->where('project_id', $data['project_id']);
|
||||
}
|
||||
if (!$has_permission_view) {
|
||||
$this->db->where('addedfrom', get_staff_user_id());
|
||||
}
|
||||
switch ($i) {
|
||||
case 1:
|
||||
$key = 'all';
|
||||
break;
|
||||
case 2:
|
||||
$key = 'billable';
|
||||
$this->db->where('billable', 1);
|
||||
break;
|
||||
case 3:
|
||||
$key = 'non_billable';
|
||||
$this->db->where('billable', 0);
|
||||
break;
|
||||
case 4:
|
||||
$key = 'billed';
|
||||
$this->db->where('billable', 1);
|
||||
$this->db->where('invoiceid IS NOT NULL');
|
||||
$this->db->where('invoiceid IN (SELECT invoiceid FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices WHERE status=2 AND id=' . db_prefix() . ($playground ? 'playground_' : '') . 'expenses.invoiceid)');
|
||||
break;
|
||||
case 5:
|
||||
$key = 'unbilled';
|
||||
$this->db->where('billable', 1);
|
||||
$this->db->where('invoiceid IS NULL');
|
||||
break;
|
||||
}
|
||||
$all_expenses = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'expenses')->result_array();
|
||||
$_total_all = [];
|
||||
$cached_taxes = [];
|
||||
foreach ($all_expenses as $expense) {
|
||||
$_total = $expense['amount'];
|
||||
if ($expense['tax'] != 0) {
|
||||
if (!isset($cached_taxes[$expense['tax']])) {
|
||||
$tax = get_tax_by_id($expense['tax']);
|
||||
$cached_taxes[$expense['tax']] = $tax;
|
||||
} else {
|
||||
$tax = $cached_taxes[$expense['tax']];
|
||||
}
|
||||
$_total+= ($_total / 100 * $tax->taxrate);
|
||||
}
|
||||
if ($expense['tax2'] != 0) {
|
||||
if (!isset($cached_taxes[$expense['tax2']])) {
|
||||
$tax = get_tax_by_id($expense['tax2']);
|
||||
$cached_taxes[$expense['tax2']] = $tax;
|
||||
} else {
|
||||
$tax = $cached_taxes[$expense['tax2']];
|
||||
}
|
||||
$_total+= ($expense['amount'] / 100 * $tax->taxrate);
|
||||
}
|
||||
array_push($_total_all, $_total);
|
||||
}
|
||||
$_result[$key]['total'] = app_format_money(array_sum($_total_all), $currency);
|
||||
}
|
||||
$_result['currency_switcher'] = $currency_switcher;
|
||||
$_result['currencyid'] = $currencyid;
|
||||
// All expenses
|
||||
/* $this->db->select('amount,tax');
|
||||
$this->db->where('currency', $currencyid);
|
||||
$this->db->select('amount, tax, invoiceid');
|
||||
$this->db->where('currency', $currencyid);
|
||||
$this->db->where('billable', 1);
|
||||
$this->db->where('invoiceid IS NOT NULL');
|
||||
$all_expenses = $this->db->get(db_prefix().'expenses')->result_array();
|
||||
$_total_all = array();
|
||||
foreach($all_expenses as $expense) {
|
||||
$_total = 0;
|
||||
if (total_rows(db_prefix(). 'invoices', array('status'=>2,'id'=>$expense['invoiceid'])) > 0) {
|
||||
$_total = $expense['amount'];
|
||||
if ($expense['tax'] != 0) {
|
||||
$tax = get_tax_by_id($expense['tax']);
|
||||
$_total += ($_total / 100 * $tax->taxrate);
|
||||
}
|
||||
}
|
||||
|
||||
array_push($_total_all,$_total);
|
||||
}
|
||||
|
||||
$_result['billed']['total'] = app_format_money(array_sum($_total_all), $currency);
|
||||
$this->db->select('amount,tax,invoiceid');
|
||||
$this->db->where('currency',$currencyid);
|
||||
$this->db->where('billable',1);
|
||||
$this->db->where('invoiceid IS NOT NULL');
|
||||
$all_expenses = $this->db->get(db_prefix().'expenses')->result_array();
|
||||
$_total_all = array();
|
||||
foreach($all_expenses as $expense) {
|
||||
$_total = 0;
|
||||
if (total_rows(db_prefix().'invoices','status NOT IN(2,5) AND id ='.$expense['invoiceid']) > 0) {
|
||||
echo $this->db->last_query();
|
||||
$_total = $expense['amount'];
|
||||
if ($expense['tax'] != 0) {
|
||||
$tax = get_tax_by_id($expense['tax']);
|
||||
$_total += ($_total / 100 * $tax->taxrate);
|
||||
}
|
||||
}
|
||||
|
||||
array_push($_total_all,$_total);
|
||||
}
|
||||
|
||||
$_result['unbilled']['total'] = app_format_money(array_sum($_total_all), $currency);*/
|
||||
return $_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update expense
|
||||
* @param mixed $data All $_POST data
|
||||
* @param mixed $id expense id to update
|
||||
* @return boolean
|
||||
*/
|
||||
public function update($data, $id, $playground = false) {
|
||||
$original_expense = $this->get($id);
|
||||
$data['date'] = to_sql_date($data['date']);
|
||||
$data['note'] = nl2br($data['note']);
|
||||
// Recurring expense set to NO, Cancelled
|
||||
if ($original_expense->repeat_every != '' && ($data['repeat_every'] ?? '') == '') {
|
||||
$data['cycles'] = 0;
|
||||
$data['total_cycles'] = 0;
|
||||
$data['last_recurring_date'] = null;
|
||||
}
|
||||
if (isset($data['repeat_every']) && $data['repeat_every'] != '') {
|
||||
$data['recurring'] = 1;
|
||||
if ($data['repeat_every'] == 'custom') {
|
||||
$data['repeat_every'] = $data['repeat_every_custom'];
|
||||
$data['recurring_type'] = $data['repeat_type_custom'];
|
||||
$data['custom_recurring'] = 1;
|
||||
} else {
|
||||
$_temp = explode('-', $data['repeat_every']);
|
||||
$data['recurring_type'] = $_temp[1];
|
||||
$data['repeat_every'] = $_temp[0];
|
||||
$data['custom_recurring'] = 0;
|
||||
}
|
||||
} else {
|
||||
$data['recurring'] = 0;
|
||||
}
|
||||
$data['cycles'] = !isset($data['cycles']) || $data['recurring'] == 0 ? 0 : $data['cycles'];
|
||||
unset($data['repeat_type_custom']);
|
||||
unset($data['repeat_every_custom']);
|
||||
$data['create_invoice_billable'] = array_key_exists('create_invoice_billable', $data) ? 1 : 0;
|
||||
$data['billable'] = array_key_exists('billable', $data) ? 1 : 0;
|
||||
$data['send_invoice_to_customer'] = array_key_exists('send_invoice_to_customer', $data) ? 1 : 0;
|
||||
if (isset($data['project_id']) && $data['project_id'] == '' || !isset($data['project_id'])) {
|
||||
$data['project_id'] = 0;
|
||||
}
|
||||
$updated = false;
|
||||
$data = hooks()->apply_filters('before_expense_updated', $data, $id);
|
||||
$custom_fields = Arr::pull($data, 'custom_fields') ?? [];
|
||||
$this->load->model('custom_fields_model');
|
||||
if ($this->custom_fields_model->handle_custom_fields_post($id, $custom_fields, false, $playground)) {
|
||||
$updated = true;
|
||||
}
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'expenses', $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$updated = true;
|
||||
}
|
||||
do_action_deprecated('after_expense_updated', [$id], '2.9.4', 'expense_updated');
|
||||
hooks()->do_action('expense_updated', ['id' => $id, 'data' => $data, 'custom_fields' => $custom_fields, 'updated' => & $updated, ]);
|
||||
if ($updated) {
|
||||
log_activity('Expense Updated [' . $id . ']');
|
||||
}
|
||||
return $updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer ID
|
||||
* @return mixed
|
||||
* Delete expense from database, if used return
|
||||
*/
|
||||
public function delete($id, $simpleDelete = false, $playground = false) {
|
||||
$_expense = $this->get($id);
|
||||
if ($_expense->invoiceid !== null && $simpleDelete == false) {
|
||||
return ['invoiced' => true, ];
|
||||
}
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'expenses');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
// Delete the custom field values
|
||||
$this->db->where('relid', $id);
|
||||
$this->db->where('fieldto', 'expenses');
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues');
|
||||
// Get related tasks
|
||||
$this->db->where('rel_type', 'expense');
|
||||
$this->db->where('rel_id', $id);
|
||||
$tasks = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'tasks')->result_array();
|
||||
foreach ($tasks as $task) {
|
||||
$this->tasks_model->delete_task($task['id'], true, $playground);
|
||||
}
|
||||
$this->delete_expense_attachment($id);
|
||||
$this->db->where('recurring_from', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'expenses', ['recurring_from' => null]);
|
||||
$this->db->where('rel_type', 'expense');
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'reminders');
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->where('rel_type', 'expense');
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'related_items');
|
||||
log_activity('Expense Deleted [' . $id . ']');
|
||||
hooks()->do_action('after_expense_deleted', $id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert expense to invoice
|
||||
* @param mixed $id expense id
|
||||
* @return mixed
|
||||
*/
|
||||
public function convert_to_invoice($id, $draft_invoice = false, $params = [], $playground = false) {
|
||||
$expense = $this->get($id);
|
||||
$new_invoice_data = [];
|
||||
$client = $this->clients_model->get($expense->clientid, $playground);
|
||||
if ($draft_invoice == true) {
|
||||
$new_invoice_data['save_as_draft'] = true;
|
||||
}
|
||||
$new_invoice_data['clientid'] = $expense->clientid;
|
||||
$new_invoice_data['number'] = get_option('next_invoice_number');
|
||||
$invoice_date = (isset($params['invoice_date']) ? $params['invoice_date'] : date('Y-m-d'));
|
||||
$new_invoice_data['date'] = _d($invoice_date);
|
||||
if (get_option('invoice_due_after') != 0) {
|
||||
$new_invoice_data['duedate'] = _d(date('Y-m-d', strtotime('+' . get_option('invoice_due_after') . ' DAY', strtotime($invoice_date))));
|
||||
}
|
||||
$new_invoice_data['show_quantity_as'] = 1;
|
||||
$new_invoice_data['terms'] = get_option('predefined_terms_invoice');
|
||||
$new_invoice_data['clientnote'] = get_option('predefined_clientnote_invoice');
|
||||
$new_invoice_data['discount_total'] = 0;
|
||||
$new_invoice_data['sale_agent'] = 0;
|
||||
$new_invoice_data['adjustment'] = 0;
|
||||
$new_invoice_data['project_id'] = $expense->project_id;
|
||||
$new_invoice_data['subtotal'] = $expense->amount;
|
||||
$total = $expense->amount;
|
||||
if ($expense->tax != 0) {
|
||||
$total+= ($expense->amount / 100 * $expense->taxrate);
|
||||
}
|
||||
if ($expense->tax2 != 0) {
|
||||
$total+= ($expense->amount / 100 * $expense->taxrate2);
|
||||
}
|
||||
$new_invoice_data['total'] = $total;
|
||||
$new_invoice_data['currency'] = $expense->currency;
|
||||
$new_invoice_data['status'] = 1;
|
||||
$new_invoice_data['adminnote'] = '';
|
||||
// Since version 1.0.6
|
||||
$new_invoice_data['billing_street'] = clear_textarea_breaks($client->billing_street);
|
||||
$new_invoice_data['billing_city'] = $client->billing_city;
|
||||
$new_invoice_data['billing_state'] = $client->billing_state;
|
||||
$new_invoice_data['billing_zip'] = $client->billing_zip;
|
||||
$new_invoice_data['billing_country'] = $client->billing_country;
|
||||
if (!empty($client->shipping_street)) {
|
||||
$new_invoice_data['shipping_street'] = clear_textarea_breaks($client->shipping_street);
|
||||
$new_invoice_data['shipping_city'] = $client->shipping_city;
|
||||
$new_invoice_data['shipping_state'] = $client->shipping_state;
|
||||
$new_invoice_data['shipping_zip'] = $client->shipping_zip;
|
||||
$new_invoice_data['shipping_country'] = $client->shipping_country;
|
||||
$new_invoice_data['include_shipping'] = 1;
|
||||
$new_invoice_data['show_shipping_on_invoice'] = 1;
|
||||
} else {
|
||||
$new_invoice_data['include_shipping'] = 0;
|
||||
$new_invoice_data['show_shipping_on_invoice'] = 1;
|
||||
}
|
||||
$modes = $this->payment_modes_model->get('', ['expenses_only !=' => 1, ], $playground);
|
||||
$temp_modes = [];
|
||||
foreach ($modes as $mode) {
|
||||
if ($mode['selected_by_default'] == 0) {
|
||||
continue;
|
||||
}
|
||||
$temp_modes[] = $mode['id'];
|
||||
}
|
||||
$new_invoice_data['billed_expenses'][1] = [$expense->expenseid, ];
|
||||
$new_invoice_data['allowed_payment_modes'] = $temp_modes;
|
||||
$new_invoice_data['newitems'][1]['description'] = _l('item_as_expense') . ' ' . $expense->name;
|
||||
$new_invoice_data['newitems'][1]['long_description'] = $expense->description;
|
||||
if (isset($params['include_note']) && $params['include_note'] == true && !empty($expense->note)) {
|
||||
$new_invoice_data['newitems'][1]['long_description'].= PHP_EOL . $expense->note;
|
||||
}
|
||||
if (isset($params['include_name']) && $params['include_name'] == true && !empty($expense->expense_name)) {
|
||||
$new_invoice_data['newitems'][1]['long_description'].= PHP_EOL . $expense->expense_name;
|
||||
}
|
||||
$new_invoice_data['newitems'][1]['unit'] = '';
|
||||
$new_invoice_data['newitems'][1]['qty'] = 1;
|
||||
$new_invoice_data['newitems'][1]['taxname'] = [];
|
||||
if ($expense->tax != 0) {
|
||||
$tax_data = get_tax_by_id($expense->tax);
|
||||
array_push($new_invoice_data['newitems'][1]['taxname'], $tax_data->name . '|' . $tax_data->taxrate);
|
||||
}
|
||||
if ($expense->tax2 != 0) {
|
||||
$tax_data = get_tax_by_id($expense->tax2);
|
||||
array_push($new_invoice_data['newitems'][1]['taxname'], $tax_data->name . '|' . $tax_data->taxrate);
|
||||
}
|
||||
$new_invoice_data['newitems'][1]['rate'] = $expense->amount;
|
||||
$new_invoice_data['newitems'][1]['order'] = 1;
|
||||
$invoiceid = $this->invoices_model->add($new_invoice_data, true, $playground);
|
||||
$this->load->model('custom_fields_model');
|
||||
if ($invoiceid) {
|
||||
$this->db->where('id', $expense->expenseid);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'expenses', ['invoiceid' => $invoiceid, ]);
|
||||
if (is_custom_fields_smart_transfer_enabled()) {
|
||||
$this->db->where('fieldto', 'expenses');
|
||||
$this->db->where('active', 1);
|
||||
$cfExpenses = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'customfields')->result_array();
|
||||
foreach ($cfExpenses as $field) {
|
||||
$tmpSlug = explode('_', $field['slug'], 2);
|
||||
if (isset($tmpSlug[1])) {
|
||||
$this->db->where('fieldto', 'invoice');
|
||||
$this->db->group_start();
|
||||
$this->db->like('slug', 'invoice_' . $tmpSlug[1], 'after');
|
||||
$this->db->where('type', $field['type']);
|
||||
$this->db->where('options', $field['options']);
|
||||
$this->db->where('active', 1);
|
||||
$this->db->group_end();
|
||||
$cfTransfer = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'customfields')->result_array();
|
||||
// Don't make mistakes
|
||||
// Only valid if 1 result returned
|
||||
// + if field names similarity is equal or more then CUSTOM_FIELD_TRANSFER_SIMILARITY%
|
||||
if (count($cfTransfer) == 1 && ((similarity($field['name'], $cfTransfer[0]['name']) * 100) >= CUSTOM_FIELD_TRANSFER_SIMILARITY)) {
|
||||
$value = $this->custom_fields_model->get_custom_field_value($id, $field['id'], 'expenses', false, $playground);
|
||||
if ($value == '') {
|
||||
continue;
|
||||
}
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues', ['relid' => $invoiceid, 'fieldid' => $cfTransfer[0]['id'], 'fieldto' => 'invoice', 'value' => $value, ]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
log_activity('Expense Converted To Invoice [ExpenseID: ' . $expense->expenseid . ', InvoiceID: ' . $invoiceid . ']');
|
||||
hooks()->do_action('expense_converted_to_invoice', ['expense_id' => $expense->expenseid, 'invoice_id' => $invoiceid]);
|
||||
return $invoiceid;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy expense
|
||||
* @param mixed $id expense id to copy from
|
||||
* @return mixed
|
||||
*/
|
||||
public function copy($id, $playground = false) {
|
||||
$expense_fields = $this->db->list_fields(db_prefix() . ($playground ? 'playground_' : '') . 'expenses');
|
||||
$expense = $this->get($id);
|
||||
$new_expense_data = [];
|
||||
foreach ($expense_fields as $field) {
|
||||
if (isset($expense->$field)) {
|
||||
// We dont need these fields.
|
||||
if ($field != 'invoiceid' && $field != 'id' && $field != 'recurring_from') {
|
||||
$new_expense_data[$field] = $expense->$field;
|
||||
}
|
||||
}
|
||||
}
|
||||
$new_expense_data['addedfrom'] = get_staff_user_id();
|
||||
$new_expense_data['dateadded'] = date('Y-m-d H:i:s');
|
||||
$new_expense_data['last_recurring_date'] = null;
|
||||
$new_expense_data['total_cycles'] = 0;
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'expenses', $new_expense_data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
// Get the old expense custom field and add to the new
|
||||
$this->load->model('custom_fields_model');
|
||||
$custom_fields = $this->custom_fields_model->get_custom_fields('expenses', [], false, $playground);
|
||||
foreach ($custom_fields as $field) {
|
||||
$value = $this->custom_fields_model->get_custom_field_value($id, $field['id'], 'expenses', false, $playground);
|
||||
if ($value == '') {
|
||||
continue;
|
||||
}
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues', ['relid' => $insert_id, 'fieldid' => $field['id'], 'fieldto' => 'expenses', 'value' => $value, ]);
|
||||
}
|
||||
log_activity('Expense Copied [ExpenseID' . $id . ', NewExpenseID: ' . $insert_id . ']');
|
||||
return $insert_id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete Expense attachment
|
||||
* @param mixed $id expense id
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete_expense_attachment($id, $playground = false) {
|
||||
$this->load->model('misc_model');
|
||||
if (is_dir($this->misc_model->get_upload_path_by_type('expense', $playground) . $id)) {
|
||||
if (delete_dir($this->misc_model->get_upload_path_by_type('expense', $playground) . $id)) {
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->where('rel_type', 'expense');
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'files');
|
||||
log_activity('Expense Receipt Deleted [ExpenseID: ' . $id . ']');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/* Categories start */
|
||||
/**
|
||||
* Get expense category
|
||||
* @param mixed $id category id (Optional)
|
||||
* @return mixed object or array
|
||||
*/
|
||||
public function get_category($id = '', $playground = false) {
|
||||
if (is_numeric($id)) {
|
||||
$this->db->where('id', $id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'expenses_categories')->row();
|
||||
}
|
||||
$this->db->order_by('name', 'asc');
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'expenses_categories')->result_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new expense category
|
||||
* @param mixed $data All $_POST data
|
||||
* @return boolean
|
||||
*/
|
||||
public function add_category($data, $playground = false) {
|
||||
$data['description'] = nl2br($data['description']);
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'expenses_categories', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
log_activity('New Expense Category Added [ID: ' . $insert_id . ']');
|
||||
return $insert_id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update expense category
|
||||
* @param mixed $data All $_POST data
|
||||
* @param mixed $id expense id to update
|
||||
* @return boolean
|
||||
*/
|
||||
public function update_category($data, $id, $playground = false) {
|
||||
$data['description'] = nl2br($data['description']);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'expenses_categories', $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Expense Category Updated [ID: ' . $id . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer ID
|
||||
* @return mixed
|
||||
* Delete expense category from database, if used return array with key referenced
|
||||
*/
|
||||
public function delete_category($id, $playground = false) {
|
||||
if (is_reference_in_table('category', db_prefix() . ($playground ? 'playground_' : '') . 'expenses', $id)) {
|
||||
return ['referenced' => true, ];
|
||||
}
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'expenses_categories');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Expense Category Deleted [' . $id . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function get_expenses_years($playground = false) {
|
||||
return $this->db->query('SELECT DISTINCT(YEAR(date)) as year FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'expenses ORDER by year DESC')->result_array();
|
||||
}
|
||||
}
|
||||
335
api/models/Invoice_items_model.php
Normal file
335
api/models/Invoice_items_model.php
Normal file
@@ -0,0 +1,335 @@
|
||||
<?php
|
||||
|
||||
use app\services\utilities\Arr;
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Invoice_items_model extends App_Model {
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy invoice item
|
||||
* @param array $data Invoice item data
|
||||
* @return boolean
|
||||
*/
|
||||
public function copy($_data, $playground = false) {
|
||||
$this->load->model('custom_fields_model');
|
||||
$custom_fields_items = $this->custom_fields_model->get_custom_fields('items', [], false, $playground);
|
||||
$data = ['description' => $_data['description'] . ' - Copy', 'rate' => $_data['rate'], 'tax' => $_data['taxid'], 'tax2' => $_data['taxid_2'], 'group_id' => $_data['group_id'], 'unit' => $_data['unit'], 'long_description' => $_data['long_description'], ];
|
||||
foreach ($_data as $column => $value) {
|
||||
if (strpos($column, 'rate_currency_') !== false) {
|
||||
$data[$column] = $value;
|
||||
}
|
||||
}
|
||||
$columns = $this->db->list_fields(db_prefix() . ($playground ? 'playground_' : '') . 'items');
|
||||
$this->load->dbforge();
|
||||
foreach ($data as $column) {
|
||||
if (!in_array($column, $columns) && strpos($column, 'rate_currency_') !== false) {
|
||||
$field = [$column => ['type' => 'decimal(15,' . get_decimal_places() . ')', 'null' => true, ], ];
|
||||
$this->dbforge->add_column(($playground ? 'playground_' : '') . 'items', $field);
|
||||
}
|
||||
}
|
||||
foreach ($custom_fields_items as $cf) {
|
||||
$data['custom_fields']['items'][$cf['id']] = $this->custom_fields_model->get_custom_field_value($_data['itemid'], $cf['id'], 'items_pr', false, $playground);
|
||||
if (!defined('COPY_CUSTOM_FIELDS_LIKE_HANDLE_POST')) {
|
||||
define('COPY_CUSTOM_FIELDS_LIKE_HANDLE_POST', true);
|
||||
}
|
||||
}
|
||||
$insert_id = $this->add($data);
|
||||
if ($insert_id) {
|
||||
hooks()->do_action('item_coppied', $insert_id);
|
||||
log_activity('Copied Item [ID:' . $_data['itemid'] . ', ' . $data['description'] . ']');
|
||||
return $insert_id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get invoice item by ID
|
||||
* @param mixed $id
|
||||
* @return mixed - array if not passed id, object if id passed
|
||||
*/
|
||||
public function get($id = '', $playground = false) {
|
||||
$columns = $this->db->list_fields(db_prefix() . ($playground ? 'playground_' : '') . 'items');
|
||||
$rateCurrencyColumns = '';
|
||||
foreach ($columns as $column) {
|
||||
if (strpos($column, 'rate_currency_') !== false) {
|
||||
$rateCurrencyColumns.= $column . ',';
|
||||
}
|
||||
}
|
||||
$this->db->select($rateCurrencyColumns . '' . db_prefix() . ($playground ? 'playground_' : '') . 'items.id as itemid,rate,
|
||||
t1.taxrate as taxrate,t1.id as taxid,t1.name as taxname,
|
||||
t2.taxrate as taxrate_2,t2.id as taxid_2,t2.name as taxname_2,
|
||||
description,long_description,group_id,' . db_prefix() . ($playground ? 'playground_' : '') . 'items_groups.name as group_name,unit');
|
||||
$this->db->from(db_prefix() . ($playground ? 'playground_' : '') . 'items');
|
||||
$this->db->join('' . db_prefix() . ($playground ? 'playground_' : '') . 'taxes t1', 't1.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'items.tax', 'left');
|
||||
$this->db->join('' . db_prefix() . ($playground ? 'playground_' : '') . 'taxes t2', 't2.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'items.tax2', 'left');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'items_groups', '' . db_prefix() . ($playground ? 'playground_' : '') . 'items_groups.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'items.group_id', 'left');
|
||||
$this->db->order_by('description', 'asc');
|
||||
if (is_numeric($id)) {
|
||||
$this->db->where(db_prefix() . ($playground ? 'playground_' : '') . 'items.id', $id);
|
||||
return $this->db->get()->row();
|
||||
}
|
||||
return $this->db->get()->result_array();
|
||||
}
|
||||
|
||||
public function get_grouped($playground = false) {
|
||||
$items = [];
|
||||
$this->db->order_by('name', 'asc');
|
||||
$groups = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'items_groups')->result_array();
|
||||
array_unshift($groups, ['id' => 0, 'name' => '', ]);
|
||||
foreach ($groups as $group) {
|
||||
$this->db->select('*,' . db_prefix() . ($playground ? 'playground_' : '') . 'items_groups.name as group_name,' . db_prefix() . ($playground ? 'playground_' : '') . 'items.id as id');
|
||||
$this->db->where('group_id', $group['id']);
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'items_groups', '' . db_prefix() . ($playground ? 'playground_' : '') . 'items_groups.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'items.group_id', 'left');
|
||||
$this->db->order_by('description', 'asc');
|
||||
$_items = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'items')->result_array();
|
||||
if (count($_items) > 0) {
|
||||
$items[$group['id']] = [];
|
||||
foreach ($_items as $i) {
|
||||
array_push($items[$group['id']], $i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new invoice item
|
||||
* @param array $data Invoice item data
|
||||
* @return boolean
|
||||
*/
|
||||
public function add($data, $playground = false) {
|
||||
unset($data['itemid']);
|
||||
if (isset($data['tax']) && $data['tax'] == '') {
|
||||
unset($data['tax']);
|
||||
}
|
||||
if (isset($data['tax2']) && $data['tax2'] == '') {
|
||||
unset($data['tax2']);
|
||||
}
|
||||
if (isset($data['group_id']) && $data['group_id'] == '') {
|
||||
$data['group_id'] = 0;
|
||||
}
|
||||
$columns = $this->db->list_fields(db_prefix() . ($playground ? 'playground_' : '') . 'items');
|
||||
$this->load->dbforge();
|
||||
foreach ($data as $column => $itemData) {
|
||||
if (!in_array($column, $columns) && strpos($column, 'rate_currency_') !== false) {
|
||||
$field = [$column => ['type' => 'decimal(15,' . get_decimal_places() . ')', 'null' => true, ], ];
|
||||
$this->dbforge->add_column('items', $field);
|
||||
}
|
||||
}
|
||||
$data = hooks()->apply_filters('before_item_created', $data);
|
||||
$custom_fields = Arr::pull($data, 'custom_fields') ?? [];
|
||||
$this->db->insert(($playground ? 'playground_' : '') . 'items', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
$this->load->model('custom_fields_model');
|
||||
$this->custom_fields_model->handle_custom_fields_post($insert_id, $custom_fields, true, $playground);
|
||||
hooks()->do_action('item_created', $insert_id);
|
||||
log_activity('New Invoice Item Added [ID:' . $insert_id . ', ' . $data['description'] . ']');
|
||||
return $insert_id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update invoiec item
|
||||
* @param array $data Invoice data to update
|
||||
* @return boolean
|
||||
*/
|
||||
public function edit($data, $playground = false) {
|
||||
$itemid = $data['itemid'];
|
||||
unset($data['itemid']);
|
||||
if (isset($data['group_id']) && $data['group_id'] == '') {
|
||||
$data['group_id'] = 0;
|
||||
}
|
||||
if (isset($data['tax']) && $data['tax'] == '') {
|
||||
$data['tax'] = null;
|
||||
}
|
||||
if (isset($data['tax2']) && $data['tax2'] == '') {
|
||||
$data['tax2'] = null;
|
||||
}
|
||||
$columns = $this->db->list_fields(db_prefix() . ($playground ? 'playground_' : '') . 'items');
|
||||
$this->load->dbforge();
|
||||
foreach ($data as $column => $itemData) {
|
||||
if (!in_array($column, $columns) && strpos($column, 'rate_currency_') !== false) {
|
||||
$field = [$column => ['type' => 'decimal(15,' . get_decimal_places() . ')', 'null' => true, ], ];
|
||||
$this->dbforge->add_column('items', $field);
|
||||
}
|
||||
}
|
||||
$updated = false;
|
||||
$data = hooks()->apply_filters('before_update_item', $data, $itemid);
|
||||
$custom_fields = Arr::pull($data, 'custom_fields') ?? [];
|
||||
$this->db->where('id', $itemid);
|
||||
$this->db->update(($playground ? 'playground_' : '') . 'items', $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$updated = true;
|
||||
}
|
||||
$this->load->model('custom_fields_model');
|
||||
if ($this->custom_fields_model->handle_custom_fields_post($itemid, $custom_fields, true, $playground)) {
|
||||
$updated = true;
|
||||
}
|
||||
do_action_deprecated('item_updated', [$itemid], '2.9.4', 'after_item_updated');
|
||||
hooks()->do_action('after_item_updated', ['id' => $itemid, 'data' => $data, 'custom_fields' => $custom_fields, 'updated' => & $updated, ]);
|
||||
if ($updated) {
|
||||
log_activity('Invoice Item Updated [ID: ' . $itemid . ', ' . $data['description'] . ']');
|
||||
}
|
||||
return $updated;
|
||||
}
|
||||
|
||||
public function search($q, $playground = false) {
|
||||
$this->db->select('rate, id, description as name, long_description as subtext');
|
||||
$this->db->like('description', $q);
|
||||
$this->db->or_like('long_description', $q);
|
||||
$items = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . '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'];
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete invoice item
|
||||
* @param mixed $id
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete($id, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'items');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$this->db->where('relid', $id);
|
||||
$this->db->where('fieldto', 'items_pr');
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues');
|
||||
log_activity('Invoice Item Deleted [ID: ' . $id . ']');
|
||||
hooks()->do_action('item_deleted', $id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function get_groups($playground = false) {
|
||||
$this->db->order_by('name', 'asc');
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'items_groups')->result_array();
|
||||
}
|
||||
|
||||
public function add_group($data, $playground = false) {
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'items_groups', $data);
|
||||
log_activity('Items Group Created [Name: ' . $data['name'] . ']');
|
||||
return $this->db->insert_id();
|
||||
}
|
||||
|
||||
public function edit_group($data, $id, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'items_groups', $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Items Group Updated [Name: ' . $data['name'] . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function delete_group($id, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
$group = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'items_groups')->row();
|
||||
if ($group) {
|
||||
$this->db->where('group_id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'items', ['group_id' => 0, ]);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'items_groups');
|
||||
log_activity('Item Group Deleted [Name: ' . $group->name . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function get_items_by_type($type, $id, $playground = false)
|
||||
{
|
||||
$this->db->select();
|
||||
$this->db->from(db_prefix() . ($playground ? 'playground_' : '') . 'itemable');
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->where('rel_type', $type);
|
||||
$this->db->order_by('item_order', 'asc');
|
||||
|
||||
return $this->db->get()->result_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new item do database, used for proposals,estimates,credit notes,invoices
|
||||
* This is repetitive action, that's why this function exists
|
||||
* @param array $item item from $_POST
|
||||
* @param mixed $rel_id relation id eq. invoice id
|
||||
* @param string $rel_type relation type eq invoice
|
||||
*/
|
||||
public function add_new_sales_item_post($item, $rel_id, $rel_type, $playground = false)
|
||||
{
|
||||
$custom_fields = false;
|
||||
|
||||
if (isset($item['custom_fields'])) {
|
||||
$custom_fields = $item['custom_fields'];
|
||||
}
|
||||
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'itemable', [
|
||||
'description' => $item['description'],
|
||||
'long_description' => nl2br($item['long_description']),
|
||||
'qty' => $item['qty'],
|
||||
'rate' => number_format($item['rate'], get_decimal_places(), '.', ''),
|
||||
'rel_id' => $rel_id,
|
||||
'rel_type' => $rel_type,
|
||||
'item_order' => $item['order'],
|
||||
'unit' => $item['unit'],
|
||||
]);
|
||||
|
||||
$id = $this->db->insert_id();
|
||||
|
||||
if ($custom_fields !== false) {
|
||||
$this->load->model('custom_fields_model');
|
||||
$this->custom_fields_model->handle_custom_fields_post($id, $custom_fields);
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function used for sales eq. invoice, estimate, proposal, credit note
|
||||
* @param mixed $item_id item id
|
||||
* @param array $post_item $item from $_POST
|
||||
* @param mixed $rel_id rel_id
|
||||
* @param string $rel_type where this item tax is related
|
||||
*/
|
||||
public function _maybe_insert_post_item_tax($item_id, $post_item, $rel_id, $rel_type, $playground = false)
|
||||
{
|
||||
$affectedRows = 0;
|
||||
if (isset($post_item['taxname']) && is_array($post_item['taxname'])) {
|
||||
foreach ($post_item['taxname'] as $taxname) {
|
||||
if ($taxname != '') {
|
||||
$tax_array = explode('|', $taxname);
|
||||
if (isset($tax_array[0]) && isset($tax_array[1])) {
|
||||
$tax_name = trim($tax_array[0]);
|
||||
$tax_rate = trim($tax_array[1]);
|
||||
if (total_rows(db_prefix() . ($playground ? 'playground_' : '') . 'item_tax', [
|
||||
'itemid' => $item_id,
|
||||
'taxrate' => $tax_rate,
|
||||
'taxname' => $tax_name,
|
||||
'rel_id' => $rel_id,
|
||||
'rel_type' => $rel_type,
|
||||
]) == 0) {
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'item_tax', [
|
||||
'itemid' => $item_id,
|
||||
'taxrate' => $tax_rate,
|
||||
'taxname' => $tax_name,
|
||||
'rel_id' => $rel_id,
|
||||
'rel_type' => $rel_type,
|
||||
]);
|
||||
$affectedRows++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $affectedRows > 0 ? true : false;
|
||||
}
|
||||
}
|
||||
1381
api/models/Invoices_model.php
Normal file
1381
api/models/Invoices_model.php
Normal file
File diff suppressed because it is too large
Load Diff
914
api/models/Leads_model.php
Normal file
914
api/models/Leads_model.php
Normal file
@@ -0,0 +1,914 @@
|
||||
<?php
|
||||
|
||||
use app\services\AbstractKanban;
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Leads_model extends App_Model {
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lead
|
||||
* @param string $id Optional - leadid
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($id = '', $where = [], $playground = false) {
|
||||
$this->db->select('*,' . db_prefix() . ($playground ? 'playground_' : '') . 'leads.name, ' . db_prefix() . ($playground ? 'playground_' : '') . 'leads.id,' . db_prefix() . ($playground ? 'playground_' : '') . 'leads_status.name as status_name,' . db_prefix() . ($playground ? 'playground_' : '') . 'leads_sources.name as source_name');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'leads_status', db_prefix() . ($playground ? 'playground_' : '') . 'leads_status.id=' . db_prefix() . ($playground ? 'playground_' : '') . 'leads.status', 'left');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'leads_sources', db_prefix() . ($playground ? 'playground_' : '') . 'leads_sources.id=' . db_prefix() . ($playground ? 'playground_' : '') . 'leads.source', 'left');
|
||||
$this->db->where($where);
|
||||
if (is_numeric($id)) {
|
||||
$this->db->where(db_prefix() . ($playground ? 'playground_' : '') . 'leads.id', $id);
|
||||
$lead = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'leads')->row();
|
||||
if ($lead) {
|
||||
if ($lead->from_form_id != 0) {
|
||||
$lead->form_data = $this->get_form(['id' => $lead->from_form_id, ]);
|
||||
}
|
||||
$lead->attachments = $this->get_lead_attachments($id, '', [], $playground);
|
||||
$lead->public_url = leads_public_url($id, $playground);
|
||||
}
|
||||
return $lead;
|
||||
}
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'leads')->result_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lead by given email
|
||||
*
|
||||
* @since 2.8.0
|
||||
*
|
||||
* @param string $email
|
||||
*
|
||||
* @return \strClass|null
|
||||
*/
|
||||
public function get_lead_by_email($email, $playground = false) {
|
||||
$this->db->where('email', $email);
|
||||
$this->db->limit(1);
|
||||
return $this->db->get(($playground ? 'playground_' : '') . 'leads')->row();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new lead to database
|
||||
* @param mixed $data lead data
|
||||
* @return mixed false || leadid
|
||||
*/
|
||||
public function add($data, $playground = false) {
|
||||
if (isset($data['custom_contact_date']) || isset($data['custom_contact_date'])) {
|
||||
if (isset($data['contacted_today'])) {
|
||||
$data['lastcontact'] = date('Y-m-d H:i:s');
|
||||
unset($data['contacted_today']);
|
||||
} else {
|
||||
$data['lastcontact'] = to_sql_date($data['custom_contact_date'], true);
|
||||
}
|
||||
}
|
||||
if (isset($data['is_public']) && ($data['is_public'] == 1 || $data['is_public'] === 'on')) {
|
||||
$data['is_public'] = 1;
|
||||
} else {
|
||||
$data['is_public'] = 0;
|
||||
}
|
||||
if (!isset($data['country']) || isset($data['country']) && $data['country'] == '') {
|
||||
$data['country'] = 0;
|
||||
}
|
||||
if (isset($data['custom_contact_date'])) {
|
||||
unset($data['custom_contact_date']);
|
||||
}
|
||||
$data['description'] = nl2br($data['description']);
|
||||
$data['dateadded'] = date('Y-m-d H:i:s');
|
||||
$data['addedfrom'] = get_staff_user_id();
|
||||
$data = hooks()->apply_filters('before_lead_added', $data);
|
||||
$tags = '';
|
||||
if (isset($data['tags'])) {
|
||||
$tags = $data['tags'];
|
||||
unset($data['tags']);
|
||||
}
|
||||
if (isset($data['custom_fields'])) {
|
||||
$custom_fields = $data['custom_fields'];
|
||||
unset($data['custom_fields']);
|
||||
}
|
||||
$data['address'] = trim($data['address']);
|
||||
$data['address'] = nl2br($data['address']);
|
||||
$data['email'] = trim($data['email']);
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'leads', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
log_activity('New Lead Added [ID: ' . $insert_id . ']');
|
||||
$this->log_lead_activity($insert_id, 'not_lead_activity_created', false, '', $playground);
|
||||
$this->load->model('misc_model');
|
||||
$this->misc_model->handle_tags_save($tags, $insert_id, 'lead');
|
||||
if (isset($custom_fields)) {
|
||||
$this->load->model('custom_fields_model');
|
||||
$this->custom_fields_model->handle_custom_fields_post($insert_id, $custom_fields, false, $playground);
|
||||
}
|
||||
$this->lead_assigned_member_notification($insert_id, $data['assigned'], $playground);
|
||||
hooks()->do_action('lead_created', $insert_id);
|
||||
return $insert_id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function lead_assigned_member_notification($lead_id, $assigned, $integration = false, $playground = false) {
|
||||
if (empty($assigned) || $assigned == 0) {
|
||||
return;
|
||||
}
|
||||
if ($integration == false) {
|
||||
if ($assigned == get_staff_user_id()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$name = $this->db->select('name')->from(db_prefix() . ($playground ? 'playground_' : '') . 'leads')->where('id', $lead_id)->get()->row()->name;
|
||||
$notification_data = ['description' => ($integration == false) ? 'not_assigned_lead_to_you' : 'not_lead_assigned_from_form', 'touserid' => $assigned, 'link' => '#leadid=' . $lead_id, 'additional_data' => ($integration == false ? serialize([$name, ]) : serialize([])), ];
|
||||
if ($integration != false) {
|
||||
$notification_data['fromcompany'] = 1;
|
||||
}
|
||||
if (add_notification($notification_data)) {
|
||||
pusher_trigger_notification([$assigned]);
|
||||
}
|
||||
$this->db->select('email');
|
||||
$this->db->where('staffid', $assigned);
|
||||
$email = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'staff')->row()->email;
|
||||
send_mail_template('lead_assigned', $lead_id, $email);
|
||||
$this->db->where('id', $lead_id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'leads', ['dateassigned' => date('Y-m-d'), ]);
|
||||
$this->load->model('staff_model');
|
||||
$not_additional_data = [e($this->staff_model->get_staff_full_name('', $playground)), '<a href="' . admin_url('profile/' . $assigned) . '" target="_blank">' . e($this->staff_model->get_staff_full_name($assigned, $playground)) . '</a>', ];
|
||||
if ($integration == true) {
|
||||
unset($not_additional_data[0]);
|
||||
array_values(($not_additional_data));
|
||||
}
|
||||
$not_additional_data = serialize($not_additional_data);
|
||||
$not_desc = ($integration == false ? 'not_lead_activity_assigned_to' : 'not_lead_activity_assigned_from_form');
|
||||
$this->log_lead_activity($lead_id, $not_desc, $integration, $not_additional_data, $playground);
|
||||
hooks()->do_action('after_lead_assigned_member_notification_sent', $lead_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update lead
|
||||
* @param array $data lead data
|
||||
* @param mixed $id leadid
|
||||
* @return boolean
|
||||
*/
|
||||
public function update($data, $id, $playground = false) {
|
||||
$current_lead_data = $this->get($id);
|
||||
$current_status = $this->get_status($current_lead_data->status, $playground);
|
||||
if ($current_status) {
|
||||
$current_status_id = $current_status->id;
|
||||
$current_status = $current_status->name;
|
||||
} else {
|
||||
if ($current_lead_data->junk == 1) {
|
||||
$current_status = _l('lead_junk');
|
||||
} else if ($current_lead_data->lost == 1) {
|
||||
$current_status = _l('lead_lost');
|
||||
} else {
|
||||
$current_status = '';
|
||||
}
|
||||
$current_status_id = 0;
|
||||
}
|
||||
$affectedRows = 0;
|
||||
if (isset($data['custom_fields'])) {
|
||||
$custom_fields = $data['custom_fields'];
|
||||
$this->load->model('custom_fields_model');
|
||||
if ($this->custom_fields_model->handle_custom_fields_post($id, $custom_fields, false, $playground)) {
|
||||
$affectedRows++;
|
||||
}
|
||||
unset($data['custom_fields']);
|
||||
}
|
||||
if (!defined('API')) {
|
||||
if (isset($data['is_public'])) {
|
||||
$data['is_public'] = 1;
|
||||
} else {
|
||||
$data['is_public'] = 0;
|
||||
}
|
||||
if (!isset($data['country']) || isset($data['country']) && $data['country'] == '') {
|
||||
$data['country'] = 0;
|
||||
}
|
||||
if (isset($data['description'])) {
|
||||
$data['description'] = nl2br($data['description']);
|
||||
}
|
||||
}
|
||||
if (isset($data['lastcontact']) && $data['lastcontact'] == '' || isset($data['lastcontact']) && $data['lastcontact'] == null) {
|
||||
$data['lastcontact'] = null;
|
||||
} else if (isset($data['lastcontact'])) {
|
||||
$data['lastcontact'] = to_sql_date($data['lastcontact'], true);
|
||||
}
|
||||
if (isset($data['tags'])) {
|
||||
$this->load->model('misc_model');
|
||||
if ($this->misc_model->handle_tags_save($data['tags'], $id, 'lead')) {
|
||||
$affectedRows++;
|
||||
}
|
||||
unset($data['tags']);
|
||||
}
|
||||
if (isset($data['remove_attachments'])) {
|
||||
foreach ($data['remove_attachments'] as $key => $val) {
|
||||
$attachment = $this->get_lead_attachments($id, $key, [], $playground);
|
||||
if ($attachment) {
|
||||
$this->delete_lead_attachment($attachment->id, $playground);
|
||||
}
|
||||
}
|
||||
unset($data['remove_attachments']);
|
||||
}
|
||||
$data['address'] = trim($data['address']);
|
||||
$data['address'] = nl2br($data['address']);
|
||||
$data['email'] = trim($data['email']);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'leads', $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$affectedRows++;
|
||||
if (isset($data['status']) && $current_status_id != $data['status']) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'leads', ['last_status_change' => date('Y-m-d H:i:s'), ]);
|
||||
$new_status_name = $this->get_status($data['status'])->name;
|
||||
$this->load->model('staff_model');
|
||||
$this->log_lead_activity($id, 'not_lead_activity_status_updated', false, serialize([$this->staff_model->get_staff_full_name('', $playground), $current_status, $new_status_name, ]), $playground);
|
||||
hooks()->do_action('lead_status_changed', ['lead_id' => $id, 'old_status' => $current_status_id, 'new_status' => $data['status'], ]);
|
||||
}
|
||||
if (($current_lead_data->junk == 1 || $current_lead_data->lost == 1) && $data['status'] != 0) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'leads', ['junk' => 0, 'lost' => 0, ]);
|
||||
}
|
||||
if (isset($data['assigned'])) {
|
||||
if ($current_lead_data->assigned != $data['assigned'] && (!empty($data['assigned']) && $data['assigned'] != 0)) {
|
||||
$this->lead_assigned_member_notification($id, $data['assigned'], $playground);
|
||||
}
|
||||
}
|
||||
log_activity('Lead Updated [ID: ' . $id . ']');
|
||||
hooks()->do_action('after_lead_updated', $id);
|
||||
return true;
|
||||
}
|
||||
if ($affectedRows > 0) {
|
||||
hooks()->do_action('after_lead_updated', $id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete lead from database and all connections
|
||||
* @param mixed $id leadid
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete($id, $playground = false) {
|
||||
$affectedRows = 0;
|
||||
hooks()->do_action('before_lead_deleted', $id);
|
||||
$lead = $this->get($id);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'leads');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$this->load->model('staff_model');
|
||||
log_activity('Lead Deleted [Deleted by: ' . $this->staff_model->get_staff_full_name('', $playground) . ', ID: ' . $id . ']');
|
||||
$attachments = $this->get_lead_attachments($id, '', [], $playground);
|
||||
foreach ($attachments as $attachment) {
|
||||
$this->delete_lead_attachment($attachment['id'], $playground);
|
||||
}
|
||||
// Delete the custom field values
|
||||
$this->db->where('relid', $id);
|
||||
$this->db->where('fieldto', 'leads');
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues');
|
||||
$this->db->where('leadid', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'lead_activity_log');
|
||||
$this->db->where('leadid', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'lead_integration_emails');
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->where('rel_type', 'lead');
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'notes');
|
||||
$this->db->where('rel_type', 'lead');
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'reminders');
|
||||
$this->db->where('rel_type', 'lead');
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'taggables');
|
||||
$this->load->model('proposals_model');
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->where('rel_type', 'lead');
|
||||
$proposals = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'proposals')->result_array();
|
||||
foreach ($proposals as $proposal) {
|
||||
$this->proposals_model->delete($proposal['id'], $playground);
|
||||
}
|
||||
// Get related tasks
|
||||
$this->db->where('rel_type', 'lead');
|
||||
$this->db->where('rel_id', $id);
|
||||
$tasks = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'tasks')->result_array();
|
||||
foreach ($tasks as $task) {
|
||||
$this->tasks_model->delete_task($task['id'], true, $playground);
|
||||
}
|
||||
if (is_gdpr()) {
|
||||
$this->db->where('(description LIKE "%' . $lead->email . '%" OR description LIKE "%' . $lead->name . '%" OR description LIKE "%' . $lead->phonenumber . '%")');
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'activity_log');
|
||||
}
|
||||
$affectedRows++;
|
||||
}
|
||||
if ($affectedRows > 0) {
|
||||
hooks()->do_action('after_lead_deleted', $id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark lead as lost
|
||||
* @param mixed $id lead id
|
||||
* @return boolean
|
||||
*/
|
||||
public function mark_as_lost($id, $playground = false) {
|
||||
$this->db->select('status');
|
||||
$this->db->from(db_prefix() . ($playground ? 'playground_' : '') . 'leads');
|
||||
$this->db->where('id', $id);
|
||||
$last_lead_status = $this->db->get()->row()->status;
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'leads', ['lost' => 1, 'status' => 0, 'last_status_change' => date('Y-m-d H:i:s'), 'last_lead_status' => $last_lead_status, ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$this->log_lead_activity($id, 'not_lead_activity_marked_lost', false, '', $playground);
|
||||
log_activity('Lead Marked as Lost [ID: ' . $id . ']');
|
||||
hooks()->do_action('lead_marked_as_lost', $id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmark lead as lost
|
||||
* @param mixed $id leadid
|
||||
* @return boolean
|
||||
*/
|
||||
public function unmark_as_lost($id, $playground = false) {
|
||||
$this->db->select('last_lead_status');
|
||||
$this->db->from(db_prefix() . ($playground ? 'playground_' : '') . 'leads');
|
||||
$this->db->where('id', $id);
|
||||
$last_lead_status = $this->db->get()->row()->last_lead_status;
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'leads', ['lost' => 0, 'status' => $last_lead_status, ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$this->log_lead_activity($id, 'not_lead_activity_unmarked_lost', false, '', $playground);
|
||||
log_activity('Lead Unmarked as Lost [ID: ' . $id . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark lead as junk
|
||||
* @param mixed $id lead id
|
||||
* @return boolean
|
||||
*/
|
||||
public function mark_as_junk($id, $playground = false) {
|
||||
$this->db->select('status');
|
||||
$this->db->from(db_prefix() . ($playground ? 'playground_' : '') . 'leads');
|
||||
$this->db->where('id', $id);
|
||||
$last_lead_status = $this->db->get()->row()->status;
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'leads', ['junk' => 1, 'status' => 0, 'last_status_change' => date('Y-m-d H:i:s'), 'last_lead_status' => $last_lead_status, ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$this->log_lead_activity($id, 'not_lead_activity_marked_junk', false, '', $playground);
|
||||
log_activity('Lead Marked as Junk [ID: ' . $id . ']');
|
||||
hooks()->do_action('lead_marked_as_junk', $id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmark lead as junk
|
||||
* @param mixed $id leadid
|
||||
* @return boolean
|
||||
*/
|
||||
public function unmark_as_junk($id, $playground = false) {
|
||||
$this->db->select('last_lead_status');
|
||||
$this->db->from(db_prefix() . ($playground ? 'playground_' : '') . 'leads');
|
||||
$this->db->where('id', $id);
|
||||
$last_lead_status = $this->db->get()->row()->last_lead_status;
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'leads', ['junk' => 0, 'status' => $last_lead_status, ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$this->log_lead_activity($id, 'not_lead_activity_unmarked_junk', false, '', $playground);
|
||||
log_activity('Lead Unmarked as Junk [ID: ' . $id . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lead attachments
|
||||
* @since Version 1.0.4
|
||||
* @param mixed $id lead id
|
||||
* @return array
|
||||
*/
|
||||
public function get_lead_attachments($id = '', $attachment_id = '', $where = [], $playground = false) {
|
||||
$this->db->where($where);
|
||||
$idIsHash = !is_numeric($attachment_id) && strlen($attachment_id) == 32;
|
||||
if (is_numeric($attachment_id) || $idIsHash) {
|
||||
$this->db->where($idIsHash ? 'attachment_key' : 'id', $attachment_id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'files')->row();
|
||||
}
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->where('rel_type', 'lead');
|
||||
$this->db->order_by('dateadded', 'DESC');
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'files')->result_array();
|
||||
}
|
||||
|
||||
public function add_attachment_to_database($lead_id, $attachment, $external = false, $form_activity = false, $playground = false) {
|
||||
$this->misc_model->add_attachment_to_database($lead_id, 'lead', $attachment, $external, $playground);
|
||||
if ($form_activity == false) {
|
||||
$this->leads_model->log_lead_activity($lead_id, 'not_lead_activity_added_attachment', false, '', $playground);
|
||||
} else {
|
||||
$this->leads_model->log_lead_activity($lead_id, 'not_lead_activity_log_attachment', true, serialize([$form_activity, ], $playground));
|
||||
}
|
||||
// No notification when attachment is imported from web to lead form
|
||||
if ($form_activity == false) {
|
||||
$lead = $this->get($lead_id);
|
||||
$not_user_ids = [];
|
||||
if ($lead->addedfrom != get_staff_user_id()) {
|
||||
array_push($not_user_ids, $lead->addedfrom);
|
||||
}
|
||||
if ($lead->assigned != get_staff_user_id() && $lead->assigned != 0) {
|
||||
array_push($not_user_ids, $lead->assigned);
|
||||
}
|
||||
$notifiedUsers = [];
|
||||
foreach ($not_user_ids as $uid) {
|
||||
$notified = add_notification(['description' => 'not_lead_added_attachment', 'touserid' => $uid, 'link' => '#leadid=' . $lead_id, 'additional_data' => serialize([$lead->name, ]), ]);
|
||||
if ($notified) {
|
||||
array_push($notifiedUsers, $uid);
|
||||
}
|
||||
}
|
||||
pusher_trigger_notification($notifiedUsers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete lead attachment
|
||||
* @param mixed $id attachment id
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete_lead_attachment($id, $playground = false) {
|
||||
$attachment = $this->get_lead_attachments('', $id, [], $playground);
|
||||
$deleted = false;
|
||||
$this->load->model('misc_model');
|
||||
if ($attachment) {
|
||||
if (empty($attachment->external)) {
|
||||
unlink($this->misc_model->get_upload_path_by_type('lead', $playground) . $attachment->rel_id . '/' . $attachment->file_name);
|
||||
}
|
||||
$this->db->where('id', $attachment->id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'files');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$deleted = true;
|
||||
log_activity('Lead Attachment Deleted [ID: ' . $attachment->rel_id . ']');
|
||||
}
|
||||
if (is_dir($this->misc_model->get_upload_path_by_type('lead', $playground) . $attachment->rel_id)) {
|
||||
// Check if no attachments left, so we can delete the folder also
|
||||
$other_attachments = list_files($this->misc_model->get_upload_path_by_type('lead', $playground) . $attachment->rel_id);
|
||||
if (count($other_attachments) == 0) {
|
||||
// okey only index.html so we can delete the folder also
|
||||
delete_dir($this->misc_model->get_upload_path_by_type('lead', $playground) . $attachment->rel_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
// Sources
|
||||
|
||||
/**
|
||||
* Get leads sources
|
||||
* @param mixed $id Optional - Source ID
|
||||
* @return mixed object if id passed else array
|
||||
*/
|
||||
public function get_source($id = false, $playground = false) {
|
||||
if (is_numeric($id)) {
|
||||
$this->db->where('id', $id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'leads_sources')->row();
|
||||
}
|
||||
$this->db->order_by('name', 'asc');
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'leads_sources')->result_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new lead source
|
||||
* @param mixed $data source data
|
||||
*/
|
||||
public function add_source($data, $playground = false) {
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'leads_sources', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
log_activity('New Leads Source Added [SourceID: ' . $insert_id . ', Name: ' . $data['name'] . ']');
|
||||
}
|
||||
return $insert_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update lead source
|
||||
* @param mixed $data source data
|
||||
* @param mixed $id source id
|
||||
* @return boolean
|
||||
*/
|
||||
public function update_source($data, $id) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'leads_sources', $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Leads Source Updated [SourceID: ' . $id . ', Name: ' . $data['name'] . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete lead source from database
|
||||
* @param mixed $id source id
|
||||
* @return mixed
|
||||
*/
|
||||
public function delete_source($id, $playground = false) {
|
||||
$current = $this->get_source($id);
|
||||
// Check if is already using in table
|
||||
if (is_reference_in_table('source', db_prefix() . ($playground ? 'playground_' : '') . 'leads', $id) || is_reference_in_table('lead_source', db_prefix() . ($playground ? 'playground_' : '') . 'leads_email_integration', $id)) {
|
||||
return ['referenced' => true, ];
|
||||
}
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'leads_sources');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
if (get_option('leads_default_source') == $id) {
|
||||
update_option('leads_default_source', '');
|
||||
}
|
||||
log_activity('Leads Source Deleted [SourceID: ' . $id . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Statuses
|
||||
|
||||
/**
|
||||
* Get lead statuses
|
||||
* @param mixed $id status id
|
||||
* @return mixed object if id passed else array
|
||||
*/
|
||||
public function get_status($id = '', $where = [], $playground = false) {
|
||||
if (is_numeric($id)) {
|
||||
$this->db->where($where);
|
||||
$this->db->where('id', $id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'leads_status')->row();
|
||||
}
|
||||
$whereKey = md5(serialize($where));
|
||||
$statuses = $this->app_object_cache->get('leads-all-statuses-' . $whereKey);
|
||||
if (!$statuses) {
|
||||
$this->db->where($where);
|
||||
$this->db->order_by('statusorder', 'asc');
|
||||
$statuses = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'leads_status')->result_array();
|
||||
$this->app_object_cache->add('leads-all-statuses-' . $whereKey, $statuses);
|
||||
}
|
||||
return $statuses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new lead status
|
||||
* @param array $data lead status data
|
||||
*/
|
||||
public function add_status($data, $playground = false) {
|
||||
if (isset($data['color']) && $data['color'] == '') {
|
||||
$data['color'] = hooks()->apply_filters('default_lead_status_color', '#757575');
|
||||
}
|
||||
if (!isset($data['statusorder'])) {
|
||||
$data['statusorder'] = total_rows(db_prefix() . ($playground ? 'playground_' : '') . 'leads_status') + 1;
|
||||
}
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'leads_status', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
log_activity('New Leads Status Added [StatusID: ' . $insert_id . ', Name: ' . $data['name'] . ']');
|
||||
return $insert_id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function update_status($data, $id, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'leads_status', $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Leads Status Updated [StatusID: ' . $id . ', Name: ' . $data['name'] . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete lead status from database
|
||||
* @param mixed $id status id
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete_status($id, $playground = false) {
|
||||
$current = $this->get_status($id);
|
||||
// Check if is already using in table
|
||||
if (is_reference_in_table('status', db_prefix() . ($playground ? 'playground_' : '') . 'leads', $id) || is_reference_in_table('lead_status', db_prefix() . ($playground ? 'playground_' : '') . 'leads_email_integration', $id)) {
|
||||
return ['referenced' => true, ];
|
||||
}
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'leads_status');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
if (get_option('leads_default_status') == $id) {
|
||||
update_option('leads_default_status', '');
|
||||
}
|
||||
log_activity('Leads Status Deleted [StatusID: ' . $id . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update canban lead status when drag and drop
|
||||
* @param array $data lead data
|
||||
* @return boolean
|
||||
*/
|
||||
public function update_lead_status($data, $playground = false) {
|
||||
$this->db->select('status');
|
||||
$this->db->where('id', $data['leadid']);
|
||||
$_old = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'leads')->row();
|
||||
$old_status = '';
|
||||
if ($_old) {
|
||||
$old_status = $this->get_status($_old->status, $playground);
|
||||
if ($old_status) {
|
||||
$old_status = $old_status->name;
|
||||
}
|
||||
}
|
||||
$affectedRows = 0;
|
||||
$current_status = $this->get_status($data['status'])->name;
|
||||
$this->db->where('id', $data['leadid']);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'leads', ['status' => $data['status'], ]);
|
||||
$_log_message = '';
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$affectedRows++;
|
||||
if ($current_status != $old_status && $old_status != '') {
|
||||
$_log_message = 'not_lead_activity_status_updated';
|
||||
$this->load->model('staff_model');
|
||||
$additional_data = serialize([$this->staff_model->get_staff_full_name('', $playground), $old_status, $current_status, ]);
|
||||
hooks()->do_action('lead_status_changed', ['lead_id' => $data['leadid'], 'old_status' => $old_status, 'new_status' => $current_status, ]);
|
||||
}
|
||||
$this->db->where('id', $data['leadid']);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'leads', ['last_status_change' => date('Y-m-d H:i:s'), ]);
|
||||
}
|
||||
if (isset($data['order'])) {
|
||||
AbstractKanban::updateOrder($data['order'], 'leadorder', 'leads', $data['status']);
|
||||
}
|
||||
if ($affectedRows > 0) {
|
||||
if ($_log_message == '') {
|
||||
return true;
|
||||
}
|
||||
$this->log_lead_activity($data['leadid'], $_log_message, false, $additional_data, $playground);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/* Ajax */
|
||||
/**
|
||||
* All lead activity by staff
|
||||
* @param mixed $id lead id
|
||||
* @return array
|
||||
*/
|
||||
public function get_lead_activity_log($id, $playground = false) {
|
||||
$sorting = hooks()->apply_filters('lead_activity_log_default_sort', 'ASC');
|
||||
$this->db->where('leadid', $id);
|
||||
$this->db->order_by('date', $sorting);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'lead_activity_log')->result_array();
|
||||
}
|
||||
|
||||
public function staff_can_access_lead($id, $staff_id = '', $playground = false) {
|
||||
$staff_id = $staff_id == '' ? get_staff_user_id() : $staff_id;
|
||||
if (has_permission('leads', $staff_id, 'view')) {
|
||||
return true;
|
||||
}
|
||||
if (total_rows(db_prefix() . ($playground ? 'playground_' : '') . 'leads', 'id="' . $this->db->escape_str($id) . '" AND (assigned=' . $this->db->escape_str($staff_id) . ' OR is_public=1 OR addedfrom=' . $CI->db->escape_str($staff_id) . ')') > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add lead activity from staff
|
||||
* @param mixed $id lead id
|
||||
* @param string $description activity description
|
||||
*/
|
||||
public function log_lead_activity($id, $description, $integration = false, $additional_data = '', $playground = false) {
|
||||
$this->load->model('staff_model');
|
||||
$log = ['date' => date('Y-m-d H:i:s'), 'description' => $description, 'leadid' => $id, 'staffid' => get_staff_user_id(), 'additional_data' => $additional_data, 'full_name' => $this->staff_model->get_staff_full_name(get_staff_user_id(), $playground), ];
|
||||
if ($integration == true) {
|
||||
$log['staffid'] = 0;
|
||||
$log['full_name'] = '[CRON]';
|
||||
}
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'lead_activity_log', $log);
|
||||
return $this->db->insert_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get email integration config
|
||||
* @return object
|
||||
*/
|
||||
public function get_email_integration($playground = false) {
|
||||
$this->db->where('id', 1);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'leads_email_integration')->row();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lead imported email activity
|
||||
* @param mixed $id leadid
|
||||
* @return array
|
||||
*/
|
||||
public function get_mail_activity($id, $playground = false) {
|
||||
$this->db->where('leadid', $id);
|
||||
$this->db->order_by('dateadded', 'asc');
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'lead_integration_emails')->result_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update email integration config
|
||||
* @param mixed $data All $_POST data
|
||||
* @return boolean
|
||||
*/
|
||||
public function update_email_integration($data, $playground = false) {
|
||||
$this->db->where('id', 1);
|
||||
$original_settings = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'leads_email_integration')->row();
|
||||
$data['create_task_if_customer'] = isset($data['create_task_if_customer']) ? 1 : 0;
|
||||
$data['active'] = isset($data['active']) ? 1 : 0;
|
||||
$data['delete_after_import'] = isset($data['delete_after_import']) ? 1 : 0;
|
||||
$data['notify_lead_imported'] = isset($data['notify_lead_imported']) ? 1 : 0;
|
||||
$data['only_loop_on_unseen_emails'] = isset($data['only_loop_on_unseen_emails']) ? 1 : 0;
|
||||
$data['notify_lead_contact_more_times'] = isset($data['notify_lead_contact_more_times']) ? 1 : 0;
|
||||
$data['mark_public'] = isset($data['mark_public']) ? 1 : 0;
|
||||
$data['responsible'] = !isset($data['responsible']) ? 0 : $data['responsible'];
|
||||
if ($data['notify_lead_contact_more_times'] != 0 || $data['notify_lead_imported'] != 0) {
|
||||
if (isset($data['notify_type']) && $data['notify_type'] == 'specific_staff') {
|
||||
if (isset($data['notify_ids_staff'])) {
|
||||
$data['notify_ids'] = serialize($data['notify_ids_staff']);
|
||||
unset($data['notify_ids_staff']);
|
||||
} else {
|
||||
$data['notify_ids'] = serialize([]);
|
||||
unset($data['notify_ids_staff']);
|
||||
}
|
||||
if (isset($data['notify_ids_roles'])) {
|
||||
unset($data['notify_ids_roles']);
|
||||
}
|
||||
} else {
|
||||
if (isset($data['notify_ids_roles'])) {
|
||||
$data['notify_ids'] = serialize($data['notify_ids_roles']);
|
||||
unset($data['notify_ids_roles']);
|
||||
} else {
|
||||
$data['notify_ids'] = serialize([]);
|
||||
unset($data['notify_ids_roles']);
|
||||
}
|
||||
if (isset($data['notify_ids_staff'])) {
|
||||
unset($data['notify_ids_staff']);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$data['notify_ids'] = serialize([]);
|
||||
$data['notify_type'] = null;
|
||||
if (isset($data['notify_ids_staff'])) {
|
||||
unset($data['notify_ids_staff']);
|
||||
}
|
||||
if (isset($data['notify_ids_roles'])) {
|
||||
unset($data['notify_ids_roles']);
|
||||
}
|
||||
}
|
||||
// Check if not empty $data['password']
|
||||
// Get original
|
||||
// Decrypt original
|
||||
// Compare with $data['password']
|
||||
// If equal unset
|
||||
// If not encrypt and save
|
||||
if (!empty($data['password'])) {
|
||||
$or_decrypted = $this->encryption->decrypt($original_settings->password);
|
||||
if ($or_decrypted == $data['password']) {
|
||||
unset($data['password']);
|
||||
} else {
|
||||
$data['password'] = $this->encryption->encrypt($data['password']);
|
||||
}
|
||||
}
|
||||
$this->db->where('id', 1);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'leads_email_integration', $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function change_status_color($data, $playground = false) {
|
||||
$this->db->where('id', $data['status_id']);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'leads_status', ['color' => $data['color'], ]);
|
||||
}
|
||||
|
||||
public function update_status_order($data, $playground = false) {
|
||||
foreach ($data['order'] as $status) {
|
||||
$this->db->where('id', $status[0]);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'leads_status', ['statusorder' => $status[1], ]);
|
||||
}
|
||||
}
|
||||
|
||||
public function get_form($where, $playground = false) {
|
||||
$this->db->where($where);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'web_to_lead')->row();
|
||||
}
|
||||
|
||||
public function add_form($data, $playground = false) {
|
||||
$data = $this->_do_lead_web_to_form_responsibles($data);
|
||||
$data['success_submit_msg'] = nl2br($data['success_submit_msg']);
|
||||
$data['form_key'] = app_generate_hash();
|
||||
$data['create_task_on_duplicate'] = (int)isset($data['create_task_on_duplicate']);
|
||||
$data['mark_public'] = (int)isset($data['mark_public']);
|
||||
if (isset($data['allow_duplicate'])) {
|
||||
$data['allow_duplicate'] = 1;
|
||||
$data['track_duplicate_field'] = '';
|
||||
$data['track_duplicate_field_and'] = '';
|
||||
$data['create_task_on_duplicate'] = 0;
|
||||
} else {
|
||||
$data['allow_duplicate'] = 0;
|
||||
}
|
||||
$data['dateadded'] = date('Y-m-d H:i:s');
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'web_to_lead', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
log_activity('New Web to Lead Form Added [' . $data['name'] . ']');
|
||||
return $insert_id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function update_form($id, $data, $playground = false) {
|
||||
$data = $this->_do_lead_web_to_form_responsibles($data, $playground);
|
||||
$data['success_submit_msg'] = nl2br($data['success_submit_msg']);
|
||||
$data['create_task_on_duplicate'] = (int)isset($data['create_task_on_duplicate']);
|
||||
$data['mark_public'] = (int)isset($data['mark_public']);
|
||||
if (isset($data['allow_duplicate'])) {
|
||||
$data['allow_duplicate'] = 1;
|
||||
$data['track_duplicate_field'] = '';
|
||||
$data['track_duplicate_field_and'] = '';
|
||||
$data['create_task_on_duplicate'] = 0;
|
||||
} else {
|
||||
$data['allow_duplicate'] = 0;
|
||||
}
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'web_to_lead', $data);
|
||||
return ($this->db->affected_rows() > 0 ? true : false);
|
||||
}
|
||||
|
||||
public function delete_form($id, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'web_to_lead');
|
||||
$this->db->where('from_form_id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'leads', ['from_form_id' => 0, ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Lead Form Deleted [' . $id . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function _do_lead_web_to_form_responsibles($data, $playground = false) {
|
||||
if (isset($data['notify_lead_imported'])) {
|
||||
$data['notify_lead_imported'] = 1;
|
||||
} else {
|
||||
$data['notify_lead_imported'] = 0;
|
||||
}
|
||||
if ($data['responsible'] == '') {
|
||||
$data['responsible'] = 0;
|
||||
}
|
||||
if ($data['notify_lead_imported'] != 0) {
|
||||
if ($data['notify_type'] == 'specific_staff') {
|
||||
if (isset($data['notify_ids_staff'])) {
|
||||
$data['notify_ids'] = serialize($data['notify_ids_staff']);
|
||||
unset($data['notify_ids_staff']);
|
||||
} else {
|
||||
$data['notify_ids'] = serialize([]);
|
||||
unset($data['notify_ids_staff']);
|
||||
}
|
||||
if (isset($data['notify_ids_roles'])) {
|
||||
unset($data['notify_ids_roles']);
|
||||
}
|
||||
} else {
|
||||
if (isset($data['notify_ids_roles'])) {
|
||||
$data['notify_ids'] = serialize($data['notify_ids_roles']);
|
||||
unset($data['notify_ids_roles']);
|
||||
} else {
|
||||
$data['notify_ids'] = serialize([]);
|
||||
unset($data['notify_ids_roles']);
|
||||
}
|
||||
if (isset($data['notify_ids_staff'])) {
|
||||
unset($data['notify_ids_staff']);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$data['notify_ids'] = serialize([]);
|
||||
$data['notify_type'] = null;
|
||||
if (isset($data['notify_ids_staff'])) {
|
||||
unset($data['notify_ids_staff']);
|
||||
}
|
||||
if (isset($data['notify_ids_roles'])) {
|
||||
unset($data['notify_ids_roles']);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function do_kanban_query($status, $search = '', $page = 1, $sort = [], $count = false) {
|
||||
_deprecated_function('Leads_model::do_kanban_query', '2.9.2', 'LeadsKanban class');
|
||||
$kanBan = (new LeadsKanban($status))->search($search)->page($page)->sortBy($sort['sort']??null, $sort['sort_by']??null);
|
||||
if ($count) {
|
||||
return $kanBan->countAll();
|
||||
}
|
||||
return $kanBan->get();
|
||||
}
|
||||
}
|
||||
1497
api/models/Misc_model.php
Normal file
1497
api/models/Misc_model.php
Normal file
File diff suppressed because it is too large
Load Diff
51
api/models/Payment_attempts_model.php
Normal file
51
api/models/Payment_attempts_model.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Payment_attempts_model extends App_Model {
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return object|null
|
||||
*/
|
||||
public function add(array $data, $playground = false) {
|
||||
$data['created_at'] = date('c');
|
||||
$this->db->insert(($playground ? 'playground_' : '') . 'payment_attempts', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
return $this->get($insert_id, $data['payment_gateway'], $playground);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* @param int $id
|
||||
* @param string $gateway
|
||||
* @return object|null
|
||||
*/
|
||||
public function get(int $id, string $gateway, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->where('payment_gateway', $gateway);
|
||||
return $this->db->get(($playground ? 'playground_' : '') . 'payment_attempts')->row();
|
||||
}
|
||||
/**
|
||||
* @param string $reference
|
||||
* @param string $gateway
|
||||
* @return object|null
|
||||
*/
|
||||
public function getByReference(string $reference, string $gateway, $playground = false) {
|
||||
$this->db->where('reference', $reference);
|
||||
$this->db->where('payment_gateway', $gateway);
|
||||
return $this->db->get(($playground ? 'playground_' : '') . 'payment_attempts')->row();
|
||||
}
|
||||
/**
|
||||
* @param int $id
|
||||
* @return bool
|
||||
*/
|
||||
public function delete(int $id, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
return (bool)$this->db->delete(($playground ? 'playground_' : '') . 'payment_attempts');
|
||||
}
|
||||
}
|
||||
275
api/models/Payment_modes_model.php
Normal file
275
api/models/Payment_modes_model.php
Normal file
@@ -0,0 +1,275 @@
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Payment_modes_model extends App_Model {
|
||||
/**
|
||||
* @deprecated 2.3.4
|
||||
* @see gateways
|
||||
* @var array
|
||||
*/
|
||||
private $payment_gateways = [];
|
||||
|
||||
/**
|
||||
* New variable because the app_payment_gateways hook is moved in the method get_payment_gateways and the gateways be duplicated
|
||||
* After the deprecated filters are removed and access to $payment_gateways is removed, this should work fine.
|
||||
* @since 2.3.4
|
||||
* @var array
|
||||
*/
|
||||
private $gateways = null;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
/**
|
||||
* @deprecated 2.3.0 use app_payment_gateways
|
||||
* @var array
|
||||
*/
|
||||
$this->payment_gateways = apply_filters_deprecated('before_add_online_payment_modes', [[]], '2.3.0', 'app_payment_gateways');
|
||||
|
||||
/**
|
||||
* @deprecated 2.3.2 use app_payment_gateways
|
||||
* @var array
|
||||
*/
|
||||
$this->payment_gateways = apply_filters_deprecated('before_add_payment_gateways', [$this->payment_gateways], '2.3.0', 'app_payment_gateways');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get payment mode
|
||||
* @param string $id payment mode id
|
||||
* @param array $where additional where only for offline modes
|
||||
* @param boolean $include_inactive whether to include inactive too
|
||||
* @param boolean $force force if it's inactive to return it back
|
||||
* @return array
|
||||
*/
|
||||
public function get($id = '', $where = [], $include_inactive = false, $force = false, $playground = false) {
|
||||
$this->db->where($where);
|
||||
if (is_numeric($id)) {
|
||||
$this->db->where('id', $id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'payment_modes')->row();
|
||||
} else if (!empty($id)) {
|
||||
foreach ($this->get_payment_gateways(true) as $gateway) {
|
||||
if ($gateway['id'] == $id) {
|
||||
if ($gateway['active'] == 0 && $force == false) {
|
||||
continue;
|
||||
}
|
||||
// The instance is already object and array_to_object is messing up
|
||||
$instance = $gateway['instance'];
|
||||
unset($gateway['instance']);
|
||||
$mode = array_to_object($gateway);
|
||||
// Add again the instance
|
||||
$mode->instance = $instance;
|
||||
$mode->show_on_pdf = 0;
|
||||
return $mode;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if ($include_inactive !== true) {
|
||||
$this->db->where('active', 1);
|
||||
}
|
||||
$modes = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'payment_modes')->result_array();
|
||||
$modes = array_merge($modes, $this->get_payment_gateways($include_inactive));
|
||||
return $modes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new payment mode
|
||||
* @param array $data payment mode $_POST data
|
||||
*/
|
||||
public function add($data, $playground = false) {
|
||||
if (isset($data['id'])) {
|
||||
unset($data['id']);
|
||||
}
|
||||
foreach (['active', 'show_on_pdf', 'selected_by_default', 'invoices_only', 'expenses_only'] as $check) {
|
||||
$data[$check] = !isset($data[$check]) ? 0 : 1;
|
||||
}
|
||||
$data = hooks()->apply_filters('before_paymentmode_added', $data);
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'payment_modes', ['name' => $data['name'], 'description' => nl2br_save_html($data['description']), 'active' => $data['active'], 'expenses_only' => $data['expenses_only'], 'invoices_only' => $data['invoices_only'], 'show_on_pdf' => $data['show_on_pdf'], 'selected_by_default' => $data['selected_by_default'], ]);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
log_activity('New Payment Mode Added [ID: ' . $insert_id . ', Name:' . $data['name'] . ']');
|
||||
hooks()->do_action('after_paymentmode_added', ['id' => $insert_id, 'data' => $data, ]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update payment mode
|
||||
* @param array $data payment mode $_POST data
|
||||
* @return boolean
|
||||
*/
|
||||
public function edit($data, $playground = false) {
|
||||
$id = $data['paymentmodeid'];
|
||||
$updated = false;
|
||||
unset($data['paymentmodeid']);
|
||||
foreach (['active', 'show_on_pdf', 'selected_by_default', 'invoices_only', 'expenses_only'] as $check) {
|
||||
$data[$check] = !isset($data[$check]) ? 0 : 1;
|
||||
}
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(($playground ? 'playground_' : '') . 'payment_modes', ['name' => $data['name'], 'description' => nl2br_save_html($data['description']), 'active' => $data['active'], 'expenses_only' => $data['expenses_only'], 'invoices_only' => $data['invoices_only'], 'show_on_pdf' => $data['show_on_pdf'], 'selected_by_default' => $data['selected_by_default'], ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$updated = true;
|
||||
}
|
||||
hooks()->do_action('after_update_paymentmode', ['id' => $id, 'data' => $data, 'updated' => & $updated, ]);
|
||||
if ($updated) {
|
||||
log_activity('Payment Mode Updated [ID: ' . $id . ', Name:' . $data['name'] . ']');
|
||||
}
|
||||
return $updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete payment mode from database
|
||||
* @param mixed $id payment mode id
|
||||
* @return mixed / if referenced array else boolean
|
||||
*/
|
||||
public function delete($id, $playground = false) {
|
||||
// Check if the payment mode is using in the invoiec payment records table.
|
||||
if (is_reference_in_table('paymentmode', db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords', $id) || is_reference_in_table('paymentmode', db_prefix() . ($playground ? 'playground_' : '') . 'expenses', $id)) {
|
||||
return ['referenced' => true, ];
|
||||
}
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(($playground ? 'playground_' : '') . 'payment_modes');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Payment Mode Deleted [' . $id . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function search($q, $limit = 0, $playground = false)
|
||||
{
|
||||
$result = [
|
||||
'result' => [],
|
||||
'type' => 'payments',
|
||||
'search_heading' => _l('payments'),
|
||||
];
|
||||
|
||||
if (has_permission('payments', '', 'view')) {
|
||||
$this->db->select(db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.*');
|
||||
$this->db->from(db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'payment_modes', db_prefix() . ($playground ? 'playground_' : '') . 'payment_modes.id='.db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.paymentmode', 'LEFT');
|
||||
$this->db->like('name', $q);
|
||||
$this->db->or_like(db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.paymentmode', $q);
|
||||
$this->db->or_like(db_prefix() . ($playground ? 'playground_' : '') . '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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.3.0
|
||||
* Get payment gateways
|
||||
* @param boolean $includeInactive whether to include the inactive ones too
|
||||
* @return array
|
||||
*/
|
||||
public function get_payment_gateways($includeInactive = false, $playground = false) {
|
||||
if (is_null($this->gateways)) {
|
||||
/**
|
||||
* Used for autoloading the payment gateways in App_gateway
|
||||
* @since 2.3.4
|
||||
*/
|
||||
hooks()->do_action('before_get_payment_gateways');
|
||||
/**
|
||||
* Moved here in 2.3.4
|
||||
* When remove $this->payment_gateways, change filter parameter below $this->payment_gateways to empty array ([])
|
||||
* @since 2.3.2
|
||||
* @var array
|
||||
*/
|
||||
$this->gateways = hooks()->apply_filters('app_payment_gateways', $this->payment_gateways);
|
||||
}
|
||||
$modes = [];
|
||||
foreach ($this->gateways as $mode) {
|
||||
if ($includeInactive !== true && $mode['active'] == 0) {
|
||||
continue;
|
||||
}
|
||||
// The the gateways unique in case duplicate ID's are found.
|
||||
if (!value_exists_in_array_by_key($modes, 'id', $mode['id'])) {
|
||||
$modes[] = $mode;
|
||||
} else {
|
||||
if (ENVIRONMENT != 'production') {
|
||||
trigger_error(sprintf('Payment Gateway ID "%1$s" already exists, ignoring duplicate gateway ID...', $mode['id']));
|
||||
}
|
||||
}
|
||||
}
|
||||
return $modes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all online payment modes
|
||||
* @deprecated 2.3.0 use get_payment_gateways instead
|
||||
* @since 1.0.1
|
||||
* @return array payment modes
|
||||
*/
|
||||
public function get_online_payment_modes($all = false, $playground = false) {
|
||||
return $this->get_payment_gateways($all, $playground);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since Version 1.0.1
|
||||
* @param integer ID
|
||||
* @param integer Status ID
|
||||
* @return boolean
|
||||
* Update payment mode status Active/Inactive
|
||||
*/
|
||||
public function change_payment_mode_status($id, $status, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(($playground ? 'playground_' : '') . 'payment_modes', ['active' => $status, ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Payment Mode Status Changed [ModeID: ' . $id . ' Status(Active/Inactive): ' . $status . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since Version 1.0.1
|
||||
* @param integer ID
|
||||
* @param integer Status ID
|
||||
* @return boolean
|
||||
* Update payment mode show to client Active/Inactive
|
||||
*/
|
||||
public function change_payment_mode_show_to_client_status($id, $status, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(($playground ? 'playground_' : '') . 'payment_modes', ['showtoclient' => $status, ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Payment Mode Show to Client Changed [ModeID: ' . $id . ' Status(Active/Inactive): ' . $status . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject custom payment gateway into the payment gateways array
|
||||
* @param string $gateway_name payment gateway name, should equal like the libraries/classname
|
||||
* @param string $module module name to load the gateway if not already loaded
|
||||
*/
|
||||
public function add_payment_gateway($gateway, $module = null, $playground = false) {
|
||||
if (is_string($gateway)) {
|
||||
$gateway = strtolower($gateway);
|
||||
// Perhaps is in subfolder e.q. gateways/Example_gateway?
|
||||
$basename = basename($gateway);
|
||||
if (!$this->load->is_loaded($basename) && $module) {
|
||||
$this->load->library($module . '/' . $gateway);
|
||||
}
|
||||
$class = $this->{$basename};
|
||||
} else {
|
||||
// register_payment_gateway(new Example_gateway(), '[module_name]');
|
||||
$class = $gateway;
|
||||
$name = get_class($class);
|
||||
if (!$class instanceof App_gateway) {
|
||||
throw new \Exception($name . ' must be an instance of "App_gateway"');
|
||||
}
|
||||
}
|
||||
if (hooks()->has_filter('app_payment_gateways', [$class, 'initMode']) === false) {
|
||||
hooks()->add_filter('app_payment_gateways', [$class, 'initMode']);
|
||||
}
|
||||
}
|
||||
}
|
||||
458
api/models/Payments_model.php
Normal file
458
api/models/Payments_model.php
Normal file
@@ -0,0 +1,458 @@
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Payments_model extends App_Model {
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->load->model('clients_model');
|
||||
$this->load->model('invoices_model');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get payment by ID
|
||||
* @param mixed $id payment id
|
||||
* @return object
|
||||
*/
|
||||
public function get($id, $playground = false) {
|
||||
$this->db->select('*,' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.id as paymentid');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'payment_modes', db_prefix() . ($playground ? 'playground_' : '') . 'payment_modes.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.paymentmode', 'left');
|
||||
$this->db->order_by(db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.id', 'asc');
|
||||
$this->db->where(db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.id', $id);
|
||||
$payment = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords')->row();
|
||||
if (!$payment) {
|
||||
return false;
|
||||
}
|
||||
// Since version 1.0.1
|
||||
$this->load->model('payment_modes_model');
|
||||
$payment_gateways = $this->payment_modes_model->get_payment_gateways(true, $playground);
|
||||
if (is_null($payment->id)) {
|
||||
foreach ($payment_gateways as $gateway) {
|
||||
if ($payment->paymentmode == $gateway['id']) {
|
||||
$payment->name = $gateway['name'];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $payment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get payment by ID
|
||||
* @param mixed $id payment id
|
||||
* @return object
|
||||
*/
|
||||
public function get_payment($id = '', $playground = false) {
|
||||
// Select all fields from the invoicepaymentrecords table, and alias the id field
|
||||
$this->db->select(db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.*, ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.id as paymentid');
|
||||
// Join the payment_modes table
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'payment_modes', db_prefix() . ($playground ? 'playground_' : '') . 'payment_modes.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.paymentmode', 'left');
|
||||
// Order by the id of invoicepaymentrecords in ascending order
|
||||
$this->db->order_by(db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.id', 'asc');
|
||||
|
||||
// Check if a specific id was provided
|
||||
if (!empty($id)) {
|
||||
// If an id was provided, add a where condition to the query
|
||||
$this->db->where(db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.id', $id);
|
||||
// Execute the query and get the single row result
|
||||
$payment = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords')->row();
|
||||
} else {
|
||||
// If no specific id was provided, execute the query and get all results
|
||||
$payment = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords')->result();
|
||||
}
|
||||
|
||||
// If no payment records were found, return false
|
||||
if (!$payment) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all invoice payments
|
||||
* @param mixed $invoiceid invoiceid
|
||||
* @return array
|
||||
*/
|
||||
public function get_invoice_payments($invoiceid, $playground = false) {
|
||||
$this->db->select('*,' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.id as paymentid');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'payment_modes', db_prefix() . ($playground ? 'playground_' : '') . 'payment_modes.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.paymentmode', 'left');
|
||||
$this->db->order_by(db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.id', 'asc');
|
||||
$this->db->where('invoiceid', $invoiceid);
|
||||
$payments = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords')->result_array();
|
||||
// Since version 1.0.1
|
||||
$this->load->model('payment_modes_model');
|
||||
$payment_gateways = $this->payment_modes_model->get_payment_gateways(true, $playground);
|
||||
$i = 0;
|
||||
foreach ($payments as $payment) {
|
||||
if (is_null($payment['id'])) {
|
||||
foreach ($payment_gateways as $gateway) {
|
||||
if ($payment['paymentmode'] == $gateway['id']) {
|
||||
$payments[$i]['id'] = $gateway['id'];
|
||||
$payments[$i]['name'] = $gateway['name'];
|
||||
}
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
return $payments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process invoice payment offline or online
|
||||
* @since Version 1.0.1
|
||||
* @param array $data $_POST data
|
||||
* @return boolean
|
||||
*/
|
||||
public function process_payment($data, $invoiceid = '', $playground = false) {
|
||||
// Offline payment mode from the admin side
|
||||
if (is_numeric($data['paymentmode'])) {
|
||||
if (is_staff_logged_in()) {
|
||||
$id = $this->add($data);
|
||||
return $id;
|
||||
}
|
||||
return false;
|
||||
// Is online payment mode request by client or staff
|
||||
} else if (!is_numeric($data['paymentmode']) && !empty($data['paymentmode'])) {
|
||||
// This request will come from admin area only
|
||||
// If admin clicked the button that dont want to pay the invoice from the getaways only want
|
||||
if (is_staff_logged_in() && staff_can('create', 'payments')) {
|
||||
if (isset($data['do_not_redirect'])) {
|
||||
$id = $this->add($data);
|
||||
return $id;
|
||||
}
|
||||
}
|
||||
if (!is_numeric($invoiceid)) {
|
||||
if (!isset($data['invoiceid'])) {
|
||||
die('No invoice specified');
|
||||
}
|
||||
$invoiceid = $data['invoiceid'];
|
||||
}
|
||||
if (isset($data['do_not_send_email_template'])) {
|
||||
unset($data['do_not_send_email_template']);
|
||||
$this->session->set_userdata(['do_not_send_email_template' => true, ]);
|
||||
}
|
||||
$invoice = $this->invoices_model->get($invoiceid, $playground);
|
||||
// Check if request coming from admin area and the user added note so we can insert the note also when the payment is recorded
|
||||
if (isset($data['note']) && $data['note'] != '') {
|
||||
$this->session->set_userdata(['payment_admin_note' => $data['note'], ]);
|
||||
}
|
||||
if (get_option('allow_payment_amount_to_be_modified') == 0) {
|
||||
$data['amount'] = get_invoice_total_left_to_pay($invoiceid, $invoice->total);
|
||||
}
|
||||
$data['invoiceid'] = $invoiceid;
|
||||
$data['invoice'] = $invoice;
|
||||
$data = hooks()->apply_filters('before_process_gateway_func', $data);
|
||||
$this->load->model('payment_modes_model');
|
||||
$gateway = $this->payment_modes_model->get($data['paymentmode'], $playground);
|
||||
$data['gateway_fee'] = $gateway->instance->getFee($data['amount']);
|
||||
$this->load->model('payment_attempts_model');
|
||||
$data['payment_attempt'] = $this->payment_attempts_model->add(['reference' => app_generate_hash(), 'amount' => $data['amount'], 'fee' => $data['gateway_fee'], 'invoice_id' => $data['invoiceid'], 'payment_gateway' => $gateway->instance->getId() ], $playground);
|
||||
$data['amount'] += $data['gateway_fee'];
|
||||
$gateway->instance->process_payment($data);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether payment exist by transaction id for the given invoice
|
||||
*
|
||||
* @param int $transactionId
|
||||
* @param int|null $invoiceId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function transaction_exists($transactionId, $invoiceId = null, $playground = false) {
|
||||
return total_rows(($playground ? 'playground_' : '') . 'invoicepaymentrecords', array_filter(['transactionid' => $transactionId, 'invoiceid' => $invoiceId, ])) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record new payment
|
||||
* @param array $data payment data
|
||||
* @return boolean
|
||||
*/
|
||||
public function add($data, $subscription = false, $playground = false) {
|
||||
// Check if field do not redirect to payment processor is set so we can unset from the database
|
||||
if (isset($data['do_not_redirect'])) {
|
||||
unset($data['do_not_redirect']);
|
||||
}
|
||||
if ($subscription != false) {
|
||||
$after_success = get_option('after_subscription_payment_captured');
|
||||
if ($after_success == 'nothing' || $after_success == 'send_invoice') {
|
||||
$data['do_not_send_email_template'] = true;
|
||||
}
|
||||
}
|
||||
if (isset($data['do_not_send_email_template'])) {
|
||||
unset($data['do_not_send_email_template']);
|
||||
$do_not_send_email_template = true;
|
||||
} else if ($this->session->has_userdata('do_not_send_email_template')) {
|
||||
$do_not_send_email_template = true;
|
||||
$this->session->unset_userdata('do_not_send_email_template');
|
||||
}
|
||||
if (is_staff_logged_in()) {
|
||||
if (isset($data['date'])) {
|
||||
$data['date'] = to_sql_date($data['date']);
|
||||
} else {
|
||||
$data['date'] = date('Y-m-d H:i:s');
|
||||
}
|
||||
if (isset($data['note'])) {
|
||||
$data['note'] = nl2br($data['note']);
|
||||
} else if ($this->session->has_userdata('payment_admin_note')) {
|
||||
$data['note'] = nl2br($this->session->userdata('payment_admin_note'));
|
||||
$this->session->unset_userdata('payment_admin_note');
|
||||
}
|
||||
} else {
|
||||
$data['date'] = date('Y-m-d H:i:s');
|
||||
}
|
||||
$data['daterecorded'] = date('Y-m-d H:i:s');
|
||||
$data = hooks()->apply_filters('before_payment_recorded', $data);
|
||||
unset($data['amount_with_fee']);
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
$invoice = $this->invoices_model->get($data['invoiceid'], $playground);
|
||||
$force_update = false;
|
||||
if (!class_exists('Invoices_model', false)) {
|
||||
$this->load->model('invoices_model');
|
||||
}
|
||||
if ($invoice->status == Invoices_model::STATUS_DRAFT) {
|
||||
$force_update = true;
|
||||
// update invoice number for invoice with draft - V2.7.2
|
||||
$this->invoices_model->change_invoice_number_when_status_draft($invoice->id, $playground);
|
||||
}
|
||||
update_invoice_status($data['invoiceid'], $force_update);
|
||||
$this->invoices_model->save_formatted_number($invoice->id, $playground);
|
||||
$activity_lang_key = 'invoice_activity_payment_made_by_staff';
|
||||
if (!is_staff_logged_in()) {
|
||||
$activity_lang_key = 'invoice_activity_payment_made_by_client';
|
||||
}
|
||||
$this->invoices_model->log_invoice_activity($data['invoiceid'], $activity_lang_key, !is_staff_logged_in() ? true : false, serialize([app_format_money($data['amount'], $invoice->currency_name), '<a href="' . admin_url('payments/payment/' . $insert_id) . '" target="_blank">#' . $insert_id . '</a>', ]));
|
||||
log_activity('Payment Recorded [ID:' . $insert_id . ', Invoice Number: ' . format_invoice_number($invoice->id) . ', Total: ' . app_format_money($data['amount'], $invoice->currency_name) . ']');
|
||||
// Send email to the client that the payment is recorded
|
||||
$payment = $this->get($insert_id);
|
||||
$payment->invoice_data = $this->invoices_model->get($payment->invoiceid, $playground);
|
||||
set_mailing_constant();
|
||||
$paymentpdf = payment_pdf($payment);
|
||||
$payment_pdf_filename = mb_strtoupper(slug_it(_l('payment') . '-' . $payment->paymentid), 'UTF-8') . '.pdf';
|
||||
$attach = $paymentpdf->Output($payment_pdf_filename, 'S');
|
||||
if (!isset($do_not_send_email_template) || ($subscription != false && $after_success == 'send_invoice_and_receipt') || ($subscription != false && $after_success == 'send_invoice')) {
|
||||
$template_name = 'invoice_payment_recorded_to_customer';
|
||||
$pdfInvoiceAttachment = false;
|
||||
$attachPaymentReceipt = true;
|
||||
$emails_sent = [];
|
||||
$where = ['active' => 1, 'invoice_emails' => 1];
|
||||
if ($subscription != false) {
|
||||
$where['is_primary'] = 1;
|
||||
$template_name = 'subscription_payment_succeeded';
|
||||
if ($after_success == 'send_invoice_and_receipt' || $after_success == 'send_invoice') {
|
||||
$invoice_number = format_invoice_number($payment->invoiceid);
|
||||
set_mailing_constant();
|
||||
$pdfInvoice = invoice_pdf($payment->invoice_data);
|
||||
$pdfInvoiceAttachment = $pdfInvoice->Output($invoice_number . '.pdf', 'S');
|
||||
if ($after_success == 'send_invoice') {
|
||||
$attachPaymentReceipt = false;
|
||||
}
|
||||
}
|
||||
// Is from settings: Send Payment Receipt
|
||||
} else {
|
||||
if (get_option('attach_invoice_to_payment_receipt_email') == 1) {
|
||||
$invoice_number = format_invoice_number($payment->invoiceid);
|
||||
set_mailing_constant();
|
||||
$pdfInvoice = invoice_pdf($payment->invoice_data);
|
||||
$pdfInvoiceAttachment = $pdfInvoice->Output($invoice_number . '.pdf', 'S');
|
||||
}
|
||||
}
|
||||
$contacts = $this->clients_model->get_contacts($invoice->clientid, $where);
|
||||
foreach ($contacts as $contact) {
|
||||
$template = mail_template($template_name, $contact, $invoice, $subscription, $payment->paymentid);
|
||||
if ($attachPaymentReceipt) {
|
||||
$template->add_attachment(['attachment' => $attach, 'filename' => $payment_pdf_filename, 'type' => 'application/pdf', ]);
|
||||
}
|
||||
if ($pdfInvoiceAttachment) {
|
||||
$template->add_attachment(['attachment' => $pdfInvoiceAttachment, 'filename' => str_replace('/', '-', $invoice_number) . '.pdf', 'type' => 'application/pdf', ]);
|
||||
}
|
||||
$merge_fields = $template->get_merge_fields();
|
||||
if ($template->send()) {
|
||||
array_push($emails_sent, $contact['email']);
|
||||
}
|
||||
$this->app_sms->trigger(SMS_TRIGGER_PAYMENT_RECORDED, $contact['phonenumber'], $merge_fields);
|
||||
}
|
||||
if (count($emails_sent) > 0) {
|
||||
$additional_activity_data = serialize([implode(', ', $emails_sent), ]);
|
||||
$activity_lang_key = 'invoice_activity_record_payment_email_to_customer';
|
||||
if ($subscription != false) {
|
||||
$activity_lang_key = 'invoice_activity_subscription_payment_succeeded';
|
||||
}
|
||||
$this->invoices_model->log_invoice_activity($invoice->id, $activity_lang_key, false, $additional_activity_data);
|
||||
}
|
||||
}
|
||||
$this->db->where('staffid', $invoice->addedfrom);
|
||||
$this->db->or_where('staffid', $invoice->sale_agent);
|
||||
$staff_invoice = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'staff')->result_array();
|
||||
$notifiedUsers = [];
|
||||
foreach ($staff_invoice as $member) {
|
||||
if (get_option('notification_when_customer_pay_invoice') == 1) {
|
||||
if (is_staff_logged_in() && $member['staffid'] == get_staff_user_id()) {
|
||||
continue;
|
||||
}
|
||||
// E.q. had permissions create not don't have, so we must re-check this
|
||||
if (user_can_view_invoice($invoice->id, $member['staffid'])) {
|
||||
$notified = add_notification(['fromcompany' => true, 'touserid' => $member['staffid'], 'description' => 'not_invoice_payment_recorded', 'link' => 'payments/payment/' . $insert_id, 'additional_data' => serialize([format_invoice_number($invoice->id), ]), ]);
|
||||
if ($notified) {
|
||||
array_push($notifiedUsers, $member['staffid']);
|
||||
}
|
||||
send_mail_template('invoice_payment_recorded_to_staff', $member['email'], $member['staffid'], $invoice, $attach, $payment->paymentid);
|
||||
}
|
||||
}
|
||||
}
|
||||
pusher_trigger_notification($notifiedUsers);
|
||||
hooks()->do_action('after_payment_added', $insert_id);
|
||||
return $insert_id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update payment
|
||||
* @param array $data payment data
|
||||
* @param mixed $id paymentid
|
||||
* @return boolean
|
||||
*/
|
||||
public function update($data, $id, $playground = false) {
|
||||
$payment = $this->get($id);
|
||||
$updated = false;
|
||||
$data['date'] = to_sql_date($data['date']);
|
||||
$data['note'] = nl2br($data['note']);
|
||||
$data = hooks()->apply_filters('before_payment_updated', $data, $id);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(($playground ? 'playground_' : '') . 'invoicepaymentrecords', $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
if ($data['amount'] != $payment->amount) {
|
||||
update_invoice_status($payment->invoiceid);
|
||||
}
|
||||
$updated = true;
|
||||
}
|
||||
hooks()->do_action('after_payment_updated', ['id' => $id, 'data' => $data, 'payment' => $payment, 'updated' => & $updated, ]);
|
||||
if ($updated) {
|
||||
log_activity('Payment Updated [Number:' . $id . ']');
|
||||
}
|
||||
return $updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete payment from database
|
||||
* @param mixed $id paymentid
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete($id, $playground = false) {
|
||||
$current = $this->get($id);
|
||||
$current_invoice = $this->invoices_model->get($current->invoiceid, $playground);
|
||||
$invoiceid = $current->invoiceid;
|
||||
hooks()->do_action('before_payment_deleted', ['paymentid' => $id, 'invoiceid' => $invoiceid, ]);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
update_invoice_status($invoiceid);
|
||||
$this->invoices_model->log_invoice_activity($invoiceid, 'invoice_activity_payment_deleted', false, serialize([$current->paymentid, app_format_money($current->amount, $current_invoice->currency_name), ]));
|
||||
log_activity('Payment Deleted [ID:' . $id . ', Invoice Number: ' . format_invoice_number($current->id) . ']');
|
||||
hooks()->do_action('after_payment_deleted', ['paymentid' => $id, 'invoiceid' => $invoiceid, ]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function add_batch_payment($paymentsData, $playground = false) {
|
||||
$sendBatchPaymentEmail = true;
|
||||
if (isset($paymentsData['do_not_send_invoice_payment_recorded'])) {
|
||||
$sendBatchPaymentEmail = false;
|
||||
}
|
||||
$paymentIds = [];
|
||||
foreach ($paymentsData['invoice'] as $data) {
|
||||
if (empty($data['invoiceid']) || empty($data['amount']) || empty($data['date']) || empty('paymentmode')) {
|
||||
continue;
|
||||
}
|
||||
$data['date'] = to_sql_date($data['date']);
|
||||
$data['daterecorded'] = date('Y-m-d H:i:s');
|
||||
$data = hooks()->apply_filters('before_payment_recorded', $data);
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
$paymentIds[] = $insert_id;
|
||||
$invoice = $this->invoices_model->get($data['invoiceid'], $playground);
|
||||
$force_update = false;
|
||||
if (!class_exists('Invoices_model', false)) {
|
||||
$this->load->model('invoices_model');
|
||||
}
|
||||
if ($invoice->status == Invoices_model::STATUS_DRAFT) {
|
||||
$force_update = true;
|
||||
// update invoice number for invoice with draft - V2.7.2
|
||||
$this->invoices_model->change_invoice_number_when_status_draft($invoice->id, $playground);
|
||||
}
|
||||
update_invoice_status($data['invoiceid'], $force_update);
|
||||
$this->invoices_model->save_formatted_number($invoice->id, $playground);
|
||||
$this->invoices_model->log_invoice_activity($data['invoiceid'], 'invoice_activity_payment_made_by_staff', false, serialize([app_format_money($data['amount'], $invoice->currency_name), '<a href="' . admin_url('payments/payment/' . $insert_id) . '" target="_blank">#' . $insert_id . '</a>', ]), $playground);
|
||||
log_activity('Payment Recorded [ID:' . $insert_id . ', Invoice Number: ' . format_invoice_number($invoice->id) . ', Total: ' . app_format_money($data['amount'], $invoice->currency_name) . ']');
|
||||
}
|
||||
hooks()->do_action('after_payment_added', $insert_id);
|
||||
}
|
||||
if (count($paymentIds) > 0 && $sendBatchPaymentEmail) {
|
||||
$this->send_batch_payment_notification_to_customers($paymentIds, $playground);
|
||||
}
|
||||
return count($paymentIds);
|
||||
}
|
||||
|
||||
private function send_batch_payment_notification_to_customers($paymentIds, $playground = false) {
|
||||
$paymentData = $this->db->select(db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.*,' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.currency,' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.clientId,' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.hash')->join(db_prefix() . ($playground ? 'playground_' : '') . 'invoices', 'invoicepaymentrecords.invoiceid=invoices.id')->where_in('invoicepaymentrecords.id', $paymentIds)->get(db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords')->result();
|
||||
// used collection groupBy as a workaround for mysql8.0 only full group mode
|
||||
$paymentData = collect($paymentData)->groupBy('clientId');
|
||||
foreach ($paymentData as $clientId => $payments) {
|
||||
$contacts = $this->get_contacts_for_payment_emails($clientId, $playground);
|
||||
foreach ($contacts as $contact) {
|
||||
if (count($payments) === 1) {
|
||||
$this->send_invoice_payment_recorded($payments[0]->id, $contact, $playground);
|
||||
} else {
|
||||
$template = mail_template('invoice_batch_payments', $payments, $contact);
|
||||
foreach ($payments as $payment) {
|
||||
$payment = $this->get($payment->id);
|
||||
$payment->invoice_data = $this->invoices_model->get($payment->invoiceid, $playground);
|
||||
$template = $this->_add_payment_mail_attachments_to_template($template, $payment, $playground);
|
||||
}
|
||||
$template->send();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function send_invoice_payment_recorded($id, $contact, $playground = false) {
|
||||
if (!class_exists('Invoices_model', false)) {
|
||||
$this->load->model('invoices_model');
|
||||
}
|
||||
// to get structure matching payment_pdf()
|
||||
$payment = $this->get($id, $playground);
|
||||
$payment->invoice_data = $this->invoices_model->get($payment->invoiceid, $playground);
|
||||
$template = mail_template('invoice_payment_recorded_to_customer', (array)$contact, $payment->invoice_data, false, $id);
|
||||
$template = $this->_add_payment_mail_attachments_to_template($template, $payment, $playground);
|
||||
return $template->send();
|
||||
}
|
||||
|
||||
private function _add_payment_mail_attachments_to_template($template, $payment, $playground = false) {
|
||||
set_mailing_constant();
|
||||
$paymentPDF = payment_pdf($payment);
|
||||
$filename = mb_strtoupper(slug_it(_l('payment') . '-' . $payment->paymentid), 'UTF-8') . '.pdf';
|
||||
$attach = $paymentPDF->Output($filename, 'S');
|
||||
$template->add_attachment(['attachment' => $attach, 'filename' => $filename, 'type' => 'application/pdf', ]);
|
||||
if (get_option('attach_invoice_to_payment_receipt_email') == 1) {
|
||||
$invoice_number = format_invoice_number($payment->invoiceid);
|
||||
set_mailing_constant();
|
||||
$pdfInvoice = invoice_pdf($payment->invoice_data);
|
||||
$pdfInvoiceAttachment = $pdfInvoice->Output($invoice_number . '.pdf', 'S');
|
||||
$template->add_attachment(['attachment' => $pdfInvoiceAttachment, 'filename' => str_replace('/', '-', $invoice_number) . '.pdf', 'type' => 'application/pdf', ]);
|
||||
}
|
||||
return $template;
|
||||
}
|
||||
|
||||
private function get_contacts_for_payment_emails($client_id, $playground = false) {
|
||||
if (!class_exists('Clients_model', false)) {
|
||||
$this->load->model('clients_model');
|
||||
}
|
||||
return $this->clients_model->get_contacts($client_id, ['active' => 1, 'invoice_emails' => 1, ], $playground);
|
||||
}
|
||||
}
|
||||
2212
api/models/Projects_model.php
Normal file
2212
api/models/Projects_model.php
Normal file
File diff suppressed because it is too large
Load Diff
920
api/models/Proposals_model.php
Normal file
920
api/models/Proposals_model.php
Normal file
@@ -0,0 +1,920 @@
|
||||
<?php
|
||||
|
||||
use app\services\AbstractKanban;
|
||||
use app\services\proposals\ProposalsPipeline;
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Proposals_model extends App_Model {
|
||||
private $statuses;
|
||||
private $copy = false;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->statuses = hooks()->apply_filters('before_set_proposal_statuses', [6, 4, 1, 5, 2, 3, ]);
|
||||
}
|
||||
|
||||
public function get_statuses() {
|
||||
return $this->statuses;
|
||||
}
|
||||
|
||||
public function get_sale_agents($playground = false) {
|
||||
return $this->db->query('SELECT DISTINCT(assigned) as sale_agent FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'proposals WHERE assigned != 0')->result_array();
|
||||
}
|
||||
|
||||
public function get_proposals_years($playground = false) {
|
||||
return $this->db->query('SELECT DISTINCT(YEAR(date)) as year FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'proposals')->result_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserting new proposal function
|
||||
* @param mixed $data $_POST data
|
||||
*/
|
||||
public function add($data, $playground = false) {
|
||||
$data['allow_comments'] = isset($data['allow_comments']) ? 1 : 0;
|
||||
$save_and_send = isset($data['save_and_send']);
|
||||
$tags = isset($data['tags']) ? $data['tags'] : '';
|
||||
if (isset($data['custom_fields'])) {
|
||||
$custom_fields = $data['custom_fields'];
|
||||
unset($data['custom_fields']);
|
||||
}
|
||||
$estimateRequestID = false;
|
||||
if (isset($data['estimate_request_id'])) {
|
||||
$estimateRequestID = $data['estimate_request_id'];
|
||||
unset($data['estimate_request_id']);
|
||||
}
|
||||
$data['address'] = trim($data['address']);
|
||||
$data['address'] = nl2br($data['address']);
|
||||
$data['datecreated'] = date('Y-m-d H:i:s');
|
||||
$data['addedfrom'] = get_staff_user_id();
|
||||
$data['hash'] = app_generate_hash();
|
||||
if (empty($data['rel_type'])) {
|
||||
unset($data['rel_type']);
|
||||
unset($data['rel_id']);
|
||||
} else {
|
||||
if (empty($data['rel_id'])) {
|
||||
unset($data['rel_type']);
|
||||
unset($data['rel_id']);
|
||||
}
|
||||
}
|
||||
$items = [];
|
||||
if (isset($data['newitems'])) {
|
||||
$items = $data['newitems'];
|
||||
unset($data['newitems']);
|
||||
}
|
||||
if ($this->copy == false) {
|
||||
$data['content'] = '{proposal_items}';
|
||||
}
|
||||
if (isset($data['rel_id'], $data['rel_type']) && $data['rel_type'] !== 'customer') {
|
||||
$data['project_id'] = null;
|
||||
}
|
||||
$hook = hooks()->apply_filters('before_create_proposal', ['data' => $data, 'items' => $items, ]);
|
||||
$data = $hook['data'];
|
||||
$items = $hook['items'];
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'proposals', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
if ($estimateRequestID !== false && $estimateRequestID != '') {
|
||||
$this->load->model('estimate_request_model');
|
||||
$completedStatus = $this->estimate_request_model->get_status_by_flag('completed', $playground);
|
||||
$this->estimate_request_model->update_request_status(['requestid' => $estimateRequestID, 'status' => $completedStatus->id, ], $playground);
|
||||
}
|
||||
if (isset($custom_fields)) {
|
||||
$this->load->model('custom_fields_model');
|
||||
$this->custom_fields_model->handle_custom_fields_post($insert_id, $custom_fields, false, $playground);
|
||||
}
|
||||
$this->load->model('misc_model');
|
||||
$this->misc_model->handle_tags_save($tags, $insert_id, 'proposal', $playground);
|
||||
$this->load->model('invoice_items_model');
|
||||
foreach ($items as $key => $item) {
|
||||
if ($itemid = $this->invoice_items_model->add_new_sales_item_post($item, $insert_id, 'proposal', $playground)) {
|
||||
$this->invoice_items_model->_maybe_insert_post_item_tax($itemid, $item, $insert_id, 'proposal', $playground);
|
||||
}
|
||||
}
|
||||
$proposal = $this->get($insert_id, [], false, $playground);
|
||||
if ($proposal->assigned != 0) {
|
||||
if ($proposal->assigned != get_staff_user_id()) {
|
||||
$notified = add_notification(['description' => 'not_proposal_assigned_to_you', 'touserid' => $proposal->assigned, 'fromuserid' => get_staff_user_id(), 'link' => 'proposals/list_proposals/' . $insert_id, 'additional_data' => serialize([$proposal->subject, ]), ]);
|
||||
if ($notified) {
|
||||
pusher_trigger_notification([$proposal->assigned]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($data['rel_type'] == 'lead') {
|
||||
$this->load->model('leads_model');
|
||||
$this->leads_model->log_lead_activity($data['rel_id'], 'not_lead_activity_created_proposal', false, serialize(['<a href="' . admin_url('proposals/list_proposals/' . $insert_id) . '" target="_blank">' . $data['subject'] . '</a>', ]), $playground);
|
||||
}
|
||||
update_sales_total_tax_column($insert_id, 'proposal', db_prefix() . ($playground ? 'playground_' : '') . 'proposals');
|
||||
log_activity('New Proposal Created [ID: ' . $insert_id . ']');
|
||||
if ($save_and_send === true) {
|
||||
$this->send_proposal_to_email($insert_id, true, '', $playground);
|
||||
}
|
||||
hooks()->do_action('proposal_created', $insert_id);
|
||||
return $insert_id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update proposal
|
||||
* @param mixed $data $_POST data
|
||||
* @param mixed $id proposal id
|
||||
* @return boolean
|
||||
*/
|
||||
public function update($data, $id, $playground = false) {
|
||||
$affectedRows = 0;
|
||||
$data['allow_comments'] = isset($data['allow_comments']) ? 1 : 0;
|
||||
$current_proposal = $this->get($id, [], false, $playground);
|
||||
$save_and_send = isset($data['save_and_send']);
|
||||
if (empty($data['rel_type'])) {
|
||||
$data['rel_id'] = null;
|
||||
$data['rel_type'] = '';
|
||||
} else {
|
||||
if (empty($data['rel_id'])) {
|
||||
$data['rel_id'] = null;
|
||||
$data['rel_type'] = '';
|
||||
}
|
||||
}
|
||||
if (isset($data['custom_fields'])) {
|
||||
$custom_fields = $data['custom_fields'];
|
||||
$this->load->model('custom_fields_model');
|
||||
if ($this->custom_fields_model->handle_custom_fields_post($id, $custom_fields, false, $playground)) {
|
||||
$affectedRows++;
|
||||
}
|
||||
unset($data['custom_fields']);
|
||||
}
|
||||
$items = [];
|
||||
if (isset($data['items'])) {
|
||||
$items = $data['items'];
|
||||
unset($data['items']);
|
||||
}
|
||||
$newitems = [];
|
||||
if (isset($data['newitems'])) {
|
||||
$newitems = $data['newitems'];
|
||||
unset($data['newitems']);
|
||||
}
|
||||
if (isset($data['tags'])) {
|
||||
$this->load->model('misc_model');
|
||||
if ($this->misc_model->handle_tags_save($data['tags'], $id, 'proposal', $playground)) {
|
||||
$affectedRows++;
|
||||
}
|
||||
}
|
||||
$data['address'] = trim($data['address']);
|
||||
$data['address'] = nl2br($data['address']);
|
||||
$hook = hooks()->apply_filters('before_proposal_updated', ['data' => $data, 'items' => $items, 'newitems' => $newitems, 'removed_items' => isset($data['removed_items']) ? $data['removed_items'] : [], ], $id);
|
||||
$data = $hook['data'];
|
||||
$data['removed_items'] = $hook['removed_items'];
|
||||
$newitems = $hook['newitems'];
|
||||
$items = $hook['items'];
|
||||
// Delete items checked to be removed from database
|
||||
foreach ($data['removed_items'] as $remove_item_id) {
|
||||
if (handle_removed_sales_item_post($remove_item_id, 'proposal')) {
|
||||
$affectedRows++;
|
||||
}
|
||||
}
|
||||
unset($data['removed_items']);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'proposals', $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$affectedRows++;
|
||||
$proposal_now = $this->get($id, [], false, $playground);
|
||||
if ($current_proposal->assigned != $proposal_now->assigned) {
|
||||
if ($proposal_now->assigned != get_staff_user_id()) {
|
||||
$notified = add_notification(['description' => 'not_proposal_assigned_to_you', 'touserid' => $proposal_now->assigned, 'fromuserid' => get_staff_user_id(), 'link' => 'proposals/list_proposals/' . $id, 'additional_data' => serialize([$proposal_now->subject, ]), ]);
|
||||
if ($notified) {
|
||||
pusher_trigger_notification([$proposal_now->assigned]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->load->model('custom_fields_model');
|
||||
foreach ($items as $key => $item) {
|
||||
if (update_sales_item_post($item['itemid'], $item)) {
|
||||
$affectedRows++;
|
||||
}
|
||||
if (isset($item['custom_fields'])) {
|
||||
if ($this->custom_fields_model->handle_custom_fields_post($item['itemid'], $item['custom_fields'], false, $playground)) {
|
||||
$affectedRows++;
|
||||
}
|
||||
}
|
||||
if (!isset($item['taxname']) || (isset($item['taxname']) && count($item['taxname']) == 0)) {
|
||||
if (delete_taxes_from_item($item['itemid'], 'proposal')) {
|
||||
$affectedRows++;
|
||||
}
|
||||
} else {
|
||||
$item_taxes = $this->get_proposal_item_taxes($item['itemid'], $playground);
|
||||
$_item_taxes_names = [];
|
||||
foreach ($item_taxes as $_item_tax) {
|
||||
array_push($_item_taxes_names, $_item_tax['taxname']);
|
||||
}
|
||||
$i = 0;
|
||||
foreach ($_item_taxes_names as $_item_tax) {
|
||||
if (!in_array($_item_tax, $item['taxname'])) {
|
||||
$this->db->where('id', $item_taxes[$i]['id'])->delete(db_prefix() . ($playground ? 'playground_' : '') . 'item_tax');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$affectedRows++;
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
if (_maybe_insert_post_item_tax($item['itemid'], $item, $id, 'proposal')) {
|
||||
$affectedRows++;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->load->model('invoice_items_model');
|
||||
foreach ($newitems as $key => $item) {
|
||||
if ($new_item_added = $this->invoice_items_model->add_new_sales_item_post($item, $id, 'proposal', $playground)) {
|
||||
$this->invoice_items_model->_maybe_insert_post_item_tax($new_item_added, $item, $id, 'proposal', $playground);
|
||||
$affectedRows++;
|
||||
}
|
||||
}
|
||||
if ($affectedRows > 0) {
|
||||
update_sales_total_tax_column($id, 'proposal', db_prefix() . ($playground ? 'playground_' : '') . 'proposals');
|
||||
log_activity('Proposal Updated [ID:' . $id . ']');
|
||||
}
|
||||
if ($save_and_send === true) {
|
||||
$this->send_proposal_to_email($id, true, '', $playground);
|
||||
}
|
||||
if ($affectedRows > 0) {
|
||||
hooks()->do_action('after_proposal_updated', $id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get proposals
|
||||
* @param mixed $id proposal id OPTIONAL
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($id = '', $where = [], $for_editor = false, $playground = false) {
|
||||
$this->db->where($where);
|
||||
if (is_client_logged_in()) {
|
||||
$this->db->where('status !=', 0);
|
||||
}
|
||||
$this->db->select('*,' . db_prefix() . ($playground ? 'playground_' : '') . 'currencies.id as currencyid, ' . db_prefix() . ($playground ? 'playground_' : '') . 'proposals.id as id, ' . db_prefix() . ($playground ? 'playground_' : '') . 'currencies.name as currency_name');
|
||||
$this->db->from(db_prefix() . ($playground ? 'playground_' : '') . 'proposals');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'currencies', db_prefix() . ($playground ? 'playground_' : '') . 'currencies.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'proposals.currency', 'left');
|
||||
if (is_numeric($id)) {
|
||||
$this->db->where(db_prefix() . ($playground ? 'playground_' : '') . 'proposals.id', $id);
|
||||
$proposal = $this->db->get()->row();
|
||||
if ($proposal) {
|
||||
$proposal->attachments = $this->get_attachments($id, $playground);
|
||||
$this->load->model('invoice_items_model');
|
||||
$proposal->items = $this->invoice_items_model->get_items_by_type('proposal', $id, $playground);
|
||||
$proposal->visible_attachments_to_customer_found = false;
|
||||
foreach ($proposal->attachments as $attachment) {
|
||||
if ($attachment['visible_to_customer'] == 1) {
|
||||
$proposal->visible_attachments_to_customer_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($proposal->project_id) {
|
||||
$this->load->model('projects_model');
|
||||
$proposal->project_data = $this->projects_model->get($proposal->project_id, $playground);
|
||||
}
|
||||
if ($for_editor == false) {
|
||||
$proposal = parse_proposal_content_merge_fields($proposal, $playground);
|
||||
}
|
||||
}
|
||||
return $proposal;
|
||||
}
|
||||
return $this->db->get()->result_array();
|
||||
}
|
||||
|
||||
public function clear_signature($id, $playground = false) {
|
||||
$this->db->select('signature');
|
||||
$this->db->where('id', $id);
|
||||
$proposal = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'proposals')->row();
|
||||
$this->load->model('misc_model');
|
||||
if ($proposal) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'proposals', ['signature' => null]);
|
||||
if (!empty($proposal->signature)) {
|
||||
unlink($this->misc_model->get_upload_path_by_type('proposal', $playground) . $id . '/' . $proposal->signature);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function update_pipeline($data, $playground = false) {
|
||||
$this->mark_action_status($data['status'], $data['proposalid'], false, $playground);
|
||||
AbstractKanban::updateOrder($data['order'], 'pipeline_order', ($playground ? 'playground_' : '') . 'proposals', $data['status']);
|
||||
}
|
||||
|
||||
public function get_attachments($proposal_id, $id = '', $playground = false) {
|
||||
// If is passed id get return only 1 attachment
|
||||
if (is_numeric($id)) {
|
||||
$this->db->where('id', $id);
|
||||
} else {
|
||||
$this->db->where('rel_id', $proposal_id);
|
||||
}
|
||||
$this->db->where('rel_type', 'proposal');
|
||||
$result = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'files');
|
||||
if (is_numeric($id)) {
|
||||
return $result->row();
|
||||
}
|
||||
return $result->result_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete proposal attachment
|
||||
* @param mixed $id attachmentid
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete_attachment($id, $playground = false) {
|
||||
$attachment = $this->get_attachments('', $id, $playground);
|
||||
$deleted = false;
|
||||
if ($attachment) {
|
||||
if (empty($attachment->external)) {
|
||||
unlink(get_upload_path_by_type('proposal', $playground) . $attachment->rel_id . '/' . $attachment->file_name);
|
||||
}
|
||||
$this->db->where('id', $attachment->id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'files');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$deleted = true;
|
||||
log_activity('Proposal Attachment Deleted [ID: ' . $attachment->rel_id . ']');
|
||||
}
|
||||
if (is_dir(get_upload_path_by_type('proposal') . $attachment->rel_id)) {
|
||||
// Check if no attachments left, so we can delete the folder also
|
||||
$other_attachments = list_files(get_upload_path_by_type('proposal', $playground) . $attachment->rel_id);
|
||||
if (count($other_attachments) == 0) {
|
||||
// okey only index.html so we can delete the folder also
|
||||
delete_dir(get_upload_path_by_type('proposal', $playground) . $attachment->rel_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add proposal comment
|
||||
* @param mixed $data $_POST comment data
|
||||
* @param boolean $client is request coming from the client side
|
||||
*/
|
||||
public function add_comment($data, $client = false, $playground = false) {
|
||||
if (is_staff_logged_in()) {
|
||||
$client = false;
|
||||
}
|
||||
if (isset($data['action'])) {
|
||||
unset($data['action']);
|
||||
}
|
||||
$data['dateadded'] = date('Y-m-d H:i:s');
|
||||
if ($client == false) {
|
||||
$data['staffid'] = get_staff_user_id();
|
||||
}
|
||||
$data['content'] = nl2br($data['content']);
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'proposal_comments', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
$proposal = $this->get($data['proposalid'], [], false, $playground);
|
||||
// No notifications client when proposal is with draft status
|
||||
if ($proposal->status == '6' && $client == false) {
|
||||
return true;
|
||||
}
|
||||
if ($client == true) {
|
||||
// Get creator and assigned
|
||||
$this->db->select('staffid,email,phonenumber');
|
||||
$this->db->where('staffid', $proposal->addedfrom);
|
||||
$this->db->or_where('staffid', $proposal->assigned);
|
||||
$staff_proposal = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'staff')->result_array();
|
||||
$notifiedUsers = [];
|
||||
foreach ($staff_proposal as $member) {
|
||||
$notified = add_notification(['description' => 'not_proposal_comment_from_client', 'touserid' => $member['staffid'], 'fromcompany' => 1, 'fromuserid' => 0, 'link' => 'proposals/list_proposals/' . $data['proposalid'], 'additional_data' => serialize([$proposal->subject, ]), ], $playground);
|
||||
if ($notified) {
|
||||
array_push($notifiedUsers, $member['staffid']);
|
||||
}
|
||||
$template = mail_template('proposal_comment_to_staff', $proposal->id, $member['email']);
|
||||
$merge_fields = $template->get_merge_fields();
|
||||
$template->send();
|
||||
// Send email/sms to admin that client commented
|
||||
$this->app_sms->trigger(SMS_TRIGGER_PROPOSAL_NEW_COMMENT_TO_STAFF, $member['phonenumber'], $merge_fields);
|
||||
}
|
||||
hooks()->do_action('after_proposal_client_add_comment', $proposal->id);
|
||||
pusher_trigger_notification($notifiedUsers);
|
||||
} else {
|
||||
// Send email/sms to client that admin commented
|
||||
$template = mail_template('proposal_comment_to_customer', $proposal);
|
||||
$merge_fields = $template->get_merge_fields();
|
||||
$template->send();
|
||||
$this->app_sms->trigger(SMS_TRIGGER_PROPOSAL_NEW_COMMENT_TO_CUSTOMER, $proposal->phone, $merge_fields);
|
||||
hooks()->do_action('after_proposal_staff_add_comment', $proposal->id);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function edit_comment($data, $id, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'proposal_comments', ['content' => nl2br($data['content']), ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get proposal comments
|
||||
* @param mixed $id proposal id
|
||||
* @return array
|
||||
*/
|
||||
public function get_comments($id, $playground = false) {
|
||||
$this->db->where('proposalid', $id);
|
||||
$this->db->order_by('dateadded', 'ASC');
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'proposal_comments')->result_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get proposal single comment
|
||||
* @param mixed $id comment id
|
||||
* @return object
|
||||
*/
|
||||
public function get_comment($id, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'proposal_comments')->row();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove proposal comment
|
||||
* @param mixed $id comment id
|
||||
* @return boolean
|
||||
*/
|
||||
public function remove_comment($id, $playground = false) {
|
||||
$comment = $this->get_comment($id, $playground);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'proposal_comments');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Proposal Comment Removed [ProposalID:' . $comment->proposalid . ', Comment Content: ' . $comment->content . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy proposal
|
||||
* @param mixed $id proposal id
|
||||
* @return mixed
|
||||
*/
|
||||
public function copy($id, $playground = false) {
|
||||
$this->copy = true;
|
||||
$proposal = $this->get($id, [], true, $playground);
|
||||
$not_copy_fields = ['addedfrom', 'id', 'datecreated', 'hash', 'status', 'invoice_id', 'estimate_id', 'is_expiry_notified', 'date_converted', 'signature', 'acceptance_firstname', 'acceptance_lastname', 'acceptance_email', 'acceptance_date', 'acceptance_ip', ];
|
||||
$fields = $this->db->list_fields(db_prefix() . ($playground ? 'playground_' : '') . 'proposals');
|
||||
$insert_data = [];
|
||||
foreach ($fields as $field) {
|
||||
if (!in_array($field, $not_copy_fields)) {
|
||||
$insert_data[$field] = $proposal->$field;
|
||||
}
|
||||
}
|
||||
$insert_data['addedfrom'] = get_staff_user_id();
|
||||
$insert_data['datecreated'] = date('Y-m-d H:i:s');
|
||||
$insert_data['date'] = _d(date('Y-m-d'));
|
||||
$insert_data['status'] = 6;
|
||||
$insert_data['hash'] = app_generate_hash();
|
||||
// in case open till is expired set new 7 days starting from current date
|
||||
if ($insert_data['open_till'] && get_option('proposal_due_after') != 0) {
|
||||
$insert_data['open_till'] = _d(date('Y-m-d', strtotime('+' . get_option('proposal_due_after') . ' DAY', strtotime(date('Y-m-d')))));
|
||||
} else if ($insert_data['open_till']) {
|
||||
$dDate = new DateTime(date('Y-m-d'));
|
||||
$dOpenTill = new DateTime($insert_data['open_till']);
|
||||
$dDiff = $dDate->diff($dOpenTill);
|
||||
$insert_data['open_till'] = _d($dDate->modify('+ ' . $dDiff->days . ' DAY')->format('Y-m-d'));
|
||||
}
|
||||
$insert_data['newitems'] = [];
|
||||
$this->load->model('custom_fields_model');
|
||||
$custom_fields_items = $this->custom_fields_model->get_custom_fields('items', [], false, $playground);
|
||||
$key = 1;
|
||||
foreach ($proposal->items as $item) {
|
||||
$insert_data['newitems'][$key]['description'] = $item['description'];
|
||||
$insert_data['newitems'][$key]['long_description'] = clear_textarea_breaks($item['long_description']);
|
||||
$insert_data['newitems'][$key]['qty'] = $item['qty'];
|
||||
$insert_data['newitems'][$key]['unit'] = $item['unit'];
|
||||
$insert_data['newitems'][$key]['taxname'] = [];
|
||||
$taxes = $this->get_proposal_item_taxes($item['id'], $playground);
|
||||
foreach ($taxes as $tax) {
|
||||
// tax name is in format TAX1|10.00
|
||||
array_push($insert_data['newitems'][$key]['taxname'], $tax['taxname']);
|
||||
}
|
||||
$insert_data['newitems'][$key]['rate'] = $item['rate'];
|
||||
$insert_data['newitems'][$key]['order'] = $item['item_order'];
|
||||
foreach ($custom_fields_items as $cf) {
|
||||
$insert_data['newitems'][$key]['custom_fields']['items'][$cf['id']] = $this->custom_fields_model->get_custom_field_value($item['id'], $cf['id'], 'items', false, $playground);
|
||||
if (!defined('COPY_CUSTOM_FIELDS_LIKE_HANDLE_POST')) {
|
||||
define('COPY_CUSTOM_FIELDS_LIKE_HANDLE_POST', true);
|
||||
}
|
||||
}
|
||||
$key++;
|
||||
}
|
||||
$id = $this->add($insert_data, $playground);
|
||||
if ($id) {
|
||||
$this->load->model('custom_fields_model');
|
||||
$custom_fields = $this->custom_fields_model->get_custom_fields('proposal', [], false, $playground);
|
||||
foreach ($custom_fields as $field) {
|
||||
$value = $this->custom_fields_model->get_custom_field_value($proposal->id, $field['id'], 'proposal', false, $playground);
|
||||
if ($value == '') {
|
||||
continue;
|
||||
}
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues', ['relid' => $id, 'fieldid' => $field['id'], 'fieldto' => 'proposal', 'value' => $value, ]);
|
||||
}
|
||||
$tags = get_tags_in($proposal->id, 'proposal', $playground);
|
||||
$this->load->model('misc_model');
|
||||
$this->misc_model->handle_tags_save($tags, $id, 'proposal', $playground);
|
||||
log_activity('Copied Proposal ' . format_proposal_number($proposal->id));
|
||||
return $id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take proposal action (change status) manually
|
||||
* @param mixed $status status id
|
||||
* @param mixed $id proposal id
|
||||
* @param boolean $client is request coming from client side or not
|
||||
* @return boolean
|
||||
*/
|
||||
public function mark_action_status($status, $id, $client = false, $playground = false) {
|
||||
$original_proposal = $this->get($id, false, [], $playground);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'proposals', ['status' => $status, ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
// Client take action
|
||||
if ($client == true) {
|
||||
$revert = false;
|
||||
// Declined
|
||||
if ($status == 2) {
|
||||
$message = 'not_proposal_proposal_declined';
|
||||
} else if ($status == 3) {
|
||||
// Accepted
|
||||
if (get_option('proposal_auto_convert_to_invoice_on_client_accept') == '1') {
|
||||
$this->convert_to_invoice($id, $playground);
|
||||
}
|
||||
$message = 'not_proposal_proposal_accepted';
|
||||
} else {
|
||||
$revert = true;
|
||||
}
|
||||
// This is protection that only 3 and 4 statuses can be taken as action from the client side
|
||||
if ($revert == true) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'proposals', ['status' => $original_proposal->status, ]);
|
||||
return false;
|
||||
}
|
||||
// Get creator and assigned;
|
||||
$this->db->where('staffid', $original_proposal->addedfrom);
|
||||
$this->db->or_where('staffid', $original_proposal->assigned);
|
||||
$staff_proposal = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'staff')->result_array();
|
||||
$notifiedUsers = [];
|
||||
foreach ($staff_proposal as $member) {
|
||||
$notified = add_notification(['fromcompany' => true, 'touserid' => $member['staffid'], 'description' => $message, 'link' => 'proposals/list_proposals/' . $id, 'additional_data' => serialize([format_proposal_number($id), ]), ]);
|
||||
if ($notified) {
|
||||
array_push($notifiedUsers, $member['staffid']);
|
||||
}
|
||||
}
|
||||
pusher_trigger_notification($notifiedUsers);
|
||||
// Send thank you to the customer email template
|
||||
if ($status == 3) {
|
||||
foreach ($staff_proposal as $member) {
|
||||
send_mail_template('proposal_accepted_to_staff', $original_proposal, $member['email']);
|
||||
}
|
||||
send_mail_template('proposal_accepted_to_customer', $original_proposal);
|
||||
hooks()->do_action('proposal_accepted', $id);
|
||||
} else {
|
||||
// Client declined send template to admin
|
||||
foreach ($staff_proposal as $member) {
|
||||
send_mail_template('proposal_declined_to_staff', $original_proposal, $member['email']);
|
||||
}
|
||||
hooks()->do_action('proposal_declined', $id);
|
||||
}
|
||||
} else {
|
||||
// in case admin mark as open the the open till date is smaller then current date set open till date 7 days more
|
||||
if ((date('Y-m-d', strtotime($original_proposal->open_till)) < date('Y-m-d')) && $status == 1) {
|
||||
$open_till = date('Y-m-d', strtotime('+7 DAY', strtotime(date('Y-m-d'))));
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'proposals', ['open_till' => $open_till, ]);
|
||||
}
|
||||
}
|
||||
log_activity('Proposal Status Changes [ProposalID:' . $id . ', Status:' . format_proposal_status($status, '', false) . ',Client Action: ' . (int)$client . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete proposal
|
||||
* @param mixed $id proposal id
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete($id, $playground = false) {
|
||||
hooks()->do_action('before_proposal_deleted', $id);
|
||||
$this->clear_signature($id, $playground);
|
||||
$proposal = $this->get($id, [], false, $playground);
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'proposals');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
if (!is_null($proposal->short_link)) {
|
||||
app_archive_short_link($proposal->short_link, $playground);
|
||||
}
|
||||
$this->load->model('misc_model');
|
||||
$this->misc_model->delete_tracked_emails($id, 'proposal', $playground);
|
||||
$this->db->where('proposalid', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'proposal_comments');
|
||||
// Get related tasks
|
||||
$this->db->where('rel_type', 'proposal');
|
||||
$this->db->where('rel_id', $id);
|
||||
$tasks = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'tasks')->result_array();
|
||||
$this->load->model('tasks_model');
|
||||
foreach ($tasks as $task) {
|
||||
$this->tasks_model->delete_task($task['id'], true, $playground);
|
||||
}
|
||||
$attachments = $this->get_attachments($id, $playground);
|
||||
foreach ($attachments as $attachment) {
|
||||
$this->delete_attachment($attachment['id'], $playground);
|
||||
}
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->where('rel_type', 'proposal');
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'notes');
|
||||
$this->db->where('relid IN (SELECT id from ' . db_prefix() . ($playground ? 'playground_' : '') . 'itemable WHERE rel_type="proposal" AND rel_id="' . $this->db->escape_str($id) . '")');
|
||||
$this->db->where('fieldto', 'items');
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues');
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->where('rel_type', 'proposal');
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'itemable');
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->where('rel_type', 'proposal');
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'item_tax');
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->where('rel_type', 'proposal');
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'taggables');
|
||||
// Delete the custom field values
|
||||
$this->db->where('relid', $id);
|
||||
$this->db->where('fieldto', 'proposal');
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues');
|
||||
$this->db->where('rel_type', 'proposal');
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'reminders');
|
||||
$this->db->where('rel_type', 'proposal');
|
||||
$this->db->where('rel_id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'views_tracking');
|
||||
log_activity('Proposal Deleted [ProposalID:' . $id . ']');
|
||||
hooks()->do_action('after_proposal_deleted', $id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get relation proposal data. Ex lead or customer will return the necesary db fields
|
||||
* @param mixed $rel_id
|
||||
* @param string $rel_type customer/lead
|
||||
* @return object
|
||||
*/
|
||||
public function get_relation_data_values($rel_id, $rel_type, $playground = false) {
|
||||
$data = new StdClass();
|
||||
if ($rel_type == 'customer') {
|
||||
$this->load->model('clients_model');
|
||||
$this->db->where('userid', $rel_id);
|
||||
$_data = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'clients')->row();
|
||||
$primary_contact_id = $this->clients_model->get_primary_contact_user_id($rel_id, $playground);
|
||||
if ($primary_contact_id) {
|
||||
$contact = $this->clients_model->get_contact($primary_contact_id, ['active' => 1], [], $playground);
|
||||
$data->email = $contact->email;
|
||||
}
|
||||
$data->phone = $_data->phonenumber;
|
||||
$data->is_using_company = false;
|
||||
if (isset($contact)) {
|
||||
$data->to = $contact->firstname . ' ' . $contact->lastname;
|
||||
} else {
|
||||
if (!empty($_data->company)) {
|
||||
$data->to = $_data->company;
|
||||
$data->is_using_company = true;
|
||||
}
|
||||
}
|
||||
$data->company = $_data->company;
|
||||
$data->address = clear_textarea_breaks($_data->address, $playground);
|
||||
$data->zip = $_data->zip;
|
||||
$data->country = $_data->country;
|
||||
$data->state = $_data->state;
|
||||
$data->city = $_data->city;
|
||||
$default_currency = $this->clients_model->get_customer_default_currency($rel_id);
|
||||
if ($default_currency != 0) {
|
||||
$data->currency = $default_currency;
|
||||
}
|
||||
} else if ($rel_type = 'lead') {
|
||||
$this->db->where('id', $rel_id);
|
||||
$_data = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'leads')->row();
|
||||
$data->phone = $_data->phonenumber;
|
||||
$data->is_using_company = false;
|
||||
if (empty($_data->company)) {
|
||||
$data->to = $_data->name;
|
||||
} else {
|
||||
$data->to = $_data->company;
|
||||
$data->is_using_company = true;
|
||||
}
|
||||
$data->company = $_data->company;
|
||||
$data->address = $_data->address;
|
||||
$data->email = $_data->email;
|
||||
$data->zip = $_data->zip;
|
||||
$data->country = $_data->country;
|
||||
$data->state = $_data->state;
|
||||
$data->city = $_data->city;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sent proposal to email
|
||||
* @param mixed $id proposalid
|
||||
* @param string $template email template to sent
|
||||
* @param boolean $attachpdf attach proposal pdf or not
|
||||
* @return boolean
|
||||
*/
|
||||
public function send_expiry_reminder($id, $playground = false) {
|
||||
$proposal = $this->get($id, [], false, $playground);
|
||||
// For all cases update this to prevent sending multiple reminders eq on fail
|
||||
$this->db->where('id', $proposal->id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'proposals', ['is_expiry_notified' => 1, ]);
|
||||
$template = mail_template('proposal_expiration_reminder', $proposal);
|
||||
$merge_fields = $template->get_merge_fields();
|
||||
$template->send();
|
||||
if (can_send_sms_based_on_creation_date($proposal->datecreated, $playground)) {
|
||||
$sms_sent = $this->app_sms->trigger(SMS_TRIGGER_PROPOSAL_EXP_REMINDER, $proposal->phone, $merge_fields);
|
||||
}
|
||||
hooks()->do_action('after_proposal_expiry_reminder_sent', $id);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function send_proposal_to_email($id, $attachpdf = true, $cc = '', $playground = false) {
|
||||
// Proposal status is draft update to sent
|
||||
if (total_rows(db_prefix() . ($playground ? 'playground_' : '') . 'proposals', ['id' => $id, 'status' => 6]) > 0) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'proposals', ['status' => 4]);
|
||||
}
|
||||
$proposal = $this->get($id, [], false, $playground);
|
||||
$sent = send_mail_template('proposal_send_to_customer', $proposal, $attachpdf, $cc, $playground);
|
||||
if ($sent) {
|
||||
// Set to status sent
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'proposals', ['status' => 4, ]);
|
||||
hooks()->do_action('proposal_sent', $id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function do_kanban_query($status, $search = '', $page = 1, $sort = [], $count = false, $playground = false) {
|
||||
_deprecated_function('Proposal_model::do_kanban_query', '2.9.2', 'ProposalsPipeline class');
|
||||
$kanBan = (new ProposalsPipeline($status))->search($search)->page($page)->sortBy($sort['sort']??null, $sort['sort_by']??null);
|
||||
if ($count) {
|
||||
return $kanBan->countAll();
|
||||
}
|
||||
return $kanBan->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert proposal to invoice
|
||||
* @param mixed $id proposal id
|
||||
* @return mixed New invoice ID
|
||||
*/
|
||||
public function convert_to_invoice($id, $playground = false) {
|
||||
// Recurring invoice date is okey lets convert it to new invoice
|
||||
$proposal = $this->get($id, [], false, $playground);
|
||||
if ($proposal->rel_type != 'customer') {
|
||||
return false;
|
||||
}
|
||||
$new_invoice_data = [];
|
||||
$new_invoice_data['clientid'] = $proposal->rel_id;
|
||||
$new_invoice_data['project_id'] = $proposal->project_id;
|
||||
$new_invoice_data['number'] = get_option('next_invoice_number');
|
||||
$new_invoice_data['date'] = _d(date('Y-m-d'));
|
||||
$new_invoice_data['duedate'] = _d(date('Y-m-d'));
|
||||
if (get_option('invoice_due_after') != 0) {
|
||||
$new_invoice_data['duedate'] = _d(date('Y-m-d', strtotime('+' . get_option('invoice_due_after') . ' DAY', strtotime(date('Y-m-d')))));
|
||||
}
|
||||
$new_invoice_data['show_quantity_as'] = $proposal->show_quantity_as;
|
||||
$new_invoice_data['currency'] = $proposal->currency;
|
||||
$new_invoice_data['subtotal'] = $proposal->subtotal;
|
||||
$new_invoice_data['total'] = $proposal->total;
|
||||
$new_invoice_data['adjustment'] = $proposal->adjustment;
|
||||
$new_invoice_data['discount_percent'] = $proposal->discount_percent;
|
||||
$new_invoice_data['discount_total'] = $proposal->discount_total;
|
||||
$new_invoice_data['discount_type'] = $proposal->discount_type;
|
||||
$new_invoice_data['sale_agent'] = $proposal->assigned;
|
||||
$new_invoice_data['billing_street'] = clear_textarea_breaks($proposal->address);
|
||||
$new_invoice_data['billing_city'] = $proposal->city;
|
||||
$new_invoice_data['billing_state'] = $proposal->state;
|
||||
$new_invoice_data['billing_zip'] = $proposal->zip;
|
||||
$new_invoice_data['billing_country'] = $proposal->country;
|
||||
$new_invoice_data['shipping_street'] = '';
|
||||
$new_invoice_data['shipping_city'] = '';
|
||||
$new_invoice_data['shipping_state'] = '';
|
||||
$new_invoice_data['shipping_zip'] = '';
|
||||
$new_invoice_data['shipping_country'] = '';
|
||||
$new_invoice_data['include_shipping'] = 0;
|
||||
$new_invoice_data['show_shipping_on_invoice'] = 0;
|
||||
$new_invoice_data['terms'] = get_option('predefined_terms_invoice');
|
||||
$new_invoice_data['clientnote'] = get_option('predefined_clientnote_invoice');
|
||||
// Set to unpaid status automatically
|
||||
$new_invoice_data['status'] = 1;
|
||||
$new_invoice_data['adminnote'] = '';
|
||||
$this->load->model('payment_modes_model');
|
||||
$modes = $this->payment_modes_model->get('', ['expenses_only !=' => 1, ]);
|
||||
$temp_modes = [];
|
||||
foreach ($modes as $mode) {
|
||||
if ($mode['selected_by_default'] == 0) {
|
||||
continue;
|
||||
}
|
||||
$temp_modes[] = $mode['id'];
|
||||
}
|
||||
$new_invoice_data['allowed_payment_modes'] = $temp_modes;
|
||||
$new_invoice_data['newitems'] = [];
|
||||
$key = 1;
|
||||
foreach ($proposal->items as $item) {
|
||||
$new_invoice_data['newitems'][$key]['description'] = $item['description'];
|
||||
$new_invoice_data['newitems'][$key]['long_description'] = clear_textarea_breaks($item['long_description']);
|
||||
$new_invoice_data['newitems'][$key]['qty'] = $item['qty'];
|
||||
$new_invoice_data['newitems'][$key]['unit'] = $item['unit'];
|
||||
$new_invoice_data['newitems'][$key]['taxname'] = [];
|
||||
$taxes = $this->get_proposal_item_taxes($item['id'], $playground);
|
||||
foreach ($taxes as $tax) {
|
||||
// tax name is in format TAX1|10.00
|
||||
array_push($new_invoice_data['newitems'][$key]['taxname'], $tax['taxname']);
|
||||
}
|
||||
$new_invoice_data['newitems'][$key]['rate'] = $item['rate'];
|
||||
$new_invoice_data['newitems'][$key]['order'] = $item['item_order'];
|
||||
$key++;
|
||||
}
|
||||
$this->load->model('invoices_model');
|
||||
$invoice_id = $this->invoices_model->add($new_invoice_data, $playground);
|
||||
if ($invoice_id) {
|
||||
// Customer accepted the estimate and is auto converted to invoice
|
||||
if (!is_staff_logged_in()) {
|
||||
$this->db->where('rel_type', 'invoice');
|
||||
$this->db->where('rel_id', $invoice_id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'sales_activity');
|
||||
$this->invoices_model->log_invoice_activity($id, 'invoice_activity_auto_converted_from_proposal', true, serialize(['<a href="' . admin_url('proposals#' . $proposal->id) . '">' . format_proposal_number($proposal->id) . '</a>', ]), $playground);
|
||||
}
|
||||
// For all cases update addefrom and sale agent from the invoice
|
||||
// May happen staff is not logged in and these values to be 0
|
||||
$this->db->where('id', $invoice_id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'invoices', ['addedfrom' => $proposal->addedfrom, 'sale_agent' => $proposal->assigned, ]);
|
||||
// Update estimate with the new invoice data and set to status accepted
|
||||
$this->db->where('id', $proposal->id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'proposals', ['invoice_id' => $invoice_id, 'status' => 3, ]);
|
||||
if (is_custom_fields_smart_transfer_enabled()) {
|
||||
$this->db->where('fieldto', 'proposal');
|
||||
$this->db->where('active', 1);
|
||||
$cfProposals = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'customfields')->result_array();
|
||||
foreach ($cfProposals as $field) {
|
||||
$tmpSlug = explode('_', $field['slug'], 2);
|
||||
if (isset($tmpSlug[1])) {
|
||||
$this->db->where('fieldto', 'invoice');
|
||||
$this->db->group_start();
|
||||
$this->db->like('slug', 'invoice_' . $tmpSlug[1], 'after');
|
||||
$this->db->where('type', $field['type']);
|
||||
$this->db->where('options', $field['options']);
|
||||
$this->db->where('active', 1);
|
||||
$this->db->group_end();
|
||||
// $this->db->where('slug LIKE "invoice_' . $tmpSlug[1] . '%" AND type="' . $field['type'] . '" AND options="' . $field['options'] . '" AND active=1');
|
||||
$cfTransfer = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'customfields')->result_array();
|
||||
// Don't make mistakes
|
||||
// Only valid if 1 result returned
|
||||
// + if field names similarity is equal or more then CUSTOM_FIELD_TRANSFER_SIMILARITY%
|
||||
if (count($cfTransfer) == 1 && ((similarity($field['name'], $cfTransfer[0]['name']) * 100) >= CUSTOM_FIELD_TRANSFER_SIMILARITY)) {
|
||||
$value = get_custom_field_value($proposal->id, $field['id'], 'estimate', false, $playground);
|
||||
if ($value == '') {
|
||||
continue;
|
||||
}
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues', ['relid' => $id, 'fieldid' => $cfTransfer[0]['id'], 'fieldto' => 'invoice', 'value' => $value, ]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
hooks()->do_action('after_proposal_converted_to_invoice', ['proposal_id' => $id, 'invoice_id' => $invoice_id]);
|
||||
log_activity('Proposal Converted to Invoice [InvoiceID: ' . $invoice_id . ', ProposalID: ' . $id . ']');
|
||||
}
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that return proposal item taxes based on passed item id
|
||||
* @param mixed $itemid
|
||||
* @return array
|
||||
*/
|
||||
public function get_proposal_item_taxes($itemid, $playground = false)
|
||||
{
|
||||
$CI = &get_instance();
|
||||
$CI->db->where('itemid', $itemid);
|
||||
$CI->db->where('rel_type', 'proposal');
|
||||
$taxes = $CI->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'item_tax')->result_array();
|
||||
$i = 0;
|
||||
foreach ($taxes as $tax) {
|
||||
$taxes[$i]['taxname'] = $tax['taxname'] . '|' . $tax['taxrate'];
|
||||
$i++;
|
||||
}
|
||||
|
||||
return $taxes;
|
||||
}
|
||||
}
|
||||
404
api/models/REST_model.php
Normal file
404
api/models/REST_model.php
Normal file
@@ -0,0 +1,404 @@
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class REST_model extends App_Model
|
||||
{
|
||||
/**
|
||||
* Token
|
||||
*/
|
||||
protected $CI;
|
||||
|
||||
/**
|
||||
* Token
|
||||
*/
|
||||
protected $token;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->load->config('api');
|
||||
$this->load->config('rest');
|
||||
|
||||
$this->load->library('Authorization_Token');
|
||||
|
||||
if (!$this->db->table_exists(db_prefix() . $this->config->item('rest_keys_table'))) {
|
||||
$this->db->query('CREATE TABLE `' . db_prefix() . $this->config->item('rest_keys_table') . '` (
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`user` VARCHAR(50) NOT NULL,
|
||||
`name` VARCHAR(50) NOT NULL,
|
||||
`token` VARCHAR(255) NOT NULL,
|
||||
`expiration_date` DATETIME NULL,
|
||||
`permission_enable` TINYINT(4) DEFAULT 0,
|
||||
`quota_limit` INT(11) NOT NULL DEFAULT 1000,
|
||||
`quota_remaining` INT(11) NOT NULL DEFAULT 1000,
|
||||
`quota_reset` DATETIME NOT NULL,
|
||||
`rate_limit` INT(11) NOT NULL DEFAULT 60,
|
||||
`rate_remaining` INT(11) NOT NULL DEFAULT 60,
|
||||
`rate_reset` DATETIME NOT NULL,
|
||||
`level` INT(11) NULL,
|
||||
`ignore_limits` INT(11) NULL,
|
||||
PRIMARY KEY (`id`));
|
||||
');
|
||||
}
|
||||
|
||||
if (!$this->db->table_exists(db_prefix() . $this->config->item('rest_key_permissions_table'))) {
|
||||
$this->db->query('CREATE TABLE `' . db_prefix() . $this->config->item('rest_key_permissions_table') . '` (
|
||||
`key_id` int(11) NOT NULL,
|
||||
`feature` varchar(50) NOT NULL,
|
||||
`capability` varchar(50) NOT NULL);
|
||||
');
|
||||
}
|
||||
|
||||
if (!$this->db->table_exists(db_prefix() . $this->config->item('rest_key_limits_table'))) {
|
||||
$this->db->query('CREATE TABLE `' . db_prefix() . $this->config->item('rest_key_limits_table') . '` (
|
||||
`id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`key_id` INT(11) NOT NULL,
|
||||
`uri` VARCHAR(511) NOT NULL,
|
||||
`class` VARCHAR(511) NOT NULL,
|
||||
`method` VARCHAR(511) NOT NULL,
|
||||
`ip_address` VARCHAR(63) NOT NULL,
|
||||
`time` DATETIME NOT NULL,
|
||||
`error` VARCHAR(63) NULL,
|
||||
PRIMARY KEY (`id`));
|
||||
');
|
||||
}
|
||||
}
|
||||
|
||||
public function get_permissions($id = '', $feature = '', $capability = '')
|
||||
{
|
||||
$this->db->select('*');
|
||||
if ('' != $id) {
|
||||
$this->db->where('key_id', $id);
|
||||
if ('' != $feature) {
|
||||
$this->db->where('feature', $feature);
|
||||
}
|
||||
if ('' != $capability) {
|
||||
$this->db->where('capability', $capability);
|
||||
}
|
||||
|
||||
return $this->db->get(db_prefix() . $this->config->item('rest_key_permissions_table'))->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[] = [
|
||||
'key_id' => $id,
|
||||
'feature' => $feature,
|
||||
'capability' => $api_capability,
|
||||
];
|
||||
}
|
||||
} else {
|
||||
$permissions[] = [
|
||||
'key_id' => $id,
|
||||
'feature' => $feature,
|
||||
'capability' => $api_capability,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($permissions as $permission) {
|
||||
$this->db->insert(db_prefix() . $this->config->item('rest_key_permissions_table'), $permission);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('New API Permssion Added [API ID: ' . $permission['key_id'] . ', Feature: ' . $permission['feature'] . ', Capability: ' . $permission['capability'] . ']');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function remove_permissions($id = '', $feature = '', $capability = '')
|
||||
{
|
||||
if ('' != $id) {
|
||||
$this->db->where('key_id', $id);
|
||||
if ('' != $feature) {
|
||||
$this->db->where('feature', $feature);
|
||||
}
|
||||
if ('' != $capability) {
|
||||
$this->db->where('capability', $capability);
|
||||
}
|
||||
|
||||
$this->db->delete(db_prefix() . $this->config->item('rest_key_permissions_table'));
|
||||
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_user($id = '')
|
||||
{
|
||||
$this->db->select('*');
|
||||
if ('' != $id) {
|
||||
$this->db->where('id', $id);
|
||||
}
|
||||
|
||||
return $this->db->get(db_prefix() . $this->config->item('rest_keys_table'))->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
|
||||
// generate a token
|
||||
$data['token'] = $this->authorization_koken->generateToken($payload);
|
||||
$today = date('Y-m-d H:i:s');
|
||||
|
||||
$data['expiration_date'] = to_sql_date($data['expiration_date'], true);
|
||||
$data['permission_enable'] = 1;
|
||||
$this->db->insert(db_prefix() . $this->config->item('rest_keys_table'), $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;
|
||||
|
||||
$this->db->where('id', $id);
|
||||
$user = $this->db->get(db_prefix() . $this->config->item('rest_keys_table'))->row();
|
||||
if (isset($user)) {
|
||||
if ($user->quota_limit != $data['quota_limit']) {
|
||||
$data['quota_remaining'] = $data['quota_limit'];
|
||||
}
|
||||
if ($user->qrate_limit != $data['rate_limit']) {
|
||||
$data['rate_remaining'] = $data['rate_limit'];
|
||||
}
|
||||
}
|
||||
|
||||
$result = false;
|
||||
$this->db->where('id', $id);
|
||||
$this->db->update(db_prefix() . $this->config->item('rest_keys_table'), $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() . $this->config->item('rest_keys_table'));
|
||||
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() . $this->config->item('rest_keys_table'))->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() . $this->config->item('rest_keys_table'))->row();
|
||||
if (isset($user)) {
|
||||
if ($user->permission_enable) {
|
||||
$this->db->where('key_id', $user->id);
|
||||
$this->db->where('feature', $feature);
|
||||
$this->db->where('capability', $capability);
|
||||
$permission = $this->db->get(db_prefix() . $this->config->item('rest_key_permissions_table'))->row();
|
||||
|
||||
if (isset($permission)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function statistics($period = 'hourly', $uri_method = '') {
|
||||
$now = time();
|
||||
$now_date = strtotime($now);
|
||||
$current_week_day = date('w', $now);
|
||||
$all_apis = [];
|
||||
|
||||
$chart = [
|
||||
"labels" => [],
|
||||
"datasets" => [
|
||||
[
|
||||
"label" => _l("success"),
|
||||
"data" => [],
|
||||
"borderColor" => "rgb(0, 255, 0)",
|
||||
"backgroundColor" => "rgba(0, 255, 0, 0.1)"
|
||||
],
|
||||
[
|
||||
"label" => _l("expiration_date"),
|
||||
"data" => [],
|
||||
"borderColor" => "rgb(200, 50, 100)",
|
||||
"backgroundColor" => "rgba(200, 50, 100, 0.1)"
|
||||
],
|
||||
[
|
||||
"label" => _l("quota_remaining"),
|
||||
"data" => [],
|
||||
"borderColor" => "rgb(200, 0, 200)",
|
||||
"backgroundColor" => "rgba(200, 0, 200, 0.1)"
|
||||
],
|
||||
[
|
||||
"label" => _l("rate_remaining"),
|
||||
"data" => [],
|
||||
"borderColor" => "rgb(200, 100, 0)",
|
||||
"backgroundColor" => "rgba(200, 100, 0, 0.1)"
|
||||
],
|
||||
]
|
||||
];
|
||||
if ($period) {
|
||||
if ($period == 'hourly') {
|
||||
$period_total = 23;
|
||||
} else if ($period == 'daily') {
|
||||
$period_total = 30;
|
||||
} else if ($period == 'weekly') {
|
||||
$period_total = 3;
|
||||
} else if ($period == 'monthly') {
|
||||
$period_total = 11;
|
||||
}
|
||||
for ($period_index = $period_total; $period_index >= 0; $period_index--) {
|
||||
if ($period == 'hourly') {
|
||||
$chart["labels"][] = date('M d H', $now - $period_index * 60 * 60);
|
||||
} else if ($period == 'daily') {
|
||||
$chart["labels"][] = date('M d', $now - $period_index * 60 * 60 * 24);
|
||||
} else if ($period == 'weekly') {
|
||||
$chart["labels"][] = date('M d', $now - ($current_week_day - 1 + $period_index * 7) * 60 * 60 * 24) . " ~ " . date('M d', $now - ($current_week_day - 1 + ($period_index - 1) * 7 + 1) * 60 * 60 * 24);
|
||||
} else if ($period == 'monthly') {
|
||||
$chart["labels"][] = date('Y M', strtotime(date('Y-m-01', strtotime("$now_date -$period_index months"))));
|
||||
}
|
||||
|
||||
foreach ($chart["datasets"] as $chart_dataset_index => $chart_dataset) {
|
||||
$this->db->select("uri, method, time, COUNT(*) AS total, error");
|
||||
if ($uri_method) {
|
||||
$uri_methods = explode(" ", urldecode($uri_method));
|
||||
$uri = $uri_methods[0];
|
||||
$method = $uri_methods[1];
|
||||
$this->db->where("uri", $uri);
|
||||
$this->db->where("method", $method);
|
||||
}
|
||||
if ($chart_dataset["label"] == _l("success")) {
|
||||
$this->db->where('error', NULL);
|
||||
} else {
|
||||
$this->db->where('error', $chart_dataset["label"]);
|
||||
}
|
||||
if ($period == 'hourly') {
|
||||
$this->db->where('time >=', date('Y-m-d H', $now - $period_index * 60 * 60));
|
||||
$this->db->where('time <', date('Y-m-d H', $now - ($period_index - 1) * 60 * 60));
|
||||
} else if ($period == 'daily') {
|
||||
$this->db->where('time >=', date('Y-m-d', $now - $period_index * 60 * 60 * 24));
|
||||
$this->db->where('time <', date('Y-m-d', $now - ($period_index - 1) * 60 * 60 * 24));
|
||||
} else if ($period == 'weekly') {
|
||||
$this->db->where('time >=', date('Y-m-d', $now - ($current_week_day - 1 + $period_index * 7) * 60 * 60 * 24));
|
||||
$this->db->where('time <', date('Y-m-d', $now - ($current_week_day - 1 + ($period_index - 1) * 7) * 60 * 60 * 24));
|
||||
} else if ($period == 'monthly') {
|
||||
$this->db->where('time >=', date('Y-m-01', strtotime("$now_date -$period_index months")));
|
||||
$this->db->where('time <=', date('Y-m-t', strtotime("$now_date -$period_index months")));
|
||||
}
|
||||
$period_apis = $this->db->get(db_prefix() . $this->config->item('rest_key_limits_table'))->row();
|
||||
$chart["datasets"][$chart_dataset_index]["data"][] = $period_apis->total;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($chart);
|
||||
}
|
||||
|
||||
public function endpoints() {
|
||||
$endpoints = [];
|
||||
$this->db->select("CONCAT(uri, ' ', method) as uri_method");
|
||||
$this->db->group_by("uri_method");
|
||||
$endpoint_apis = $this->db->get(db_prefix() . $this->config->item('rest_key_limits_table'))->result_array();
|
||||
foreach ($endpoint_apis as $endpoint_api) {
|
||||
$endpoints[] = $endpoint_api["uri_method"];
|
||||
}
|
||||
return $endpoints;
|
||||
}
|
||||
}
|
||||
121
api/models/Roles_model.php
Normal file
121
api/models/Roles_model.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Roles_model extends App_Model {
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new employee role
|
||||
* @param mixed $data
|
||||
*/
|
||||
public function add($data, $playground = false) {
|
||||
$permissions = [];
|
||||
if (isset($data['permissions'])) {
|
||||
$permissions = $data['permissions'];
|
||||
}
|
||||
$data['permissions'] = serialize($permissions);
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'roles', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
log_activity('New Role Added [ID: ' . $insert_id . '.' . $data['name'] . ']');
|
||||
return $insert_id;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update employee role
|
||||
* @param array $data role data
|
||||
* @param mixed $id role id
|
||||
* @return boolean
|
||||
*/
|
||||
public function update($data, $id, $playground = false) {
|
||||
$affectedRows = 0;
|
||||
$permissions = [];
|
||||
if (isset($data['permissions'])) {
|
||||
$permissions = $data['permissions'];
|
||||
}
|
||||
$data['permissions'] = serialize($permissions);
|
||||
$update_staff_permissions = false;
|
||||
if (isset($data['update_staff_permissions'])) {
|
||||
$update_staff_permissions = true;
|
||||
unset($data['update_staff_permissions']);
|
||||
}
|
||||
$this->db->where('roleid', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'roles', $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$affectedRows++;
|
||||
}
|
||||
if ($update_staff_permissions == true) {
|
||||
$this->load->model('staff_model');
|
||||
$staff = $this->staff_model->get('', ['role' => $id, ], $playground);
|
||||
foreach ($staff as $member) {
|
||||
if ($this->staff_model->update_permissions($permissions, $member['staffid'], $playground)) {
|
||||
$affectedRows++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($affectedRows > 0) {
|
||||
log_activity('Role Updated [ID: ' . $id . ', Name: ' . $data['name'] . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get employee role by id
|
||||
* @param mixed $id Optional role id
|
||||
* @return mixed array if not id passed else object
|
||||
*/
|
||||
public function get($id = '', $playground = false) {
|
||||
if (is_numeric($id)) {
|
||||
$role = $this->app_object_cache->get('role-' . $id);
|
||||
if ($role) {
|
||||
return $role;
|
||||
}
|
||||
$this->db->where('roleid', $id);
|
||||
$role = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'roles')->row();
|
||||
$role->permissions = !empty($role->permissions) ? unserialize($role->permissions) : [];
|
||||
$this->app_object_cache->add('role-' . $id, $role);
|
||||
return $role;
|
||||
}
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'roles')->result_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete employee role
|
||||
* @param mixed $id role id
|
||||
* @return mixed
|
||||
*/
|
||||
public function delete($id, $playground = false) {
|
||||
$current = $this->get($id);
|
||||
// Check first if role is used in table
|
||||
if (is_reference_in_table('role', db_prefix() . ($playground ? 'playground_' : '') . 'staff', $id)) {
|
||||
return ['referenced' => true, ];
|
||||
}
|
||||
$affectedRows = 0;
|
||||
$this->db->where('roleid', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'roles');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$affectedRows++;
|
||||
}
|
||||
if ($affectedRows > 0) {
|
||||
log_activity('Role Deleted [ID: ' . $id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function get_contact_permissions($id, $playground = false) {
|
||||
$this->db->where('userid', $id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'contact_permissions')->result_array();
|
||||
}
|
||||
|
||||
public function get_role_staff($role_id, $playground = false) {
|
||||
$this->db->where('role', $role_id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'staff')->result_array();
|
||||
}
|
||||
}
|
||||
71
api/models/Spam_filters_model.php
Normal file
71
api/models/Spam_filters_model.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Spam_filters_model extends App_Model {
|
||||
private $table;
|
||||
|
||||
public function __construct() {
|
||||
$this->table = 'spam_filters';
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function get($rel_type, $playground = false) {
|
||||
$this->db->where('rel_type', $rel_type);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . $this->table)->result_array();
|
||||
}
|
||||
|
||||
public function add($data, $type, $playground = false) {
|
||||
$data['rel_type'] = $type;
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . $this->table, $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
return $insert_id ? $insert_id : false;
|
||||
}
|
||||
|
||||
public function edit($data, $playground = false) {
|
||||
$this->db->where('id', $data['id']);
|
||||
unset($data['id']);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . $this->table, $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function delete($id, $type, $playground = false) {
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(($playground ? 'playground_' : '') . $this->table);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Spam Filter Deleted');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function check($email, $subject, $message, $rel_type, $playground = false) {
|
||||
$status = false;
|
||||
$spam_filters = $this->get($rel_type, $playground);
|
||||
foreach ($spam_filters as $filter) {
|
||||
$type = $filter['type'];
|
||||
$value = $filter['value'];
|
||||
if ($type == 'sender') {
|
||||
if (strtolower($value) == strtolower($email)) {
|
||||
$status = 'Blocked Sender';
|
||||
}
|
||||
}
|
||||
if ($type == 'subject') {
|
||||
if (strpos('x' . strtolower($subject), strtolower($value))) {
|
||||
$status = 'Blocked Subject';
|
||||
}
|
||||
}
|
||||
if ($type == 'phrase') {
|
||||
if (strpos('x' . strtolower($message), strtolower($value))) {
|
||||
$status = 'Blocked Phrase';
|
||||
}
|
||||
}
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
}
|
||||
625
api/models/Staff_model.php
Normal file
625
api/models/Staff_model.php
Normal file
@@ -0,0 +1,625 @@
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Staff_model extends App_Model {
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->load->model('departments_model');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get staff full name
|
||||
* @param string $userid Optional
|
||||
* @return string Firstname and Lastname
|
||||
*/
|
||||
public function get_staff_full_name($userid = '', $playground = false)
|
||||
{
|
||||
$tmpStaffUserId = get_staff_user_id();
|
||||
if ($userid == '' || $userid == $tmpStaffUserId) {
|
||||
if (isset($GLOBALS['current_user'])) {
|
||||
return $GLOBALS['current_user']->firstname . ' ' . $GLOBALS['current_user']->lastname;
|
||||
}
|
||||
|
||||
$userid = $tmpStaffUserId;
|
||||
}
|
||||
|
||||
$staff = $this->app_object_cache->get('staff-full-name-data-' . $userid);
|
||||
|
||||
if (!$staff) {
|
||||
$this->db->where('staffid', $userid);
|
||||
$staff = $this->db->select('firstname,lastname')->from(db_prefix() . ($playground ? 'playground_' : '') . 'staff')->get()->row();
|
||||
$this->app_object_cache->add('staff-full-name-data-' . $userid, $staff);
|
||||
}
|
||||
|
||||
return $staff ? $staff->firstname . ' ' . $staff->lastname : '';
|
||||
}
|
||||
|
||||
public function delete($id, $transfer_data_to, $playground = false) {
|
||||
if (!is_numeric($transfer_data_to)) {
|
||||
return false;
|
||||
}
|
||||
if ($id == $transfer_data_to) {
|
||||
return false;
|
||||
}
|
||||
hooks()->do_action('before_delete_staff_member', ['id' => $id, 'transfer_data_to' => $transfer_data_to, ]);
|
||||
$name = $this->get_staff_full_name($id, $playground);
|
||||
$transferred_to = $this->get_staff_full_name($transfer_data_to, $playground);
|
||||
$this->db->where('addedfrom', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'estimates', ['addedfrom' => $transfer_data_to, ]);
|
||||
$this->db->where('sale_agent', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'estimates', ['sale_agent' => $transfer_data_to, ]);
|
||||
$this->db->where('addedfrom', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'invoices', ['addedfrom' => $transfer_data_to, ]);
|
||||
$this->db->where('sale_agent', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'invoices', ['sale_agent' => $transfer_data_to, ]);
|
||||
$this->db->where('addedfrom', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'expenses', ['addedfrom' => $transfer_data_to, ]);
|
||||
$this->db->where('addedfrom', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'notes', ['addedfrom' => $transfer_data_to, ]);
|
||||
$this->db->where('userid', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'newsfeed_post_comments', ['userid' => $transfer_data_to, ]);
|
||||
$this->db->where('creator', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'newsfeed_posts', ['creator' => $transfer_data_to, ]);
|
||||
$this->db->where('staff_id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'projectdiscussions', ['staff_id' => $transfer_data_to, ]);
|
||||
$this->db->where('addedfrom', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'projects', ['addedfrom' => $transfer_data_to, ]);
|
||||
$this->db->where('addedfrom', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes', ['addedfrom' => $transfer_data_to, ]);
|
||||
$this->db->where('staff_id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'credits', ['staff_id' => $transfer_data_to, ]);
|
||||
$this->db->where('staff_id', $id);
|
||||
$this->db->update(($playground ? 'playground_' : '') . 'filters', ['staff_id' => $transfer_data_to, ]);
|
||||
$this->db->where('staffid', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'project_files', ['staffid' => $transfer_data_to, ]);
|
||||
$this->db->where('staffid', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'proposal_comments', ['staffid' => $transfer_data_to, ]);
|
||||
$this->db->where('addedfrom', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'proposals', ['addedfrom' => $transfer_data_to, ]);
|
||||
$this->db->where('addedfrom', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'templates', ['addedfrom' => $transfer_data_to, ]);
|
||||
$this->db->where('staffid', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'task_comments', ['staffid' => $transfer_data_to, ]);
|
||||
$this->db->where('addedfrom', $id);
|
||||
$this->db->where('is_added_from_contact', 0);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'tasks', ['addedfrom' => $transfer_data_to, ]);
|
||||
$this->db->where('staffid', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'files', ['staffid' => $transfer_data_to, ]);
|
||||
$this->db->where('renewed_by_staff_id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'contract_renewals', ['renewed_by_staff_id' => $transfer_data_to, ]);
|
||||
$this->db->where('addedfrom', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'task_checklist_items', ['addedfrom' => $transfer_data_to, ]);
|
||||
$this->db->where('assigned', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'task_checklist_items', ['assigned' => $transfer_data_to, ]);
|
||||
$this->db->where('finished_from', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'task_checklist_items', ['finished_from' => $transfer_data_to, ]);
|
||||
$this->db->where('admin', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'ticket_replies', ['admin' => $transfer_data_to, ]);
|
||||
$this->db->where('admin', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'tickets', ['admin' => $transfer_data_to, ]);
|
||||
$this->db->where('addedfrom', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'leads', ['addedfrom' => $transfer_data_to, ]);
|
||||
$this->db->where('assigned', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'leads', ['assigned' => $transfer_data_to, ]);
|
||||
$this->db->where('staff_id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'taskstimers', ['staff_id' => $transfer_data_to, ]);
|
||||
$this->db->where('addedfrom', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'contracts', ['addedfrom' => $transfer_data_to, ]);
|
||||
$this->db->where('assigned_from', $id);
|
||||
$this->db->where('is_assigned_from_contact', 0);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'task_assigned', ['assigned_from' => $transfer_data_to, ]);
|
||||
$this->db->where('responsible', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'leads_email_integration', ['responsible' => $transfer_data_to, ]);
|
||||
$this->db->where('responsible', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'web_to_lead', ['responsible' => $transfer_data_to, ]);
|
||||
$this->db->where('responsible', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_request_forms', ['responsible' => $transfer_data_to, ]);
|
||||
$this->db->where('assigned', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_requests', ['assigned' => $transfer_data_to, ]);
|
||||
$this->db->where('created_from', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'subscriptions', ['created_from' => $transfer_data_to, ]);
|
||||
$this->db->where('notify_type', 'specific_staff');
|
||||
$web_to_lead = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'web_to_lead')->result_array();
|
||||
foreach ($web_to_lead as $form) {
|
||||
if (!empty($form['notify_ids'])) {
|
||||
$staff = unserialize($form['notify_ids']);
|
||||
if (is_array($staff) && in_array($id, $staff) && ($key = array_search($id, $staff)) !== false) {
|
||||
unset($staff[$key]);
|
||||
$staff = serialize(array_values($staff));
|
||||
$this->db->where('id', $form['id']);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'web_to_lead', ['notify_ids' => $staff, ]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->db->where('notify_type', 'specific_staff');
|
||||
$estimate_requests = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_request_forms')->result_array();
|
||||
foreach ($estimate_requests as $form) {
|
||||
if (!empty($form['notify_ids'])) {
|
||||
$staff = unserialize($form['notify_ids']);
|
||||
if (is_array($staff) && in_array($id, $staff) && ($key = array_search($id, $staff)) !== false) {
|
||||
unset($staff[$key]);
|
||||
$staff = serialize(array_values($staff));
|
||||
$this->db->where('id', $form['id']);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'estimate_request_forms', ['notify_ids' => $staff, ]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->db->where('id', 1);
|
||||
$leads_email_integration = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'leads_email_integration')->row();
|
||||
if ($leads_email_integration->notify_type == 'specific_staff') {
|
||||
if (!empty($leads_email_integration->notify_ids)) {
|
||||
$staff = unserialize($leads_email_integration->notify_ids);
|
||||
if (is_array($staff) && in_array($id, $staff) && ($key = array_search($id, $staff)) !== false) {
|
||||
unset($staff[$key]);
|
||||
$staff = serialize(array_values($staff));
|
||||
$this->db->where('id', 1);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'leads_email_integration', ['notify_ids' => $staff, ]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->db->where('assigned', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'tickets', ['assigned' => 0, ]);
|
||||
$this->db->where('staff', 1);
|
||||
$this->db->where('userid', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'dismissed_announcements');
|
||||
$this->db->where('userid', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'newsfeed_comment_likes');
|
||||
$this->db->where('userid', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'newsfeed_post_likes');
|
||||
$this->db->where('staff_id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'customer_admins');
|
||||
$this->db->where('fieldto', 'staff');
|
||||
$this->db->where('relid', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'customfieldsvalues');
|
||||
$this->db->where('userid', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'events');
|
||||
$this->db->where('touserid', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'notifications');
|
||||
$this->db->where('staff_id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'user_meta');
|
||||
$this->db->where('staff_id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'project_members');
|
||||
$this->db->where('staff_id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'project_notes');
|
||||
$this->db->where('creator', $id);
|
||||
$this->db->or_where('staff', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'reminders');
|
||||
$this->db->where('staffid', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'staff_departments');
|
||||
$this->db->where('staffid', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'todos');
|
||||
$this->db->where('staff', 1);
|
||||
$this->db->where('user_id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'user_auto_login');
|
||||
$this->db->where('staff_id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'staff_permissions');
|
||||
$this->db->where('staffid', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'task_assigned');
|
||||
$this->db->where('staffid', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'task_followers');
|
||||
$this->db->where('staff_id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'pinned_projects');
|
||||
$this->db->where('staffid', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'staff');
|
||||
log_activity('Staff Member Deleted [Name: ' . $name . ', Data Transferred To: ' . $transferred_to . ']');
|
||||
hooks()->do_action('staff_member_deleted', ['id' => $id, 'transfer_data_to' => $transfer_data_to, ]);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get staff member/s
|
||||
* @param mixed $id Optional - staff id
|
||||
* @param mixed $where where in query
|
||||
* @return mixed if id is passed return object else array
|
||||
*/
|
||||
public function get($id = '', $where = [], $playground = false) {
|
||||
$select_str = '*,CONCAT(firstname,\' \',lastname) as full_name';
|
||||
// Used to prevent multiple queries on logged in staff to check the total unread notifications in core/AdminController.php
|
||||
if (is_staff_logged_in() && $id != '' && $id == get_staff_user_id()) {
|
||||
$select_str.= ',(SELECT COUNT(*) FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'notifications WHERE touserid=' . get_staff_user_id() . ' and isread=0) as total_unread_notifications, (SELECT COUNT(*) FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'todos WHERE finished=0 AND staffid=' . get_staff_user_id() . ') as total_unfinished_todos';
|
||||
}
|
||||
$this->db->select($select_str);
|
||||
$this->db->where($where);
|
||||
if (is_numeric($id)) {
|
||||
$this->db->where('staffid', $id);
|
||||
$staff = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'staff')->row();
|
||||
if ($staff) {
|
||||
$staff->permissions = $this->get_staff_permissions($id, $playground);
|
||||
}
|
||||
return $staff;
|
||||
}
|
||||
$this->db->order_by('firstname', 'desc');
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'staff')->result_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get staff permissions
|
||||
* @param mixed $id staff id
|
||||
* @return array
|
||||
*/
|
||||
public function get_staff_permissions($id, $playground = false) {
|
||||
// Fix for version 2.3.1 tables upgrade
|
||||
if (defined('DOING_DATABASE_UPGRADE')) {
|
||||
return [];
|
||||
}
|
||||
$permissions = $this->app_object_cache->get('staff-' . $id . '-permissions');
|
||||
if (!$permissions && !is_array($permissions)) {
|
||||
$this->db->where('staff_id', $id);
|
||||
$permissions = $this->db->get(($playground ? 'playground_' : '') . 'staff_permissions')->result_array();
|
||||
$this->app_object_cache->add('staff-' . $id . '-permissions', $permissions);
|
||||
}
|
||||
return $permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new staff member
|
||||
* @param array $data staff $_POST data
|
||||
*/
|
||||
public function add($data, $playground = false) {
|
||||
if (isset($data['fakeusernameremembered'])) {
|
||||
unset($data['fakeusernameremembered']);
|
||||
}
|
||||
if (isset($data['fakepasswordremembered'])) {
|
||||
unset($data['fakepasswordremembered']);
|
||||
}
|
||||
// First check for all cases if the email exists.
|
||||
$data = hooks()->apply_filters('before_create_staff_member', $data);
|
||||
$this->db->where('email', $data['email']);
|
||||
$email = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'staff')->row();
|
||||
if ($email) {
|
||||
die('Email already exists');
|
||||
}
|
||||
$data['admin'] = 0;
|
||||
if (is_admin()) {
|
||||
if (isset($data['administrator'])) {
|
||||
$data['admin'] = 1;
|
||||
unset($data['administrator']);
|
||||
}
|
||||
}
|
||||
$send_welcome_email = true;
|
||||
$original_password = $data['password'];
|
||||
if (!isset($data['send_welcome_email'])) {
|
||||
$send_welcome_email = false;
|
||||
} else {
|
||||
unset($data['send_welcome_email']);
|
||||
}
|
||||
$data['password'] = app_hash_password($data['password']);
|
||||
$data['datecreated'] = date('Y-m-d H:i:s');
|
||||
if (isset($data['departments'])) {
|
||||
$departments = $data['departments'];
|
||||
unset($data['departments']);
|
||||
}
|
||||
$permissions = [];
|
||||
if (isset($data['permissions'])) {
|
||||
$permissions = $data['permissions'];
|
||||
unset($data['permissions']);
|
||||
}
|
||||
if (isset($data['custom_fields'])) {
|
||||
$custom_fields = $data['custom_fields'];
|
||||
unset($data['custom_fields']);
|
||||
}
|
||||
if ($data['admin'] == 1) {
|
||||
$data['is_not_staff'] = 0;
|
||||
}
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'staff', $data);
|
||||
$staffid = $this->db->insert_id();
|
||||
if ($staffid) {
|
||||
$slug = $data['firstname'] . ' ' . $data['lastname'];
|
||||
if ($slug == ' ') {
|
||||
$slug = 'unknown-' . $staffid;
|
||||
}
|
||||
if ($send_welcome_email == true) {
|
||||
send_mail_template('staff_created', $data['email'], $staffid, $original_password, $playground);
|
||||
}
|
||||
$this->db->where('staffid', $staffid);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'staff', ['media_path_slug' => slug_it($slug), ]);
|
||||
if (isset($custom_fields)) {
|
||||
$this->load->model('custom_fields_model');
|
||||
$this->custom_fields_model->handle_custom_fields_post($staffid, $custom_fields, false, $playground);
|
||||
}
|
||||
if (isset($departments)) {
|
||||
foreach ($departments as $department) {
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'staff_departments', ['staffid' => $staffid, 'departmentid' => $department, ]);
|
||||
}
|
||||
}
|
||||
// Delete all staff permission if is admin we dont need permissions stored in database (in case admin check some permissions)
|
||||
$this->update_permissions($data['admin'] == 1 ? [] : $permissions, $staffid, $playground);
|
||||
log_activity('New Staff Member Added [ID: ' . $staffid . ', ' . $data['firstname'] . ' ' . $data['lastname'] . ']');
|
||||
// Get all announcements and set it to read.
|
||||
$this->db->select('announcementid');
|
||||
$this->db->from(db_prefix() . ($playground ? 'playground_' : '') . 'announcements');
|
||||
$this->db->where('showtostaff', 1);
|
||||
$announcements = $this->db->get()->result_array();
|
||||
foreach ($announcements as $announcement) {
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'dismissed_announcements', ['announcementid' => $announcement['announcementid'], 'staff' => 1, 'userid' => $staffid, ]);
|
||||
}
|
||||
hooks()->do_action('staff_member_created', $staffid);
|
||||
return $staffid;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update staff member info
|
||||
* @param array $data staff data
|
||||
* @param mixed $id staff id
|
||||
* @return boolean
|
||||
*/
|
||||
public function update($data, $id, $playground = false) {
|
||||
if (isset($data['fakeusernameremembered'])) {
|
||||
unset($data['fakeusernameremembered']);
|
||||
}
|
||||
if (isset($data['fakepasswordremembered'])) {
|
||||
unset($data['fakepasswordremembered']);
|
||||
}
|
||||
$data = hooks()->apply_filters('before_update_staff_member', $data, $id);
|
||||
if (is_admin()) {
|
||||
if (isset($data['administrator'])) {
|
||||
$data['admin'] = 1;
|
||||
unset($data['administrator']);
|
||||
} else {
|
||||
if ($id != get_staff_user_id()) {
|
||||
if ($id == 1) {
|
||||
return ['cant_remove_main_admin' => true, ];
|
||||
}
|
||||
} else {
|
||||
return ['cant_remove_yourself_from_admin' => true, ];
|
||||
}
|
||||
$data['admin'] = 0;
|
||||
}
|
||||
}
|
||||
$affectedRows = 0;
|
||||
if (isset($data['departments'])) {
|
||||
$departments = $data['departments'];
|
||||
unset($data['departments']);
|
||||
}
|
||||
$permissions = [];
|
||||
if (isset($data['permissions'])) {
|
||||
$permissions = $data['permissions'];
|
||||
unset($data['permissions']);
|
||||
}
|
||||
if (isset($data['custom_fields'])) {
|
||||
$custom_fields = $data['custom_fields'];
|
||||
$this->load->model('custom_fields_model');
|
||||
if ($this->custom_fields_model->handle_custom_fields_post($id, $custom_fields, false, $playground)) {
|
||||
$affectedRows++;
|
||||
}
|
||||
unset($data['custom_fields']);
|
||||
}
|
||||
if (empty($data['password'])) {
|
||||
unset($data['password']);
|
||||
} else {
|
||||
$data['password'] = app_hash_password($data['password']);
|
||||
$data['last_password_change'] = date('Y-m-d H:i:s');
|
||||
}
|
||||
// if (isset($data['two_factor_auth_enabled'])) {
|
||||
// $data['two_factor_auth_enabled'] = 1;
|
||||
// } else {
|
||||
// $data['two_factor_auth_enabled'] = 0;
|
||||
// }
|
||||
if (isset($data['is_not_staff'])) {
|
||||
$data['is_not_staff'] = 1;
|
||||
} else {
|
||||
$data['is_not_staff'] = 0;
|
||||
}
|
||||
if (isset($data['admin']) && $data['admin'] == 1) {
|
||||
$data['is_not_staff'] = 0;
|
||||
}
|
||||
$staff_departments = $this->departments_model->get_staff_departments($id, false, $playground);
|
||||
if (sizeof($staff_departments) > 0) {
|
||||
if (!isset($data['departments'])) {
|
||||
$this->db->where('staffid', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'staff_departments');
|
||||
} else {
|
||||
foreach ($staff_departments as $staff_department) {
|
||||
if (isset($departments)) {
|
||||
if (!in_array($staff_department['departmentid'], $departments)) {
|
||||
$this->db->where('staffid', $id);
|
||||
$this->db->where('departmentid', $staff_department['departmentid']);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'staff_departments');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$affectedRows++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($departments)) {
|
||||
foreach ($departments as $department) {
|
||||
$this->db->where('staffid', $id);
|
||||
$this->db->where('departmentid', $department);
|
||||
$_exists = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'staff_departments')->row();
|
||||
if (!$_exists) {
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'staff_departments', ['staffid' => $id, 'departmentid' => $department, ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$affectedRows++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (isset($departments)) {
|
||||
foreach ($departments as $department) {
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'staff_departments', ['staffid' => $id, 'departmentid' => $department, ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$affectedRows++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->db->where('staffid', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'staff', $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$affectedRows++;
|
||||
}
|
||||
if ($this->update_permissions((isset($data['admin']) && $data['admin'] == 1 ? [] : $permissions), $id, $playground)) {
|
||||
$affectedRows++;
|
||||
}
|
||||
if ($affectedRows > 0) {
|
||||
hooks()->do_action('staff_member_updated', $id);
|
||||
log_activity('Staff Member Updated [ID: ' . $id . ', ' . $data['firstname'] . ' ' . $data['lastname'] . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function update_permissions($permissions, $id, $playground = false) {
|
||||
$this->db->where('staff_id', $id);
|
||||
$this->db->delete(($playground ? 'playground_' : '') . 'staff_permissions');
|
||||
$is_staff_member = is_staff_member($id);
|
||||
foreach ($permissions as $feature => $capabilities) {
|
||||
foreach ($capabilities as $capability) {
|
||||
// Maybe do this via hook.
|
||||
if ($feature == 'leads' && !$is_staff_member) {
|
||||
continue;
|
||||
}
|
||||
$this->db->insert(($playground ? 'playground_' : '') . 'staff_permissions', ['staff_id' => $id, 'feature' => $feature, 'capability' => $capability]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function update_profile($data, $id, $playground = false) {
|
||||
$data = hooks()->apply_filters('before_staff_update_profile', $data, $id);
|
||||
if (empty($data['password'])) {
|
||||
unset($data['password']);
|
||||
} else {
|
||||
$data['password'] = app_hash_password($data['password']);
|
||||
$data['last_password_change'] = date('Y-m-d H:i:s');
|
||||
}
|
||||
unset($data['two_factor_auth_enabled']);
|
||||
unset($data['google_auth_secret']);
|
||||
$this->db->where('staffid', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'staff', $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
hooks()->do_action('staff_member_profile_updated', $id);
|
||||
log_activity('Staff Profile Updated [Staff: ' . $this->get_staff_full_name($id, $playground) . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change staff passwordn
|
||||
* @param mixed $data password data
|
||||
* @param mixed $userid staff id
|
||||
* @return mixed
|
||||
*/
|
||||
public function change_password($data, $userid, $playground = false) {
|
||||
$data = hooks()->apply_filters('before_staff_change_password', $data, $userid);
|
||||
$member = $this->get($userid, [], $playground);
|
||||
// CHeck if member is active
|
||||
if ($member->active == 0) {
|
||||
return [['memberinactive' => true, ], ];
|
||||
}
|
||||
// Check new old password
|
||||
if (!app_hasher()->CheckPassword($data['oldpassword'], $member->password)) {
|
||||
return [['passwordnotmatch' => true, ], ];
|
||||
}
|
||||
$data['newpasswordr'] = app_hash_password($data['newpasswordr']);
|
||||
$this->db->where('staffid', $userid);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'staff', ['password' => $data['newpasswordr'], 'last_password_change' => date('Y-m-d H:i:s'), ]);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Staff Password Changed [' . $userid . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change staff status / active / inactive
|
||||
* @param mixed $id staff id
|
||||
* @param mixed $status status(0/1)
|
||||
*/
|
||||
public function change_staff_status($id, $status, $playground = false) {
|
||||
$status = hooks()->apply_filters('before_staff_status_change', $status, $id);
|
||||
$this->db->where('staffid', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'staff', ['active' => $status, ]);
|
||||
log_activity('Staff Status Changed [StaffID: ' . $id . ' - Status(Active/Inactive): ' . $status . ']');
|
||||
hooks()->do_action('after_staff_status_change', $id);
|
||||
}
|
||||
|
||||
public function get_logged_time_data($id = '', $filter_data = [], $playground = false) {
|
||||
if ($id == '') {
|
||||
$id = get_staff_user_id();
|
||||
}
|
||||
$result['timesheets'] = [];
|
||||
$result['total'] = [];
|
||||
$result['this_month'] = [];
|
||||
$first_day_this_month = date('Y-m-01'); // hard-coded '01' for first day
|
||||
$last_day_this_month = date('Y-m-t 23:59:59');
|
||||
$result['last_month'] = [];
|
||||
$first_day_last_month = date('Y-m-01', strtotime('-1 MONTH')); // hard-coded '01' for first day
|
||||
$last_day_last_month = date('Y-m-t 23:59:59', strtotime('-1 MONTH'));
|
||||
$result['this_week'] = [];
|
||||
$first_day_this_week = date('Y-m-d', strtotime('monday this week'));
|
||||
$last_day_this_week = date('Y-m-d 23:59:59', strtotime('sunday this week'));
|
||||
$result['last_week'] = [];
|
||||
$first_day_last_week = date('Y-m-d', strtotime('monday last week'));
|
||||
$last_day_last_week = date('Y-m-d 23:59:59', strtotime('sunday last week'));
|
||||
$this->db->select('task_id,start_time,end_time,staff_id,' . db_prefix() . ($playground ? 'playground_' : '') . 'taskstimers.hourly_rate,name,' . db_prefix() . ($playground ? 'playground_' : '') . 'taskstimers.id,rel_id,rel_type, billed');
|
||||
$this->db->where('staff_id', $id);
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'tasks', db_prefix() . ($playground ? 'playground_' : '') . 'tasks.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'taskstimers.task_id', 'left');
|
||||
$timers = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'taskstimers')->result_array();
|
||||
$_end_time_static = time();
|
||||
$filter_period = false;
|
||||
if (isset($filter_data['period-from']) && $filter_data['period-from'] != '' && isset($filter_data['period-to']) && $filter_data['period-to'] != '') {
|
||||
$filter_period = true;
|
||||
$from = to_sql_date($filter_data['period-from']);
|
||||
$from = date('Y-m-d', strtotime($from));
|
||||
$to = to_sql_date($filter_data['period-to']);
|
||||
$to = date('Y-m-d', strtotime($to));
|
||||
}
|
||||
foreach ($timers as $timer) {
|
||||
$start_date = date('Y-m-d', $timer['start_time']);
|
||||
$end_time = $timer['end_time'];
|
||||
$notFinished = false;
|
||||
if ($timer['end_time'] == null) {
|
||||
$end_time = $_end_time_static;
|
||||
$notFinished = true;
|
||||
}
|
||||
$total = $end_time - $timer['start_time'];
|
||||
$result['total'][] = $total;
|
||||
$timer['total'] = $total;
|
||||
$timer['end_time'] = $end_time;
|
||||
$timer['not_finished'] = $notFinished;
|
||||
if ($start_date >= $first_day_this_month && $start_date <= $last_day_this_month) {
|
||||
$result['this_month'][] = $total;
|
||||
if (isset($filter_data['this_month']) && $filter_data['this_month'] != '') {
|
||||
$result['timesheets'][$timer['id']] = $timer;
|
||||
}
|
||||
}
|
||||
if ($start_date >= $first_day_last_month && $start_date <= $last_day_last_month) {
|
||||
$result['last_month'][] = $total;
|
||||
if (isset($filter_data['last_month']) && $filter_data['last_month'] != '') {
|
||||
$result['timesheets'][$timer['id']] = $timer;
|
||||
}
|
||||
}
|
||||
if ($start_date >= $first_day_this_week && $start_date <= $last_day_this_week) {
|
||||
$result['this_week'][] = $total;
|
||||
if (isset($filter_data['this_week']) && $filter_data['this_week'] != '') {
|
||||
$result['timesheets'][$timer['id']] = $timer;
|
||||
}
|
||||
}
|
||||
if ($start_date >= $first_day_last_week && $start_date <= $last_day_last_week) {
|
||||
$result['last_week'][] = $total;
|
||||
if (isset($filter_data['last_week']) && $filter_data['last_week'] != '') {
|
||||
$result['timesheets'][$timer['id']] = $timer;
|
||||
}
|
||||
}
|
||||
if ($filter_period == true) {
|
||||
if ($start_date >= $from && $start_date <= $to) {
|
||||
$result['timesheets'][$timer['id']] = $timer;
|
||||
}
|
||||
}
|
||||
}
|
||||
$result['total'] = array_sum($result['total']);
|
||||
$result['this_month'] = array_sum($result['this_month']);
|
||||
$result['last_month'] = array_sum($result['last_month']);
|
||||
$result['this_week'] = array_sum($result['this_week']);
|
||||
$result['last_week'] = array_sum($result['last_week']);
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
218
api/models/Statement_model.php
Normal file
218
api/models/Statement_model.php
Normal file
@@ -0,0 +1,218 @@
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Statement_model extends App_Model {
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get customer statement formatted
|
||||
* @param mixed $customer_id customer id
|
||||
* @param string $from date from
|
||||
* @param string $to date to
|
||||
* @return array
|
||||
*/
|
||||
public function get_statement($customer_id, $from, $to, $playground = false) {
|
||||
$sql = 'SELECT
|
||||
' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.id as invoice_id, hash,
|
||||
' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.date as date,
|
||||
' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.duedate, concat(' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.date, \' \', RIGHT(' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.datecreated,LOCATE(\' \',' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.datecreated) - 3)) as tmp_date,
|
||||
' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.duedate as duedate,
|
||||
' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.total as invoice_amount
|
||||
FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices WHERE clientid =' . $this->db->escape_str($customer_id);
|
||||
if ($from == $to) {
|
||||
$sqlDate = 'date="' . $this->db->escape_str($from) . '"';
|
||||
} else {
|
||||
$sqlDate = '(date BETWEEN "' . $this->db->escape_str($from) . '" AND "' . $this->db->escape_str($to) . '")';
|
||||
}
|
||||
$sql.= ' AND ' . $sqlDate;
|
||||
$invoices = $this->db->query($sql . '
|
||||
AND status != ' . Invoices_model::STATUS_DRAFT . '
|
||||
AND status != ' . Invoices_model::STATUS_CANCELLED . '
|
||||
ORDER By date DESC')->result_array();
|
||||
// Credit notes
|
||||
$sql_credit_notes = 'SELECT
|
||||
' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes.id as credit_note_id,
|
||||
' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes.date as date,
|
||||
concat(' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes.date, \' \', RIGHT(' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes.datecreated,LOCATE(\' \',' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes.datecreated) - 3)) as tmp_date,
|
||||
' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes.total as credit_note_amount
|
||||
FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes WHERE clientid =' . $this->db->escape_str($customer_id) . ' AND status != 3';
|
||||
$sql_credit_notes.= ' AND ' . $sqlDate;
|
||||
$credit_notes = $this->db->query($sql_credit_notes)->result_array();
|
||||
// Credits applied
|
||||
$sql_credits_applied = 'SELECT ' . db_prefix() . ($playground ? 'playground_' : '') . 'credits.id as credit_id, invoice_id as credit_invoice_id,
|
||||
' . db_prefix() . ($playground ? 'playground_' : '') . 'credits.credit_id as credit_applied_credit_note_id,
|
||||
' . db_prefix() . ($playground ? 'playground_' : '') . 'credits.date as date, concat(' . db_prefix() . ($playground ? 'playground_' : '') . 'credits.date, \' \', RIGHT(' . db_prefix() . ($playground ? 'playground_' : '') . 'credits.date_applied,LOCATE(\' \',' . db_prefix() . ($playground ? 'playground_' : '') . 'credits.date_applied) - 3)) as tmp_date,
|
||||
' . db_prefix() . ($playground ? 'playground_' : '') . 'credits.amount as credit_amount
|
||||
FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'credits JOIN ' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes ON ' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'credits.credit_id
|
||||
';
|
||||
$sql_credits_applied.= ' WHERE clientid =' . $this->db->escape_str($customer_id);
|
||||
$sqlDateCreditsAplied = str_replace('date', db_prefix() . ($playground ? 'playground_' : '') . 'credits.date', $sqlDate);
|
||||
$sql_credits_applied.= ' AND ' . $sqlDateCreditsAplied;
|
||||
$credits_applied = $this->db->query($sql_credits_applied)->result_array();
|
||||
// Replace error ambigious column in where clause
|
||||
$sqlDatePayments = str_replace('date', db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.date', $sqlDate);
|
||||
$sql_payments = 'SELECT
|
||||
' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.id as payment_id,
|
||||
' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.date as date,
|
||||
concat(' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.date, \' \', RIGHT(' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.daterecorded,LOCATE(\' \',' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.daterecorded) - 3)) as tmp_date,
|
||||
' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.invoiceid as payment_invoice_id,
|
||||
' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.amount as payment_total
|
||||
FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords
|
||||
JOIN ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices ON ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.invoiceid
|
||||
WHERE ' . $sqlDatePayments . ' AND ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.clientid = ' . $this->db->escape_str($customer_id) . '
|
||||
ORDER by ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.date DESC';
|
||||
$payments = $this->db->query($sql_payments)->result_array();
|
||||
$sqlCreditNoteRefunds = str_replace('date', 'refunded_on', $sqlDate);
|
||||
$sql_credit_notes_refunds = 'SELECT id as credit_note_refund_id, credit_note_id as refund_credit_note_id, amount as refund_amount, concat(' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnote_refunds.refunded_on, \' \', RIGHT(' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnote_refunds.created_at,LOCATE(\' \',' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnote_refunds.created_at) - 3)) as tmp_date,
|
||||
refunded_on as date FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnote_refunds
|
||||
WHERE ' . $sqlCreditNoteRefunds . ' AND credit_note_id IN (SELECT id FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes WHERE clientid=' . $this->db->escape_str($customer_id) . ')
|
||||
';
|
||||
$credit_notes_refunds = $this->db->query($sql_credit_notes_refunds)->result_array();
|
||||
// merge results
|
||||
$merged = array_merge($invoices, $payments, $credit_notes, $credits_applied, $credit_notes_refunds);
|
||||
// sort by date
|
||||
usort($merged, function ($a, $b) {
|
||||
// fake date select sorting
|
||||
return strtotime($a['tmp_date']) - strtotime($b['tmp_date']);
|
||||
});
|
||||
// Define final result variable
|
||||
$result = [];
|
||||
// Store in result array key
|
||||
$result['result'] = $merged;
|
||||
// Invoiced amount during the period
|
||||
$result['invoiced_amount'] = $this->db->query('SELECT
|
||||
SUM(' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.total) as invoiced_amount
|
||||
FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices
|
||||
WHERE clientid = ' . $this->db->escape_str($customer_id) . '
|
||||
AND ' . $sqlDate . ' AND status != ' . Invoices_model::STATUS_DRAFT . ' AND status != ' . Invoices_model::STATUS_CANCELLED . '')->row()->invoiced_amount;
|
||||
if ($result['invoiced_amount'] === null) {
|
||||
$result['invoiced_amount'] = 0;
|
||||
}
|
||||
$result['credit_notes_amount'] = $this->db->query('SELECT
|
||||
SUM(' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes.total) as credit_notes_amount
|
||||
FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes
|
||||
WHERE clientid = ' . $this->db->escape_str($customer_id) . '
|
||||
AND ' . $sqlDate . ' AND status != 3')->row()->credit_notes_amount;
|
||||
if ($result['credit_notes_amount'] === null) {
|
||||
$result['credit_notes_amount'] = 0;
|
||||
}
|
||||
$result['refunds_amount'] = $this->db->query('SELECT
|
||||
SUM(' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnote_refunds.amount) as refunds_amount
|
||||
FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnote_refunds
|
||||
WHERE ' . $sqlCreditNoteRefunds . ' AND credit_note_id IN (SELECT id FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes WHERE clientid=' . $this->db->escape_str($customer_id) . ')
|
||||
')->row()->refunds_amount;
|
||||
if ($result['refunds_amount'] === null) {
|
||||
$result['refunds_amount'] = 0;
|
||||
}
|
||||
$result['invoiced_amount'] = $result['invoiced_amount'] - $result['credit_notes_amount'];
|
||||
// Amount paid during the period
|
||||
$result['amount_paid'] = $this->db->query('SELECT
|
||||
SUM(' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.amount) as amount_paid
|
||||
FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords
|
||||
JOIN ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices ON ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.invoiceid
|
||||
WHERE ' . $sqlDatePayments . ' AND ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.clientid = ' . $this->db->escape_str($customer_id))->row()->amount_paid;
|
||||
if ($result['amount_paid'] === null) {
|
||||
$result['amount_paid'] = 0;
|
||||
}
|
||||
// Beginning balance is all invoices amount before the FROM date - payments received before FROM date
|
||||
$result['beginning_balance'] = $this->db->query('
|
||||
SELECT (
|
||||
COALESCE(SUM(' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.total),0) - (
|
||||
(
|
||||
SELECT COALESCE(SUM(' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.amount),0)
|
||||
FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords
|
||||
JOIN ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices ON ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.invoiceid
|
||||
WHERE ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoicepaymentrecords.date < "' . $this->db->escape_str($from) . '"
|
||||
AND ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.clientid=' . $this->db->escape_str($customer_id) . '
|
||||
) + (
|
||||
SELECT COALESCE(SUM(' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes.total),0)
|
||||
FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes
|
||||
WHERE ' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes.date < "' . $this->db->escape_str($from) . '"
|
||||
AND ' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes.clientid=' . $this->db->escape_str($customer_id) . '
|
||||
) - (
|
||||
SELECT COALESCE(SUM(' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnote_refunds.amount),0)
|
||||
FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnote_refunds
|
||||
WHERE ' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnote_refunds.refunded_on < "' . $this->db->escape_str($from) . '"
|
||||
AND ' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnote_refunds.credit_note_id IN (SELECT id FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'creditnotes WHERE clientid=' . $this->db->escape_str($customer_id) . ')
|
||||
)
|
||||
)
|
||||
)
|
||||
as beginning_balance FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices
|
||||
WHERE date < "' . $this->db->escape_str($from) . '"
|
||||
AND clientid = ' . $this->db->escape_str($customer_id) . '
|
||||
AND status != ' . Invoices_model::STATUS_DRAFT . '
|
||||
AND status != ' . Invoices_model::STATUS_CANCELLED)->row()->beginning_balance;
|
||||
if ($result['beginning_balance'] === null) {
|
||||
$result['beginning_balance'] = 0;
|
||||
}
|
||||
$dec = get_decimal_places();
|
||||
if (function_exists('bcsub')) {
|
||||
$result['balance_due'] = bcsub($result['invoiced_amount'], $result['amount_paid'], $dec);
|
||||
$result['balance_due'] = bcadd($result['balance_due'], $result['beginning_balance'], $dec);
|
||||
$result['balance_due'] = bcadd($result['balance_due'], $result['refunds_amount'], $dec);
|
||||
} else {
|
||||
$result['balance_due'] = number_format($result['invoiced_amount'] - $result['amount_paid'], $dec, '.', '');
|
||||
$result['balance_due'] = $result['balance_due'] + number_format($result['beginning_balance'], $dec, '.', '');
|
||||
$result['balance_due'] = $result['balance_due'] + number_format($result['refunds_amount'], $dec, '.', '');
|
||||
}
|
||||
// Subtract amount paid - refund, because the refund is not actually paid amount
|
||||
$result['amount_paid'] = $result['amount_paid'] - $result['refunds_amount'];
|
||||
$result['client_id'] = $customer_id;
|
||||
$result['client'] = $this->clients_model->get($customer_id, $playground);
|
||||
$result['from'] = $from;
|
||||
$result['to'] = $to;
|
||||
$customer_currency = $this->clients_model->get_customer_default_currency($customer_id, $playground);
|
||||
$this->load->model('currencies_model');
|
||||
if ($customer_currency != 0) {
|
||||
$currency = $this->currencies_model->get($customer_currency, $playground);
|
||||
} else {
|
||||
$currency = $this->currencies_model->get_base_currency($playground, $playground);
|
||||
}
|
||||
$result['currency'] = $currency;
|
||||
return hooks()->apply_filters('statement', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send customer statement to email
|
||||
* @param mixed $customer_id customer id
|
||||
* @param array $send_to array of contact emails to send
|
||||
* @param string $from date from
|
||||
* @param string $to date to
|
||||
* @param string $cc email CC
|
||||
* @return boolean
|
||||
*/
|
||||
public function send_statement_to_email($customer_id, $send_to, $from, $to, $cc = '', $playground = false) {
|
||||
$sent = false;
|
||||
if (is_array($send_to) && count($send_to) > 0) {
|
||||
$statement = $this->get_statement($customer_id, to_sql_date($from), to_sql_date($to), $playground);
|
||||
set_mailing_constant();
|
||||
$pdf = statement_pdf($statement);
|
||||
$pdf_file_name = slug_it(_l('customer_statement') . '-' . $statement['client']->company);
|
||||
$attach = $pdf->Output($pdf_file_name . '.pdf', 'S');
|
||||
$i = 0;
|
||||
$this->load->model('clients_model');
|
||||
foreach ($send_to as $contact_id) {
|
||||
if ($contact_id != '') {
|
||||
// Send cc only for the first contact
|
||||
if (!empty($cc) && $i > 0) {
|
||||
$cc = '';
|
||||
}
|
||||
$contact = $this->clients_model->get_contact($contact_id, $playground);
|
||||
$template = mail_template('customer_statement', $contact->email, $contact_id, $statement, $cc);
|
||||
$template->add_attachment(['attachment' => $attach, 'filename' => $pdf_file_name . '.pdf', 'type' => 'application/pdf', ]);
|
||||
if ($template->send()) {
|
||||
$sent = true;
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
if ($sent) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
186
api/models/Subscriptions_model.php
Normal file
186
api/models/Subscriptions_model.php
Normal file
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Subscriptions_model extends App_Model {
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->load->model('clients_model');
|
||||
}
|
||||
|
||||
public function get($where = [], $playground = false) {
|
||||
$this->select($playground);
|
||||
$this->join($playground);
|
||||
$this->db->where($where);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'subscriptions')->result_array();
|
||||
}
|
||||
|
||||
public function get_by_id($id, $where = [], $playground = false) {
|
||||
$this->select($playground);
|
||||
$this->join($playground);
|
||||
$this->db->where(db_prefix() . ($playground ? 'playground_' : '') . 'subscriptions.id', $id);
|
||||
$this->db->where($where);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'subscriptions')->row();
|
||||
}
|
||||
|
||||
public function get_by_hash($hash, $where = [], $playground = false) {
|
||||
$this->select($playground);
|
||||
$this->join($playground);
|
||||
$this->db->where('hash', $hash);
|
||||
$this->db->where($where);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'subscriptions')->row();
|
||||
}
|
||||
|
||||
public function get_child_invoices($id, $playground = false) {
|
||||
$this->db->select('id');
|
||||
$this->db->where('subscription_id', $id);
|
||||
$invoices = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'invoices')->result_array();
|
||||
$child = [];
|
||||
$this->load->model('invoices_model');
|
||||
foreach ($invoices as $invoice) {
|
||||
$child[] = $this->invoices_model->get($invoice['id'], $playground);
|
||||
}
|
||||
return $child;
|
||||
}
|
||||
|
||||
public function add($data, $playground = false) {
|
||||
$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() . ($playground ? 'playground_' : '') . 'subscriptions', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
|
||||
if ($insert_id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function create($data, $playground = false) {
|
||||
$data = $this->handleSelectedTax($data, $playground);
|
||||
$this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'subscriptions', array_merge($data, ['created' => date('Y-m-d H:i:s'), 'hash' => app_generate_hash(), 'created_from' => get_staff_user_id(), ]));
|
||||
return $this->db->insert_id();
|
||||
}
|
||||
|
||||
public function update($id = '', $data, $playground = false) {
|
||||
if ($id) {
|
||||
$data = $this->handleSelectedTax($data, $playground);
|
||||
$this->db->where(db_prefix() . ($playground ? 'playground_' : '') . 'subscriptions.id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'subscriptions', $data);
|
||||
return $this->db->affected_rows() > 0;
|
||||
} else {
|
||||
if (isset($data['id'])){
|
||||
$this->db->where('id', $data['id']);
|
||||
$event = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . '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() . ($playground ? 'playground_' : '') . 'subscriptions', $data);
|
||||
if ($this->db->affected_rows() > 0){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function select($playground = false) {
|
||||
$this->db->select(db_prefix() . ($playground ? 'playground_' : '') . 'subscriptions.id as id, stripe_tax_id, stripe_tax_id_2, terms, in_test_environment, date, next_billing_cycle, status, ' . db_prefix() . ($playground ? 'playground_' : '') . 'subscriptions.project_id as project_id, description, ' . db_prefix() . ($playground ? 'playground_' : '') . 'subscriptions.created_from as created_from, ' . db_prefix() . ($playground ? 'playground_' : '') . 'subscriptions.name as name, ' . db_prefix() . ($playground ? 'playground_' : '') . 'currencies.name as currency_name, ' . db_prefix() . ($playground ? 'playground_' : '') . 'currencies.symbol, currency, clientid, ends_at, date_subscribed, stripe_plan_id,stripe_subscription_id,quantity,hash,description_in_item,' . db_prefix() . ($playground ? 'playground_' : '') . 'taxes.name as tax_name, ' . db_prefix() . ($playground ? 'playground_' : '') . 'taxes.taxrate as tax_percent, ' . db_prefix() . ($playground ? 'playground_' : '') . 'taxes_2.name as tax_name_2, ' . db_prefix() . ($playground ? 'playground_' : '') . 'taxes_2.taxrate as tax_percent_2, tax_id, tax_id_2, stripe_id as stripe_customer_id,' . $this->clients_model->get_sql_select_client_company('company', $playground));
|
||||
}
|
||||
|
||||
private function join($playground = false) {
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'currencies', db_prefix() . ($playground ? 'playground_' : '') . 'currencies.id=' . db_prefix() . ($playground ? 'playground_' : '') . 'subscriptions.currency');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'taxes', '' . db_prefix() . ($playground ? 'playground_' : '') . 'taxes.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'subscriptions.tax_id', 'left');
|
||||
$this->db->join('' . db_prefix() . ($playground ? 'playground_' : '') . 'taxes as ' . db_prefix() . ($playground ? 'playground_' : '') . 'taxes_2', '' . db_prefix() . ($playground ? 'playground_' : '') . 'taxes_2.id = ' . db_prefix() . ($playground ? 'playground_' : '') . 'subscriptions.tax_id_2', 'left');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'clients', db_prefix() . ($playground ? 'playground_' : '') . 'clients.userid=' . db_prefix() . ($playground ? 'playground_' : '') . 'subscriptions.clientid');
|
||||
}
|
||||
|
||||
public function send_email_template($id, $cc = '', $template = 'subscription_send_to_customer', $playground = false) {
|
||||
$subscription = $this->get_by_id($id, [], $playground);
|
||||
$contact = $this->clients_model->get_contact($this->clients_model->get_primary_contact_user_id($subscription->clientid, $playground), ['active' => 1], [], $playground);
|
||||
if (!$contact) {
|
||||
return false;
|
||||
}
|
||||
$sent = send_mail_template($template, $subscription, $contact, $cc);
|
||||
if ($sent) {
|
||||
if ($template == 'subscription_send_to_customer') {
|
||||
$this->db->where(db_prefix() . ($playground ? 'playground_' : '') . 'subscriptions.id', $id);
|
||||
$this->db->update(db_prefix() . ($playground ? 'playground_' : '') . 'subscriptions', ['last_sent_at' => date('c') ]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function delete($id, $simpleDelete = false, $playground = false) {
|
||||
$subscription = $this->get_by_id($id, [], $playground);
|
||||
if ($subscription->in_test_environment === '0') {
|
||||
if (!empty($subscription->stripe_subscription_id) && $simpleDelete == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'subscriptions');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
$this->load->model('misc_model');
|
||||
$this->misc_model->delete_tracked_emails($id, 'subscription', $playground);
|
||||
$this->db->where('subscription_id');
|
||||
$this->db->update(($playground ? 'playground_' : '') . 'invoices', ['subscription_id' => 0]);
|
||||
return $subscription;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function handleSelectedTax($data, $playground = false) {
|
||||
$this->load->library('stripe_core');
|
||||
foreach (['stripe_tax_id', 'stripe_tax_id_2'] as $key) {
|
||||
$localKey = $key === 'stripe_tax_id' ? 'tax_id' : 'tax_id_2';
|
||||
if (isset($data[$key]) && !empty($data[$key])) {
|
||||
$stripe_tax = $this->stripe_core->retrieve_tax_rate($data[$key]);
|
||||
$displayName = $stripe_tax->display_name;
|
||||
// Region label when using Stripe Region Label field.
|
||||
$displayName.= !empty($stripe_tax->jurisdiction) ? ' - ' . $stripe_tax->jurisdiction : '';
|
||||
$this->db->where('name', $displayName);
|
||||
$this->db->where('taxrate', $percentage = number_format($stripe_tax->percentage, get_decimal_places()));
|
||||
$dbTax = $this->db->get(($playground ? 'playground_' : '') . 'taxes')->row();
|
||||
if (!$dbTax) {
|
||||
$this->db->insert(($playground ? 'playground_' : '') . 'taxes', ['name' => $displayName, 'taxrate' => $percentage, ]);
|
||||
$data[$localKey] = $this->db->insert_id();
|
||||
} else {
|
||||
$data[$localKey] = $dbTax->id;
|
||||
}
|
||||
} else if (isset($data[$key]) && !$data[$key]) {
|
||||
$data[$localKey] = 0;
|
||||
$data[$key] = null;
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
1844
api/models/Tasks_model.php
Normal file
1844
api/models/Tasks_model.php
Normal file
File diff suppressed because it is too large
Load Diff
101
api/models/Taxes_model.php
Normal file
101
api/models/Taxes_model.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Taxes_model extends App_Model {
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tax by id
|
||||
* @param mixed $id tax id
|
||||
* @return mixed if id passed return object else array
|
||||
*/
|
||||
public function get($id = '', $playground = false) {
|
||||
if (is_numeric($id)) {
|
||||
$this->db->where('id', $id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'taxes')->row();
|
||||
}
|
||||
$this->db->order_by('taxrate', 'ASC');
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'taxes')->result_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new tax
|
||||
* @param array $data tax data
|
||||
* @return boolean
|
||||
*/
|
||||
public function add($data, $playground = false) {
|
||||
unset($data['taxid']);
|
||||
$data['name'] = trim($data['name']);
|
||||
$data['taxrate'] = trim($data['taxrate']);
|
||||
$data = hooks()->apply_filters('before_tax_created', $data);
|
||||
$this->db->insert(($playground ? 'playground_' : '') . 'taxes', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
log_activity('New Tax Added [ID: ' . $insert_id . ', ' . $data['name'] . ']');
|
||||
hooks()->do_action('after_tax_created', ['id' => $insert_id, 'data' => $data, ]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit tax
|
||||
* @param array $data tax data
|
||||
* @return boolean
|
||||
*/
|
||||
public function edit($data, $playground = false) {
|
||||
if (total_rows(db_prefix() . ($playground ? 'playground_' : '') . 'expenses', ['tax' => $data['taxid'], ]) > 0) {
|
||||
return ['tax_is_using_expenses' => true, ];
|
||||
}
|
||||
$updated = false;
|
||||
$taxid = $data['taxid'];
|
||||
$original_tax = get_tax_by_id($taxid, $playground);
|
||||
unset($data['taxid']);
|
||||
$data['name'] = trim($data['name']);
|
||||
$data['taxrate'] = trim($data['taxrate']);
|
||||
$data = hooks()->apply_filters('before_update_tax', $data, $taxid);
|
||||
$this->db->where('id', $taxid);
|
||||
$this->db->update(($playground ? 'playground_' : '') . 'taxes', $data);
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
// Check if this task is used in settings
|
||||
$default_taxes = unserialize(get_option('default_tax'));
|
||||
$i = 0;
|
||||
foreach ($default_taxes as $tax) {
|
||||
$current_tax = $this->get($taxid, $playground);
|
||||
$tax_name = $original_tax->name . '|' . $original_tax->taxrate;
|
||||
if (strpos('x' . $tax, $tax_name) !== false) {
|
||||
$default_taxes[$i] = str_ireplace($tax_name, $current_tax->name . '|' . $current_tax->taxrate, $default_taxes[$i]);
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
update_option('default_tax', serialize($default_taxes));
|
||||
$updated = true;
|
||||
}
|
||||
hooks()->do_action('after_update_tax', ['id' => $taxid, 'data' => $data, 'updated' => & $updated, ]);
|
||||
if ($updated) {
|
||||
log_activity('Tax Updated [ID: ' . $taxid . ', ' . $data['name'] . ']');
|
||||
}
|
||||
return $updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete tax from database
|
||||
* @param mixed $id tax id
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete($id, $playground = false) {
|
||||
if (is_reference_in_table('tax', db_prefix() . ($playground ? 'playground_' : '') . 'items', $id) || is_reference_in_table('tax2', db_prefix() . ($playground ? 'playground_' : '') . 'items', $id) || is_reference_in_table('tax', db_prefix() . ($playground ? 'playground_' : '') . 'expenses', $id) || is_reference_in_table('tax2', db_prefix() . ($playground ? 'playground_' : '') . 'expenses', $id) || is_reference_in_table('tax_id', db_prefix() . ($playground ? 'playground_' : '') . 'subscriptions', $id) || is_reference_in_table('tax_id_2', db_prefix() . ($playground ? 'playground_' : '') . 'subscriptions', $id)) {
|
||||
return ['referenced' => true, ];
|
||||
}
|
||||
$this->db->where('id', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'taxes');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Tax Deleted [ID: ' . $id . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
1393
api/models/Tickets_model.php
Normal file
1393
api/models/Tickets_model.php
Normal file
File diff suppressed because it is too large
Load Diff
73
api/models/User_autologin.php
Normal file
73
api/models/User_autologin.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class User_Autologin extends App_Model {
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if autologin found
|
||||
* @param mixed $user_id clientid/staffid
|
||||
* @param string $key key from cookie to retrieve from database
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($user_id, $key, $playground = false) {
|
||||
// check if user is staff
|
||||
$this->db->where('user_id', $user_id);
|
||||
$this->db->where('key_id', $key);
|
||||
$user = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'user_auto_login')->row();
|
||||
if (!$user) {
|
||||
return null;
|
||||
}
|
||||
if ($user->staff == 1) {
|
||||
$table = db_prefix() . ($playground ? 'playground_' : '') . 'staff';
|
||||
$this->db->select($table . '.staffid as id');
|
||||
$_id = 'staffid';
|
||||
$staff = true;
|
||||
} else {
|
||||
$table = db_prefix() . ($playground ? 'playground_' : '') . 'contacts';
|
||||
$this->db->select($table . '.id as id');
|
||||
$_id = 'id';
|
||||
$staff = false;
|
||||
}
|
||||
$this->db->select($table . '.' . $_id);
|
||||
$this->db->from($table);
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'user_auto_login', db_prefix() . ($playground ? 'playground_' : '') . 'user_auto_login.user_id = ' . $table . '.' . $_id);
|
||||
$this->db->where(db_prefix() . ($playground ? 'playground_' : '') . 'user_auto_login.user_id', $user_id);
|
||||
$this->db->where(db_prefix() . ($playground ? 'playground_' : '') . 'user_auto_login.key_id', $key);
|
||||
$query = $this->db->get();
|
||||
if ($query) {
|
||||
if ($query->num_rows() == 1) {
|
||||
$user = $query->row();
|
||||
$user->staff = $staff;
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set new autologin if user have clicked remember me
|
||||
* @param mixed $user_id clientid/userid
|
||||
* @param string $key cookie key
|
||||
* @param integer $staff is staff or client
|
||||
*/
|
||||
public function set($user_id, $key, $staff, $playground = false) {
|
||||
return $this->db->insert(db_prefix() . ($playground ? 'playground_' : '') . 'user_auto_login', ['user_id' => $user_id, 'key_id' => $key, 'user_agent' => substr($this->input->user_agent(), 0, 149), 'last_ip' => $this->input->ip_address(), 'staff' => $staff, ]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete user autologin
|
||||
* @param mixed $user_id clientid/userid
|
||||
* @param string $key cookie key
|
||||
* @param integer $staff is staff or client
|
||||
*/
|
||||
public function delete($user_id, $key, $staff, $playground = false) {
|
||||
$this->db->where('user_id', $user_id);
|
||||
$this->db->where('key_id', $key);
|
||||
$this->db->where('staff', $staff);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'user_auto_login');
|
||||
}
|
||||
}
|
||||
440
api/models/Utilities_model.php
Normal file
440
api/models/Utilities_model.php
Normal file
@@ -0,0 +1,440 @@
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
class Utilities_model extends App_Model {
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new event
|
||||
* @param array $data event $_POST data
|
||||
*/
|
||||
public function event($data, $playground = false) {
|
||||
$data['userid'] = get_staff_user_id();
|
||||
$data['start'] = to_sql_date($data['start'], true);
|
||||
if ($data['end'] == '') {
|
||||
unset($data['end']);
|
||||
} else {
|
||||
$data['end'] = to_sql_date($data['end'], true);
|
||||
}
|
||||
if (isset($data['public'])) {
|
||||
$data['public'] = 1;
|
||||
} else {
|
||||
$data['public'] = 0;
|
||||
}
|
||||
$data['description'] = nl2br($data['description']);
|
||||
if (isset($data['eventid'])) {
|
||||
unset($data['userid']);
|
||||
$this->db->where('eventid', $data['eventid']);
|
||||
$event = $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . '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() . ($playground ? 'playground_' : '') . '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() . ($playground ? 'playground_' : '') . 'events', $data);
|
||||
$insert_id = $this->db->insert_id();
|
||||
if ($insert_id) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get event by passed id
|
||||
* @param mixed $id eventid
|
||||
* @return object
|
||||
*/
|
||||
public function get_event_by_id($id, $playground = false) {
|
||||
$this->db->where('eventid', $id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'events')->row();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all user events
|
||||
* @return array
|
||||
*/
|
||||
public function get_all_events($start, $end, $playground = false) {
|
||||
$is_staff_member = is_staff_member();
|
||||
$this->db->select('title,start,end,eventid,userid,color,public');
|
||||
// Check if is passed start and end date
|
||||
$this->db->where('(start BETWEEN "' . $start . '" AND "' . $end . '")');
|
||||
$this->db->where('userid', get_staff_user_id());
|
||||
if ($is_staff_member) {
|
||||
$this->db->or_where('public', 1);
|
||||
}
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'events')->result_array();
|
||||
}
|
||||
|
||||
public function get_event($id, $playground = false) {
|
||||
$this->db->where('eventid', $id);
|
||||
return $this->db->get(db_prefix() . ($playground ? 'playground_' : '') . 'events')->row();
|
||||
}
|
||||
|
||||
public function get_calendar_data($start, $end, $client_id = '', $contact_id = '', $filters = false, $playground = false) {
|
||||
$start = $this->db->escape_str($start);
|
||||
$end = $this->db->escape_str($end);
|
||||
$client_id = $this->db->escape_str($client_id);
|
||||
$contact_id = $this->db->escape_str($contact_id);
|
||||
$is_admin = is_admin();
|
||||
$has_permission_tasks_view = staff_can('view', 'tasks');
|
||||
$has_permission_projects_view = staff_can('view', 'projects');
|
||||
$has_permission_invoices = staff_can('view', 'invoices');
|
||||
$has_permission_invoices_own = staff_can('view_own', 'invoices');
|
||||
$has_permission_estimates = staff_can('view', 'estimates');
|
||||
$has_permission_estimates_own = staff_can('view_own', 'estimates');
|
||||
$has_permission_contracts = staff_can('view', 'contracts');
|
||||
$has_permission_contracts_own = staff_can('view_own', 'contracts');
|
||||
$has_permission_proposals = staff_can('view', 'proposals');
|
||||
$has_permission_proposals_own = staff_can('view_own', 'proposals');
|
||||
$data = [];
|
||||
$client_data = false;
|
||||
if (is_numeric($client_id) && is_numeric($contact_id)) {
|
||||
$client_data = true;
|
||||
$has_contact_permission_invoices = has_contact_permission('invoices', $contact_id);
|
||||
$has_contact_permission_estimates = has_contact_permission('estimates', $contact_id);
|
||||
$has_contact_permission_proposals = has_contact_permission('proposals', $contact_id);
|
||||
$has_contact_permission_contracts = has_contact_permission('contracts', $contact_id);
|
||||
$has_contact_permission_projects = has_contact_permission('projects', $contact_id);
|
||||
}
|
||||
$hook = ['client_data' => $client_data, ];
|
||||
if ($client_data == true) {
|
||||
$hook['client_id'] = $client_id;
|
||||
$hook['contact_id'] = $contact_id;
|
||||
}
|
||||
$data = hooks()->apply_filters('before_fetch_events', $data, $hook);
|
||||
$ff = false;
|
||||
if ($filters) {
|
||||
// excluded calendar_filters from post
|
||||
$ff = (count($filters) > 1 && isset($filters['calendar_filters']) ? true : false);
|
||||
}
|
||||
if (get_option('show_invoices_on_calendar') == 1 && !$ff || $ff && array_key_exists('invoices', $filters)) {
|
||||
$noPermissionsQuery = get_invoices_where_sql_for_staff(get_staff_user_id());
|
||||
$this->load->model('clients_model');
|
||||
$this->db->select('duedate as date,number,id,clientid,hash,' . $this->clients_model->get_sql_select_client_company('company', $playground));
|
||||
$this->db->from(db_prefix() . ($playground ? 'playground_' : '') . 'invoices');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'clients', db_prefix() . ($playground ? 'playground_' : '') . 'clients.userid=' . db_prefix() . ($playground ? 'playground_' : '') . 'invoices.clientid', 'left');
|
||||
$this->db->where_not_in('status', [2, 5, ]);
|
||||
$this->db->where('(duedate BETWEEN "' . $start . '" AND "' . $end . '")');
|
||||
if ($client_data) {
|
||||
$this->db->where('clientid', $client_id);
|
||||
if (get_option('exclude_invoice_from_client_area_with_draft_status') == 1) {
|
||||
$this->db->where('status !=', 6);
|
||||
}
|
||||
} else {
|
||||
if (!$has_permission_invoices) {
|
||||
$this->db->where($noPermissionsQuery);
|
||||
}
|
||||
}
|
||||
$invoices = $this->db->get()->result_array();
|
||||
foreach ($invoices as $invoice) {
|
||||
if (($client_data && !$has_contact_permission_invoices) || (!$client_data && !user_can_view_invoice($invoice['id']))) {
|
||||
continue;
|
||||
}
|
||||
$rel_showcase = '';
|
||||
/**
|
||||
* Show company name on calendar tooltip for admins
|
||||
*/
|
||||
if (!$client_data) {
|
||||
$rel_showcase = ' (' . $invoice['company'] . ')';
|
||||
}
|
||||
$number = format_invoice_number($invoice['id']);
|
||||
$invoice['_tooltip'] = _l('calendar_invoice') . ' - ' . $number . $rel_showcase;
|
||||
$invoice['title'] = $number;
|
||||
$invoice['color'] = get_option('calendar_invoice_color');
|
||||
if (!$client_data) {
|
||||
$invoice['url'] = admin_url('invoices/list_invoices/' . $invoice['id']);
|
||||
} else {
|
||||
$invoice['url'] = site_url('invoice/' . $invoice['id'] . '/' . $invoice['hash']);
|
||||
}
|
||||
array_push($data, $invoice);
|
||||
}
|
||||
}
|
||||
if (get_option('show_estimates_on_calendar') == 1 && !$ff || $ff && array_key_exists('estimates', $filters)) {
|
||||
$noPermissionsQuery = get_estimates_where_sql_for_staff(get_staff_user_id());
|
||||
$this->load->model('clients_model');
|
||||
$this->db->select('number,id,clientid,hash,CASE WHEN expirydate IS NULL THEN date ELSE expirydate END as date,' . $this->clients_model->get_sql_select_client_company('company', $playground), false);
|
||||
$this->db->from(db_prefix() . ($playground ? 'playground_' : '') . 'estimates');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'clients', db_prefix() . ($playground ? 'playground_' : '') . 'clients.userid=' . db_prefix() . ($playground ? 'playground_' : '') . 'estimates.clientid', 'left');
|
||||
$this->db->where('status !=', 3, false);
|
||||
$this->db->where('status !=', 4, false);
|
||||
// $this->db->where('expirydate IS NOT NULL');
|
||||
$this->db->where("CASE WHEN expirydate IS NULL THEN (date BETWEEN '$start' AND '$end') ELSE (expirydate BETWEEN '$start' AND '$end') END", null, false);
|
||||
if ($client_data) {
|
||||
$this->db->where('clientid', $client_id, false);
|
||||
if (get_option('exclude_estimate_from_client_area_with_draft_status') == 1) {
|
||||
$this->db->where('status !=', 1, false);
|
||||
}
|
||||
} else {
|
||||
if (!$has_permission_estimates) {
|
||||
$this->db->where($noPermissionsQuery);
|
||||
}
|
||||
}
|
||||
$estimates = $this->db->get()->result_array();
|
||||
foreach ($estimates as $estimate) {
|
||||
if (($client_data && !$has_contact_permission_estimates) || (!$client_data && !user_can_view_estimate($estimate['id']))) {
|
||||
continue;
|
||||
}
|
||||
$rel_showcase = '';
|
||||
if (!$client_data) {
|
||||
$rel_showcase = ' (' . $estimate['company'] . ')';
|
||||
}
|
||||
$number = format_estimate_number($estimate['id']);
|
||||
$estimate['_tooltip'] = _l('calendar_estimate') . ' - ' . $number . $rel_showcase;
|
||||
$estimate['title'] = $number;
|
||||
$estimate['color'] = get_option('calendar_estimate_color');
|
||||
if (!$client_data) {
|
||||
$estimate['url'] = admin_url('estimates/list_estimates/' . $estimate['id']);
|
||||
} else {
|
||||
$estimate['url'] = site_url('estimate/' . $estimate['id'] . '/' . $estimate['hash']);
|
||||
}
|
||||
array_push($data, $estimate);
|
||||
}
|
||||
}
|
||||
if (get_option('show_proposals_on_calendar') == 1 && !$ff || $ff && array_key_exists('proposals', $filters)) {
|
||||
$noPermissionsQuery = get_proposals_sql_where_staff(get_staff_user_id());
|
||||
$this->db->select('subject,id,hash,CASE WHEN open_till IS NULL THEN date ELSE open_till END as date', false);
|
||||
$this->db->from(db_prefix() . ($playground ? 'playground_' : '') . 'proposals');
|
||||
$this->db->where('status !=', 2, false);
|
||||
$this->db->where('status !=', 3, false);
|
||||
$this->db->where("CASE WHEN open_till IS NULL THEN (date BETWEEN '$start' AND '$end') ELSE (open_till BETWEEN '$start' AND '$end') END", null, false);
|
||||
if ($client_data) {
|
||||
$this->db->where('rel_type', 'customer');
|
||||
$this->db->where('rel_id', $client_id, false);
|
||||
if (get_option('exclude_proposal_from_client_area_with_draft_status')) {
|
||||
$this->db->where('status !=', 6, false);
|
||||
}
|
||||
} else {
|
||||
if (!$has_permission_proposals) {
|
||||
$this->db->where($noPermissionsQuery);
|
||||
}
|
||||
}
|
||||
$proposals = $this->db->get()->result_array();
|
||||
foreach ($proposals as $proposal) {
|
||||
if (($client_data && !$has_contact_permission_proposals) || (!$client_data && !user_can_view_proposal($proposal['id']))) {
|
||||
continue;
|
||||
}
|
||||
$proposal['_tooltip'] = _l('proposal');
|
||||
$proposal['title'] = $proposal['subject'];
|
||||
$proposal['color'] = get_option('calendar_proposal_color');
|
||||
if (!$client_data) {
|
||||
$proposal['url'] = admin_url('proposals/list_proposals/' . $proposal['id']);
|
||||
} else {
|
||||
$proposal['url'] = site_url('proposal/' . $proposal['id'] . '/' . $proposal['hash']);
|
||||
}
|
||||
array_push($data, $proposal);
|
||||
}
|
||||
}
|
||||
if (get_option('show_tasks_on_calendar') == 1 && !$ff || $ff && array_key_exists('tasks', $filters)) {
|
||||
if ($client_data && !$has_contact_permission_projects) {
|
||||
} else {
|
||||
$this->db->select(db_prefix() . ($playground ? 'playground_' : '') . 'tasks.name as title,id,' . tasks_rel_name_select_query() . ' as rel_name,rel_id,status,milestone,CASE WHEN duedate IS NULL THEN startdate ELSE duedate END as date', false);
|
||||
$this->db->from(db_prefix() . ($playground ? 'playground_' : '') . 'tasks');
|
||||
$this->db->where('status !=', 5);
|
||||
$this->db->where("CASE WHEN duedate IS NULL THEN (startdate BETWEEN '$start' AND '$end') ELSE (duedate BETWEEN '$start' AND '$end') END", null, false);
|
||||
if ($client_data) {
|
||||
$this->db->where('rel_type', 'project');
|
||||
$this->db->where('rel_id IN (SELECT id FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'projects WHERE clientid=' . $client_id . ')');
|
||||
$this->db->where('rel_id IN (SELECT project_id FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'project_settings WHERE name="view_tasks" AND value=1)');
|
||||
$this->db->where('visible_to_client', 1);
|
||||
}
|
||||
if ((!$has_permission_tasks_view || get_option('calendar_only_assigned_tasks') == '1') && !$client_data) {
|
||||
$this->db->where('(id IN (SELECT taskid FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'task_assigned WHERE staffid = ' . get_staff_user_id() . '))');
|
||||
}
|
||||
$tasks = $this->db->get()->result_array();
|
||||
foreach ($tasks as $task) {
|
||||
$rel_showcase = '';
|
||||
if (!empty($task['rel_id']) && !$client_data) {
|
||||
$rel_showcase = ' (' . $task['rel_name'] . ')';
|
||||
}
|
||||
$task['date'] = $task['date'];
|
||||
$name = mb_substr($task['title'], 0, 60) . '...';
|
||||
$task['_tooltip'] = _l('calendar_task') . ' - ' . $name . $rel_showcase;
|
||||
$task['title'] = $name;
|
||||
$status = get_task_status_by_id($task['status']);
|
||||
$task['color'] = $status['color'];
|
||||
if (!$client_data) {
|
||||
$task['onclick'] = 'init_task_modal(' . $task['id'] . '); return false';
|
||||
$task['url'] = '#';
|
||||
} else {
|
||||
$task['url'] = site_url('clients/project/' . $task['rel_id'] . '?group=project_tasks&taskid=' . $task['id']);
|
||||
}
|
||||
$task['className'] = $task['milestone'] ? ['milestone-' . $task['milestone']] : '';
|
||||
array_push($data, $task);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$client_data) {
|
||||
$available_reminders = $this->app->get_available_reminders_keys();
|
||||
$hideNotifiedReminders = get_option('hide_notified_reminders_from_calendar');
|
||||
foreach ($available_reminders as $key) {
|
||||
if (get_option('show_' . $key . '_reminders_on_calendar') == 1 && !$ff || $ff && array_key_exists($key . '_reminders', $filters)) {
|
||||
$this->db->select('date,description,firstname,lastname,creator,staff,rel_id')->from(db_prefix() . ($playground ? 'playground_' : '') . 'reminders')->where('(date BETWEEN "' . $start . '" AND "' . $end . '")')->where('rel_type', $key)->join(db_prefix() . ($playground ? 'playground_' : '') . 'staff', db_prefix() . ($playground ? 'playground_' : '') . 'staff.staffid = ' . db_prefix() . ($playground ? 'playground_' : '') . 'reminders.staff');
|
||||
if ($hideNotifiedReminders == '1') {
|
||||
$this->db->where('isnotified', 0);
|
||||
}
|
||||
$reminders = $this->db->get()->result_array();
|
||||
foreach ($reminders as $reminder) {
|
||||
if ((get_staff_user_id() == $reminder['creator'] || get_staff_user_id() == $reminder['staff']) || $is_admin) {
|
||||
$_reminder['title'] = '';
|
||||
if (get_staff_user_id() != $reminder['staff']) {
|
||||
$_reminder['title'].= '(' . $reminder['firstname'] . ' ' . $reminder['lastname'] . ') ';
|
||||
}
|
||||
$name = mb_substr($reminder['description'], 0, 60) . '...';
|
||||
$_reminder['_tooltip'] = _l('calendar_' . $key . '_reminder') . ' - ' . $name;
|
||||
$_reminder['title'].= $name;
|
||||
$_reminder['date'] = $reminder['date'];
|
||||
$_reminder['color'] = get_option('calendar_reminder_color');
|
||||
if ($key == 'customer') {
|
||||
$url = admin_url('clients/client/' . $reminder['rel_id']);
|
||||
} else if ($key == 'invoice') {
|
||||
$url = admin_url('invoices/list_invoices/' . $reminder['rel_id']);
|
||||
} else if ($key == 'estimate') {
|
||||
$url = admin_url('estimates/list_estimates/' . $reminder['rel_id']);
|
||||
} else if ($key == 'lead') {
|
||||
$url = '#';
|
||||
$_reminder['onclick'] = 'init_lead(' . $reminder['rel_id'] . '); return false;';
|
||||
} else if ($key == 'proposal') {
|
||||
$url = admin_url('proposals/list_proposals/' . $reminder['rel_id']);
|
||||
} else if ($key == 'expense') {
|
||||
$url = admin_url('expenses/list_expenses/' . $reminder['rel_id']);
|
||||
} else if ($key == 'credit_note') {
|
||||
$url = admin_url('credit_notes/list_credit_notes/' . $reminder['rel_id']);
|
||||
} else if ($key == 'ticket') {
|
||||
$url = admin_url('tickets/ticket/' . $reminder['rel_id']);
|
||||
} else if ($key == 'task') {
|
||||
$url = '#';
|
||||
$_reminder['onclick'] = 'init_task_modal(' . $reminder['rel_id'] . '); return false;';
|
||||
}
|
||||
$_reminder['url'] = $url;
|
||||
array_push($data, $_reminder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (get_option('show_contracts_on_calendar') == 1 && !$ff || $ff && array_key_exists('contracts', $filters)) {
|
||||
$this->load->model('clients_model');
|
||||
$this->db->select('hash, subject as title, dateend, datestart, id, client, content, ' . $this->clients_model->get_sql_select_client_company('company', $playground));
|
||||
$this->db->from(db_prefix() . ($playground ? 'playground_' : '') . 'contracts');
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'clients', db_prefix() . ($playground ? 'playground_' : '') . 'clients.userid=' . db_prefix() . ($playground ? 'playground_' : '') . 'contracts.client');
|
||||
$this->db->where('trash', 0);
|
||||
if ($client_data) {
|
||||
$this->db->where('client', $client_id);
|
||||
$this->db->where('not_visible_to_client', 0);
|
||||
} else {
|
||||
if (!$has_permission_contracts) {
|
||||
$this->db->where(db_prefix() . ($playground ? 'playground_' : '') . 'contracts.addedfrom', get_staff_user_id());
|
||||
}
|
||||
}
|
||||
$this->db->where('(dateend > "' . date('Y-m-d') . '" AND dateend IS NOT NULL AND dateend BETWEEN "' . $start . '" AND "' . $end . '" OR datestart >"' . date('Y-m-d') . '")');
|
||||
$contracts = $this->db->get()->result_array();
|
||||
foreach ($contracts as $contract) {
|
||||
if (!$has_permission_contracts && !$has_permission_contracts_own && !$client_data) {
|
||||
continue;
|
||||
} else if ($client_data && !$has_contact_permission_contracts) {
|
||||
continue;
|
||||
}
|
||||
$rel_showcase = '';
|
||||
if (!$client_data) {
|
||||
$rel_showcase = ' (' . $contract['company'] . ')';
|
||||
}
|
||||
$name = $contract['title'];
|
||||
$_contract['title'] = $name;
|
||||
$_contract['color'] = get_option('calendar_contract_color');
|
||||
$_contract['_tooltip'] = _l('calendar_contract') . ' - ' . $name . $rel_showcase;
|
||||
if (!$client_data) {
|
||||
$_contract['url'] = admin_url('contracts/contract/' . $contract['id']);
|
||||
} else {
|
||||
$_contract['url'] = site_url('contract/' . $contract['id'] . '/' . $contract['hash']);
|
||||
}
|
||||
if (!empty($contract['dateend'])) {
|
||||
$_contract['date'] = $contract['dateend'];
|
||||
} else {
|
||||
$_contract['date'] = $contract['datestart'];
|
||||
}
|
||||
array_push($data, $_contract);
|
||||
}
|
||||
}
|
||||
// calendar_project
|
||||
if (get_option('show_projects_on_calendar') == 1 && !$ff || $ff && array_key_exists('projects', $filters)) {
|
||||
$this->load->model('clients_model');
|
||||
$this->db->select('name as title,id,clientid, CASE WHEN deadline IS NULL THEN start_date ELSE deadline END as date,' . $this->clients_model->get_sql_select_client_company('company', $playground), false);
|
||||
$this->db->from(db_prefix() . ($playground ? 'playground_' : '') . 'projects');
|
||||
// Exclude cancelled and finished
|
||||
$this->db->where('status !=', 4);
|
||||
$this->db->where('status !=', 5);
|
||||
$this->db->where("CASE WHEN deadline IS NULL THEN (start_date BETWEEN '$start' AND '$end') ELSE (deadline BETWEEN '$start' AND '$end') END", null, false);
|
||||
$this->db->join(db_prefix() . ($playground ? 'playground_' : '') . 'clients', db_prefix() . ($playground ? 'playground_' : '') . 'clients.userid=' . db_prefix() . ($playground ? 'playground_' : '') . 'projects.clientid');
|
||||
if (!$client_data && !$has_permission_projects_view) {
|
||||
$this->db->where('id IN (SELECT project_id FROM ' . db_prefix() . ($playground ? 'playground_' : '') . 'project_members WHERE staff_id=' . get_staff_user_id() . ')');
|
||||
} else if ($client_data) {
|
||||
$this->db->where('clientid', $client_id);
|
||||
}
|
||||
$projects = $this->db->get()->result_array();
|
||||
foreach ($projects as $project) {
|
||||
$rel_showcase = '';
|
||||
if (!$client_data) {
|
||||
$rel_showcase = ' (' . $project['company'] . ')';
|
||||
} else {
|
||||
if (!$has_contact_permission_projects) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$name = $project['title'];
|
||||
$_project['title'] = $name;
|
||||
$_project['color'] = get_option('calendar_project_color');
|
||||
$_project['_tooltip'] = _l('calendar_project') . ' - ' . $name . $rel_showcase;
|
||||
if (!$client_data) {
|
||||
$_project['url'] = admin_url('projects/view/' . $project['id']);
|
||||
} else {
|
||||
$_project['url'] = site_url('clients/project/' . $project['id']);
|
||||
}
|
||||
$_project['date'] = $project['date'];
|
||||
array_push($data, $_project);
|
||||
}
|
||||
}
|
||||
if (!$client_data && !$ff || (!$client_data && $ff && array_key_exists('events', $filters))) {
|
||||
$events = $this->get_all_events($start, $end, $playground);
|
||||
foreach ($events as $event) {
|
||||
if ($event['userid'] != get_staff_user_id() && !$is_admin) {
|
||||
$event['is_not_creator'] = true;
|
||||
$event['onclick'] = true;
|
||||
}
|
||||
$event['_tooltip'] = _l('calendar_event') . ' - ' . $event['title'];
|
||||
$event['color'] = $event['color'];
|
||||
array_push($data, $event);
|
||||
}
|
||||
}
|
||||
return hooks()->apply_filters('calendar_data', $data, ['start' => $start, 'end' => $end, 'client_id' => $client_id, 'contact_id' => $contact_id, ]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete user event
|
||||
* @param mixed $id event id
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete_event($id, $playground = false) {
|
||||
$this->db->where('eventid', $id);
|
||||
$this->db->delete(db_prefix() . ($playground ? 'playground_' : '') . 'events');
|
||||
if ($this->db->affected_rows() > 0) {
|
||||
log_activity('Event Deleted [' . $id . ']');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user