$columns['quote_type'] = array('title' => 'Type', 'callback' => function ($quote) { echo htmlspecialchars($quote['type']); }); $columns['quote_status'] = array('title' => 'Status', 'callback' => function ($quote) { echo htmlspecialchars($quote['status']); }); if (module_config::c('quote_allow_staff_assignment', 1)) { $columns['quote_staff'] = array('title' => 'Staff Member', 'callback' => function ($quote) { echo module_user::link_open($quote['user_id'], true); }); } if (module_job::can_i('view', 'Jobs')) { $job_ids = array(); $columns['job'] = array('title' => 'Job', 'callback' => function ($quote) use(&$job_ids) { $job_ids = array(); foreach (module_job::get_jobs(array('quote_id' => $quote['quote_id'])) as $job) { $job = module_job::get_job($job['job_id']); if (!$job) { continue; } echo module_job::link_open($job['job_id'], true); $job_ids[] = $job['job_id']; echo " "; echo '<span class="'; if ($job['total_amount_due'] > 0) { echo 'error_text'; } else { echo 'success_text'; } echo '">'; if ($job['total_amount'] > 0) {
public function get_data() { if (count($this->_get_data_cache)) { return $this->_get_data_cache; } $file = false; if ($this->file_id > 0) { $file = get_single("file", "file_id", $this->file_id); } // check user has permissions to view this file. // for now we just base this on the customer id check if ($file) { // staff listing $staff = get_multiple('file_user_rel', array('file_id' => $file['file_id']), 'user_id'); $file['staff_ids'] = array_keys($staff); $file['type'] = isset($file['file_url']) && $file['file_url'] ? 'remote' : (isset($file['bucket']) && $file['bucket'] ? 'bucket' : 'upload'); if ($this->do_permissions) { switch (module_file::get_file_data_access()) { case _FILE_ACCESS_ALL: // all files, no limits on SQL here break; case _FILE_ACCESS_JOBS: $jobs = module_job::get_jobs(array(), array('columns' => 'u.job_id AS id')); if (!$file['job_id'] || !isset($jobs[$file['job_id']])) { $file = false; } break; case _FILE_ACCESS_ME: if ($file['create_user_id'] != module_security::get_loggedin_id()) { $file = false; } break; case _FILE_ACCESS_ASSIGNED: if (!in_array(module_security::get_loggedin_id(), $file['staff_ids'])) { $file = false; } break; case _FILE_ACCESS_CUSTOMERS: default: if (class_exists('module_customer', false)) { //added for compat in newsletter system that doesn't have customer module $customer_permission_check = module_customer::get_customer($file['customer_id']); if ($customer_permission_check['customer_id'] != $file['customer_id']) { $file = false; } } } // file data access switch } } if (!$file) { $file = array('new' => true, 'type' => 'upload', 'file_id' => 0, 'customer_id' => isset($_REQUEST['customer_id']) ? $_REQUEST['customer_id'] : 0, 'job_id' => isset($_REQUEST['job_id']) ? $_REQUEST['job_id'] : 0, 'quote_id' => isset($_REQUEST['quote_id']) ? $_REQUEST['quote_id'] : 0, 'description' => '', 'status' => module_config::c('file_default_status', 'Uploaded'), 'file_name' => '', 'file_url' => '', 'staff_ids' => array(), 'bucket' => 0, 'bucket_parent_file_id' => 0, 'approved_time' => 0); } $this->_get_data_cache = $file; return $file; }
<?php } ?> </tbody> </table> </div> <?php $fieldset_data['elements_before'] = ob_get_clean(); } echo module_form::generate_fieldset($fieldset_data); } } // show the jobs linked to this website. if (module_job::is_plugin_enabled() && module_job::can_i('view', 'Jobs')) { $jobs = module_job::get_jobs(array('website_id' => $website_id)); if (count($jobs) || module_job::can_i('create', 'Jobs')) { $h = array('type' => 'h3', 'title' => module_config::c('project_name_single', 'Website') . ' Jobs'); if (module_job::can_i('create', 'Jobs')) { $h['button'] = array('title' => 'New Job', 'url' => module_job::link_generate('new', array('arguments' => array('website_id' => $website_id)))); } $fieldset_data = array('heading' => $h); if (count($jobs)) { $c = 0; ob_start(); ?> <div class="content_box_wheader"> <table border="0" cellspacing="0" cellpadding="2" class="tableclass tableclass_rows tableclass_full"> <thead>
public static function get_invoice($invoice_id, $basic = false, $skip_permissions = false) { $invoice = array(); $invoice_id = (int) $invoice_id; if ((int) $invoice_id > 0) { // we check the cache to see if the 'full' copy of this invoice exists anywhere yet. // if it does $cache_key = self::_invoice_cache_key($invoice_id, array($invoice_id, $basic, $skip_permissions, isset($_REQUEST['customer_id']) ? $_REQUEST['customer_id'] : 0, isset($_REQUEST['job_id']) ? $_REQUEST['job_id'] : 0)); if ($cached_item = module_cache::get('invoice', $cache_key)) { return $cached_item; } $cache_key_full = self::_invoice_cache_key($invoice_id, array($invoice_id, false, $skip_permissions, isset($_REQUEST['customer_id']) ? $_REQUEST['customer_id'] : 0, isset($_REQUEST['job_id']) ? $_REQUEST['job_id'] : 0)); if ($cache_key_full != $cache_key && ($cached_item = module_cache::get('invoice', $cache_key_full))) { return $cached_item; } $cache_timeout = module_config::c('cache_objects', 60); if ($basic === 2) { // used in links. just want the invoice name really. // todo - cache. meh return get_single('invoice', 'invoice_id', $invoice_id); } else { $sql = "SELECT i.*"; $sql .= ", c.primary_user_id "; // AS user_id // DONE - change this to the invoice table. drop down to select invoice contact. auto select based on contacts role? $sql .= ", c.customer_name AS customer_name "; $sql .= ", GROUP_CONCAT(DISTINCT j.`website_id` SEPARATOR ',') AS website_ids"; // the website id(s) $sql .= ", GROUP_CONCAT(DISTINCT j.`job_id` SEPARATOR ',') AS job_ids"; // the job id(s) $sql .= ", j.customer_id AS new_customer_id "; $sql .= " FROM `" . _DB_PREFIX . "invoice` i "; $sql .= " LEFT JOIN `" . _DB_PREFIX . "invoice_item` ii USING (invoice_id) "; $sql .= " LEFT JOIN `" . _DB_PREFIX . "task` t ON ii.task_id = t.task_id"; $sql .= " LEFT JOIN `" . _DB_PREFIX . "job` j ON t.job_id = j.job_id"; $sql .= " LEFT JOIN `" . _DB_PREFIX . "customer` c ON i.customer_id = c.customer_id "; //$sql .= " LEFT JOIN `"._DB_PREFIX."user` u ON c.primary_user_id = u.user_id "; $sql .= " WHERE i.invoice_id = " . (int) $invoice_id; $sql .= " GROUP BY i.invoice_id"; $invoice = qa1($sql); if (isset($invoice['website_id']) && $invoice['website_id']) { $website_ids = explode(',', $invoice['website_ids']); if (!in_array($invoice['website_id'], $website_ids)) { $website_ids[] = $invoice['website_id']; $invoice['website_ids'] = implode(',', $website_ids); } } } if (isset($invoice['job_ids']) && strlen(trim($invoice['job_ids'])) > 0) { $invoice['job_ids'] = explode(',', $invoice['job_ids']); } else { $invoice['job_ids'] = array(); } // check permissions if ($invoice && isset($invoice['invoice_id']) && $invoice['invoice_id'] == $invoice_id) { switch (self::get_invoice_access_permissions()) { case _INVOICE_ACCESS_ALL: break; case _INVOICE_ACCESS_STAFF: if ($invoice['vendor_user_id'] != module_security::get_loggedin_id()) { if ($skip_permissions) { $invoice['_no_access'] = true; // set a flag for custom processing. we check for this when calling get_customer with the skip permissions argument. (eg: in the ticket file listing link) } else { $invoice = false; } } break; case _INVOICE_ACCESS_JOB: // only invoices from jobs! $has_invoice_access = false; $jobs = module_job::get_jobs(); foreach ($invoice['job_ids'] as $invoice_job_id) { if (isset($jobs[$invoice_job_id])) { $has_invoice_access = true; } } unset($jobs); if (!$has_invoice_access) { if ($skip_permissions) { $invoice['_no_access'] = true; // set a flag for custom processing. we check for this when calling get_customer with the skip permissions argument. (eg: in the ticket file listing link) } else { $invoice = false; } } break; case _INVOICE_ACCESS_CUSTOMER: // tie in with customer permissions to only get invoices from customers we can access. $customers = module_customer::get_customers(); $has_invoice_access = false; if (isset($customers[$invoice['customer_id']])) { $has_invoice_access = true; } unset($customers); /*foreach($customers as $customer){ // todo, if($invoice['customer_id'] == 0) // ignore this permission if($customer['customer_id']==$invoice['customer_id']){ $has_invoice_access = true; break; } }*/ if (!$has_invoice_access) { if ($skip_permissions) { $invoice['_no_access'] = true; // set a flag for custom processing. we check for this when calling get_customer with the skip permissions argument. (eg: in the ticket file listing link) } else { $invoice = false; } } break; } // print_r($invoice);exit; if (!$invoice) { return array(); } $original_invoice = $invoice; $invoice['taxes'] = get_multiple('invoice_tax', array('invoice_id' => $invoice_id), 'invoice_tax_id', 'exact', 'order'); // set the job id of the first job just for kicks if (isset($invoice['deposit_job_id']) && (int) $invoice['deposit_job_id'] > 0) { $invoice['job_ids'][] = $invoice['deposit_job_id']; } if (isset($invoice['website_ids'])) { $invoice['website_ids'] = explode(',', $invoice['website_ids']); } else { $invoice['website_ids'] = array(); } // incase teh customer id on this invoice changes: if (isset($invoice['new_customer_id']) && $invoice['new_customer_id'] > 0 && $invoice['new_customer_id'] != $invoice['customer_id']) { $invoice['customer_id'] = $invoice['new_customer_id']; update_insert('invoice_id', $invoice_id, 'invoice', array('customer_id' => $invoice['new_customer_id'])); } if ($invoice['customer_id'] > 0) { $customer_data = module_customer::get_customer($invoice['customer_id']); if ($customer_data && class_exists('module_company', false) && isset($invoice['company_id']) && !$invoice['company_id'] && isset($customer_data['company_ids']) && count($customer_data['company_ids']) == 1) { // check if this customer has a company. $invoice['company_id'] = key($customer_data['company_ids']); } } if ($basic === true) { module_cache::put('invoice', $cache_key, $invoice, $cache_timeout); return $invoice; } } } // not sure why this code was here, commenting it out for now until we need it. /*if(isset($invoice['customer_id']) && isset($invoice['job_id']) && $invoice['customer_id'] <= 0 && $invoice['job_id'] > 0){ $job_data = module_job::get_job($invoice['job_id'],false); $invoice['customer_id'] = $job_data['customer_id']; }*/ if (!$invoice || !is_array($invoice) || !isset($invoice['invoice_id']) || !$invoice['invoice_id']) { $customer_id = isset($_REQUEST['customer_id']) ? $_REQUEST['customer_id'] : 0; $job_id = isset($_REQUEST['job_id']) ? $_REQUEST['job_id'] : 0; $currency_id = module_config::c('default_currency_id', 1); if ($customer_id > 0) { // find a default website to use ? } else { if ($job_id > 0) { // only a job, no customer. set the customer id. $job_data = module_job::get_job($job_id, false); $customer_id = $job_data['customer_id']; $currency_id = $job_data['currency_id']; } } // work out an invoice number $invoice_number = self::new_invoice_number($customer_id); $invoice = array('invoice_id' => 'new', 'customer_id' => $customer_id, 'job_id' => $job_id, 'job_ids' => $job_id > 0 ? array($job_id) : array(), 'currency_id' => $currency_id, 'name' => $invoice_number, 'cached_total' => 0, 'discount_description' => $job_id > 0 && isset($job_data['discount_description']) ? $job_data['discount_description'] : _l('Discount:'), 'discount_amount' => $job_id > 0 && isset($job_data['discount_amount']) ? $job_data['discount_amount'] : 0, 'discount_type' => $job_id > 0 && isset($job_data['discount_type']) ? $job_data['discount_type'] : module_config::c('invoice_discount_type', _DISCOUNT_TYPE_BEFORE_TAX), 'tax_type' => module_config::c('invoice_tax_type', 0), 'date_create' => date('Y-m-d'), 'date_sent' => '', 'date_due' => date('Y-m-d', strtotime('+' . module_config::c('invoice_due_days', 30) . ' days')), 'date_paid' => '', 'hourly_rate' => module_config::c('hourly_rate', 60), 'status' => module_config::s('invoice_status_default', 'New'), 'user_id' => '', 'date_renew' => '', 'renew_invoice_id' => '', 'deposit_job_id' => 0, 'date_cancel' => '0000-00-00', 'total_amount_deposits' => 0, 'total_amount_deposits_tax' => 0, 'default_task_type' => module_config::c('default_task_type', _TASK_TYPE_HOURS_AMOUNT), 'overdue_email_auto' => module_config::c('overdue_email_auto', 0), 'renew_auto' => 0, 'renew_email' => 0, 'overdue' => false, 'invoice_template_print' => '', 'website_id' => '0', 'website_ids' => ''); $invoice['total_tax_rate'] = module_config::c('tax_percent', 10); $invoice['total_tax_name'] = module_config::c('tax_name', 'TAX'); $customer_data = false; if ($customer_id > 0) { $customer_data = module_customer::get_customer($customer_id); } if ($customer_data && $customer_data['customer_id'] && $customer_data['customer_id'] == $customer_id) { // is there a default invoice template for this customer? if (class_exists('module_extra', false)) { $extras = module_extra::get_extras(array('owner_table' => 'customer', 'owner_id' => $customer_id)); foreach ($extras as $e) { if ($e['extra_key'] == 'invoice_template_print') { $invoice['invoice_template_print'] = $e['extra']; } } } if ($customer_data['primary_user_id']) { $invoice['primary_user_id'] = $customer_data['primary_user_id']; } if (isset($customer_data['default_tax']) && $customer_data['default_tax'] >= 0) { $invoice['total_tax_rate'] = $customer_data['default_tax']; $invoice['total_tax_name'] = $customer_data['default_tax_name']; } } } // drag some details from the related job $first_job_id = 0; if (!(int) $invoice_id) { if (isset($invoice['job_ids']) && $invoice['job_ids']) { $first_job_id = current($invoice['job_ids']); } else { if (isset($invoice['job_id']) && $invoice['job_id']) { $first_job_id = $invoice['job_id']; // abckwards compatibility } else { $first_job_id = 0; } } if ($first_job_id > 0) { $job_data = module_job::get_job($first_job_id, false); $invoice['hourly_rate'] = $job_data['hourly_rate']; $invoice['taxes'] = $job_data['taxes']; //$invoice['total_tax_rate'] = $job_data['total_tax_rate']; //$invoice['total_tax_name'] = $job_data['total_tax_name']; } } // new support for multiple taxes if (!isset($invoice['taxes']) || !count($invoice['taxes']) && $invoice['total_tax_rate'] > 0) { $invoice['taxes'] = array(); if ($first_job_id > 0 && !(int) $invoice_id) { // taxes set above from job } else { $tax_rates = explode(',', $invoice['total_tax_rate']); $tax_names = explode(',', $invoice['total_tax_name']); foreach ($tax_rates as $tax_rate_id => $tax_rate_amount) { if ($tax_rate_amount > 0) { $invoice['taxes'][] = array('order' => 0, 'percent' => $tax_rate_amount, 'name' => isset($tax_names[$tax_rate_id]) ? $tax_names[$tax_rate_id] : $invoice['total_tax_name'], 'total' => 0, 'amount' => 0, 'discount' => 0, 'increment' => module_config::c('tax_multiple_increment', 0)); } } } } // work out total hours etc.. //$invoice['total_hours'] = 0; //$invoice['total_hours_completed'] = 0; //$invoice['total_hours_overworked'] = 0; $invoice['discount_amount_on_tax'] = 0; // used in job.php $invoice['total_sub_amount'] = 0; $invoice['total_sub_amount_taxable'] = 0; $invoice_items = self::get_invoice_items((int) $invoice['invoice_id'], $invoice); foreach ($invoice_items as $invoice_item) { if ($invoice_item['invoice_item_amount'] != 0) { // we have a custom amount for this invoice_item $invoice['total_sub_amount'] += $invoice_item['invoice_item_amount']; if ($invoice_item['taxable']) { $invoice['total_sub_amount_taxable'] += $invoice_item['invoice_item_amount']; if (module_config::c('tax_calculate_mode', _TAX_CALCULATE_AT_END) == _TAX_CALCULATE_INCREMENTAL) { // tax calculated along the way (this isn't the recommended way, but was included as a feature request) // we add tax to each of the tax array items //$invoice['total_tax'] += round(($invoice_item['invoice_item_amount'] * ($invoice['total_tax_rate'] / 100)),module_config::c('currency_decimal_places',2)); foreach ($invoice['taxes'] as $invoice_tax_id => $invoice_tax) { if (!isset($invoice['taxes'][$invoice_tax_id]['total'])) { $invoice['taxes'][$invoice_tax_id]['total'] = 0; } $invoice['taxes'][$invoice_tax_id]['total'] += $invoice_item['invoice_item_amount']; $invoice['taxes'][$invoice_tax_id]['amount'] += round($invoice_item['invoice_item_amount'] * ($invoice_tax['percent'] / 100), module_config::c('currency_decimal_places', 2)); } } } } } //$invoice['final_modification'] = 0; // hack for discount modes - change this to just 'discount_amount' cos that is all that uses this variable. HERE // add any discounts. if ($invoice['discount_amount'] != 0) { if ($invoice['discount_type'] == _DISCOUNT_TYPE_AFTER_TAX) { // after tax discount :::::::::: // handled below. //$invoice['final_modification'] = -$invoice['discount_amount']; } else { if ($invoice['discount_type'] == _DISCOUNT_TYPE_BEFORE_TAX) { // before tax discount::::: //$invoice['final_modification'] = -$invoice['discount_amount']; // problem : this 'discount_amount_on_tax' calculation may not match the correct final discount calculation as per below if (module_config::c('tax_calculate_mode', _TAX_CALCULATE_AT_END) == _TAX_CALCULATE_INCREMENTAL) { // tax calculated along the way. // we have discounted the 'total amount taxable' so that means we need to reduce the tax amount by that much as well. foreach ($invoice['taxes'] as $invoice_tax_id => $invoice_tax) { $this_tax_discount = round($invoice['discount_amount'] * ($invoice['taxes'][$invoice_tax_id]['percent'] / 100), module_config::c('currency_decimal_places', 2)); $invoice['discount_amount_on_tax'] += $this_tax_discount; if (!isset($invoice['taxes'][$invoice_tax_id]['total'])) { $invoice['taxes'][$invoice_tax_id]['total'] = 0; } $invoice['taxes'][$invoice_tax_id]['total'] -= $invoice['discount_amount']; $invoice['taxes'][$invoice_tax_id]['amount'] -= $this_tax_discount; $invoice['taxes'][$invoice_tax_id]['discount'] = $this_tax_discount; } } else { // we work out what the tax would have been if there was no applied discount // this is used in job.php $invoice['taxes_backup'] = $invoice['taxes']; $invoice['total_sub_amount_taxable_backup'] = $invoice['total_sub_amount_taxable']; $total_tax_before_discount = 0; foreach ($invoice['taxes'] as $invoice_tax_id => $invoice_tax) { $invoice['taxes'][$invoice_tax_id]['total'] = $invoice['total_sub_amount_taxable']; $invoice['taxes'][$invoice_tax_id]['amount'] = round($invoice['total_sub_amount_taxable'] * ($invoice_tax['percent'] / 100), module_config::c('currency_decimal_places', 2)); // here we adjust the 'total_sub_amount_taxable' to include the value from the previous calculation. // this is for multiple taxes that addup as they go (eg: Canada) if (isset($invoice_tax['increment']) && $invoice_tax['increment']) { $invoice['total_sub_amount_taxable'] += $invoice['taxes'][$invoice_tax_id]['amount']; } $total_tax_before_discount += $invoice['taxes'][$invoice_tax_id]['amount']; } $invoice['taxes'] = $invoice['taxes_backup']; $invoice['total_sub_amount_taxable'] = $invoice['total_sub_amount_taxable_backup']; } // remove the discount amount from the 'sub total' and the 'taxable total' but don't go negative on it. // remove the discount from any non-taxable portion first. $non_taxable_amount = $invoice['total_sub_amount'] - $invoice['total_sub_amount_taxable']; $non_taxable_discount = min($invoice['discount_amount'], $non_taxable_amount); $taxable_discount = $invoice['discount_amount'] - $non_taxable_discount; //echo "non tax $non_taxable_amount \n nontax discount: $non_taxable_discount \n tax discount: $taxable_discount \n";print_r($invoice);exit; $invoice['total_sub_amount'] -= $invoice['discount_amount']; $invoice['total_sub_amount_taxable'] -= $taxable_discount; // $invoice['total_sub_amount']-=$invoice['discount_amount']; // $invoice['total_sub_amount_taxable']-=$invoice['discount_amount']; } } } //$invoice['total_hours_remain'] = $invoice['total_hours'] - $invoice['total_hours_completed']; //$invoice['total_percent_complete'] = $invoice['total_hours'] > 0 ? round($invoice['total_hours_remain'] / $invoice['total_hours'],2) : 0; //if(isset($invoice['total_tax_rate'])){ if (module_config::c('tax_calculate_mode', _TAX_CALCULATE_AT_END) == _TAX_CALCULATE_INCREMENTAL && isset($invoice['total_tax']) && $invoice['total_tax'] > 0) { // tax already calculated above. } else { if (module_config::c('tax_calculate_mode', _TAX_CALCULATE_AT_END) == _TAX_CALCULATE_AT_END) { // tax needs to be calculated based on the total_sub_amount_taxable $previous_invoice_tax_id = false; foreach ($invoice['taxes'] as $invoice_tax_id => $invoice_tax) { $invoice['taxes'][$invoice_tax_id]['total'] = $invoice['total_sub_amount_taxable']; if (isset($invoice_tax['increment']) && $invoice_tax['increment'] && $previous_invoice_tax_id) { $invoice['taxes'][$invoice_tax_id]['total'] += $invoice['taxes'][$previous_invoice_tax_id]['amount']; } $invoice['taxes'][$invoice_tax_id]['amount'] = round($invoice['taxes'][$invoice_tax_id]['total'] * ($invoice_tax['percent'] / 100), module_config::c('currency_decimal_places', 2)); // here we adjust the 'total_sub_amount_taxable' to include the value from the previous calculation. // this is for multiple taxes that addup as they go (eg: Canada) $previous_invoice_tax_id = $invoice_tax_id; } //$invoice['total_tax'] = round(($invoice['total_sub_amount_taxable'] * ($invoice['total_tax_rate'] / 100)),module_config::c('currency_decimal_places',2)); } else { //$invoice['total_tax'] = 0; } } if (isset($invoice['tax_type']) && $invoice['tax_type'] == 1) { // hack! not completely correct, oh well. // todo - make this work with more than 1 tax rate. // $amount / 1.05 ( this is 1 + tax %) // this will only work if a single tax has been included. if (is_array($invoice['taxes']) && count($invoice['taxes']) > 1) { set_error('Included tax calculation only works with 1 tax rate'); } else { if (is_array($invoice['taxes']) && count($invoice['taxes'])) { reset($invoice['taxes']); $invoice_tax_id = key($invoice['taxes']); if (isset($invoice['taxes'][$invoice_tax_id])) { $taxable_amount = $invoice['total_sub_amount_taxable'] / (1 + $invoice['taxes'][$invoice_tax_id]['percent'] / 100); $invoice['taxes'][$invoice_tax_id]['amount'] = $invoice['total_sub_amount_taxable'] - $taxable_amount; $invoice['total_sub_amount'] = $invoice['total_sub_amount'] - $invoice['taxes'][$invoice_tax_id]['amount']; } } } } $invoice['total_tax'] = 0; foreach ($invoice['taxes'] as $invoice_tax_id => $invoice_tax) { $invoice['total_tax'] += $invoice_tax['amount']; } if (isset($total_tax_before_discount)) { $invoice['discount_amount_on_tax'] += $total_tax_before_discount - $invoice['total_tax']; } $invoice['total_amount'] = $invoice['total_sub_amount'] + $invoice['total_tax']; if ($invoice['discount_type'] == _DISCOUNT_TYPE_AFTER_TAX) { $invoice['total_amount'] -= $invoice['discount_amount']; } $invoice['total_amount'] = round($invoice['total_amount'], module_config::c('currency_decimal_places', 2)); $invoice['overdue'] = $invoice['date_due'] && $invoice['date_due'] != '0000-00-00' && (!$invoice['date_paid'] || $invoice['date_paid'] == '0000-00-00') && strtotime($invoice['date_due']) < strtotime(date('Y-m-d')); if ($basic === 1) { // so we don't go clearning cache and working out how much has been paid. // used in the finance module while displaying dashboard summary. return $invoice; } // find the user id if none exists. /*if($invoice['customer_id'] && !$invoice['user_id']){ $customer_data = module_customer::get_customer($invoice['customer_id']); if($customer_data && $customer_data['customer_id'] == $invoice['customer_id']){ if($customer_data['primary_user_id']){ $invoice['user_id'] = $customer_data['primary_user_id']; }else{ $customer_contacts = module_user::get_contacts(array('customer_id'=>$invoice['customer_id'])); foreach($customer_contacts as $contact){ // todo - search roles or something to find the accountant. $invoice['user_id'] = $contact['user_id']; break; } } } }*/ $paid = 0; /* START DEPOSITS */ $invoice['total_amount_deposits'] = 0; // calculate deposits separately. $invoice['total_amount_deposits_tax'] = 0; // calculate deposits separately. //module_cache::clear_cache(); // no longer clearnig cache, it does it in get_invoice_payments. //module_cache::clear('invoice'); foreach (self::get_invoice_payments($invoice_id) as $payment) { if ($payment['date_paid'] && $payment['date_paid'] != '0000-00-00') { if ($payment['payment_type'] == _INVOICE_PAYMENT_TYPE_DEPOSIT) { // what invoice did this payment come from? $deposit_invoice = module_invoice::get_invoice($payment['other_id']); if ($deposit_invoice && $deposit_invoice['invoice_id'] == $payment['other_id']) { $invoice['total_amount_deposits'] += min($deposit_invoice['total_amount'] - $deposit_invoice['total_tax'], $payment['amount'] - $deposit_invoice['total_tax']); $invoice['total_amount_deposits_tax'] += $deposit_invoice['total_tax']; } } else { $paid += $payment['amount']; } } } if ($invoice['total_amount_deposits'] > 0) { // we need to reduce the 'total_amount' of this invoice so it doesn't double up with the other paid deposit invoice $invoice['total_amount'] -= $invoice['total_amount_deposits']; } if ($invoice['total_amount_deposits_tax'] > 0) { //$invoice['total_tax'] -= $invoice['total_amount_deposits_tax']; // we need to reduce the 'total_amount' of this invoice so it doesn't double up with the other paid deposit invoice $invoice['total_amount'] -= $invoice['total_amount_deposits_tax']; } /* END DEPOSITS */ // any extra fees (eG: paypap fee?) $invoice['fees'] = self::get_fees($invoice_id, $invoice); foreach ($invoice['fees'] as $fee) { $invoice['total_amount'] += $fee['total']; } // dont go negative on payments: $invoice['total_amount_paid'] = max(0, min($invoice['total_amount'], $paid)); $invoice['total_amount_credit'] = 0; if ($invoice['total_amount'] > 0 && $paid > $invoice['total_amount']) { // raise a credit against this customer for the difference. $invoice['total_amount_credit'] = round($paid - $invoice['total_amount'], 2); //echo $invoice['total_amount_overpaid'];exit; } if ($invoice['total_amount'] != $invoice['cached_total']) { if ((int) $invoice_id > 0) { update_insert('invoice_id', $invoice_id, 'invoice', array('cached_total' => $invoice['total_amount'])); } $invoice['cached_total'] = $invoice['total_amount']; } $invoice['total_amount_due'] = round($invoice['total_amount'] - $invoice['total_amount_paid'], module_config::c('currency_decimal_places', 2)); if ($invoice['date_cancel'] != '0000-00-00') { $invoice['total_amount_due'] = 0; } // a special addition for deposit invoices. if (isset($invoice['deposit_job_id']) && $invoice['deposit_job_id']) { // we find out how much deposit has actually been paid // and how much is remaining that hasn't been allocated to any other invoices $invoice['deposit_remaining'] = 0; if ($invoice['total_amount_paid'] > 0) { $invoice['deposit_remaining'] = $invoice['total_amount_paid']; $payments = get_multiple('invoice_payment', array('payment_type' => _INVOICE_PAYMENT_TYPE_DEPOSIT, 'other_id' => $invoice['invoice_id'])); foreach ($payments as $payment) { $invoice['deposit_remaining'] = $invoice['deposit_remaining'] - $payment['amount']; } } } // save our database cache values: if ((int) $invoice_id > 0) { foreach (array('total_amount', 'total_amount_due') as $cacheable_item) { if (isset($invoice[$cacheable_item]) && (!isset($original_invoice) || !isset($original_invoice['c_' . $cacheable_item]) || $original_invoice['c_' . $cacheable_item] != $invoice[$cacheable_item])) { // cacheable items can be the same name or prefixed with c_ update_insert('invoice_id', $invoice_id, 'invoice', array("c_{$cacheable_item}" => $invoice[$cacheable_item])); $invoice["c_{$cacheable_item}"] = $invoice[$cacheable_item]; } } } if (isset($cache_key)) { module_cache::put('invoice', $cache_key, $invoice, $cache_timeout); } return $invoice; }
<a href="<?php echo module_quote::link_open($job['quote_id'], false); ?> "><?php _e('Open'); ?> </a> <?php } })); } if (file_exists('includes/plugin_invoice/pages/invoice_recurring.php')) { if ((int) $job_id > 0) { // see if this job was renewed from anywhere $job_history = module_job::get_jobs(array('renew_job_id' => $job_id)); if (count($job_history)) { foreach ($job_history as $job_h) { $fieldset_data['elements'][] = array('title' => 'Renewal History', 'fields' => array(_l('This job was renewed from %s on %s', module_job::link_open($job_h['job_id'], true), print_date($job_h['date_renew'])))); } } } $fieldset_data['elements'][] = array('title' => 'Renewal Date', 'fields' => array(function () use(&$job) { if ($job['renew_job_id']) { echo _l('This job was renewed on %s.', print_date($job['date_renew'])); echo '<br/>'; echo _l('A new job was created, please click <a href="%s">here</a> to view it.', module_job::link_open($job['renew_job_id'])); } else { if ($job['date_renew'] != '0000-00-00' && (!$job['date_start'] || $job['date_start'] == '0000-00-00')) { echo '<p>Warning: Please set a Job "Start Date" for renewals to work correctly</p>'; }
?> <form action="" method="post"> <?php module_form::print_form_auth(); ?> <?php $search_bar = array('elements' => array('name' => array('title' => _l('File Name / Description:'), 'field' => array('type' => 'text', 'name' => 'search[generic]', 'value' => isset($search['generic']) ? $search['generic'] : '')))); if (class_exists('module_job', false)) { $search_bar['elements']['job'] = array('title' => _l('Job:'), 'field' => array('type' => 'select', 'name' => 'search[job_id]', 'value' => isset($search['job_id']) ? $search['job_id'] : '', 'options' => module_job::get_jobs(), 'options_array_id' => 'name')); } echo module_form::search_bar($search_bar); $table_manager = module_theme::new_table_manager(); $columns = array(); $columns['file_name'] = array('title' => 'File Name', 'callback' => function ($file) { echo module_file::link_open($file['file_id'], true); if (isset($file['file_url']) && strlen($file['file_url'])) { echo ' '; echo '<a href="' . htmlspecialchars($file['file_url']) . '">' . htmlspecialchars($file['file_url']) . '</a>'; } }, 'cell_class' => 'row_action'); $columns['file_description'] = array('title' => 'Description', 'callback' => function ($file) { echo module_security::purify_html($file['description']); }); $columns['file_status'] = array('title' => 'Status', 'callback' => function ($file) {
if (class_exists('module_customer', false)) { $c = array(); $res = module_customer::get_customers(); foreach ($res as $row) { $c[$row['customer_id']] = $row['customer_name']; } if ($file['customer_id'] && !isset($c[$file['customer_id']])) { // this file is related to another job. from another customer. $related_customer = module_customer::get_customer($file['customer_id'], true); $c[$file['customer_id']] = $related_customer['customer_name']; } $fieldset_data['elements'][] = array('title' => 'Customer', 'field' => array('type' => 'select', 'name' => 'customer_id', 'value' => $file['customer_id'], 'options' => $c)); } if (class_exists('module_job', false) && class_exists('module_customer', false)) { $c = array(); $res = module_job::get_jobs(array('customer_id' => $file['customer_id'])); foreach ($res as $row) { $c[$row['job_id']] = $row['name']; } if ($file['job_id'] && !isset($c[$file['job_id']])) { // this file is related to another job. from another customer. $related_job = module_job::get_job($file['job_id'], false, true); if ($related_job && $related_job['job_id'] == $file['job_id']) { $related_customer = module_customer::get_customer($related_job['customer_id'], true); if ($related_customer && $related_customer['customer_id'] == $related_job['customer_id']) { $c[$file['job_id']] = _l('%s (from %s)', $related_job['name'], $related_customer['customer_name']); } else { $file['job_id'] = false; } } else { $file['job_id'] = false;
public static function hook_filter_var_job_list($call, $attributes) { if (!is_array($attributes)) { $attributes = array(); } foreach (module_job::get_jobs(array('customer_id' => isset($_REQUEST['customer_id']) ? (int) $_REQUEST['customer_id'] : false), array('columns' => 'u.job_id, u.name')) as $job) { $attributes[$job['job_id']] = $job['name']; } return $attributes; }
</td> </tr> <?php } ?> <?php if (class_exists('module_job', false)) { ?> <tr> <th><?php _e('Related Job:'); ?> </th> <td> <?php $jobs = module_job::get_jobs(array('customer_id' => $customer_id)); if ($can_edit_emails) { echo print_select_box($jobs, 'job_id', isset($email['job_id']) ? $email['job_id'] : false, '', true, 'name'); } else { if (isset($email['job_id']) && $email['job_id']) { echo isset($jobs[$email['job_id']]) ? htmlspecialchars($jobs[$email['job_id']]['name']) : _l('Deleted'); } else { _e('N/A'); } } ?> </td> </tr> <?php } ?>
public function delete_customer($customer_id, $remove_linked_data = true) { $customer_id = (int) $customer_id; if ($customer_id > 0) { if (_DEMO_MODE && $customer_id == 1) { set_error('Sorry this is a Demo Customer. It cannot be changed.'); redirect_browser(self::link_open($customer_id)); } $customer = self::get_customer($customer_id); if ($customer && $customer['customer_id'] == $customer_id) { // todo: Delete emails (wack these in this customer_deleted hook) hook_handle_callback('customer_deleted', $customer_id, $remove_linked_data); if (class_exists('module_group', false)) { // remove the customer from his groups module_group::delete_member($customer_id, 'customer'); } if (class_exists('module_extra', false)) { module_extra::delete_extras('customer', 'customer_id', $customer_id); } // remove the contacts from this customer foreach (module_user::get_contacts(array('customer_id' => $customer_id)) as $val) { if ($val['customer_id'] && $val['customer_id'] == $customer_id) { module_user::delete_user($val['user_id']); } } // remove staff delete_from_db('customer_user_rel', 'customer_id', $customer_id); if (class_exists('module_note', false)) { module_note::note_delete("customer", 'customer_id', $customer_id); } handle_hook("address_delete", $this, 'all', "customer", 'customer_id', $customer_id); // todo, check the 'delete' permission on each one of these 'delete' method calls // do that better when we remove each of these and put them into the customer delete hook if ($remove_linked_data) { if (class_exists('module_website', false) && module_website::is_plugin_enabled()) { foreach (module_website::get_websites(array('customer_id' => $customer_id)) as $val) { if ($val['customer_id'] && $val['customer_id'] == $customer_id) { module_website::delete_website($val['website_id']); } } } if (class_exists('module_job', false) && module_job::is_plugin_enabled()) { foreach (module_job::get_jobs(array('customer_id' => $customer_id)) as $val) { if ($val['customer_id'] && $val['customer_id'] == $customer_id) { module_job::delete_job($val['job_id']); } } } if (class_exists('module_invoice', false) && module_invoice::is_plugin_enabled()) { foreach (module_invoice::get_invoices(array('customer_id' => $customer_id)) as $val) { if ($val['customer_id'] && $val['customer_id'] == $customer_id) { module_invoice::delete_invoice($val['invoice_id']); } } } if (class_exists('module_quote', false) && module_quote::is_plugin_enabled()) { foreach (module_quote::get_quotes(array('customer_id' => $customer_id)) as $val) { if ($val['customer_id'] && $val['customer_id'] == $customer_id) { module_quote::delete_quote($val['quote_id']); } } } //handle_hook("file_delete",$this,"customer",'customer_id',$customer_id); } else { // instead of deleting these records we just update them to customer_id = 0 if (class_exists('module_website', false) && module_website::is_plugin_enabled()) { foreach (module_website::get_websites(array('customer_id' => $customer_id)) as $val) { if ($val['customer_id'] && $val['customer_id'] == $customer_id) { update_insert('website_id', $val['website_id'], 'website', array('customer_id' => 0)); } } } if (class_exists('module_job', false) && module_job::is_plugin_enabled()) { foreach (module_job::get_jobs(array('customer_id' => $customer_id)) as $val) { if ($val['customer_id'] && $val['customer_id'] == $customer_id) { update_insert('job_id', $val['job_id'], 'job', array('customer_id' => 0)); } } } if (class_exists('module_invoice', false) && module_invoice::is_plugin_enabled()) { foreach (module_invoice::get_invoices(array('customer_id' => $customer_id)) as $val) { if ($val['customer_id'] && $val['customer_id'] == $customer_id) { update_insert('invoice_id', $val['invoice_id'], 'invoice', array('customer_id' => 0)); } } } if (class_exists('module_quote', false) && module_quote::is_plugin_enabled()) { foreach (module_quote::get_quotes(array('customer_id' => $customer_id)) as $val) { if ($val['customer_id'] && $val['customer_id'] == $customer_id) { update_insert('quote_id', $val['quote_id'], 'quote', array('customer_id' => 0)); } } } if (class_exists('module_file', false) && module_file::is_plugin_enabled()) { foreach (module_file::get_files(array('owner_id' => $customer_id, 'owner_table' => 'customer')) as $val) { if ($val['customer_id'] && $val['customer_id'] == $customer_id) { update_insert('file_id', $val['file_id'], 'file', array('owner_id' => 0, 'owner_table' => '')); } } } } // finally delete the main customer record // (this is so the above code works with its sql joins) $sql = "DELETE FROM " . _DB_PREFIX . "customer WHERE customer_id = '" . $customer_id . "' LIMIT 1"; query($sql); } } }
module_group::display_groups(array('title' => $page_type_single . ' Groups', 'owner_table' => 'customer', 'owner_id' => $customer_id, 'view_link' => $module->link_open($customer_id))); } $note_summary_owners = array(); // generate a list of all possible notes we can display for this customer. // display all the notes which are owned by all the sites we have access to // display all the notes which are owned by all the users we have access to foreach (module_user::get_contacts(array('customer_id' => $customer_id)) as $val) { $note_summary_owners['user'][] = $val['user_id']; } if (class_exists('module_website', false) && module_website::is_plugin_enabled()) { foreach (module_website::get_websites(array('customer_id' => $customer_id)) as $val) { $note_summary_owners['website'][] = $val['website_id']; } } if (class_exists('module_job', false) && module_job::is_plugin_enabled()) { foreach (module_job::get_jobs(array('customer_id' => $customer_id)) as $val) { $note_summary_owners['job'][] = $val['job_id']; foreach (module_invoice::get_invoices(array('job_id' => $val['job_id'])) as $val) { $note_summary_owners['invoice'][$val['invoice_id']] = $val['invoice_id']; } } } if (class_exists('module_invoice', false) && module_invoice::is_plugin_enabled()) { foreach (module_invoice::get_invoices(array('customer_id' => $customer_id)) as $val) { $note_summary_owners['invoice'][$val['invoice_id']] = $val['invoice_id']; } } if (class_exists('module_note', false) && module_note::is_plugin_enabled()) { module_note::display_notes(array('title' => 'All ' . $page_type_single . ' Notes', 'owner_table' => 'customer', 'owner_id' => $customer_id, 'view_link' => $module->link_open($customer_id), 'display_summary' => true, 'summary_owners' => $note_summary_owners)); } }
* Deploy: 9809 f200f46c2a19bb98d112f2d32a8de0c4 * Envato: 4ffca17e-861e-4921-86c3-8931978c40ca * Package Date: 2015-11-25 02:55:20 * IP Address: 67.79.165.254 */ if (!$job_safe) { die('denied'); } $search = isset($_REQUEST['search']) && is_array($_REQUEST['search']) ? $_REQUEST['search'] : array(); if (isset($_REQUEST['customer_id'])) { $search['customer_id'] = $_REQUEST['customer_id']; } if (!isset($search['completed'])) { $search['completed'] = module_config::c('job_search_completed_default', 1); } $jobs = module_job::get_jobs($search); // hack to add a "export" option to the pagination results. if (class_exists('module_import_export', false) && module_job::can_i('view', 'Export Jobs')) { module_import_export::enable_pagination_hook(array('name' => 'Job Export', 'fields' => array('Job ID' => 'job_id', 'Job Title' => 'name', 'Hourly Rate' => 'hourly_rate', 'Start Date' => 'date_start', 'Due Date' => 'date_due', 'Completed Date' => 'date_completed', module_config::c('project_name_single', 'Website') . ' Name' => 'website_name', 'Customer Name' => 'customer_name', 'Type' => 'type', 'Status' => 'status', 'Staff Member' => 'staff_member', 'Tax Name' => 'total_tax_name', 'Tax Percent' => 'total_tax_rate', 'Renewal Date' => 'date_renew'), 'extra' => array('owner_table' => 'job', 'owner_id' => 'job_id'))); } $header = array('title' => _l('Customer Jobs'), 'main' => true, 'button' => array()); if (module_job::can_i('create', 'Jobs')) { $header['button'][] = array('url' => module_job::link_open('new'), 'title' => 'Add New Job', 'type' => 'add'); } if (class_exists('module_import_export', false) && module_job::can_i('view', 'Import Jobs')) { $link = module_import_export::import_link(array('callback' => 'module_job::handle_import', 'callback_preview' => 'module_job::handle_import_row_debug', 'name' => 'Jobs', 'return_url' => $_SERVER['REQUEST_URI'], 'group' => 'job', 'fields' => array('Job ID' => 'job_id', 'Job Title' => 'name', 'Hourly Rate' => 'hourly_rate', 'Start Date' => 'date_start', 'Due Date' => 'date_due', 'Completed Date' => 'date_completed', module_config::c('project_name_single', 'Website') . ' Name' => 'website_name', 'Customer Name' => 'customer_name', 'Type' => 'type', 'Status' => 'status', 'Staff Member' => 'staff_member', 'Tax Name' => 'total_tax_name', 'Tax Percent' => 'total_tax_rate', 'Renewal Date' => 'date_renew'), 'extra' => array('owner_table' => 'job', 'owner_id' => 'job_id'))); $header['button'][] = array('url' => $link, 'title' => 'Import Jobs', 'type' => 'add'); } print_heading($header); ?>
public static function delete_website($website_id) { $website_id = (int) $website_id; if (_DEMO_MODE && $website_id == 1) { set_error('Sorry this is a Demo Website. It cannot be deleted.'); return; } if ((int) $website_id > 0) { $original_website_data = self::get_website($website_id); if (!$original_website_data || $original_website_data['website_id'] != $website_id) { return false; } } if (!self::can_i('delete', 'Websites')) { return false; } hook_handle_callback('website_deleted', $website_id); $sql = "DELETE FROM " . _DB_PREFIX . "website WHERE website_id = '" . $website_id . "' LIMIT 1"; query($sql); if (class_exists('module_group', false)) { module_group::delete_member($website_id, 'website'); } foreach (module_job::get_jobs(array('website_id' => $website_id)) as $val) { module_job::delete_job($val['website_id']); } module_note::note_delete("website", $website_id); module_extra::delete_extras('website', 'website_id', $website_id); }
echo module_form::generate_fieldset($fieldset_data); unset($fieldset_data); } $form_actions = array('class' => 'action_bar action_bar_left', 'elements' => array(array('type' => 'save_button', 'name' => 'butt_save', 'onclick' => "\$('#form_redirect').val('" . module_quote::link_open(false) . "');", 'value' => _l('Save and Return')), array('type' => 'save_button', 'name' => 'butt_save', 'value' => _l('Save')), array('ignore' => !$quote_id || !function_exists('convert_html2pdf'), 'type' => 'submit', 'name' => 'butt_print', 'value' => _l('Print PDF')), array('ignore' => !$quote_id, 'type' => 'submit', 'name' => 'butt_email', 'value' => _l('Email')), array('ignore' => !((int) $quote_id && module_quote::can_i('create', 'Quotes')), 'type' => 'submit', 'name' => 'butt_duplicate', 'value' => _l('Duplicate')), array('ignore' => !((int) $quote_id && module_quote::can_i('delete', 'Quotes')), 'type' => 'delete_button', 'name' => 'butt_del', 'value' => _l('Delete')), array('type' => 'button', 'name' => 'cancel', 'value' => _l('Cancel'), 'class' => 'submit_button', 'onclick' => "window.location.href='" . module_quote::link_open(false) . "';"))); echo module_form::generate_form_actions($form_actions); if ($do_perm_finish_check) { // we call our permission check // render finish method here instead of in index.php // this allows quote task edit permissions without quote edit permissions. // HOPE THIS WORKS! :) module_security::render_page_finished(); } hook_handle_callback('layout_column_half', 2, '65'); /**** DEPOSIT INVOICE *****/ if ($quote_id > 0) { $jobs = module_job::get_jobs(array('quote_id' => $quote_id)); if (count($jobs)) { ob_start(); ?> <div class="tableclass_form content"> <?php foreach ($jobs as $j) { ?> <p align="center"> <?php echo _l('This Quote has been converted into a Job: %s.', module_job::link_open($j['job_id'], true, $j)); ?> <br/>
.attr("value", value).text(key)); }); }, fail: function(){ alert('Changing customer failed, please refresh and try again.'); } }); }); }); </script> <?php })); $fieldset_data['elements'][] = array('title' => 'Linked Job', 'fields' => array(function () use(&$finance, $locked) { $d = array(); if ($finance['customer_id']) { $jobs = module_job::get_jobs(array('customer_id' => $finance['customer_id'])); foreach ($jobs as $job) { $d[$job['job_id']] = $job['name']; } } echo print_select_box($d, 'job_id', isset($finance['job_id']) ? $finance['job_id'] : 0, '', _l(' - None - ')); if (isset($finance['job_id']) && $finance['job_id']) { echo ' <a href="' . module_job::link_open($finance['job_id'], false) . '">' . _l('Open Job') . '</a>'; } })); } $fieldset_data['elements'][] = array('title' => 'Linked Invoice', 'fields' => array(function () use(&$finance, $locked) { $d = array(); if ($finance['customer_id']) { $invoices = module_invoice::get_invoices(array('customer_id' => $finance['customer_id'])); foreach ($invoices as $invoice) {