diff --git a/application/controllers/Sales.php b/application/controllers/Sales.php index b3aaadb36..14655839c 100644 --- a/application/controllers/Sales.php +++ b/application/controllers/Sales.php @@ -4,6 +4,7 @@ require_once("Secure_Controller.php"); define('PRICE_MODE_STANDARD', 0); define('PRICE_MODE_KIT', 1); +define('PAYMENT_TYPE_UNASSIGNED', '--'); class Sales extends Secure_Controller { @@ -1166,6 +1167,11 @@ class Sales extends Secure_Controller $data['selected_customer_name'] = $sale_info['customer_name']; $data['selected_customer_id'] = $sale_info['customer_id']; $data['sale_info'] = $sale_info; + $balance_due = $sale_info['amount_due'] - $sale_info['amount_tendered']; + if($balance_due < 0) + { + $balance_due = 0; + } $data['payments'] = array(); foreach($this->Sale->get_sale_payments($sale_id)->result() as $payment) @@ -1177,8 +1183,19 @@ class Sales extends Secure_Controller $data['payments'][] = $payment; } + $data['payment_type_new'] = PAYMENT_TYPE_UNASSIGNED; + $data['payment_amount_new'] = $balance_due; + + $data['balance_due'] = $balance_due != 0; + // don't allow gift card to be a payment option in a sale transaction edit because it's a complex change $data['payment_options'] = $this->xss_clean($this->Sale->get_payment_options(FALSE)); + + // Set up a slightly modified list of payment types for new payment entry + $new_payment_options = $this->Sale->get_payment_options(FALSE); + $new_payment_options["--"] = $this->lang->line('common_none_selected_text'); + $data['new_payment_options'] = $this->xss_clean($new_payment_options); + $this->load->view('sales/form', $data); } @@ -1240,6 +1257,7 @@ class Sales extends Secure_Controller public function save($sale_id = -1) { $newdate = $this->input->post('date'); + $employee_id = $this->Employee->get_logged_in_employee_info()->person_id; $date_formatter = date_create_from_format($this->config->item('dateformat') . ' ' . $this->config->item('timeformat'), $newdate); @@ -1251,39 +1269,28 @@ class Sales extends Secure_Controller 'invoice_number' => $this->input->post('invoice_number') != '' ? $this->input->post('invoice_number') : NULL ); - // go through all the payment type input from the form, make sure the form matches the name and iterator number + // In order to maintain tradition the only element that can change on prior payments is the payment type $payments = array(); $number_of_payments = $this->input->post('number_of_payments'); for($i = 0; $i < $number_of_payments; ++$i) { + $payment_id = $this->input->post('payment_id_' . $i); $payment_amount = $this->input->post('payment_amount_' . $i); $payment_type = $this->input->post('payment_type_' . $i); - // remove any 0 payment if by mistake any was introduced at sale time - if($payment_amount != 0) - { - // search for any payment of the same type that was already added, if that's the case add up the new payment amount - $key = FALSE; - if(!empty($payments)) - { - // search in the multi array the key of the entry containing the current payment_type - // NOTE: in PHP5.5 the array_map could be replaced by an array_column - $key = array_search($payment_type, array_map(function ($v) - { - return $v['payment_type']; - }, $payments)); - } - // if no previous payment is found add a new one - if($key === FALSE) - { - $payments[] = array('payment_type' => $payment_type, 'payment_amount' => $payment_amount); - } - else - { - // add up the new payment amount to an existing payment type - $payments[$key]['payment_amount'] += $payment_amount; - } - } + // To maintain tradition we will also delete any payments with 0 amount assuming these are mistakes + // introduced at sale time. This is now done in Sale.php + + $payments[] = array('payment_id' => $payment_id, 'payment_type' => $payment_type, 'payment_amount' => $payment_amount, 'payment_user' => $employee_id); + } + + $payment_id = -1; + $payment_amount = $this->input->post('payment_amount_new'); + $payment_type = $this->input->post('payment_type_new'); + + if($payment_type != PAYMENT_TYPE_UNASSIGNED && $payment_amount <> 0) + { + $payments[] = array('payment_id' => $payment_id, 'payment_type' => $payment_type, 'payment_amount' => $payment_amount, 'payment_user' => $employee_id); } if($this->Sale->update($sale_id, $sale_data, $payments)) @@ -1480,7 +1487,7 @@ class Sales extends Secure_Controller { foreach($array as $key => $val) { - if ($val['item_id'] === $id) + if($val['item_id'] === $id) { return $key; } diff --git a/application/libraries/Sale_lib.php b/application/libraries/Sale_lib.php index 5263c87de..a9f65ed4f 100644 --- a/application/libraries/Sale_lib.php +++ b/application/libraries/Sale_lib.php @@ -485,15 +485,18 @@ class Sale_lib $totals['prediscount_subtotal'] = $prediscount_subtotal; $totals['total_discount'] = $total_discount; $totals['subtotal'] = $subtotal; + $sales_tax = 0; foreach($taxes as $tax_excluded) { if($tax_excluded['tax_type'] == Tax_lib::TAX_TYPE_EXCLUDED) { $total = bcadd($total, $tax_excluded['sale_tax_amount']); + $sales_tax = bcadd($sales_tax, $tax_excluded['sale_tax_amount']); } } $totals['total'] = $total; + $totals['tax_total'] = $sales_tax; if($cash_rounding) { diff --git a/application/migrations/20190427100000_paymenttracking.php b/application/migrations/20190427100000_paymenttracking.php new file mode 100644 index 000000000..430d4891b --- /dev/null +++ b/application/migrations/20190427100000_paymenttracking.php @@ -0,0 +1,20 @@ + diff --git a/application/migrations/sqlscripts/3.3.0_paymenttracking.sql b/application/migrations/sqlscripts/3.3.0_paymenttracking.sql new file mode 100644 index 000000000..84870add8 --- /dev/null +++ b/application/migrations/sqlscripts/3.3.0_paymenttracking.sql @@ -0,0 +1,26 @@ +-- Improve payment tracking + +RENAME TABLE ospos_sales_payments TO ospos_sales_payments_backup; + +CREATE TABLE `ospos_sales_payments` ( + `payment_id` int(11) NOT NULL AUTO_INCREMENT, + `sale_id` int(10) NOT NULL, + `payment_type` varchar(40) NOT NULL, + `payment_amount` decimal(15,2) NOT NULL, + `payment_user` int(11) NOT NULL DEFAULT 0, + `payment_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `reference_code` varchar(40) NOT NULL DEFAULT '', + PRIMARY KEY (`payment_id`), + KEY `payment_sale` (`sale_id`, `payment_type`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +INSERT INTO ospos_sales_payments (sale_id, payment_type, payment_amount, payment_user) +SELECT payments.sale_id, payments.payment_type, payments.payment_amount, sales.employee_id +FROM ospos_sales_payments_backup AS payments +JOIN ospos_sales AS sales ON payments.sale_id = sales.sale_id +ORDER BY payments.sale_id, payments.payment_type; + +DROP TABLE IF EXISTS ospos_sales_payments_backup; + +ALTER TABLE `ospos_sales_payments` + ADD CONSTRAINT `ospos_sales_payments_ibfk_1` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales` (`sale_id`); diff --git a/application/models/Sale.php b/application/models/Sale.php index 9086bda44..e649a8ff3 100644 --- a/application/models/Sale.php +++ b/application/models/Sale.php @@ -538,19 +538,43 @@ class Sale extends CI_Model //Run these queries as a transaction, we want to make sure we do all or nothing $this->db->trans_start(); - // first delete all payments - $this->db->delete('sales_payments', array('sale_id' => $sale_id)); - // add new payments foreach($payments as $payment) { - $sales_payments_data = array( - 'sale_id' => $sale_id, - 'payment_type' => $payment['payment_type'], - 'payment_amount' => $payment['payment_amount'] - ); + $payment_id = $payment['payment_id']; + $payment_type = $payment['payment_type']; + $payment_amount = $payment['payment_amount']; + $payment_user = $payment['payment_user']; - $success = $this->db->insert('sales_payments', $sales_payments_data); + if($payment_id == - 1 && $payment_amount > 0) + { + // Add a new payment transaction + $sales_payments_data = array( + 'sale_id' => $sale_id, + 'payment_type' => $payment_type, + 'payment_amount' => $payment_amount, + 'payment_user' => $payment_user + ); + $success = $this->db->insert('sales_payments', $sales_payments_data); + } + + if($payment_id != - 1) + { + if($payment_amount > 0) + { + // Update existing payment transactions (payment_type only) + $sales_payments_data = array( + 'payment_type' => $payment_type + ); + $this->db->where('payment_id',$payment_id); + $success = $this->db->update('sales_payments', $sales_payments_data); + } + else + { + // Remove existing payment transactions with a payment amount of zero + $success = $this->db->delete('sales_payments', array('payment_id' => $payment_id)); + } + } } $this->db->trans_complete(); @@ -633,9 +657,12 @@ class Sale extends CI_Model $sales_payments_data = array( 'sale_id' => $sale_id, 'payment_type' => $payment['payment_type'], - 'payment_amount' => $payment['payment_amount'] + 'payment_amount' => $payment['payment_amount'], + 'payment_user' => $employee_id ); + $this->db->insert('sales_payments', $sales_payments_data); + $total_amount = floatval($total_amount) + floatval($payment['payment_amount']); } diff --git a/application/models/reports/Summary_payments.php b/application/models/reports/Summary_payments.php index 1f4bc3f13..7c160e76b 100644 --- a/application/models/reports/Summary_payments.php +++ b/application/models/reports/Summary_payments.php @@ -162,8 +162,8 @@ class Summary_payments extends Summary_report ); $this->db->query('UPDATE ' . $this->db->dbprefix('sumpay_items_temp') . ' AS sumpay_items ' - . 'SET trans_amount = trans_amount + (SELECT total_taxes FROM ' . $this->db->dbprefix('sumpay_taxes_temp') - . ' AS sumpay_taxes WHERE sumpay_items.sale_id = sumpay_taxes.sale_id)'); + . 'SET trans_amount = trans_amount + IFNULL((SELECT total_taxes FROM ' . $this->db->dbprefix('sumpay_taxes_temp') + . ' AS sumpay_taxes WHERE sumpay_items.sale_id = sumpay_taxes.sale_id),0)'); $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->dbprefix('sumpay_payments_temp') . ' (INDEX(sale_id)) diff --git a/application/views/sales/form.php b/application/views/sales/form.php index d873721aa..35561e39c 100755 --- a/application/views/sales/form.php +++ b/application/views/sales/form.php @@ -15,7 +15,7 @@ 'date','value'=>to_datetime(strtotime($sale_info['sale_time'])), 'class'=>'datetime form-control input-sm'));?> - + config->item('invoice_enable') == TRUE) { @@ -35,6 +35,31 @@ } ?> + +