public static function get_invoice_items($invoice_id, $invoice = array()) { $invoice_id = (int) $invoice_id; $invoice_items = array(); if (!$invoice_id && isset($_REQUEST['job_id']) && (int) $_REQUEST['job_id'] > 0) { // hack for half completed invoices if (isset($_REQUEST['amount_due']) && $_REQUEST['amount_due'] > 0) { $amount = (double) $_REQUEST['amount_due']; $invoice_items = array('new0' => array('description' => isset($_REQUEST['description']) ? $_REQUEST['description'] : _l('Invoice Item'), 'custom_description' => '', 'long_description' => '', 'custom_long_description' => '', 'amount' => $amount, 'manual_task_type' => _TASK_TYPE_AMOUNT_ONLY, 'hours' => 0, 'taxable' => false, 'task_id' => 0)); } else { $job_id = (int) $_REQUEST['job_id']; if ($job_id > 0) { // we return the items from the job rather than the items from the invoice. // for new invoice creation. $tasks = module_job::get_invoicable_tasks($job_id); $x = 0; $job = module_job::get_job($job_id, false); $invoice['hourly_rate'] = $job['hourly_rate']; foreach ($tasks as $task) { if (!isset($task['custom_description'])) { $task['custom_description'] = ''; } if (!isset($task['custom_long_description'])) { $task['custom_long_description'] = ''; } //$task['task_id'] = 'new'.$x; // the 'hourly_rate' column will hold either // = for hours/amount the default hourly rate from the job // = for qty/amount the raw amount that will multiplu hours by // = for amount only will be the raw amount. $invoice_task_type = isset($task['manual_task_type']) && $task['manual_task_type'] >= 0 ? $task['manual_task_type'] : $job['default_task_type']; if ($invoice_task_type == _TASK_TYPE_QTY_AMOUNT) { $task['hourly_rate'] = $task['amount']; $task['amount'] = 0; // this forces our calc below to calculate teh amount for us. } else { $task['hourly_rate'] = $job['hourly_rate']; } $invoice_items['new' . $x] = $task; $x++; } //print_r($tasks);exit; } } } else { if ($invoice_id) { if (!$invoice) { $invoice = self::get_invoice($invoice_id, true); } $sql = "SELECT ii.invoice_item_id AS id, ii.*, t.job_id, t.description AS description, ii.description as custom_description, ii.long_description as custom_long_description, t.task_order, ii.task_order AS custom_task_order "; // , j.hourly_rate $sql .= ", t.date_done AS task_date_done "; $sql .= ", t.task_id "; $sql .= " FROM `" . _DB_PREFIX . "invoice_item` ii "; $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 .= " WHERE ii.invoice_id = {$invoice_id}"; $sql .= " ORDER BY t.task_order "; $invoice_items = qa($sql); } } // print_r($invoice_items); // DAVE READ THIS: tasks come in with 'hours' and 'amount' and 'manual_task_type' // calculate the 'task_hourly_rate' and 'invoite_item_amount' based on this. // 'amount' is NOT used in invoice items. only 'invoice_item_amount' //echo '<pre>';print_r($invoice_items);echo '</pre>'; foreach ($invoice_items as $invoice_item_id => $invoice_item_data) { $invoice_item_data['task_hours'] = ''; $invoice_item_data['task_hours_completed'] = ''; if (isset($invoice_item_data['job_id']) && $invoice_item_data['task_id'] && $invoice_item_data['job_id'] && $invoice_item_data['task_id']) { $job_tasks = module_job::get_tasks($invoice_item_data['job_id']); if (isset($job_tasks[$invoice_item_data['task_id']])) { // copied from ajax_task_edit.php: if (function_exists('decimal_time_out')) { $completed_value = decimal_time_out($job_tasks[$invoice_item_data['task_id']]['completed']); $hours_value = decimal_time_out($job_tasks[$invoice_item_data['task_id']]['hours']); } else { $completed_value = number_out($job_tasks[$invoice_item_data['task_id']]['completed'], true); $hours_value = number_out($job_tasks[$invoice_item_data['task_id']]['hours'], true); } $invoice_item_data['task_hours'] = $hours_value; $invoice_item_data['task_hours_completed'] = $completed_value; } } // new feature, task type. $invoice_item_data['manual_task_type_real'] = $invoice_item_data['manual_task_type']; if ($invoice_item_data['manual_task_type'] < 0 && isset($invoice['default_task_type'])) { $invoice_item_data['manual_task_type'] = $invoice['default_task_type']; } if (isset($invoice_item_data['hours_mins'])) { if ($invoice_item_data['hours_mins'] == 0) { $invoice_item_data['hours_mins'] = 0; } else { $invoice_item_data['hours_mins'] = str_replace(".", ":", $invoice_item_data['hours_mins']); } } // if there are no hours logged against this task if (!$invoice_item_data['hours']) { //$invoice_item_data['task_hourly_rate']=0; } // task_hourly_rate is used for calculations, if the hourly_rate is -1 then we use the default invoice hourly rate $invoice_item_data['task_hourly_rate'] = isset($invoice_item_data['hourly_rate']) && $invoice_item_data['hourly_rate'] != 0 && $invoice_item_data['hourly_rate'] != -1 ? $invoice_item_data['hourly_rate'] : $invoice['hourly_rate']; // if we have a custom price for this task if ($invoice_item_data['manual_task_type'] == _TASK_TYPE_HOURS_AMOUNT) { if ($invoice_item_data['amount'] != 0) { $invoice_item_data['invoice_item_amount'] = $invoice_item_data['amount']; if ($invoice_item_data['hours'] == 0) { // hack to fix $0 invoices $invoice_item_data['hours'] = 1; $invoice_item_data['task_hourly_rate'] = $invoice_item_data['amount']; } //echo '<pre>';print_r($invoice_items);echo '</pre>'; if (isset($invoice_item_data['hours_mins']) && !empty($invoice_item_data['hours_mins']) && function_exists('decimal_time_in')) { $invoice_item_data['hours'] = decimal_time_in($invoice_item_data['hours_mins']); } if ($invoice_item_data['task_hourly_rate'] * $invoice_item_data['hours'] != $invoice_item_data['amount']) { // check the rounding, just to be sure. if (round($invoice_item_data['task_hourly_rate'] * $invoice_item_data['hours'], 2) == round($invoice_item_data['amount'], 2)) { // all good } else { // hack to fix manual amount with non-matching hours. $invoice_item_data['task_hourly_rate'] = $invoice_item_data['amount'] / $invoice_item_data['hours']; } } } else { $invoice_item_data['invoice_item_amount'] = $invoice_item_data['task_hourly_rate'] * $invoice_item_data['hours']; } } else { if ($invoice_item_data['manual_task_type'] == _TASK_TYPE_QTY_AMOUNT) { if ($invoice_item_data['amount'] != 0) { $invoice_item_data['invoice_item_amount'] = $invoice_item_data['amount']; } else { $invoice_item_data['invoice_item_amount'] = $invoice_item_data['task_hourly_rate'] * $invoice_item_data['hours']; } //$invoice_item_data['amount'] = $invoice_item_data['hourly_rate'] * $invoice_item_data['hours']; //$invoice_item_data['invoice_item_amount'] = $invoice_item_data['amount']; //$invoice_item_data['task_hourly_rate'] = $invoice_item_data['hourly_rate']; /*if($invoice_item_data['hours']>0){ $invoice_item_data['task_hourly_rate'] = round($invoice_item_data['invoice_item_amount']/$invoice_item_data['hours'],module_config::c('currency_decimal_places',2)); }else{ }*/ } else { // this item is an 'amount only' column. // no calculations based on quantity and hours. if ($invoice_item_data['amount'] != 0) { $invoice_item_data['task_hourly_rate'] = $invoice_item_data['amount']; $invoice_item_data['invoice_item_amount'] = $invoice_item_data['amount']; } else { $invoice_item_data['task_hourly_rate'] = 0; $invoice_item_data['invoice_item_amount'] = 0; } /* $invoice_item_data['task_hourly_rate'] = isset($invoice_item_data['hourly_rate']) && $invoice_item_data['hourly_rate']>0 ? $invoice_item_data['hourly_rate'] : $invoice['hourly_rate']; if($invoice_item_data['amount']!=0 && $invoice_item_data['amount'] != ($invoice_item_data['hours']*$invoice_item_data['task_hourly_rate'])){ $invoice_item_data['invoice_item_amount'] = $invoice_item_data['amount']; if(module_config::c('invoice_calculate_item_price_auto',1) && $invoice_item_data['hours'] > 0){ $invoice_item_data['task_hourly_rate'] = round($invoice_item_data['invoice_item_amount']/$invoice_item_data['hours'],module_config::c('currency_decimal_places',2)); }else{ $invoice_item_data['task_hourly_rate'] = false; } }else if($invoice_item_data['hours']>0){ $invoice_item_data['invoice_item_amount'] = $invoice_item_data['hours']*$invoice_item_data['task_hourly_rate']; }else{ $invoice_item_data['invoice_item_amount'] = 0; $invoice_item_data['task_hourly_rate'] = false; }*/ } } /*$invoice_item_amount = $invoice_item_data['amount'] > 0 ? $invoice_item_data['amount'] : $invoice_item_data['hours']*$task_hourly_rate; if($invoice_item_data['amount']>0 && !$invoice_item_data['hours']){ $invoice_item_amount = $invoice_item_data['amount']; $invoice_item_data['hours'] = 1; $task_hourly_rate = $invoice_item_data['amount']; // not sure if this will be buggy }else{ $invoice_item_amount = $invoice_item_data['hours']*$task_hourly_rate; }*/ // new feature, date done. if (isset($invoice_item_data['date_done']) && $invoice_item_data['date_done'] != '0000-00-00') { // $invoice_item_data['date_done'] is ok to print! } else { $invoice_item_data['date_done'] = '0000-00-00'; // check if this is linked to a task. if ($invoice_item_data['task_id']) { if (isset($invoice_item_data['task_date_done'])) { // moved it into SQL above, instead of doing a get_single() call below for each invoice line item if ($invoice_item_data['task_date_done'] && $invoice_item_data['task_date_done'] != '0000-00-00') { $invoice_item_data['date_done'] = $invoice_item_data['task_date_done']; } else { if (isset($invoice['date_create']) && $invoice['date_create'] != '0000-00-00') { $invoice_item_data['date_done'] = $invoice['date_create']; } } } else { $task = get_single('task', 'task_id', $invoice_item_data['task_id']); if ($task && isset($task['date_done']) && $task['date_done'] != '0000-00-00') { $invoice_item_data['date_done'] = $task['date_done']; // move it over ready for printing below } else { if (isset($invoice['date_create']) && $invoice['date_create'] != '0000-00-00') { $invoice_item_data['date_done'] = $invoice['date_create']; } } } } } // set a default taxes to match the invoice taxes if none defined if ((!isset($invoice_item_data['taxes']) || !count($invoice_item_data['taxes'])) && isset($invoice_item_data['taxable']) && $invoice_item_data['taxable'] && isset($invoice['taxes']) && count($invoice['taxes'])) { $invoice_item_data['taxes'] = $invoice['taxes']; } if (!isset($invoice_item_data['taxes'])) { $invoice_item_data['taxes'] = array(); } $invoice_items[$invoice_item_id] = $invoice_item_data; } //print_r($invoice_items);exit; return $invoice_items; }
public static function get_finance_summary($week_start, $week_end, $multiplyer = 1, $row_limit = 7) { $cache_key = 'finance_sum_' . md5(module_security::get_loggedin_id() . '_' . serialize(func_get_args())); $cache_timeout = module_config::c('cache_objects', 60); if ($cached_item = module_cache::get('finance', $cache_key)) { return $cached_item; } $base_href = module_finance::link_generate(false, array('full' => false, 'page' => 'dashboard_popup', 'arguments' => array('display_mode' => 'ajax')), array('foo')); $base_href .= '&'; /*$base_href .= (strpos($base_href,'?')!==false) ? '&' : '?'; $base_href .= 'display_mode=ajax&'; $base_href .= 'home_page_stats=true&';*/ // init structure: if ($multiplyer > 1) { $row_limit++; } for ($x = 0; $x < $row_limit; $x++) { //$time = strtotime("+$x days",strtotime($week_start)); $time = strtotime("+" . $x * $multiplyer . " days", strtotime($week_start)); $data[date("Ymd", $time)] = array("day" => $time, "hours" => 0, "amount" => 0, "amount_invoiced" => 0, "amount_paid" => 0, "amount_spent" => 0); if (class_exists('module_envato', false)) { $data[date("Ymd", $time)]['envato_earnings'] = 0; } } $data['total'] = array('day' => _l('Totals:'), 'week' => _l('Totals:'), 'hours' => 0, 'amount' => 0, 'amount_invoiced' => 0, 'amount_paid' => 0, 'amount_spent' => 0); if (class_exists('module_envato', false)) { $data['total']['envato_earnings'] = 0; } if (class_exists('module_job', false)) { module_debug::log(array('title' => 'Finance Dashboard Job', 'data' => '')); // find all task LOGS completed within these dayes $sql = "SELECT t.task_id, tl.date_created, t.hours AS task_hours, t.amount, tl.hours AS hours_logged, p.job_id, p.hourly_rate, t.date_done "; // $sql .= " FROM `"._DB_PREFIX."task_log` tl "; // $sql .= " LEFT JOIN `"._DB_PREFIX."task` t ON tl.task_id = t.task_id "; $sql .= " FROM `" . _DB_PREFIX . "task` t"; $sql .= " LEFT JOIN `" . _DB_PREFIX . "task_log` tl ON t.task_id = tl.task_id "; $sql .= " LEFT JOIN `" . _DB_PREFIX . "job` p ON t.job_id = p.job_id"; $sql .= " WHERE ( (tl.date_created >= '{$week_start}' AND tl.date_created < '{$week_end}') OR (t.fully_completed = 1 AND t.date_done >= '{$week_start}' AND t.date_done < '{$week_end}') )"; $sql .= " AND t.job_id IN ( "; $valid_job_ids = module_job::get_valid_job_ids(); if (count($valid_job_ids)) { foreach ($valid_job_ids as $valid_job_id) { $sql .= (int) $valid_job_id['job_id'] . ", "; } $sql = rtrim($sql, ', '); } else { $sql .= ' NULL '; } $sql .= " ) "; // echo $sql; $tasks = query($sql); $logged_tasks = array(); while ($r = mysql_fetch_assoc($tasks)) { if (!$r['date_created']) { $r['date_created'] = $r['date_done']; } if ($multiplyer > 1) { $week_day = date('w', strtotime($r['date_created'])) - 1; $r['date_created'] = date('Y-m-d', strtotime('-' . $week_day . ' days', strtotime($r['date_created']))); } $key = date("Ymd", strtotime($r['date_created'])); if (!isset($data[$key])) { // for some reason we're getting results here that shouldn't be in the list // for now we just skip these results until I figure out why (only had 1 guy report this error, maybe misconfig) continue; } // copied from dashboard_popup_hours_logged.php // needed get_tasks call to do the _JOB_TASK_ACCESS_ASSIGNED_ONLY permission check $jobtasks = module_job::get_tasks($r['job_id']); $task = isset($jobtasks[$r['task_id']]) ? $jobtasks[$r['task_id']] : false; if (!$task) { continue; } if (!isset($task['manual_task_type']) || $task['manual_task_type'] < 0) { $task['manual_task_type'] = $task['default_task_type']; } if (isset($r['hours_logged']) && $r['hours_logged'] > 0) { if ($r['hours_logged'] == $task['completed']) { // this listing is the only logged hours for this task. if ($task['fully_completed']) { // task complete, we show the final amount and hours. if ($task['amount'] > 0) { if ($task['manual_task_type'] == _TASK_TYPE_QTY_AMOUNT) { $display_amount = $task['amount'] * $task['hours']; } else { $display_amount = $task['amount']; } } else { $display_amount = $r['task_hours'] * $r['hourly_rate']; } } else { // task isn't fully completed yet, just use hourly rate for now. $display_amount = $r['hours_logged'] * $r['hourly_rate']; } } else { // this is part of a bigger log of hours for this single task. $display_amount = $r['hours_logged'] * $r['hourly_rate']; } $hours_logged = $r['task_hours'] > 0 ? $r['hours_logged'] : 0; } else { // there are no logged hours for this particular task, but it is set to completed. // we just assume it is completed on this day. if ($task['amount'] > 0) { if ($task['manual_task_type'] == _TASK_TYPE_QTY_AMOUNT) { $display_amount = $task['amount'] * $task['hours']; } else { $display_amount = $task['amount']; } } else { $display_amount = $r['task_hours'] * $r['hourly_rate']; } $hours_logged = $task['hours']; } $data[$key]['amount'] += $display_amount; $data['total']['amount'] += $display_amount; $data[$key]['hours'] += $hours_logged; $data['total']['hours'] += $hours_logged; /*$hourly_rate = $r['hourly_rate']; if($hours_logged > 0 && $r['amount'] > 0 && $hourly_rate > 0){ // there is a custom amount assigned to thsi task. // only calculate this amount if the full hours is complete. $hourly_rate = $r['amount'] / $r['task_hours']; } if($hours_logged > 0 && $hourly_rate > 0){ $data[$key]['amount'] += ($hours_logged * $hourly_rate); $data['total']['amount'] += ($hours_logged * $hourly_rate); }*/ } } module_debug::log(array('title' => 'Finance Dashboard Invoices', 'data' => '')); // find invoices sent this week. $sql = "SELECT i.* "; $sql .= " FROM `" . _DB_PREFIX . "invoice` i "; $sql .= " LEFT JOIN `" . _DB_PREFIX . "invoice_item` ii ON i.invoice_id = ii.invoice_id "; if (class_exists('module_job', false)) { $sql .= " LEFT JOIN `" . _DB_PREFIX . "task` t ON ii.task_id = t.task_id "; $sql .= " LEFT JOIN `" . _DB_PREFIX . "job` p ON t.job_id = p.job_id "; } $sql .= " WHERE (i.date_create >= '{$week_start}' AND i.date_create <= '{$week_end}')"; $sql .= " GROUP BY i.invoice_id"; // todo - sql in here to limit what they can see. $invoices = query($sql); // group invoices into days of the week. while ($invoice_data = mysql_fetch_assoc($invoices)) { //$invoice_data = module_invoice::get_invoice($i['invoice_id']); if ($invoice_data) { if ($multiplyer > 1) { $week_day = date('w', strtotime($invoice_data['date_create'])) - 1; $invoice_data['date_create'] = date('Y-m-d', strtotime('-' . $week_day . ' days', strtotime($invoice_data['date_create']))); } $key = date("Ymd", strtotime($invoice_data['date_create'])); if (!isset($data[$key])) { // for some reason we're getting results here that shouldn't be in the list // for now we just skip these results until I figure out why (only had 1 guy report this error, maybe misconfig) continue; } if (isset($data[$key])) { $data[$key]['amount_invoiced'] += $invoice_data['c_total_amount']; $data['total']['amount_invoiced'] += $invoice_data['c_total_amount']; } } } module_debug::log(array('title' => 'Finance Dashboard Finances', 'data' => '')); // find all payments made this week. // we also have to search for entries in the new "finance" table and make sure we dont double up here. $finance_records = module_finance::get_finances(array('date_from' => $week_start, 'date_to' => $week_end)); foreach ($finance_records as $finance_record) { if (isset($finance_record['payment_type']) && ($finance_record['payment_type'] == _INVOICE_PAYMENT_TYPE_OVERPAYMENT_CREDIT || $finance_record['payment_type'] == _INVOICE_PAYMENT_TYPE_CREDIT)) { // CODE COPIED FROM FINANCE_LIST.PHP // dont add these ones to the totals on the dashboard continue; } if ($finance_record['credit'] > 0) { if ($multiplyer > 1) { $week_day = date('w', strtotime($finance_record['transaction_date'])) - 1; $finance_record['transaction_date'] = date('Y-m-d', strtotime('-' . $week_day . ' days', strtotime($finance_record['transaction_date']))); } $key = date("Ymd", strtotime($finance_record['transaction_date'])); if (isset($data[$key])) { $data[$key]['amount_paid'] += $finance_record['amount']; $data['total']['amount_paid'] += $finance_record['amount']; } } if ($finance_record['debit'] > 0) { if ($multiplyer > 1) { $week_day = date('w', strtotime($finance_record['transaction_date'])) - 1; $finance_record['transaction_date'] = date('Y-m-d', strtotime('-' . $week_day . ' days', strtotime($finance_record['transaction_date']))); } $key = date("Ymd", strtotime($finance_record['transaction_date'])); if (isset($data[$key])) { $data[$key]['amount_spent'] += $finance_record['amount']; $data['total']['amount_spent'] += $finance_record['amount']; } } } module_debug::log(array('title' => 'Finance Dashboard DONE!', 'data' => '')); /*$sql = "SELECT p.* "; $sql .= " FROM `"._DB_PREFIX."invoice_payment` p "; $sql .= " WHERE (p.date_paid >= '$week_start' AND p.date_paid <= '$week_end')"; // todo - sql in here to limit what they can see. $payments = query($sql); // group invoices into days of the week. while($payment = mysql_fetch_assoc($payments)){ //$invoice_data = module_invoice::get_invoice($i['invoice_id']); if($multiplyer > 1){ $week_day = date('w',strtotime($payment['date_paid'])) - 1; $payment['date_paid'] = date('Y-m-d',strtotime('-'.$week_day.' days',strtotime($payment['date_paid']))); } $key = date("Ymd",strtotime($payment['date_paid'])); if(isset($data[$key])){ $data[$key]['amount_paid'] += $payment['amount']; $data['total']['amount_paid'] += $payment['amount']; } }*/ if (class_exists('module_envato', false)) { $envato_currency = "USD"; $envato = new envato_api(); $local_currency = $envato->read_setting("local_currency", "AUD"); $currency_convert_multiplier = $envato->currency_convert($envato_currency, $local_currency); // find summary of earnings between these dates in the envato statement. $week_start_time = strtotime($week_start); $week_end_time = strtotime($week_end); $sql = "SELECT * FROM `" . _DB_PREFIX . "envato_statement` s WHERE `time` >= '{$week_start_time}' AND `time` <= {$week_end_time}"; $sql .= " AND ( `type` = 'sale' OR `type` = 'referral_cut' )"; foreach (qa($sql) as $sale) { $sale_time = $sale['time']; if ($multiplyer > 1) { $week_day = date('w', $sale_time) - 1; $sale_time = strtotime('-' . $week_day . ' days', $sale_time); } $key = date("Ymd", $sale_time); if (!isset($data[$key])) { continue; } $data[$key]['envato_earnings'] += round($currency_convert_multiplier * $sale['earnt'], 2); $data['total']['envato_earnings'] += round($currency_convert_multiplier * $sale['earnt'], 2); /*if($sale['type']=='sale'){ $sales_count++; } $sales_amount+= $sale['earnt'];*/ } } if ($multiplyer > 1) { // dont want totals on previous weeks listing unset($data['total']); } foreach ($data as $data_id => $row) { //$row['amount'] = dollar($row['amount']); $row['chart_amount'] = $row['amount']; $row['amount'] = currency((int) $row['amount']); $row['chart_amount_invoiced'] = $row['amount_invoiced']; $row['amount_invoiced'] = currency((int) $row['amount_invoiced']); $row['chart_amount_paid'] = $row['amount_paid']; $row['amount_paid'] = currency((int) $row['amount_paid']); $row['chart_amount_spent'] = $row['amount_spent']; $row['amount_spent'] = currency((int) $row['amount_spent']); if (class_exists('module_envato', false)) { $row['chart_envato_earnings'] = $row['envato_earnings']; $row['envato_earnings'] = currency((int) $row['envato_earnings']); } // combine together $row['chart_hours'] = $row['hours']; $row['hours'] = sprintf('%s (%s)', $row['hours'], $row['amount']); if (is_numeric($row['day'])) { $time = $row['day']; $date = date('Y-m-d', $time); $row['date'] = $date; if ($multiplyer > 1) { $date .= '|' . date('Y-m-d', strtotime('+' . $multiplyer . ' days', $time)); } //$row['hours'] = '<a href="'.$base_href.'w=hours&date='.$date.'" class="summary_popup">'. _l('%s hours',$row['hours']) . '</a>'; $row['hours_link'] = '<a href="' . $base_href . 'w=hours&date=' . $date . '" class="summary_popup">' . $row['hours'] . '</a>'; $row['amount_link'] = '<a href="' . $base_href . 'w=hours&date=' . $date . '" class="summary_popup">' . $row['amount'] . '</a>'; $row['amount_invoiced_link'] = '<a href="' . $base_href . 'w=amount_invoiced&date=' . $date . '" class="summary_popup">' . $row['amount_invoiced'] . '</a>'; $row['amount_paid_link'] = '<a href="' . $base_href . 'w=amount_paid&date=' . $date . '" class="summary_popup">' . $row['amount_paid'] . '</a>'; $row['amount_spent_link'] = '<a href="' . $base_href . 'w=amount_spent&date=' . $date . '" class="summary_popup">' . $row['amount_spent'] . '</a>'; $row['day'] = _l(date('D', $time)) . ' ' . date('j', $time) . _l(date('S', $time)); $row['week'] = _l(date('M', $time)) . ' ' . date('j', $time) . _l(date('S', $time)); // if it's today. if ($time == strtotime(date("Y-m-d"))) { $row['highlight'] = true; } } else { } $data[$data_id] = $row; } module_cache::put('finance', $cache_key, $data, $cache_timeout); return $data; }
public static function hook_job_task_after($hook, $job_id, $task_id, $job_data, $task_data) { $comments = get_multiple('job_discussion', array('job_id' => $job_id, 'task_id' => $task_id), 'job_discussion_id', 'exact', 'job_discussion_id'); if ($job_data && isset($job_data['job_discussion']) && $job_data['job_discussion'] == 1) { // disabled & hidden. return; } if ($job_data && isset($job_data['job_discussion']) && $job_data['job_discussion'] == 2 && count($comments) == 0) { // disabled & shown. return; } if (isset($_POST['job_discussion_add_job_id']) && isset($_POST['job_discussion_add_task_id']) && $_POST['job_discussion_add_job_id'] == $job_id && $_POST['job_discussion_add_task_id'] == $task_id && isset($_POST['note']) && strlen($_POST['note'])) { $x = 0; while (ob_get_level() && $x++ < 10) { ob_end_clean(); } $current_user_id = module_security::get_loggedin_id(); $customer = module_customer::get_customer($job_data['customer_id']); if (!$current_user_id) { if ($job_data['customer_id'] && $customer['primary_user_id']) { $current_user_id = $customer['primary_user_id']; } } $result = array(); // adding a new note. $job_discussion_id = update_insert('job_discussion_id', 0, 'job_discussion', array('job_id' => $job_id, 'task_id' => $task_id, 'user_id' => $current_user_id, 'note' => $_POST['note'])); $result['job_discussion_id'] = $job_discussion_id; $result['count'] = count($comments) + 1; $tasks = module_job::get_tasks($job_id); $result['email_customer'] = array(); if (isset($_POST['sendemail_customer']) && is_array($_POST['sendemail_customer'])) { //$_POST['sendemail_customer'] == 'yes' && $customer['primary_user_id']){ // send email to customer primary user id. $customer_contacts = module_user::get_contacts(array('customer_id' => $job_data['customer_id'])); foreach ($_POST['sendemail_customer'] as $user_id) { $user_id = (int) $user_id; if ($user_id && isset($customer_contacts[$user_id])) { // we can email this user. $user = module_user::get_user($user_id, false); if ($user && $user['user_id'] == $user_id) { $values = array_merge($user, $job_data); $values['job_url'] = module_job::link_public($job_id); $values['job_url'] .= (strpos($values['job_url'], '?') === false ? '?' : '&') . 'discuss=' . $task_id . '#discuss' . $task_id; $values['job_name'] = $job_data['name']; $values['customer_name'] = $user['name'] . ' ' . $user['last_name']; $values['note'] = $_POST['note']; //todo: no order if no showning numbers $values['task_name'] = '#' . $tasks[$task_id]['task_order'] . ': ' . $tasks[$task_id]['description']; $template = module_template::get_template_by_key('job_discussion_email_customer'); $template->assign_values($values); $html = $template->render('html'); $email = module_email::new_email(); $email->replace_values = $values; $email->set_to('user', $user['user_id']); $email->set_from('user', $current_user_id); $email->set_subject($template->description); // do we send images inline? $email->set_html($html); if ($email->send()) { // it worked successfully!! $result['email_customer'][] = $user['user_id']; } else { /// log err? } } } } /*$user = module_user::get_user($customer['primary_user_id'],false); if($user['user_id'] == $customer['primary_user_id']){ $values = array_merge($user,$job_data); $values['job_url'] = module_job::link_public($job_id); $values['job_url'] .= (strpos($values['job_url'],'?')===false ? '?' : '&').'discuss='.$task_id.'#discuss'.$task_id; $values['job_name'] = $job_data['name']; $values['customer_name'] = $user['name'].' '.$user['last_name']; $values['note'] = $_POST['note']; //todo: no order if no showning numbers $values['task_name'] = '#'.$tasks[$task_id]['task_order'].': '.$tasks[$task_id]['description']; $template = module_template::get_template_by_key('job_discussion_email_customer'); $template->assign_values($values); $html = $template->render('html'); $email = module_email::new_email(); $email->replace_values = $values; $email->set_to('user',$user['user_id']); $email->set_from('user',$current_user_id); $email->set_subject($template->description); // do we send images inline? $email->set_html($html); if($email->send()){ // it worked successfully!! $result['email_customer'] = 1; }else{ /// log err? $result['email_customer'] = 0; } }else{ // log error? $result['email_customer'] = 0; }*/ } if (isset($_POST['sendemail_staff']) && is_array($_POST['sendemail_staff'])) { // == 'yes' && $job_data['user_id'] // todo: handle the restul better when sending to multiple people $result['email_staff_list'] = $_POST['sendemail_staff']; foreach ($_POST['sendemail_staff'] as $staff_id) { // send email to staff $staff_id = (int) $staff_id; if (!$staff_id) { $result['nostaff'] = 1; continue; } if (isset($task_data['user_id']) && $task_data['user_id'] == $staff_id || isset($job_data['user_id']) && $job_data['user_id'] == $staff_id) { //$user = module_user::get_user($job_data['user_id'],false); $user = module_user::get_user($staff_id, false); if ($user['user_id'] == $staff_id) { $values = array_merge($user, $job_data); $values['job_url'] = module_job::link_public($job_id); $values['job_url'] .= (strpos($values['job_url'], '?') === false ? '?' : '&') . 'discuss=' . $task_id . '#discuss' . $task_id; $values['job_name'] = $job_data['name']; $values['staff_name'] = $user['name'] . ' ' . $user['last_name']; $values['note'] = $_POST['note']; //todo: no order if no showning numbers $values['task_name'] = '#' . $tasks[$task_id]['task_order'] . ': ' . $tasks[$task_id]['description']; $template = module_template::get_template_by_key('job_discussion_email_staff'); $template->assign_values($values); $html = $template->render('html'); $email = module_email::new_email(); $email->replace_values = $values; $email->set_to('user', $staff_id); $email->set_from('user', $current_user_id); $email->set_subject($template->description); // do we send images inline? $email->set_html($html); if ($email->send()) { // it worked successfully!! $result['email_staff'] = 1; } else { /// log err? $result['email_staff'] = 0; } } else { // log error? $result['email_staff'] = 0; } } } } $x = 0; while ($x++ < 5 && ob_get_level()) { ob_end_clean(); } header("Content-type: text/javascript", true); echo json_encode($result); exit; } $label = htmlspecialchars(module_config::c('job_discussion_button_label', 'Task Comments')); ?> <a href="<?php echo self::link_public($job_id, $task_id); ?> " id="discuss<?php echo $task_id; ?> " class="task_job_discussion <?php echo $label ? 'with_text' : ''; ?> " title="<?php _e('View Discussion'); ?> "><span><?php echo count($comments) > 0 ? count($comments) : ''; ?> </span><?php echo $label; ?> </a> <div class="task_job_discussion_holder"<?php echo isset($_REQUEST['discuss']) && $_REQUEST['discuss'] == $task_id ? ' style="display:block;"' : ''; ?> > <?php if (isset($_REQUEST['discuss']) && $_REQUEST['discuss'] == $task_id) { $_REQUEST['t'] = $task_id; $_REQUEST['i'] = $job_id; $_REQUEST['hash'] = self::link_public($job_id, $task_id, true); self::external_hook('public'); } ?> </div> <?php }
foreach ($staff_members as $staff_member) { $staff_member_rel[$staff_member['user_id']] = $staff_member['name']; } $c = array(); $customers = module_customer::get_customers(); foreach ($customers as $customer) { $c[$customer['customer_id']] = $customer['customer_name']; } if (count($c) == 1) { $job['customer_id'] = key($c); } // check permissions. if (class_exists('module_security', false)) { module_security::check_page(array('category' => 'Job', 'page_name' => 'Jobs', 'module' => 'job', 'feature' => 'create')); } $job_tasks = module_job::get_tasks($job_id); ?> <script type="text/javascript"> var completed_tasks_hidden = false; // set with session variable / cookie var editing_task_id = false; function show_completed_tasks(){ } function hide_completed_tasks(){ } function setamount(a,task_id){ var amount = 0; if(a.match(/:/)){
public static function get_statistics_staff($search) { $staff_members = module_user::get_staff_members(); $statistics = array(); foreach ($staff_members as $staff_member) { $statistics[$staff_member['user_id']] = array('user_id' => $staff_member['user_id'], 'job_ids' => array(), 'job_count' => 0, 'task_count' => 0, 'task_ids' => array(), 'task_complete_ids' => array(), 'tasks_complete' => 0, 'hours_logged' => 0, 'hours_billed' => 0, 'amount_billed' => 0, 'amount_invoiced' => 0); $sql = "SELECT COUNT(j.job_id) AS job_count "; $sql .= " FROM `" . _DB_PREFIX . "job` j"; $sql .= " WHERE j.user_id = " . (int) $staff_member['user_id']; if (isset($search['date_from']) && $search['date_from']) { $sql .= " AND j.date_start >= '" . input_date($search['date_from']) . "'"; } if (isset($search['date_to']) && $search['date_to']) { $sql .= " AND j.date_start <= '" . input_date($search['date_to']) . "'"; } $res = qa1($sql); $statistics[$staff_member['user_id']]['job_count'] = $res['job_count']; $sql = "SELECT COUNT(t.task_id) AS task_count "; $sql .= " FROM `" . _DB_PREFIX . "task` t"; $sql .= " LEFT JOIN `" . _DB_PREFIX . "job` j ON t.job_id = j.job_id"; $sql .= " WHERE 1"; $sql .= " AND t.user_id = " . (int) $staff_member['user_id']; if (isset($search['date_from']) && $search['date_from']) { $sql .= " AND j.date_start >= '" . input_date($search['date_from']) . "'"; } if (isset($search['date_to']) && $search['date_to']) { $sql .= " AND j.date_start <= '" . input_date($search['date_to']) . "'"; } $res = qa1($sql); $statistics[$staff_member['user_id']]['task_count'] = $res['task_count']; // tasks completed on this date: $sql = "SELECT COUNT(t.task_id) AS task_count "; $sql .= " FROM `" . _DB_PREFIX . "task` t"; $sql .= " LEFT JOIN `" . _DB_PREFIX . "job` j ON t.job_id = j.job_id"; $sql .= " WHERE 1"; $sql .= " AND t.user_id = " . (int) $staff_member['user_id']; if (isset($search['date_from']) && $search['date_from']) { $sql .= " AND t.date_done >= '" . input_date($search['date_from']) . "'"; } if (isset($search['date_to']) && $search['date_to']) { $sql .= " AND t.date_done <= '" . input_date($search['date_to']) . "'"; } $res = qa1($sql); $statistics[$staff_member['user_id']]['tasks_complete'] = $res['task_count']; $sql = "SELECT t.task_id, tl.date_created, t.hours AS task_hours, t.amount, tl.hours AS hours_logged, p.job_id, p.hourly_rate "; $sql .= ", tl.create_user_id AS logged_user_id"; $sql .= " FROM `" . _DB_PREFIX . "task_log` tl "; $sql .= " LEFT JOIN `" . _DB_PREFIX . "task` t ON tl.task_id = t.task_id "; $sql .= " LEFT JOIN `" . _DB_PREFIX . "job` p ON tl.job_id = p.job_id"; $sql .= " WHERE 1 "; $sql .= " AND ( tl.create_user_id = " . (int) $staff_member['user_id'] . " )"; //t.user_id = ".(int)$staff_member['user_id'] . " OR if (isset($search['date_from']) && $search['date_from']) { $sql .= " AND tl.log_time >= '" . strtotime(input_date($search['date_from']) . " 00:00:00") . "'"; } if (isset($search['date_to']) && $search['date_to']) { $sql .= " AND tl.log_time <= '" . strtotime(input_date($search['date_to']) . " 23:59:59") . "'"; } //echo $sql; $tasks = query($sql); while ($r = mysql_fetch_assoc($tasks)) { //print_r($r); $jobtasks = module_job::get_tasks($r['job_id']); $statistics[$staff_member['user_id']]['job_ids'][$r['job_id']] = true; $task = $jobtasks[$r['task_id']]; // this user has been assiged to this job individual task. if ($task['fully_completed']) { $statistics[$staff_member['user_id']]['task_complete_ids'][$r['task_id']] = true; $statistics[$staff_member['user_id']]['hours_billed'] += $r['task_hours']; if ($task['amount'] > 0) { $statistics[$staff_member['user_id']]['amount_billed'] += $task['amount']; } else { $statistics[$staff_member['user_id']]['amount_billed'] += $r['task_hours'] * $r['hourly_rate']; } $sql = "SELECT * FROM `" . _DB_PREFIX . "invoice_item` ii WHERE ii.task_id = " . (int) $r['task_id']; $task_invoice = qa1($sql); if ($task_invoice && $task_invoice['task_id'] == $r['task_id']) { if ($task_invoice['amount'] > 0) { $statistics[$staff_member['user_id']]['amount_invoiced'] += $task_invoice['amount']; } else { $statistics[$staff_member['user_id']]['amount_invoiced'] += $task_invoice['hours'] * $task_invoice['hourly_rate']; } } } $statistics[$staff_member['user_id']]['task_ids'][$r['task_id']] = true; $statistics[$staff_member['user_id']]['hours_logged'] += $r['hours_logged']; } //$statistics[$staff_member['user_id']]['job_count'] = count($statistics[$staff_member['user_id']]['job_ids']); } return $statistics; }
public function run_cron($debug = false) { // we only want to perform these cron actions if we're after a certain time of day // because we dont want to be generating these renewals and sending them at midnight, can get confusing $after_time = module_config::c('invoice_automatic_after_time', 7); $time_of_day = date('G'); if ($time_of_day < $after_time) { if ($debug) { echo "Not performing automatic invoice operations until after {$after_time}:00 - it is currently {$time_of_day}:" . date('i') . "<br>\n"; } return; } // find automatic job renewals $sql = "SELECT p.* FROM `" . _DB_PREFIX . "job` p "; $sql .= " WHERE p.date_renew != '0000-00-00'"; $sql .= " AND p.date_start != '0000-00-00'"; $sql .= " AND p.date_renew <= '" . date('Y-m-d') . "'"; $sql .= " AND (p.renew_job_id IS NULL OR p.renew_job_id = 0)"; $sql .= " AND (p.renew_auto = 1)"; $renew_jobs = qa($sql); foreach ($renew_jobs as $renew_job) { // time to automatically renew this job! woo! if ($debug) { echo "Automatically Renewing Job " . module_job::link_open($renew_job['job_id'], true) . "<br>\n"; } //$job_details = $this->get_job($renew_job['job_id']); $job_invoices = module_invoice::get_invoices(array('job_id' => $renew_job['job_id'])); $unpaid_invoice = false; foreach ($job_invoices as $job_invoice) { $job_invoice = module_invoice::get_invoice($job_invoice['invoice_id']); if ($job_invoice['total_amount_due'] > 0) { $unpaid_invoice = true; } } if (module_config::c('invoice_auto_renew_only_paid_invoices', 1) && $unpaid_invoice) { if ($debug) { echo "Not automatically renewing this job because it has unpaid invoices. <br>\n"; } } else { $new_job_id = $this->renew_job($renew_job['job_id'], true); if ($new_job_id) { //module_cache::clear_cache(); if ($debug) { echo "Job Automatically Renewed: " . module_job::link_open($new_job_id, true) . "<br>\n"; } if ($renew_job['renew_invoice']) { // we want to tick all these tasks off and invoice this job, then send this invoice to the customer. $job_tasks = module_job::get_tasks($new_job_id); foreach ($job_tasks as $job_task_id => $job_task) { $job_tasks[$job_task_id]['fully_completed_t'] = 1; $job_tasks[$job_task_id]['fully_completed'] = 1; } $this->save_job_tasks($new_job_id, array('job_task' => $job_tasks)); //module_cache::clear_cache(); // generate an invoice for this job. $_REQUEST['job_id'] = $new_job_id; $new_invoice = module_invoice::get_invoice('new'); $new_invoice['date_create'] = $renew_job['date_renew']; $new_invoice['invoice_invoice_item'] = module_invoice::get_invoice_items('new', $new_invoice); $new_invoice_id = module_invoice::save_invoice('new', $new_invoice); //module_cache::clear_cache(); if ($debug) { echo "Generated new invoice for renewed job: " . module_invoice::link_open($new_invoice_id, true) . "<br/>"; } if ($debug) { echo "Emailing invoice to customer..."; } if (module_invoice::email_invoice_to_customer($new_invoice_id)) { if ($debug) { echo "send successfully"; } } else { if ($debug) { echo "send failed"; } } if ($debug) { echo "<br>\n"; } } } } } }
?> </th> <th><?php _e('Task %%'); ?> </th> <th><?php _e('Amount'); ?> </th> </tr> </thead> <tbody> <?php foreach ($res as $r) { $tasks = module_job::get_tasks($r['job_id']); $task = $tasks[$r['task_id']]; if (!$task) { continue; } if (!isset($task['manual_task_type']) || $task['manual_task_type'] < 0) { $task['manual_task_type'] = $task['default_task_type']; } $foo = $r['task_name']; if (strlen($foo) > 20) { $foo = substr($foo, 0, 20) . '...'; } // we have to find if the user has logged more or less or exactly the same amount of hours // for this task. // eg: they could log 2 hours against a 1 hour task // eg: they could log 0.1 hours against a 1 hour task
_e('Done Date'); ?> </th> <?php } ?> <th nowrap="nowrap">%</th> <th nowrap="nowrap"><?php _e('Invoiced'); ?> </th> </tr> </thead> <?php $c = 0; foreach (module_job::get_tasks($job_id) as $task_id => $task_data) { $c++; // todo-move this into a method so we can update it via ajax. $percentage = module_job::get_percentage($task_data); $task_due_time = strtotime($task_data['date_due']); if (!isset($task_data['manual_task_type']) || $task_data['manual_task_type'] < 0) { $task_data['manual_task_type'] = $job_data['default_task_type']; } ?> <tbody id="task_preview_<?php echo $task_id; ?> " class="task_preview"> <tr class="<?php echo $c % 2 ? 'odd' : 'even';
public static function get_website($website_id) { $website = get_single("website", "website_id", $website_id); if ($website) { switch (module_customer::get_customer_data_access()) { case _CUSTOMER_ACCESS_ALL: // all customers! so this means all jobs! break; case _CUSTOMER_ACCESS_ALL_COMPANY: case _CUSTOMER_ACCESS_CONTACTS: case _CUSTOMER_ACCESS_STAFF: $valid_customer_ids = module_security::get_customer_restrictions(); $is_valid_website = isset($valid_customer_ids[$website['customer_id']]); if (!$is_valid_website) { $website = false; } break; case _CUSTOMER_ACCESS_TASKS: // only customers who have linked jobs that I am assigned to. $has_job_access = false; if (isset($website['customer_id']) && $website['customer_id']) { $jobs = module_job::get_jobs(array('customer_id' => $website['customer_id'])); foreach ($jobs as $job) { if ($job['user_id'] == module_security::get_loggedin_id()) { $has_job_access = true; break; } $tasks = module_job::get_tasks($job['job_id']); foreach ($tasks as $task) { if ($task['user_id'] == module_security::get_loggedin_id()) { $has_job_access = true; break; } } } } if (!$has_job_access) { $website = false; } break; } } if (!$website) { $website = array('website_id' => 'new', 'customer_id' => isset($_REQUEST['customer_id']) ? $_REQUEST['customer_id'] : 0, 'name' => '', 'status' => module_config::s('website_status_default', 'New'), 'url' => ''); } return $website; }