mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-10-22 16:24:41 -04:00
Merge pull request #3026 from opensourcepos/cash-rounding-register
Correct issues with cash rounding.
This commit is contained in:
9 files changed
+291
-95
No files matched your search
@@ -144,3 +144,13 @@ define('SALE_TYPE_RETURN', 4);
|
||||
|
||||
define('PERCENT', 0);
|
||||
define('FIXED', 1);
|
||||
|
||||
define('PRICE_MODE_STANDARD', 0);
|
||||
define('PRICE_MODE_KIT', 1);
|
||||
|
||||
define('PAYMENT_TYPE_UNASSIGNED', '--');
|
||||
|
||||
define('CASH_ADJUSTMENT_TRUE', 1);
|
||||
define('CASH_ADJUSTMENT_FALSE', 0);
|
||||
define('CASH_MODE_TRUE', 1);
|
||||
define('CASH_MODE_FALSE', 0);
|
||||
@@ -2,10 +2,6 @@
|
||||
|
||||
require_once("Secure_Controller.php");
|
||||
|
||||
define('PRICE_MODE_STANDARD', 0);
|
||||
define('PRICE_MODE_KIT', 1);
|
||||
define('PAYMENT_TYPE_UNASSIGNED', '--');
|
||||
|
||||
class Sales extends Secure_Controller
|
||||
{
|
||||
public function __construct()
|
||||
@@ -263,7 +259,7 @@ class Sales extends Secure_Controller
|
||||
$data = array();
|
||||
|
||||
$payment_type = $this->input->post('payment_type');
|
||||
if($payment_type != $this->lang->line('sales_giftcard'))
|
||||
if($payment_type !== $this->lang->line('sales_giftcard'))
|
||||
{
|
||||
$this->form_validation->set_rules('amount_tendered', 'lang:sales_amount_tendered', 'trim|required|callback_numeric');
|
||||
}
|
||||
@@ -274,7 +270,7 @@ class Sales extends Secure_Controller
|
||||
|
||||
if($this->form_validation->run() == FALSE)
|
||||
{
|
||||
if($payment_type == $this->lang->line('sales_giftcard'))
|
||||
if($payment_type === $this->lang->line('sales_giftcard'))
|
||||
{
|
||||
$data['error'] = $this->lang->line('sales_must_enter_numeric_giftcard');
|
||||
}
|
||||
@@ -285,7 +281,7 @@ class Sales extends Secure_Controller
|
||||
}
|
||||
else
|
||||
{
|
||||
if($payment_type == $this->lang->line('sales_giftcard'))
|
||||
if($payment_type === $this->lang->line('sales_giftcard'))
|
||||
{
|
||||
// in case of giftcard payment the register input amount_tendered becomes the giftcard number
|
||||
$giftcard_num = $this->input->post('amount_tendered');
|
||||
@@ -316,7 +312,7 @@ class Sales extends Secure_Controller
|
||||
$this->sale_lib->add_payment($payment_type, $amount_tendered);
|
||||
}
|
||||
}
|
||||
elseif($payment_type == $this->lang->line('sales_rewards'))
|
||||
elseif($payment_type === $this->lang->line('sales_rewards'))
|
||||
{
|
||||
$customer_id = $this->sale_lib->get_customer();
|
||||
$package_id = $this->Customer->get_info($customer_id)->package_id;
|
||||
@@ -348,6 +344,20 @@ class Sales extends Secure_Controller
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif($payment_type === $this->lang->line('sales_cash'))
|
||||
{
|
||||
$amount_due = $this->sale_lib->get_total();
|
||||
$sales_total = $this->sale_lib->get_total(FALSE);
|
||||
|
||||
$amount_tendered = $this->input->post('amount_tendered');
|
||||
$this->sale_lib->add_payment($payment_type, $amount_tendered);
|
||||
$cash_adjustment_amount = $amount_due - $sales_total;
|
||||
if($cash_adjustment_amount <> 0)
|
||||
{
|
||||
$this->session->set_userdata('cash_mode', CASH_MODE_TRUE);
|
||||
$this->sale_lib->add_payment($this->lang->line('sales_cash_adjustment'), $cash_adjustment_amount, CASH_ADJUSTMENT_TRUE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$amount_tendered = $this->input->post('amount_tendered');
|
||||
@@ -571,22 +581,22 @@ class Sales extends Secure_Controller
|
||||
$data['payments_total'] = $totals['payment_total'];
|
||||
$data['payments_cover_total'] = $totals['payments_cover_total'];
|
||||
$data['cash_rounding'] = $this->session->userdata('cash_rounding');
|
||||
$data['cash_mode'] = $this->session->userdata('cash_mode');
|
||||
$data['prediscount_subtotal'] = $totals['prediscount_subtotal'];
|
||||
$data['cash_total'] = $totals['cash_total'];
|
||||
$data['non_cash_total'] = $totals['total'];
|
||||
$data['cash_amount_due'] = $totals['cash_amount_due'];
|
||||
$data['non_cash_amount_due'] = $totals['amount_due'];
|
||||
|
||||
if($data['cash_rounding'])
|
||||
if($data['cash_mode'])
|
||||
{
|
||||
$data['total'] = $totals['cash_total'];
|
||||
$data['amount_due'] = $totals['cash_amount_due'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$data['total'] = $totals['total'];
|
||||
$data['amount_due'] = $totals['amount_due'];
|
||||
}
|
||||
|
||||
$data['amount_change'] = $data['amount_due'] * -1;
|
||||
|
||||
if($data['amount_change'] > 0)
|
||||
@@ -609,6 +619,7 @@ class Sales extends Secure_Controller
|
||||
if($this->sale_lib->is_invoice_mode())
|
||||
{
|
||||
$invoice_format = $this->config->item('sales_invoice_format');
|
||||
|
||||
// generate final invoice number (if using the invoice in sales by receipt mode then the invoice number can be manually entered or altered in some way
|
||||
if(!empty($invoice_format) && $invoice_number == NULL)
|
||||
{
|
||||
@@ -787,6 +798,7 @@ class Sales extends Secure_Controller
|
||||
|
||||
// generate email attachment: invoice in pdf format
|
||||
$html = $this->load->view("sales/" . $type . "_email", $sale_data, TRUE);
|
||||
|
||||
// load pdf helper
|
||||
$this->load->helper(array('dompdf', 'file'));
|
||||
$filename = sys_get_temp_dir() . '/' . $this->lang->line("sales_" . $type) . '-' . str_replace('/', '-', $number) . '.pdf';
|
||||
@@ -903,7 +915,9 @@ class Sales extends Secure_Controller
|
||||
private function _load_sale_data($sale_id)
|
||||
{
|
||||
$this->sale_lib->clear_all();
|
||||
$this->sale_lib->reset_cash_flags();
|
||||
$cash_rounding = $this->sale_lib->reset_cash_rounding();
|
||||
$data['cash_rounding'] = $cash_rounding;
|
||||
|
||||
$sale_info = $this->Sale->get_info($sale_id)->row_array();
|
||||
$this->sale_lib->copy_entire_sale($sale_id);
|
||||
$data = array();
|
||||
@@ -922,18 +936,18 @@ class Sales extends Secure_Controller
|
||||
|
||||
// Returns 'subtotal', 'total', 'cash_total', 'payment_total', 'amount_due', 'cash_amount_due', 'payments_cover_total'
|
||||
$totals = $this->sale_lib->get_totals($tax_details[0]);
|
||||
$this->session->set_userdata('cash_adjustment_amount', $totals['cash_adjustment_amount']);
|
||||
$data['subtotal'] = $totals['subtotal'];
|
||||
$data['total'] = $totals['total'];
|
||||
$data['payments_total'] = $totals['payment_total'];
|
||||
$data['payments_cover_total'] = $totals['payments_cover_total'];
|
||||
$data['cash_rounding'] = $this->session->userdata('cash_rounding');
|
||||
$data['cash_mode'] = $this->session->userdata('cash_mode');
|
||||
$data['prediscount_subtotal'] = $totals['prediscount_subtotal'];
|
||||
$data['cash_total'] = $totals['cash_total'];
|
||||
$data['non_cash_total'] = $totals['total'];
|
||||
$data['cash_amount_due'] = $totals['cash_amount_due'];
|
||||
$data['non_cash_amount_due'] = $totals['amount_due'];
|
||||
|
||||
if($this->session->userdata('cash_rounding'))
|
||||
if($data['cash_mode'] && ($data['selected_payment_type'] === $this->lang->line('sales_cash') || $data['payments_total'] > 0))
|
||||
{
|
||||
$data['total'] = $totals['cash_total'];
|
||||
$data['amount_due'] = $totals['cash_amount_due'];
|
||||
@@ -943,6 +957,7 @@ class Sales extends Secure_Controller
|
||||
$data['total'] = $totals['total'];
|
||||
$data['amount_due'] = $totals['amount_due'];
|
||||
}
|
||||
|
||||
$data['amount_change'] = $data['amount_due'] * -1;
|
||||
|
||||
$employee_info = $this->Employee->get_info($this->sale_lib->get_employee());
|
||||
@@ -1013,6 +1028,11 @@ class Sales extends Secure_Controller
|
||||
$sale_id = -1;
|
||||
$this->session->set_userdata('sale_id', -1);
|
||||
}
|
||||
$cash_rounding = $this->sale_lib->reset_cash_rounding();
|
||||
|
||||
// cash_rounding indicates only that the site is configured for cash rounding
|
||||
$data['cash_rounding'] = $cash_rounding;
|
||||
|
||||
$data['cart'] = $this->sale_lib->get_cart();
|
||||
$customer_info = $this->_load_customer_data($this->sale_lib->get_customer(), $data, TRUE);
|
||||
|
||||
@@ -1027,22 +1047,29 @@ class Sales extends Secure_Controller
|
||||
$data['taxes'] = $tax_details[0];
|
||||
$data['discount'] = $this->sale_lib->get_discount();
|
||||
$data['payments'] = $this->sale_lib->get_payments();
|
||||
|
||||
// Returns 'subtotal', 'total', 'cash_total', 'payment_total', 'amount_due', 'cash_amount_due', 'payments_cover_total'
|
||||
$totals = $this->sale_lib->get_totals($tax_details[0]);
|
||||
|
||||
$data['item_count'] = $totals['item_count'];
|
||||
$data['total_units'] = $totals['total_units'];
|
||||
$data['subtotal'] = $totals['subtotal'];
|
||||
$data['total'] = $totals['total'];
|
||||
$data['payments_total'] = $totals['payment_total'];
|
||||
$data['payments_cover_total'] = $totals['payments_cover_total'];
|
||||
$data['cash_rounding'] = $this->session->userdata('cash_rounding');
|
||||
|
||||
// cash_mode indicates whether this sale is going to be processed using cash_rounding
|
||||
$cash_mode = $this->session->userdata('cash_mode');
|
||||
$data['cash_mode'] = $cash_mode;
|
||||
$data['prediscount_subtotal'] = $totals['prediscount_subtotal'];
|
||||
$data['cash_total'] = $totals['cash_total'];
|
||||
$data['non_cash_total'] = $totals['total'];
|
||||
$data['cash_amount_due'] = $totals['cash_amount_due'];
|
||||
$data['non_cash_amount_due'] = $totals['amount_due'];
|
||||
|
||||
if($data['cash_rounding'])
|
||||
$data['selected_payment_type'] = $this->sale_lib->get_payment_type();
|
||||
|
||||
if($data['cash_mode'] && ($data['selected_payment_type'] == $this->lang->line('sales_cash') || $data['payments_total'] > 0))
|
||||
{
|
||||
$data['total'] = $totals['cash_total'];
|
||||
$data['amount_due'] = $totals['cash_amount_due'];
|
||||
@@ -1052,11 +1079,12 @@ class Sales extends Secure_Controller
|
||||
$data['total'] = $totals['total'];
|
||||
$data['amount_due'] = $totals['amount_due'];
|
||||
}
|
||||
|
||||
$data['amount_change'] = $data['amount_due'] * -1;
|
||||
|
||||
$data['comment'] = $this->sale_lib->get_comment();
|
||||
$data['email_receipt'] = $this->sale_lib->is_email_receipt();
|
||||
$data['selected_payment_type'] = $this->sale_lib->get_payment_type();
|
||||
|
||||
if($customer_info && $this->config->item('customer_reward_enable') == TRUE)
|
||||
{
|
||||
$data['payment_options'] = $this->Sale->get_payment_options(TRUE, TRUE);
|
||||
@@ -1143,8 +1171,8 @@ class Sales extends Secure_Controller
|
||||
$data['selected_employee_id'] = $sale_info['employee_id'];
|
||||
$data['selected_employee_name'] = $this->xss_clean($employee_info->first_name . ' ' . $employee_info->last_name);
|
||||
$data['sale_info'] = $sale_info;
|
||||
$balance_due = $sale_info['amount_due'] - $sale_info['amount_tendered'];
|
||||
if($balance_due < 0)
|
||||
$balance_due = round($sale_info['amount_due'] - $sale_info['amount_tendered'] + $sale_info['cash_refund'], totals_decimals(), PHP_ROUND_HALF_UP);
|
||||
if(!$this->sale_lib->reset_cash_rounding() && $balance_due < 0)
|
||||
{
|
||||
$balance_due = 0;
|
||||
}
|
||||
@@ -1165,12 +1193,19 @@ class Sales extends Secure_Controller
|
||||
$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
|
||||
$new_payment_options = $this->xss_clean($this->Sale->get_payment_options(FALSE));
|
||||
$data['payment_options'] = $new_payment_options;
|
||||
$payment_options = $this->Sale->get_payment_options(FALSE);
|
||||
|
||||
if($this->sale_lib->reset_cash_rounding())
|
||||
{
|
||||
$payment_options[$this->lang->line('sales_cash_adjustment')] = $this->lang->line('sales_cash_adjustment');
|
||||
}
|
||||
|
||||
$data['payment_options'] = $this->xss_clean($payment_options);
|
||||
|
||||
// Set up a slightly modified list of payment types for new payment entry
|
||||
$new_payment_options["--"] = $this->lang->line('common_none_selected_text');
|
||||
$data['new_payment_options'] = $new_payment_options;
|
||||
$payment_options["--"] = $this->lang->line('common_none_selected_text');
|
||||
|
||||
$data['new_payment_options'] = $this->xss_clean($payment_options);
|
||||
|
||||
$this->load->view('sales/form', $data);
|
||||
}
|
||||
@@ -1248,6 +1283,7 @@ class Sales extends Secure_Controller
|
||||
|
||||
// In order to maintain tradition the only element that can change on prior payments is the payment type
|
||||
$payments = array();
|
||||
$amount_tendered = 0;
|
||||
$number_of_payments = $this->input->post('number_of_payments');
|
||||
for($i = 0; $i < $number_of_payments; ++$i)
|
||||
{
|
||||
@@ -1257,6 +1293,20 @@ class Sales extends Secure_Controller
|
||||
$refund_type = $this->input->post('refund_type_' . $i);
|
||||
$cash_refund = $this->input->post('refund_amount_' . $i);
|
||||
|
||||
if($payment_type == $this->lang->line('sales_cash_adjustment'))
|
||||
{
|
||||
$cash_adjustment = CASH_ADJUSTMENT_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
$cash_adjustment = CASH_ADJUSTMENT_FALSE;
|
||||
}
|
||||
|
||||
if(!$cash_adjustment)
|
||||
{
|
||||
$amount_tendered += $payment_amount - $cash_refund;
|
||||
}
|
||||
|
||||
// if the refund is not cash ...
|
||||
if(empty(strstr($refund_type, $this->lang->line('sales_cash'))))
|
||||
{
|
||||
@@ -1270,11 +1320,8 @@ class Sales extends Secure_Controller
|
||||
}
|
||||
}
|
||||
|
||||
// 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 models/Sale.php
|
||||
|
||||
$payments[] = array('payment_id' => $payment_id, 'payment_type' => $payment_type, 'payment_amount' => $payment_amount, 'cash_refund' => $cash_refund, 'employee_id' => $employee_id);
|
||||
$payments[] = array('payment_id' => $payment_id, 'payment_type' => $payment_type, 'payment_amount' => $payment_amount, 'cash_refund' => $cash_refund, 'cash_adjustment' => $cash_adjustment, 'employee_id' => $employee_id);
|
||||
}
|
||||
|
||||
$payment_id = -1;
|
||||
@@ -1283,7 +1330,24 @@ class Sales extends Secure_Controller
|
||||
|
||||
if($payment_type != PAYMENT_TYPE_UNASSIGNED && $payment_amount <> 0)
|
||||
{
|
||||
$payments[] = array('payment_id' => $payment_id, 'payment_type' => $payment_type, 'payment_amount' => $payment_amount, 'cash_refund' => 0.00, 'employee_id' => $employee_id);
|
||||
$cash_refund = 0;
|
||||
if($payment_type == $this->lang->line('sales_cash_adjustment'))
|
||||
{
|
||||
$cash_adjustment = CASH_ADJUSTMENT_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
$cash_adjustment = CASH_ADJUSTMENT_FALSE;
|
||||
$amount_tendered += $payment_amount;
|
||||
$sale_info = $this->Sale->get_info($sale_id)->row_array();
|
||||
|
||||
if($amount_tendered > $sale_info['amount_due'])
|
||||
{
|
||||
$cash_refund = $amount_tendered - $sale_info['amount_due'];
|
||||
}
|
||||
}
|
||||
|
||||
$payments[] = array('payment_id' => $payment_id, 'payment_type' => $payment_type, 'payment_amount' => $payment_amount, 'cash_refund' => $cash_refund, 'cash_adjustment' => $cash_adjustment, 'employee_id' => $employee_id);
|
||||
}
|
||||
|
||||
$this->Inventory->update('POS '.$sale_id, ['trans_date' => $sale_time]);
|
||||
|
||||
@@ -10,6 +10,7 @@ $lang["sales_amount_tendered"] = "Amount Tendered";
|
||||
$lang["sales_authorized_signature"] = "Authorised Signature";
|
||||
$lang["sales_cancel_sale"] = "Cancel";
|
||||
$lang["sales_cash"] = "Cash";
|
||||
$lang["sales_cash_adjustment"] = "Cash Adjustment";
|
||||
$lang["sales_cash_deposit"] = "Cash Deposit";
|
||||
$lang["sales_cash_filter"] = "Cash";
|
||||
$lang["sales_change_due"] = "Change Due";
|
||||
|
||||
@@ -10,6 +10,7 @@ $lang["sales_amount_tendered"] = "Amount Tendered";
|
||||
$lang["sales_authorized_signature"] = "Authorized Signature";
|
||||
$lang["sales_cancel_sale"] = "Cancel";
|
||||
$lang["sales_cash"] = "Cash";
|
||||
$lang["sales_cash_adjustment"] = "Cash Adjustment";
|
||||
$lang["sales_cash_deposit"] = "Cash Deposit";
|
||||
$lang["sales_cash_filter"] = "Cash";
|
||||
$lang["sales_change_due"] = "Change Due";
|
||||
|
||||
@@ -366,8 +366,14 @@ class Sale_lib
|
||||
$this->CI->session->set_userdata('sales_payments', $payments_data);
|
||||
}
|
||||
|
||||
// Multiple Payments
|
||||
public function add_payment($payment_id, $payment_amount)
|
||||
/**
|
||||
* Adds a new payment to the payments array or updates an existing one.
|
||||
* It will also disable cash_mode if an non-qualifying payment type is added.
|
||||
* @param $payment_id
|
||||
* @param $payment_amount
|
||||
* @param int $cash_adjustment
|
||||
*/
|
||||
public function add_payment($payment_id, $payment_amount, $cash_adjustment = CASH_ADJUSTMENT_FALSE)
|
||||
{
|
||||
$payments = $this->get_payments();
|
||||
if(isset($payments[$payment_id]))
|
||||
@@ -378,11 +384,20 @@ class Sale_lib
|
||||
else
|
||||
{
|
||||
//add to existing array
|
||||
$payment = array($payment_id => array('payment_type' => $payment_id, 'payment_amount' => $payment_amount, 'cash_refund' => 0));
|
||||
$payment = array($payment_id => array('payment_type' => $payment_id, 'payment_amount' => $payment_amount,
|
||||
'cash_refund' => 0, 'cash_adjustment' => $cash_adjustment));
|
||||
|
||||
$payments += $payment;
|
||||
}
|
||||
|
||||
if($this->CI->session->userdata('cash_mode'))
|
||||
{
|
||||
if($this->CI->session->userdata('cash_rounding') && $payment_id != $this->CI->lang->line('sales_cash') && $payment_id != $this->CI->lang->line('sales_cash_adjustment'))
|
||||
{
|
||||
$this->CI->session->set_userdata('cash_mode', CASH_MODE_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
$this->set_payments($payments);
|
||||
}
|
||||
|
||||
@@ -402,11 +417,28 @@ class Sale_lib
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Multiple Payments
|
||||
/**
|
||||
* Delete the selected payment from the payment array and if cash rounding is enabled
|
||||
* and the payment type is one of the cash types then automatically delete the other
|
||||
* @param $payment_id
|
||||
*/
|
||||
public function delete_payment($payment_id)
|
||||
{
|
||||
$payments = $this->get_payments();
|
||||
unset($payments[urldecode($payment_id)]);
|
||||
$decoded_payment_id = urldecode($payment_id);
|
||||
unset($payments[$decoded_payment_id]);
|
||||
$cash_rounding = $this->reset_cash_rounding();
|
||||
if($cash_rounding)
|
||||
{
|
||||
if($decoded_payment_id == $this->CI->lang->line('sales_cash'))
|
||||
{
|
||||
unset($payments[$this->CI->lang->line('sales_cash_adjustment')]);
|
||||
}
|
||||
if($decoded_payment_id == $this->CI->lang->line('sales_cash_adjustment'))
|
||||
{
|
||||
unset($payments[$this->CI->lang->line('sales_cash')]);
|
||||
}
|
||||
}
|
||||
$this->set_payments($payments);
|
||||
}
|
||||
|
||||
@@ -416,18 +448,30 @@ class Sale_lib
|
||||
$this->CI->session->unset_userdata('sales_payments');
|
||||
}
|
||||
|
||||
// Multiple Payments
|
||||
/**
|
||||
* Retrieve the total payments made, excluding any cash adjustments
|
||||
* and establish if cash_mode is in play
|
||||
*/
|
||||
public function get_payments_total()
|
||||
{
|
||||
$subtotal = 0.0;
|
||||
$this->reset_cash_flags();
|
||||
$cash_mode_eligible = CASH_MODE_TRUE;
|
||||
|
||||
foreach($this->get_payments() as $payments)
|
||||
{
|
||||
$subtotal = bcadd($payments['payment_amount'], $subtotal);
|
||||
if($this->CI->session->userdata('cash_rounding') && $this->CI->lang->line('sales_cash') != $payments['payment_type'])
|
||||
if(!$payments['cash_adjustment'])
|
||||
{
|
||||
$this->CI->session->set_userdata('cash_rounding', 0);
|
||||
$subtotal = bcadd($payments['payment_amount'], $subtotal);
|
||||
}
|
||||
if($this->CI->lang->line('sales_cash') != $payments['payment_type'] && $this->CI->lang->line('sales_cash_adjustment') != $payments['payment_type'])
|
||||
{
|
||||
$cash_mode_eligible = CASH_MODE_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if($cash_mode_eligible && $this->CI->session->userdata('cash_rounding'))
|
||||
{
|
||||
$this->CI->session->set_userdata('cash_mode', CASH_MODE_TRUE);
|
||||
}
|
||||
|
||||
return $subtotal;
|
||||
@@ -435,12 +479,10 @@ class Sale_lib
|
||||
|
||||
/**
|
||||
* Returns 'subtotal', 'total', 'cash_total', 'payment_total', 'amount_due', 'cash_amount_due', 'paid_in_full'
|
||||
* 'subtotal', 'discounted_subtotal', 'tax_exclusive_subtotal', 'item_count', 'total_units'
|
||||
* 'subtotal', 'discounted_subtotal', 'tax_exclusive_subtotal', 'item_count', 'total_units', 'cash_adjustment_amount'
|
||||
*/
|
||||
public function get_totals($taxes)
|
||||
{
|
||||
$cash_rounding = $this->CI->session->userdata('cash_rounding');
|
||||
|
||||
$totals = array();
|
||||
|
||||
$prediscount_subtotal = 0.0;
|
||||
@@ -489,6 +531,11 @@ class Sale_lib
|
||||
$totals['total'] = $total;
|
||||
$totals['tax_total'] = $sales_tax;
|
||||
|
||||
$payment_total = $this->get_payments_total();
|
||||
$totals['payment_total'] = $payment_total;
|
||||
$cash_rounding = $this->CI->session->userdata('cash_rounding');
|
||||
$cash_mode = $this->CI->session->userdata('cash_mode');
|
||||
|
||||
if($cash_rounding)
|
||||
{
|
||||
$cash_total = $this->check_for_cash_rounding($total);
|
||||
@@ -500,16 +547,13 @@ class Sale_lib
|
||||
$totals['cash_total'] = $cash_total;
|
||||
}
|
||||
|
||||
$payment_total = $this->get_payments_total();
|
||||
$totals['payment_total'] = $payment_total;
|
||||
|
||||
$amount_due = bcsub($total, $payment_total);
|
||||
$totals['amount_due'] = $amount_due;
|
||||
|
||||
$cash_amount_due = bcsub($cash_total, $payment_total);
|
||||
$totals['cash_amount_due'] = $cash_amount_due;
|
||||
|
||||
if($cash_rounding)
|
||||
if($cash_mode)
|
||||
{
|
||||
$current_due = $cash_amount_due;
|
||||
}
|
||||
@@ -532,6 +576,14 @@ class Sale_lib
|
||||
|
||||
$totals['item_count'] = $item_count;
|
||||
$totals['total_units'] = $total_units;
|
||||
$totals['cash_adjustment_amount'] = 0;
|
||||
|
||||
if($totals['payments_cover_total'])
|
||||
{
|
||||
$totals['cash_adjustment_amount'] = round($cash_total - $totals['total'], totals_decimals(), PHP_ROUND_HALF_UP);
|
||||
}
|
||||
|
||||
$cash_mode = $this->CI->session->userdata('cash_mode');
|
||||
|
||||
return $totals;
|
||||
}
|
||||
@@ -1006,9 +1058,34 @@ class Sale_lib
|
||||
$this->add_item($row->item_id, $row->quantity_purchased, $row->item_location, $row->discount, $row->discount_type, PRICE_MODE_STANDARD, NULL, NULL, $row->item_unit_price, $row->description, $row->serialnumber, $sale_id, TRUE, $row->print_option);
|
||||
}
|
||||
|
||||
$this->CI->session->set_userdata('cash_mode', CASH_MODE_FALSE);
|
||||
|
||||
// Establish cash_mode for this sale by inspecting the payments
|
||||
if($this->CI->session->userdata('cash_rounding'))
|
||||
{
|
||||
$cash_types_only = true;
|
||||
foreach($this->CI->Sale->get_sale_payments($sale_id)->result() as $row)
|
||||
{
|
||||
if($row->payment_type != $this->CI->lang->line('sales_cash') && $row->payment_type != $this->CI->lang->line('sales_cash_adjustment'))
|
||||
{
|
||||
$cash_types_only = FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
if($cash_types_only)
|
||||
{
|
||||
$this->CI->session->set_userdata('cash_mode', CASH_MODE_TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->CI->session->set_userdata('cash_mode', CASH_MODE_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
// Now load payments
|
||||
foreach($this->CI->Sale->get_sale_payments($sale_id)->result() as $row)
|
||||
{
|
||||
$this->add_payment($row->payment_type, $row->payment_amount);
|
||||
$this->add_payment($row->payment_type, $row->payment_amount, $row->cash_adjustment);
|
||||
}
|
||||
|
||||
$this->set_customer($this->CI->Sale->get_customer($sale_id)->person_id);
|
||||
@@ -1051,18 +1128,13 @@ class Sale_lib
|
||||
$this->CI->session->unset_userdata('payment_type');
|
||||
}
|
||||
|
||||
public function reset_cash_flags()
|
||||
/**
|
||||
* Determines if cash rounding should be a consideration for this site
|
||||
* It also set resets the cash mode to disabled which will then be re-evaluated when
|
||||
* retrieving payments.
|
||||
*/
|
||||
public function reset_cash_rounding()
|
||||
{
|
||||
if($this->CI->config->item('payment_options_order') != 'cashdebitcredit')
|
||||
{
|
||||
$cash_mode = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$cash_mode = 0;
|
||||
}
|
||||
$this->CI->session->set_userdata('cash_mode', $cash_mode);
|
||||
|
||||
$cash_rounding_code = $this->CI->config->item('cash_rounding_code');
|
||||
|
||||
if(cash_decimals() < totals_decimals() || $cash_rounding_code == Rounding_mode::HALF_FIVE)
|
||||
@@ -1074,6 +1146,9 @@ class Sale_lib
|
||||
$cash_rounding = 0;
|
||||
}
|
||||
$this->CI->session->set_userdata('cash_rounding', $cash_rounding);
|
||||
$this->CI->session->set_userdata('cash_mode', CASH_MODE_FALSE);
|
||||
|
||||
return $cash_rounding;
|
||||
}
|
||||
|
||||
public function is_customer_taxable()
|
||||
@@ -1234,11 +1309,16 @@ class Sale_lib
|
||||
return $subtotal;
|
||||
}
|
||||
|
||||
public function get_total()
|
||||
/**
|
||||
* Calculates the total sales amount with the default option to include cash rounding
|
||||
* @param bool $include_cash_rounding
|
||||
* @return float|int|string
|
||||
*/
|
||||
public function get_total($include_cash_rounding = TRUE)
|
||||
{
|
||||
$total = $this->calculate_subtotal(TRUE);
|
||||
|
||||
$cash_rounding = $this->CI->session->userdata('cash_rounding');
|
||||
$cash_mode = $this->CI->session->userdata('cash_mode');
|
||||
|
||||
if(!$this->CI->config->item('tax_included'))
|
||||
{
|
||||
@@ -1249,7 +1329,7 @@ class Sale_lib
|
||||
}
|
||||
}
|
||||
|
||||
if($cash_rounding)
|
||||
if($include_cash_rounding && $cash_mode)
|
||||
{
|
||||
$total = $this->check_for_cash_rounding($total);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
class Migration_cashrounding extends CI_Migration
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function up()
|
||||
{
|
||||
$this->db->query('ALTER TABLE ' . $this->db->dbprefix('sales_payments') . ' ADD COLUMN `cash_adjustment` tinyint NOT NULL DEFAULT 0 AFTER `cash_refund`');
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->db->query('ALTER TABLE ' . $this->db->dbprefix('sales_payments') . ' DROP COLUMN `cash_adjustment`');
|
||||
}
|
||||
}
|
||||
?>
|
||||
+44
-27
@@ -15,7 +15,9 @@ class Sale extends CI_Model
|
||||
' (PRIMARY KEY(sale_id), INDEX(sale_id))
|
||||
(
|
||||
SELECT payments.sale_id AS sale_id,
|
||||
IFNULL(SUM(payments.payment_amount), 0) AS sale_payment_amount,
|
||||
SUM(CASE WHEN payments.cash_adjustment = 0 THEN payments.payment_amount ELSE 0 END) AS sale_payment_amount,
|
||||
SUM(CASE WHEN payments.cash_adjustment = 1 THEN payments.payment_amount ELSE 0 END) AS sale_cash_adjustment,
|
||||
SUM(payments.cash_refund) AS sale_cash_refund,
|
||||
GROUP_CONCAT(CONCAT(payments.payment_type, " ", (payments.payment_amount - payments.cash_refund)) SEPARATOR ", ") AS payment_type
|
||||
FROM ' . $this->db->dbprefix('sales_payments') . ' AS payments
|
||||
INNER JOIN ' . $this->db->dbprefix('sales') . ' AS sales
|
||||
@@ -29,18 +31,23 @@ class Sale extends CI_Model
|
||||
|
||||
$sale_price = 'CASE WHEN sales_items.discount_type = ' . PERCENT . ' THEN sales_items.item_unit_price * sales_items.quantity_purchased * (1 - sales_items.discount / 100) ELSE sales_items.item_unit_price * sales_items.quantity_purchased - sales_items.discount END';
|
||||
|
||||
$sales_tax = 'ROUND(IFNULL(SUM(sales_items_taxes.sales_tax), 0), ' . $decimals . ')';
|
||||
$internal_tax = 'ROUND(IFNULL(SUM(sales_items_taxes.internal_tax), 0), ' . $decimals . ')';
|
||||
$sales_tax = "ROUND(IFNULL(SUM(sales_items_taxes.sales_tax), 0), $decimals)";
|
||||
$internal_tax = "ROUND(IFNULL(SUM(sales_items_taxes.internal_tax), 0), $decimals)";
|
||||
$cash_adjustment = 'IFNULL(SUM(payments.sale_cash_adjustment), 0)';
|
||||
|
||||
if($this->config->item('tax_included'))
|
||||
{
|
||||
$sale_total = 'ROUND(SUM(' . $sale_price . '),' . $decimals . ')';
|
||||
$sale_total = "ROUND(SUM($sale_price), $decimals) + $cash_adjustment";
|
||||
// $sale_subtotal = "$sale_total - $internal_tax";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sale_total = 'ROUND(SUM(' . $sale_price . '),' . $decimals . ') + ' . $sales_tax;
|
||||
// $sale_subtotal = "ROUND(SUM($sale_price), $decimals) - $internal_tax - $cash_adjustment";
|
||||
$sale_total = "ROUND(SUM($sale_price), $decimals) + $sales_tax + $cash_adjustment";
|
||||
}
|
||||
|
||||
|
||||
|
||||
// create a temporary table to contain all the sum of taxes per sale item
|
||||
$this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->dbprefix('sales_items_taxes_temp') .
|
||||
' (INDEX(sale_id), INDEX(item_id)) ENGINE=MEMORY
|
||||
@@ -75,10 +82,12 @@ class Sale extends CI_Model
|
||||
MAX(customer_p.last_name) AS last_name,
|
||||
MAX(customer_p.email) AS email,
|
||||
MAX(customer_p.comments) AS comments,
|
||||
MAX(IFNULL(payments.sale_cash_adjustment, 0)) AS cash_adjustment,
|
||||
MAX(IFNULL(payments.sale_cash_refund, 0)) AS cash_refund,
|
||||
' . "
|
||||
$sale_total AS amount_due,
|
||||
MAX(IFNULL(payments.sale_payment_amount, 0)) AS amount_tendered,
|
||||
MAX(IFNULL(payments.sale_payment_amount,0)) - $sale_total AS change_due,
|
||||
(MAX(payments.sale_payment_amount)) - ($sale_total) AS change_due,
|
||||
" . '
|
||||
MAX(payments.payment_type) AS payment_type
|
||||
');
|
||||
@@ -131,7 +140,8 @@ class Sale extends CI_Model
|
||||
' (PRIMARY KEY(sale_id), INDEX(sale_id))
|
||||
(
|
||||
SELECT payments.sale_id AS sale_id,
|
||||
IFNULL(SUM(payments.payment_amount), 0) AS sale_payment_amount,
|
||||
SUM(CASE WHEN payments.cash_adjustment = 0 THEN payments.payment_amount ELSE 0 END) AS sale_payment_amount,
|
||||
SUM(CASE WHEN payments.cash_adjustment = 1 THEN payments.payment_amount ELSE 0 END) AS sale_cash_adjustment,
|
||||
GROUP_CONCAT(CONCAT(payments.payment_type, " ", (payments.payment_amount - payments.cash_refund)) SEPARATOR ", ") AS payment_type
|
||||
FROM ' . $this->db->dbprefix('sales_payments') . ' AS payments
|
||||
INNER JOIN ' . $this->db->dbprefix('sales') . ' AS sales
|
||||
@@ -149,9 +159,10 @@ class Sale extends CI_Model
|
||||
$tax = 'IFNULL(SUM(sales_items_taxes.tax), 0)';
|
||||
$sales_tax = 'IFNULL(SUM(sales_items_taxes.sales_tax), 0)';
|
||||
$internal_tax = 'IFNULL(SUM(sales_items_taxes.internal_tax), 0)';
|
||||
$cash_adjustment = 'IFNULL(SUM(payments.sale_cash_adjustment), 0)';
|
||||
|
||||
$sale_subtotal = 'ROUND(SUM(' . $sale_price . '), ' . $decimals . ') - ' . $internal_tax;
|
||||
$sale_total = 'ROUND(SUM(' . $sale_price . '), ' . $decimals . ') + ' . $sales_tax;
|
||||
$sale_subtotal = "ROUND(SUM($sale_price), $decimals) - $internal_tax";
|
||||
$sale_total = "ROUND(SUM($sale_price), $decimals) + $sales_tax + $cash_adjustment";
|
||||
|
||||
// create a temporary table to contain all the sum of taxes per sale item
|
||||
$this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->dbprefix('sales_items_taxes_temp') .
|
||||
@@ -197,7 +208,7 @@ class Sale extends CI_Model
|
||||
($sale_total - $sale_cost) AS profit,
|
||||
$sale_total AS amount_due,
|
||||
MAX(payments.sale_payment_amount) AS amount_tendered,
|
||||
(MAX(payments.sale_payment_amount) - ($sale_total)) AS change_due,
|
||||
(MAX(payments.sale_payment_amount)) - ($sale_total) AS change_due,
|
||||
" . '
|
||||
MAX(payments.payment_type) AS payment_type
|
||||
');
|
||||
@@ -550,17 +561,19 @@ class Sale extends CI_Model
|
||||
$payment_type = $payment['payment_type'];
|
||||
$payment_amount = $payment['payment_amount'];
|
||||
$cash_refund = $payment['cash_refund'];
|
||||
$cash_adjustment = $payment['cash_adjustment'];
|
||||
$employee_id = $payment['employee_id'];
|
||||
|
||||
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,
|
||||
'cash_refund' => $cash_refund,
|
||||
'employee_id' => $employee_id
|
||||
'sale_id' => $sale_id,
|
||||
'payment_type' => $payment_type,
|
||||
'payment_amount' => $payment_amount,
|
||||
'cash_refund' => $cash_refund,
|
||||
'cash_adjustment' => $cash_adjustment,
|
||||
'employee_id' => $employee_id
|
||||
);
|
||||
$success = $this->db->insert('sales_payments', $sales_payments_data);
|
||||
}
|
||||
@@ -572,7 +585,8 @@ class Sale extends CI_Model
|
||||
$sales_payments_data = array(
|
||||
'payment_type' => $payment_type,
|
||||
'payment_amount' => $payment_amount,
|
||||
'cash_refund' => $cash_refund
|
||||
'cash_refund' => $cash_refund,
|
||||
'cash_adjustment' => $cash_adjustment
|
||||
);
|
||||
$this->db->where('payment_id', $payment_id);
|
||||
$success = $this->db->update('sales_payments', $sales_payments_data);
|
||||
@@ -589,7 +603,6 @@ class Sale extends CI_Model
|
||||
|
||||
$success &= $this->db->trans_status();
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
@@ -658,11 +671,12 @@ class Sale extends CI_Model
|
||||
}
|
||||
|
||||
$sales_payments_data = array(
|
||||
'sale_id' => $sale_id,
|
||||
'payment_type' => $payment['payment_type'],
|
||||
'payment_amount' => $payment['payment_amount'],
|
||||
'cash_refund' => $payment['cash_refund'],
|
||||
'employee_id' => $employee_id
|
||||
'sale_id' => $sale_id,
|
||||
'payment_type' => $payment['payment_type'],
|
||||
'payment_amount' => $payment['payment_amount'],
|
||||
'cash_refund' => $payment['cash_refund'],
|
||||
'cash_adjustment' => $payment['cash_adjustment'],
|
||||
'employee_id' => $employee_id
|
||||
);
|
||||
|
||||
$this->db->insert('sales_payments', $sales_payments_data);
|
||||
@@ -1126,15 +1140,17 @@ class Sale extends CI_Model
|
||||
$sales_tax = 'IFNULL(SUM(sales_items_taxes.sales_tax), 0)';
|
||||
$internal_tax = 'IFNULL(SUM(sales_items_taxes.internal_tax), 0)';
|
||||
|
||||
$cash_adjustment = 'IFNULL(SUM(payments.sale_cash_adjustment), 0)';
|
||||
|
||||
if($this->config->item('tax_included'))
|
||||
{
|
||||
$sale_total = 'ROUND(SUM(' . $sale_price . '), ' . $decimals . ')';
|
||||
$sale_subtotal = $sale_total . ' - ' . $internal_tax;
|
||||
$sale_total = "ROUND(SUM($sale_price), $decimals) + $cash_adjustment";
|
||||
$sale_subtotal = "$sale_total - $internal_tax";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sale_subtotal = 'ROUND(SUM(' . $sale_price . '), ' . $decimals . ') - ' . $internal_tax;
|
||||
$sale_total = 'ROUND(SUM(' . $sale_price . '), ' . $decimals . ') + ' . $sales_tax;
|
||||
$sale_subtotal = "ROUND(SUM($sale_price), $decimals) - $internal_tax + $cash_adjustment";
|
||||
$sale_total = "ROUND(SUM($sale_price), $decimals) + $sales_tax + $cash_adjustment";
|
||||
}
|
||||
|
||||
// create a temporary table to contain all the sum of taxes per sale item
|
||||
@@ -1162,7 +1178,8 @@ class Sale extends CI_Model
|
||||
' (PRIMARY KEY(sale_id), INDEX(sale_id))
|
||||
(
|
||||
SELECT payments.sale_id AS sale_id,
|
||||
IFNULL(SUM(payments.payment_amount), 0) AS sale_payment_amount,
|
||||
SUM(CASE WHEN payments.cash_adjustment = 0 THEN payments.payment_amount ELSE 0 END) AS sale_payment_amount,
|
||||
SUM(CASE WHEN payments.cash_adjustment = 1 THEN payments.payment_amount ELSE 0 END) AS sale_cash_adjustment,
|
||||
GROUP_CONCAT(CONCAT(payments.payment_type, " ", (payments.payment_amount - payments.cash_refund)) SEPARATOR ", ") AS payment_type
|
||||
FROM ' . $this->db->dbprefix('sales_payments') . ' AS payments
|
||||
INNER JOIN ' . $this->db->dbprefix('sales') . ' AS sales
|
||||
|
||||
@@ -157,7 +157,9 @@ class Summary_payments extends Summary_report
|
||||
$this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->dbprefix('sumpay_payments_temp') .
|
||||
' (INDEX(sale_id)) ENGINE=MEMORY
|
||||
(
|
||||
SELECT sales.sale_id, COUNT(sales.sale_id) AS number_payments, SUM(sales_payments.payment_amount) AS total_payments,
|
||||
SELECT sales.sale_id, COUNT(sales.sale_id) AS number_payments,
|
||||
SUM(CASE WHEN sales_payments.cash_adjustment = 0 THEN sales_payments.payment_amount ELSE 0 END) AS total_payments,
|
||||
SUM(CASE WHEN sales_payments.cash_adjustment = 1 THEN sales_payments.payment_amount ELSE 0 END) AS total_cash_adjustment,
|
||||
SUM(sales_payments.cash_refund) AS total_cash_refund
|
||||
FROM ' . $this->db->dbprefix('sales') . ' AS sales
|
||||
LEFT OUTER JOIN ' . $this->db->dbprefix('sales_payments') . ' AS sales_payments
|
||||
|
||||
@@ -891,8 +891,9 @@ $(document).ready(function()
|
||||
});
|
||||
});
|
||||
|
||||
function check_payment_type() {
|
||||
var cash_rounding = <?php echo json_encode($cash_rounding); ?>;
|
||||
function check_payment_type()
|
||||
{
|
||||
var cash_mode = <?php echo json_encode($cash_mode); ?>;
|
||||
|
||||
if($("#payment_types").val() == "<?php echo $this->lang->line('sales_giftcard'); ?>")
|
||||
{
|
||||
@@ -904,9 +905,9 @@ function check_payment_type() {
|
||||
$(".non-giftcard-input").attr('disabled', true);
|
||||
$(".giftcard-input:enabled").val('').focus();
|
||||
}
|
||||
else if($("#payment_types").val() == "<?php echo $this->lang->line('sales_cash'); ?>" && cash_rounding)
|
||||
else if(($("#payment_types").val() == "<?php echo $this->lang->line('sales_cash'); ?>" && cash_mode == '1'))
|
||||
{
|
||||
$("#sale_total").html("<?php echo to_currency($cash_total); ?>");
|
||||
$("#sale_total").html("<?php echo to_currency($non_cash_total); ?>");
|
||||
$("#sale_amount_due").html("<?php echo to_currency($cash_amount_due); ?>");
|
||||
$("#amount_tendered_label").html("<?php echo $this->lang->line('sales_amount_tendered'); ?>");
|
||||
$("#amount_tendered:enabled").val("<?php echo to_currency_no_money($cash_amount_due); ?>");
|
||||
@@ -916,9 +917,9 @@ function check_payment_type() {
|
||||
else
|
||||
{
|
||||
$("#sale_total").html("<?php echo to_currency($non_cash_total); ?>");
|
||||
$("#sale_amount_due").html("<?php echo to_currency($non_cash_amount_due); ?>");
|
||||
$("#sale_amount_due").html("<?php echo to_currency($amount_due); ?>");
|
||||
$("#amount_tendered_label").html("<?php echo $this->lang->line('sales_amount_tendered'); ?>");
|
||||
$("#amount_tendered:enabled").val("<?php echo to_currency_no_money($non_cash_amount_due); ?>");
|
||||
$("#amount_tendered:enabled").val("<?php echo to_currency_no_money($amount_due); ?>");
|
||||
$(".giftcard-input").attr('disabled', true);
|
||||
$(".non-giftcard-input").attr('disabled', false);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user