diff --git a/app/Controllers/Sales.php b/app/Controllers/Sales.php index 0e859d292..a9b18a48a 100644 --- a/app/Controllers/Sales.php +++ b/app/Controllers/Sales.php @@ -431,21 +431,24 @@ class Sales extends Secure_Controller return $this->reload($data); } + $isReturnMode = $this->sale_lib->get_mode() === 'return'; + $amountTenderedRule = $isReturnMode ? 'trim|required|decimal_locale' : 'trim|required|decimal_locale|nonNegativeDecimal'; + if ($paymentType === lang('Sales.giftcard')) { - $rules = ['amount_tendered' => 'trim|required|integer']; //For giftcards, amount_tendered becomes the giftcard number which must be an integer + $rules = ['amount_tendered' => 'trim|required|integer']; $messages = ['amount_tendered' => lang('Sales.must_enter_numeric_giftcard')]; } elseif (in_array($paymentType, get_reference_code_payment_types())) { $min = (int)($this->config['payment_reference_code_min'] ?? 3); $max = (int)($this->config['payment_reference_code_max'] ?? 20); $rules = [ - 'amount_tendered' => 'trim|required|decimal_locale|nonNegativeDecimal', + 'amount_tendered' => $amountTenderedRule, 'reference_code' => "trim|required|alpha_numeric|min_length[$min]|max_length[$max]", ]; $messages = [ 'amount_tendered' => [ 'required' => lang('Sales.must_enter_numeric'), 'decimal_locale' => lang('Sales.must_enter_numeric'), - 'nonNegativeDecimal' => lang('Sales.negative_amount_invalid'), + 'nonNegativeDecimal' => lang('Sales.negative_amount_tendered'), ], 'reference_code' => [ 'required' => lang('Sales.must_enter_reference_code'), @@ -455,12 +458,12 @@ class Sales extends Secure_Controller ], ]; } else { - $rules = ['amount_tendered' => 'trim|required|decimal_locale|nonNegativeDecimal']; + $rules = ['amount_tendered' => $amountTenderedRule]; $messages = [ 'amount_tendered' => [ 'required' => lang('Sales.must_enter_numeric'), 'decimal_locale' => lang('Sales.must_enter_numeric'), - 'nonNegativeDecimal' => lang('Sales.negative_amount_invalid'), + 'nonNegativeDecimal' => lang('Sales.negative_amount_tendered'), ], ]; } @@ -1733,7 +1736,7 @@ class Sales extends Secure_Controller { $sale_id = $this->sale_lib->get_sale_id(); if ($sale_id != NEW_ENTRY && $sale_id != '') { - $sale_type = $this->sale_lib->get_sale_type(); + $sale_type = $this->sale_lib->getSaleType(); if ($this->config['dinner_table_enable']) { $dinner_table = $this->sale_lib->get_dinner_table(); @@ -1787,7 +1790,7 @@ class Sales extends Secure_Controller $invoice_number = $this->sale_lib->get_invoice_number(); $work_order_number = $this->sale_lib->get_work_order_number(); $quote_number = $this->sale_lib->get_quote_number(); - $sale_type = $this->sale_lib->get_sale_type(); + $sale_type = $this->sale_lib->getSaleType(); if ($sale_type == '') { $sale_type = SALE_TYPE_POS; @@ -1837,15 +1840,22 @@ class Sales extends Secure_Controller */ public function postUnsuspend(): ResponseInterface|string { - $sale_id = $this->request->getPost('suspended_sale_id', FILTER_SANITIZE_NUMBER_INT); - $this->sale_lib->clear_all(); + $personId = $this->session->get('person_id'); - if ($sale_id > 0) { - $this->sale_lib->copy_entire_sale($sale_id); + if (!$this->employee->has_grant('reports_sales', $personId)) { + return $this->response->setStatusCode(403) + ->setJSON(['success' => false, 'message' => lang('Sales.not_authorized')]); + } + + $saleId = $this->request->getPost('suspended_sale_id', FILTER_SANITIZE_NUMBER_INT); + + if ($saleId > 0 && $this->sale->getSaleStatus($saleId) == SUSPENDED) { + $this->sale_lib->clear_all(); + $this->sale_lib->copy_entire_sale($saleId); } // Set current register mode to reflect that of unsuspended order type - $this->change_register_mode($this->sale_lib->get_sale_type()); + $this->change_register_mode($this->sale_lib->getSaleType()); return $this->reload(); } diff --git a/app/Language/ar-EG/Sales.php b/app/Language/ar-EG/Sales.php index 3a9d52864..0ceabcba6 100644 --- a/app/Language/ar-EG/Sales.php +++ b/app/Language/ar-EG/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'يجب إدخال رقم للمبلغ الفعلى المدفوع.', 'must_enter_numeric_giftcard' => 'رقم بطاقة الهدية يجب أن يكون رقم.', 'must_enter_reference_code' => 'يجب إدخال رقم المرجع/الاسترداد.', - 'negative_amount_invalid' => 'لا يمكن أن يكون المبلغ المدفوع سالبًا.', + 'negative_amount_tendered' => 'لا يمكن أن يكون المبلغ المدفوع سالبًا.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/ar-LB/Sales.php b/app/Language/ar-LB/Sales.php index 0f118c69f..5746d89b1 100644 --- a/app/Language/ar-LB/Sales.php +++ b/app/Language/ar-LB/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'يجب إدخال رقم للمبلغ الفعلى المدفوع.', 'must_enter_numeric_giftcard' => 'رمز بطاقة الهدية يجب أن يكتون ارقام فقط.', 'must_enter_reference_code' => 'يجب إدخال رقم المرجع/الاسترداد.', - 'negative_amount_invalid' => 'لا يمكن أن يكون المبلغ المدفوع سالبًا.', + 'negative_amount_tendered' => 'لا يمكن أن يكون المبلغ المدفوع سالبًا.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/az/Sales.php b/app/Language/az/Sales.php index cf674c3b3..1816a7045 100644 --- a/app/Language/az/Sales.php +++ b/app/Language/az/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Ödəniş məbləği rəqəm ilə olmalıdır.', 'must_enter_numeric_giftcard' => 'Hədiyyə Kartın nömrəsi rəqəmlə olmalıdır.', 'must_enter_reference_code' => 'İstinad/Axtarış nömrəsi daxil edilməlidir.', - 'negative_amount_invalid' => 'Ödənilən məbləğ mənfi ola bilməz.', + 'negative_amount_tendered' => 'Ödənilən məbləğ mənfi ola bilməz.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/bg/Sales.php b/app/Language/bg/Sales.php index 4854f6000..1d7449804 100644 --- a/app/Language/bg/Sales.php +++ b/app/Language/bg/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Сумата Предложена трябва да е число.', 'must_enter_numeric_giftcard' => 'Gift Card номера трябва да бъде число.', 'must_enter_reference_code' => 'Трябва да се въведе референтен/извличащ номер.', - 'negative_amount_invalid' => 'Предоставената сума не може да бъде отрицателна.', + 'negative_amount_tendered' => 'Предоставената сума не може да бъде отрицателна.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/bs/Sales.php b/app/Language/bs/Sales.php index 4eb0fc0b6..a137b75b9 100644 --- a/app/Language/bs/Sales.php +++ b/app/Language/bs/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Ponuđeni iznos mora biti broj.', 'must_enter_numeric_giftcard' => 'Broj poklon kartice mora biti broj.', 'must_enter_reference_code' => 'Referentni/broj za preuzimanje mora biti unesen.', - 'negative_amount_invalid' => 'Ponuđeni iznos ne može biti negativan.', + 'negative_amount_tendered' => 'Ponuđeni iznos ne može biti negativan.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/ckb/Sales.php b/app/Language/ckb/Sales.php index 0e116c8be..d19903158 100644 --- a/app/Language/ckb/Sales.php +++ b/app/Language/ckb/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'بڕی پێشکەشکراو دەبێت ژمارەیەک بێت.', 'must_enter_numeric_giftcard' => 'ژمارەی کارتی دیاری دەبێت ژمارەیەک بێت.', 'must_enter_reference_code' => 'ژمارەی مەرجع/وەرگرتن دەبێت بنووسرێت.', - 'negative_amount_invalid' => 'بڕی پێشکەشکراو ناتوانێت نەرێنی بێت.', + 'negative_amount_tendered' => 'بڕی پێشکەشکراو ناتوانێت نەرێنی بێت.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/cs/Sales.php b/app/Language/cs/Sales.php index 61d6717b9..c43ac87f9 100644 --- a/app/Language/cs/Sales.php +++ b/app/Language/cs/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => '', 'must_enter_numeric_giftcard' => 'Číslo dárkového poukazu musí být číslo.', 'must_enter_reference_code' => 'Je nutné zadat referenční/vyhledávací číslo.', - 'negative_amount_invalid' => 'Uhrazená částka nemůže být záporná.', + 'negative_amount_tendered' => 'Uhrazená částka nemůže být záporná.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/da/Sales.php b/app/Language/da/Sales.php index 268f04b05..1e323bb00 100644 --- a/app/Language/da/Sales.php +++ b/app/Language/da/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => '', 'must_enter_numeric_giftcard' => '', 'must_enter_reference_code' => 'Reference-/hentningsnummer skal angives.', - 'negative_amount_invalid' => 'Det modtagne beløb kan ikke være negativt.', + 'negative_amount_tendered' => 'Det modtagne beløb kan ikke være negativt.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/de-CH/Sales.php b/app/Language/de-CH/Sales.php index e0d2aea08..456ef2c6a 100644 --- a/app/Language/de-CH/Sales.php +++ b/app/Language/de-CH/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Eingabe muss eine Zahl sein', 'must_enter_numeric_giftcard' => 'Gutschein-Nr. muss eine Zahl sein', 'must_enter_reference_code' => 'Referenz-/Abrufnummer muss eingegeben werden.', - 'negative_amount_invalid' => 'Der erhaltene Betrag darf nicht negativ sein.', + 'negative_amount_tendered' => 'Der erhaltene Betrag darf nicht negativ sein.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/de-DE/Sales.php b/app/Language/de-DE/Sales.php index dac8f73e4..74e1b6931 100644 --- a/app/Language/de-DE/Sales.php +++ b/app/Language/de-DE/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Eingabe muss eine Zahl sein.', 'must_enter_numeric_giftcard' => 'Gutschein-Nr. muss eine Zahl sein.', 'must_enter_reference_code' => 'Referenz-/Abrufnummer muss eingegeben werden.', - 'negative_amount_invalid' => 'Der erhaltene Betrag darf nicht negativ sein.', + 'negative_amount_tendered' => 'Der erhaltene Betrag darf nicht negativ sein.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/el/Sales.php b/app/Language/el/Sales.php index 5071e522b..9d29975ce 100644 --- a/app/Language/el/Sales.php +++ b/app/Language/el/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Το Ποσό Είσπραξης πρέπει να είναι Αριθμός.', 'must_enter_numeric_giftcard' => 'Ο Αριθμός της Δωροκάρτας πρέπει να είναι αριθμός.', 'must_enter_reference_code' => 'Πρέπει να εισαχθεί αριθμός αναφοράς/ανάκτησης.', - 'negative_amount_invalid' => 'Το ποσό είσπραξης δεν μπορεί να είναι αρνητικό.', + 'negative_amount_tendered' => 'Το ποσό είσπραξης δεν μπορεί να είναι αρνητικό.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/en-GB/Sales.php b/app/Language/en-GB/Sales.php index a4ee6de58..759488469 100644 --- a/app/Language/en-GB/Sales.php +++ b/app/Language/en-GB/Sales.php @@ -132,7 +132,7 @@ return [ 'must_enter_numeric' => 'Amount Tendered must be a number.', 'must_enter_numeric_giftcard' => 'Gift Card Number must be a number.', 'must_enter_reference_code' => 'Reference/Retrieval Number must be entered.', - 'negative_amount_invalid' => 'Amount Tendered cannot be negative.', + 'negative_amount_tendered' => 'Amount Tendered cannot be negative.', 'negative_discount_invalid' => 'Discount cannot be negative.', 'negative_price_invalid' => 'Price cannot be negative.', 'negative_quantity_invalid' => 'Quantity cannot be negative.', diff --git a/app/Language/en/Sales.php b/app/Language/en/Sales.php index dc52456bc..e24afb2cb 100644 --- a/app/Language/en/Sales.php +++ b/app/Language/en/Sales.php @@ -132,7 +132,7 @@ return [ 'must_enter_numeric' => 'Amount Tendered must be a number.', 'must_enter_numeric_giftcard' => 'Gift Card Number must be a number.', 'must_enter_reference_code' => 'Reference/Retrieval Number must be entered.', - 'negative_amount_invalid' => 'Amount Tendered cannot be negative.', + 'negative_amount_tendered' => 'Amount Tendered cannot be negative.', 'negative_discount_invalid' => 'Discount cannot be negative.', 'negative_price_invalid' => 'Price cannot be negative.', 'negative_quantity_invalid' => 'Quantity cannot be negative.', diff --git a/app/Language/es-ES/Sales.php b/app/Language/es-ES/Sales.php index efa97775d..13f95e176 100644 --- a/app/Language/es-ES/Sales.php +++ b/app/Language/es-ES/Sales.php @@ -132,7 +132,7 @@ return [ 'must_enter_numeric' => 'Cantidad Recibida debe ser número.', 'must_enter_numeric_giftcard' => 'Número de Tarjeta de Regalo debe ser número.', 'must_enter_reference_code' => 'Se debe ingresar el número de referencia/recuperación.', - 'negative_amount_invalid' => 'La cantidad recibida no puede ser negativa.', + 'negative_amount_tendered' => 'La cantidad recibida no puede ser negativa.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/es-MX/Sales.php b/app/Language/es-MX/Sales.php index 52460fc19..c0d0f9d75 100644 --- a/app/Language/es-MX/Sales.php +++ b/app/Language/es-MX/Sales.php @@ -132,7 +132,7 @@ return [ 'must_enter_numeric' => 'Cantidad recibida debe ser un número.', 'must_enter_numeric_giftcard' => 'Número de Tarjeta de Regalo debe ser un número.', 'must_enter_reference_code' => 'Se debe ingresar el número de referencia/recuperación.', - 'negative_amount_invalid' => 'La cantidad recibida no puede ser negativa.', + 'negative_amount_tendered' => 'La cantidad recibida no puede ser negativa.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/fa/Sales.php b/app/Language/fa/Sales.php index 613b1cea0..f74f83722 100644 --- a/app/Language/fa/Sales.php +++ b/app/Language/fa/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'مقدار پیشنهادی باید یک عدد باشد.', 'must_enter_numeric_giftcard' => 'شماره کارت هدیه باید یک عدد باشد.', 'must_enter_reference_code' => 'شماره مرجع/بازیابی باید وارد شود.', - 'negative_amount_invalid' => 'مبلغ مناقصه نمی‌تواند منفی باشد.', + 'negative_amount_tendered' => 'مبلغ مناقصه نمی‌تواند منفی باشد.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/fr/Sales.php b/app/Language/fr/Sales.php index 79761d7eb..296828807 100644 --- a/app/Language/fr/Sales.php +++ b/app/Language/fr/Sales.php @@ -132,7 +132,7 @@ return [ 'must_enter_numeric' => 'Veuillez entrer une valeur numérique pour la somme.', 'must_enter_numeric_giftcard' => 'Veuillez entrer une valeur numérique pour le numéro de carte.', 'must_enter_reference_code' => 'Le numéro de référence/récupération doit être saisi.', - 'negative_amount_invalid' => 'Le montant présenté ne peut pas être négatif.', + 'negative_amount_tendered' => 'Le montant présenté ne peut pas être négatif.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/he/Sales.php b/app/Language/he/Sales.php index 6ddb1b40e..20de06108 100644 --- a/app/Language/he/Sales.php +++ b/app/Language/he/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'סכום ההצעה חייב להיות מספר.', 'must_enter_numeric_giftcard' => 'מספר כרטיס המתנה חייב להיות מספר.', 'must_enter_reference_code' => 'יש להזין מספר אסמכתא/אחזור.', - 'negative_amount_invalid' => 'סכום ההצעה לא יכול להיות שלילי.', + 'negative_amount_tendered' => 'סכום ההצעה לא יכול להיות שלילי.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/hr-HR/Sales.php b/app/Language/hr-HR/Sales.php index 8e9261cec..ad646824c 100644 --- a/app/Language/hr-HR/Sales.php +++ b/app/Language/hr-HR/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Morate unijeti numeričku vrijednost za količinu', 'must_enter_numeric_giftcard' => 'Morate unijeti numeričku vrijednost za poklon bon', 'must_enter_reference_code' => 'Referentni/broj za preuzimanje mora biti unesen.', - 'negative_amount_invalid' => 'Ponuđeni iznos ne može biti negativan.', + 'negative_amount_tendered' => 'Ponuđeni iznos ne može biti negativan.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/hu/Sales.php b/app/Language/hu/Sales.php index 05204e008..1fa4a4be1 100644 --- a/app/Language/hu/Sales.php +++ b/app/Language/hu/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Számot kell megadnia a megrendelt mennyiséghez', 'must_enter_numeric_giftcard' => 'Vásárlási utalvány számát adja meg', 'must_enter_reference_code' => 'A hivatkozási/visszakeresési számot meg kell adni.', - 'negative_amount_invalid' => 'Az összeg nem lehet negatív.', + 'negative_amount_tendered' => 'Az összeg nem lehet negatív.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/hy/Sales.php b/app/Language/hy/Sales.php index a85d5e77d..b353872e2 100644 --- a/app/Language/hy/Sales.php +++ b/app/Language/hy/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => '', 'must_enter_numeric_giftcard' => '', 'must_enter_reference_code' => 'Պետք է մուտքագրվի հղման/որոնման համարը։', - 'negative_amount_invalid' => 'Վճարված գումարը չի կարող բացասական լինել.', + 'negative_amount_tendered' => 'Վճարված գումարը չի կարող բացասական լինել.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/id/Sales.php b/app/Language/id/Sales.php index b01ebc237..1244050bb 100644 --- a/app/Language/id/Sales.php +++ b/app/Language/id/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Nilai yang dimasukkan harus berupa angka.', 'must_enter_numeric_giftcard' => 'Nomor Gift Card harus berupa angka.', 'must_enter_reference_code' => 'Nomor referensi/pengambilan harus dimasukkan.', - 'negative_amount_invalid' => 'Nilai pembayaran tidak boleh negatif.', + 'negative_amount_tendered' => 'Nilai pembayaran tidak boleh negatif.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/it/Sales.php b/app/Language/it/Sales.php index e2e28c479..ffe406909 100644 --- a/app/Language/it/Sales.php +++ b/app/Language/it/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Import Offerto deve essere un numero.', 'must_enter_numeric_giftcard' => 'Numero Carta Regalo deve essere un numero.', 'must_enter_reference_code' => 'Il numero di riferimento/recupero deve essere inserito.', - 'negative_amount_invalid' => 'L\'importo offerto non può essere negativo.', + 'negative_amount_tendered' => 'L\'importo offerto non può essere negativo.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/ka/Sales.php b/app/Language/ka/Sales.php index 5770c7317..05a2f5eb1 100644 --- a/app/Language/ka/Sales.php +++ b/app/Language/ka/Sales.php @@ -132,7 +132,7 @@ return [ 'must_enter_numeric' => '', 'must_enter_numeric_giftcard' => '', 'must_enter_reference_code' => 'მიუთითეთ საცნობარო/მოძიების ნომერი.', - 'negative_amount_invalid' => 'გადახდილი თანხა არ შეიძლება იყოს უარყოფითი.', + 'negative_amount_tendered' => 'გადახდილი თანხა არ შეიძლება იყოს უარყოფითი.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/km/Sales.php b/app/Language/km/Sales.php index c4413ae97..154d5d376 100644 --- a/app/Language/km/Sales.php +++ b/app/Language/km/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => '', 'must_enter_numeric_giftcard' => '', 'must_enter_reference_code' => 'លេខយោង/ទាញយកត្រូវតែបញ្ចូល។', - 'negative_amount_invalid' => 'ទឹកប្រាក់បានមកពីការបង់មិនអាចជាចំនួនអវិជ្ជមានបានទេ។', + 'negative_amount_tendered' => 'ទឹកប្រាក់បានមកពីការបង់មិនអាចជាចំនួនអវិជ្ជមានបានទេ។', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/lo/Sales.php b/app/Language/lo/Sales.php index dafdfdfda..76a8b2b70 100644 --- a/app/Language/lo/Sales.php +++ b/app/Language/lo/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Amount Tendered must be a number.', 'must_enter_numeric_giftcard' => 'Gift Card Number must be a number.', 'must_enter_reference_code' => 'ຕ້ອງປ້ອນໝາຍເລກອ້າງອີງ/ດຶງຂໍ້ມູນ.', - 'negative_amount_invalid' => 'ຈຳນວນເງິນທີ່ຈ່າຍບໍ່ສາມາດເປັນຄ່າລົບໄດ້.', + 'negative_amount_tendered' => 'ຈຳນວນເງິນທີ່ຈ່າຍບໍ່ສາມາດເປັນຄ່າລົບໄດ້.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/ml/Sales.php b/app/Language/ml/Sales.php index 1878eb4ba..c6905a922 100644 --- a/app/Language/ml/Sales.php +++ b/app/Language/ml/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => '', 'must_enter_numeric_giftcard' => '', 'must_enter_reference_code' => 'റഫറൻസ്/റിട്രീവൽ നമ്പർ നൽകണം.', - 'negative_amount_invalid' => 'നൽകിയ തുക നെഗറ്റീവ് ആകാൻ പാടില്ല.', + 'negative_amount_tendered' => 'നൽകിയ തുക നെഗറ്റീവ് ആകാൻ പാടില്ല.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/nb/Sales.php b/app/Language/nb/Sales.php index 5d039019f..fcda1eb44 100644 --- a/app/Language/nb/Sales.php +++ b/app/Language/nb/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => '', 'must_enter_numeric_giftcard' => '', 'must_enter_reference_code' => 'Referanse-/hentingsnummer må angis.', - 'negative_amount_invalid' => 'Det mottatte beløpet kan ikke være negativt.', + 'negative_amount_tendered' => 'Det mottatte beløpet kan ikke være negativt.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/nl-BE/Sales.php b/app/Language/nl-BE/Sales.php index 7f9bb4f5a..203bd88b0 100644 --- a/app/Language/nl-BE/Sales.php +++ b/app/Language/nl-BE/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Het ontvangen bedrag moet een numerieke waarde zijn.', 'must_enter_numeric_giftcard' => 'Er moet een geldige code worden ingevuld voor de cadeaubon.', 'must_enter_reference_code' => 'Referentie-/ophaalnummer moet worden ingevoerd.', - 'negative_amount_invalid' => 'Het ontvangen bedrag mag niet negatief zijn.', + 'negative_amount_tendered' => 'Het ontvangen bedrag mag niet negatief zijn.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/nl-NL/Sales.php b/app/Language/nl-NL/Sales.php index 6029eeb1a..4d0e52991 100644 --- a/app/Language/nl-NL/Sales.php +++ b/app/Language/nl-NL/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Betaald bedrag moet een getal zijn.', 'must_enter_numeric_giftcard' => 'Cadeaubonnummer moet een getal zijn.', 'must_enter_reference_code' => 'Referentie-/ophaalnummer moet worden ingevoerd.', - 'negative_amount_invalid' => 'Het betaalde bedrag mag niet negatief zijn.', + 'negative_amount_tendered' => 'Het betaalde bedrag mag niet negatief zijn.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/pl/Sales.php b/app/Language/pl/Sales.php index 6cbcf806d..311ab14e1 100644 --- a/app/Language/pl/Sales.php +++ b/app/Language/pl/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => '', 'must_enter_numeric_giftcard' => '', 'must_enter_reference_code' => 'Należy podać numer referencyjny/pobierania.', - 'negative_amount_invalid' => 'Otrzymana kwota nie może być ujemna.', + 'negative_amount_tendered' => 'Otrzymana kwota nie może być ujemna.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/pt-BR/Sales.php b/app/Language/pt-BR/Sales.php index 324404dd1..92fed364f 100644 --- a/app/Language/pt-BR/Sales.php +++ b/app/Language/pt-BR/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Deve entrar valor numérico para montante da proposta apresentada.', 'must_enter_numeric_giftcard' => 'Deve entrar valor numérico para o número de cartão presente.', 'must_enter_reference_code' => 'O número de referência/recuperação deve ser informado.', - 'negative_amount_invalid' => 'O valor pago não pode ser negativo.', + 'negative_amount_tendered' => 'O valor pago não pode ser negativo.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/ro/Sales.php b/app/Language/ro/Sales.php index b2dfa96f5..c1112ae56 100644 --- a/app/Language/ro/Sales.php +++ b/app/Language/ro/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Valoare ofertata trebuie sa fie numerica.', 'must_enter_numeric_giftcard' => 'Numar Card Cadou trebuie sa fie numeric.', 'must_enter_reference_code' => 'Numărul de referință/recuperare trebuie introdus.', - 'negative_amount_invalid' => 'Suma oferită nu poate fi negativă.', + 'negative_amount_tendered' => 'Suma oferită nu poate fi negativă.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/ru/Sales.php b/app/Language/ru/Sales.php index 23494a29f..bf62460b0 100644 --- a/app/Language/ru/Sales.php +++ b/app/Language/ru/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Предложенная сумма должна быть числом.', 'must_enter_numeric_giftcard' => 'Номер подарочной карты должен быть числом.', 'must_enter_reference_code' => 'Необходимо ввести справочный/поисковый номер.', - 'negative_amount_invalid' => 'Предложенная сумма не может быть отрицательной.', + 'negative_amount_tendered' => 'Предложенная сумма не может быть отрицательной.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/sv/Sales.php b/app/Language/sv/Sales.php index 16e0e815b..428034df0 100644 --- a/app/Language/sv/Sales.php +++ b/app/Language/sv/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Belopp som anslås måste vara ett nummer.', 'must_enter_numeric_giftcard' => 'Presentkortets nummer måste vara ett nummer.', 'must_enter_reference_code' => 'Referens-/hämtningsnummer måste anges.', - 'negative_amount_invalid' => 'Det upplagda beloppet kan inte vara negativt.', + 'negative_amount_tendered' => 'Det upplagda beloppet kan inte vara negativt.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/sw-KE/Sales.php b/app/Language/sw-KE/Sales.php index 015c19ca9..f4be216c9 100644 --- a/app/Language/sw-KE/Sales.php +++ b/app/Language/sw-KE/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Kiasi Kilicholipwa lazima kiwe Namba.', 'must_enter_numeric_giftcard' => 'Namba ya Kadi ya Zawadi lazima iwe Namba.', 'must_enter_reference_code' => 'Nambari ya Kumbukumbu/Upatikanaji lazima iingizwe.', - 'negative_amount_invalid' => 'Kiasi kilicholipwa hakiwezi kuwa hasi.', + 'negative_amount_tendered' => 'Kiasi kilicholipwa hakiwezi kuwa hasi.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/sw-TZ/Sales.php b/app/Language/sw-TZ/Sales.php index 015c19ca9..f4be216c9 100644 --- a/app/Language/sw-TZ/Sales.php +++ b/app/Language/sw-TZ/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Kiasi Kilicholipwa lazima kiwe Namba.', 'must_enter_numeric_giftcard' => 'Namba ya Kadi ya Zawadi lazima iwe Namba.', 'must_enter_reference_code' => 'Nambari ya Kumbukumbu/Upatikanaji lazima iingizwe.', - 'negative_amount_invalid' => 'Kiasi kilicholipwa hakiwezi kuwa hasi.', + 'negative_amount_tendered' => 'Kiasi kilicholipwa hakiwezi kuwa hasi.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/ta/Sales.php b/app/Language/ta/Sales.php index ef38285a3..5ce5deef7 100644 --- a/app/Language/ta/Sales.php +++ b/app/Language/ta/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'தொகை ஒரு எண்ணாக இருக்க வேண்டும்.', 'must_enter_numeric_giftcard' => 'பரிசு அட்டை எண் ஒரு எண்ணாக இருக்க வேண்டும்.', 'must_enter_reference_code' => 'குறிப்பு/மீட்டெடுப்பு எண் உள்ளிட வேண்டும்.', - 'negative_amount_invalid' => 'கொடுத்த தொகை எதிர்மறையாக இருக்கக்கூடாது.', + 'negative_amount_tendered' => 'கொடுத்த தொகை எதிர்மறையாக இருக்கக்கூடாது.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/th/Sales.php b/app/Language/th/Sales.php index 11a60cb49..8485f1a05 100644 --- a/app/Language/th/Sales.php +++ b/app/Language/th/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'จำนวนที่ถุกประมูลต้องใส่ข้อมุลที่เปนตัวเลข', 'must_enter_numeric_giftcard' => 'เลขที่บัตรของขวัญ ต้องใส่ตัวเลขเท่านั้น', 'must_enter_reference_code' => 'ต้องระบุหมายเลขอ้างอิง/การดึงข้อมูล', - 'negative_amount_invalid' => 'ชำระเข้ามาไม่สามารถเป็นค่าติดลบได้', + 'negative_amount_tendered' => 'ชำระเข้ามาไม่สามารถเป็นค่าติดลบได้', 'negative_discount_invalid' => 'ส่วนลดไม่สามารถเป็นค่าติดลบได้', 'negative_price_invalid' => 'ราคาไม่สามารถเป็นค่าติดลบได้', 'negative_quantity_invalid' => 'จำนวนไม่สามารถเป็นค่าติดลบได้', diff --git a/app/Language/tl/Sales.php b/app/Language/tl/Sales.php index 6bc15d7d4..534d3037f 100644 --- a/app/Language/tl/Sales.php +++ b/app/Language/tl/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Amount Tendered must be a number.', 'must_enter_numeric_giftcard' => 'Gift Card Number must be a number.', 'must_enter_reference_code' => 'Ang Numero ng Sanggunian/Pagkuha ay dapat ipasok.', - 'negative_amount_invalid' => 'Hindi maaaring negatibo ang halagang ibinayad.', + 'negative_amount_tendered' => 'Hindi maaaring negatibo ang halagang ibinayad.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/tr/Sales.php b/app/Language/tr/Sales.php index 9384bf721..7654b7918 100644 --- a/app/Language/tr/Sales.php +++ b/app/Language/tr/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Ödenen Tutar sayı olmalıdır.', 'must_enter_numeric_giftcard' => 'Hediye Çeki Numarası sayı olmalıdır.', 'must_enter_reference_code' => 'Referans/Alım numarası girilmelidir.', - 'negative_amount_invalid' => 'Ödenen tutar negatif olamaz.', + 'negative_amount_tendered' => 'Ödenen tutar negatif olamaz.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/uk/Sales.php b/app/Language/uk/Sales.php index 2fc731b7c..bd145f0d8 100644 --- a/app/Language/uk/Sales.php +++ b/app/Language/uk/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Введена сума повинна бути числом.', 'must_enter_numeric_giftcard' => 'Номер подарункової картки повинен бути цифровим.', 'must_enter_reference_code' => 'Необхідно ввести довідковий/пошуковий номер.', - 'negative_amount_invalid' => 'Запропонована сума не може бути від\'ємною.', + 'negative_amount_tendered' => 'Запропонована сума не може бути від\'ємною.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/ur/Sales.php b/app/Language/ur/Sales.php index 801e53d5f..f1d2bb914 100644 --- a/app/Language/ur/Sales.php +++ b/app/Language/ur/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => '', 'must_enter_numeric_giftcard' => '', 'must_enter_reference_code' => 'حوالہ/بازیابی نمبر درج کرنا ضروری ہے۔', - 'negative_amount_invalid' => 'ادا کی گئی رقم منفی نہیں ہو سکتی۔', + 'negative_amount_tendered' => 'ادا کی گئی رقم منفی نہیں ہو سکتی۔', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/vi/Sales.php b/app/Language/vi/Sales.php index d3237c9fe..28cbd47ac 100644 --- a/app/Language/vi/Sales.php +++ b/app/Language/vi/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => 'Số tiền thanh toán phải là dạng số.', 'must_enter_numeric_giftcard' => 'Số Thẻ quà tặng phải là dạng số.', 'must_enter_reference_code' => 'Số tham chiếu/truy xuất phải được nhập.', - 'negative_amount_invalid' => 'Số tiền thanh toán không được là số âm.', + 'negative_amount_tendered' => 'Số tiền thanh toán không được là số âm.', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/zh-Hans/Sales.php b/app/Language/zh-Hans/Sales.php index c2905b0e4..68ff43dcb 100644 --- a/app/Language/zh-Hans/Sales.php +++ b/app/Language/zh-Hans/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => '已收帳款必須輸入數值', 'must_enter_numeric_giftcard' => '禮金券編號必須輸入數值', 'must_enter_reference_code' => '必须输入参考/检索编号。', - 'negative_amount_invalid' => '已收帐款不能为负数。', + 'negative_amount_tendered' => '已收帐款不能为负数。', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Language/zh-Hant/Sales.php b/app/Language/zh-Hant/Sales.php index 0eed9c321..a097e11c9 100644 --- a/app/Language/zh-Hant/Sales.php +++ b/app/Language/zh-Hant/Sales.php @@ -131,7 +131,7 @@ return [ 'must_enter_numeric' => '已收帳款必須輸入數值.', 'must_enter_numeric_giftcard' => '禮金券編號必須輸入數值.', 'must_enter_reference_code' => '必須輸入參考/檢索編號。', - 'negative_amount_invalid' => '已收帳款不能為負數。', + 'negative_amount_tendered' => '已收帳款不能為負數。', 'negative_discount_invalid' => '', 'negative_price_invalid' => '', 'negative_quantity_invalid' => '', diff --git a/app/Libraries/Barcode_lib.php b/app/Libraries/Barcode_lib.php index e7f96a47d..1b62e1c4d 100644 --- a/app/Libraries/Barcode_lib.php +++ b/app/Libraries/Barcode_lib.php @@ -147,7 +147,7 @@ class Barcode_lib $barcode = $this->generate_barcode($item, $barcode_config); $display_table = ''; $display_table .= ''; - $display_table .= ''; + $display_table .= ''; $display_table .= ''; $display_table .= ''; $display_table .= '
' . $this->manageDisplayLayout($barcode_config['barcode_first_row'], $item, $barcode_config) . '
'.$barcode.'
' . $barcode . '
' . $this->manageDisplayLayout($barcode_config['barcode_second_row'], $item, $barcode_config) . '
' . $this->manageDisplayLayout($barcode_config['barcode_third_row'], $item, $barcode_config) . '
'; diff --git a/app/Libraries/Sale_lib.php b/app/Libraries/Sale_lib.php index 0a28588bb..747406469 100644 --- a/app/Libraries/Sale_lib.php +++ b/app/Libraries/Sale_lib.php @@ -331,9 +331,9 @@ class Sale_lib /** * @return int|null */ - public function get_sale_type(): ?int + public function getSaleType(): ?int { - return $this->session->get('sale_type', 0); + return $this->session->get('sale_type') ?? 0; } /** diff --git a/app/Models/Giftcard.php b/app/Models/Giftcard.php index a12466265..8900f7b5c 100644 --- a/app/Models/Giftcard.php +++ b/app/Models/Giftcard.php @@ -311,12 +311,9 @@ class Giftcard extends Model $builder->update(['value' => $value]); } - /** - * Atomically decrements a gift card's value, failing if the balance is insufficient - */ public function decrementGiftcardValue(string $giftcardNumber, float $amount): bool { - if ($amount <= 0) { + if ($amount <= 0.0) { return false; } diff --git a/app/Models/Sale.php b/app/Models/Sale.php index 77391fb04..7446d99f5 100644 --- a/app/Models/Sale.php +++ b/app/Models/Sale.php @@ -805,7 +805,7 @@ class Sale extends Model // Start a transaction to assure data integrity $this->db->transStart(); - $sale_status = $this->get_sale_status($sale_id); + $sale_status = $this->getSaleStatus($sale_id); if ($update_inventory && $sale_status == COMPLETED) { // Defect, not all item deletions will be undone? @@ -1225,12 +1225,14 @@ class Sale extends Model /** * Gets the sale status for the selected sale */ - public function get_sale_status(int $sale_id): int + public function getSaleStatus(int $sale_id): ?int { $builder = $this->db->table('sales'); $builder->where('sale_id', $sale_id); - return $builder->get()->getRow()->sale_status; + $row = $builder->get()->getRow(); + + return $row === null ? null : $row->sale_status; } /** diff --git a/tests/Controllers/SalesControllerTest.php b/tests/Controllers/SalesControllerTest.php index 7f6118e45..11be40fe5 100644 --- a/tests/Controllers/SalesControllerTest.php +++ b/tests/Controllers/SalesControllerTest.php @@ -10,20 +10,26 @@ use CodeIgniter\Config\Services; use App\Models\Employee; use Config\Database; use Tests\Support\ItemFixtureTrait; +use Tests\Support\SaleFixtureTrait; /** * Regression tests for GHSA-3xf6-8fmq-44wg. * * A cashier holding only the base "sales" grant (no "reports_sales") must * not be able to reach the per-sale endpoints that getManage() gates - * behind reports_sales: getRow, getEdit, postSave, getReceipt, getInvoice, - * getSendPdf, getSendReceipt. + * behind reports_sales: getSearch, getRow, getEdit, postSave, getReceipt, + * getInvoice, getSendPdf, getSendReceipt. + * + * Also covers: getSearch() (the AJAX endpoint that + * supplies every row of the Sales Takings list) was the one sibling that + * returned the full ledger and was missing the reports_sales check. */ class SalesControllerTest extends CIUnitTestCase { use DatabaseTestTrait; use FeatureTestTrait; use ItemFixtureTrait; + use SaleFixtureTrait; protected $migrate = true; protected $migrateOnce = true; @@ -214,49 +220,6 @@ class SalesControllerTest extends CIUnitTestCase ]); } - /** - * Inserts a minimal completed sale row directly, bypassing Sale::save_value() - * (which requires a full cart/inventory/tax pipeline unrelated to this - * authorization check). Sale::get_info() inner-joins sales_items, so a - * matching item/sales_items row is required for the sale to be found. - */ - protected function createSale(int $employeeId): int - { - $unique = uniqid(); - $db = Database::connect(); - - $db->table('items')->insert([ - 'name' => "Test Item $unique", - 'category' => 'Test', - 'description' => 'Test item', - 'cost_price' => 1, - 'unit_price' => 1, - 'item_number' => "TEST-$unique", - ]); - $itemId = (int) $db->insertID(); - - $db->table('sales')->insert([ - 'sale_time' => date('Y-m-d H:i:s'), - 'customer_id' => null, - 'employee_id' => $employeeId, - 'comment' => 'test sale', - 'invoice_number' => null, - ]); - $saleId = (int) $db->insertID(); - - $db->table('sales_items')->insert([ - 'sale_id' => $saleId, - 'item_id' => $itemId, - 'line' => 1, - 'quantity_purchased' => 1, - 'item_cost_price' => 1, - 'item_unit_price' => 1, - 'item_location' => 1, - ]); - - return $saleId; - } - /** * Seeds a single cart line directly in the session, mirroring the shape * Sale_lib::add_item() produces, so tests can target postEditItem's @@ -310,6 +273,20 @@ class SalesControllerTest extends CIUnitTestCase $this->assertFalse($result['success']); } + public function testCashierWithoutReportsSalesCannotGetSearch(): void + { + $cashierId = $this->createCashierEmployee(); + $this->createSale($cashierId); + $this->loginAs($cashierId); + + $response = $this->get('/sales/search'); + + $response->assertStatus(403); + $result = json_decode($response->getJSON(), true); + $this->assertFalse($result['success']); + $this->assertSame(lang('Sales.not_authorized'), $result['message']); + } + public function testCashierWithoutReportsSalesCannotGetEdit(): void { $cashierId = $this->createCashierEmployee(); @@ -395,19 +372,6 @@ class SalesControllerTest extends CIUnitTestCase $this->assertSame(lang('Sales.not_authorized'), $result['message']); } - public function testCashierWithoutReportsSalesCannotGetSearch(): void - { - $cashierId = $this->createCashierEmployee(); - $this->createSale($cashierId); - $this->loginAs($cashierId); - - $response = $this->get('/sales/search'); - - $response->assertStatus(403); - $result = json_decode($response->getJSON(), true); - $this->assertFalse($result['success']); - } - public function testEmployeeWithReportsSalesCanGetSearch(): void { $supervisorId = $this->createReportsSalesEmployee(); @@ -519,6 +483,101 @@ class SalesControllerTest extends CIUnitTestCase $this->assertEquals('0.01', $cart[1]['price']); } + public function testPostAddPaymentRejectsNegativeAmountTendered(): void + { + $cashierId = $this->createCashierWithoutChangePriceGrant(); + $this->loginAs($cashierId); + $itemId = $this->createTestItem(); + $this->seedCartLine(1, '1.00', $itemId); + + $forgedPaymentType = lang('Sales.giftcard') . ':AUDIT-100'; + + $response = $this->post('/sales/addPayment', [ + 'payment_type' => $forgedPaymentType, + 'amount_tendered' => '-500', + ]); + + $response->assertStatus(200); + $response->assertSee(lang('Sales.must_enter_numeric')); + + // ... and the negative payment must NOT have been added to the cart. + $session = Services::session(); + $payments = $session->get('sales_payments'); + $this->assertArrayNotHasKey($forgedPaymentType, (array) $payments); + } + + public function testPostAddPaymentRejectsMalformedAmountTendered(): void + { + $cashierId = $this->createCashierWithoutChangePriceGrant(); + $this->loginAs($cashierId); + $itemId = $this->createTestItem(); + $this->seedCartLine(1, '1.00', $itemId); + + $response = $this->post('/sales/addPayment', [ + 'payment_type' => lang('Sales.cash'), + 'amount_tendered' => 'ABC123', + ]); + + $response->assertStatus(200); + $response->assertSee(lang('Sales.must_enter_numeric')); + + $session = Services::session(); + $payments = $session->get('sales_payments'); + $this->assertArrayNotHasKey(lang('Sales.cash'), (array) $payments); + } + + public function testCashierWithoutReportsSalesCannotUnsuspend(): void + { + $victimId = $this->createReportsSalesEmployee(); + $saleId = $this->createSuspendedSale($victimId); + + $cashierId = $this->createCashierEmployee(); + $this->loginAs($cashierId); + + $response = $this->post('/sales/unsuspend', [ + 'suspended_sale_id' => $saleId, + ]); + + $response->assertStatus(403); + $result = json_decode($response->getJSON(), true); + $this->assertFalse($result['success']); + + $session = Services::session(); + $this->assertNotEquals($saleId, $session->get('sale_id')); + } + + public function testEmployeeWithReportsSalesCannotUnsuspendCompletedSale(): void + { + $victimId = $this->createReportsSalesEmployee(); + $saleId = $this->createSale($victimId); + + $supervisorId = $this->createReportsSalesEmployee(); + $this->loginAs($supervisorId); + + $this->post('/sales/unsuspend', [ + 'suspended_sale_id' => $saleId, + ]); + + $session = Services::session(); + $this->assertNotEquals($saleId, $session->get('sale_id')); + } + + public function testEmployeeWithReportsSalesCanUnsuspendSale(): void + { + $ownerId = $this->createReportsSalesEmployee(); + $saleId = $this->createSuspendedSale($ownerId); + + $supervisorId = $this->createReportsSalesEmployee(); + $this->loginAs($supervisorId); + + $this->post('/sales/unsuspend', [ + 'suspended_sale_id' => $saleId, + ]); + + $session = Services::session(); + $this->assertEquals($saleId, $session->get('sale_id')); + } + protected function createGiftcard(float $value): int { $giftcardNumber = random_int(1000000, 9999999); @@ -719,4 +778,42 @@ class SalesControllerTest extends CIUnitTestCase $this->assertStringNotContainsString('assertStringContainsString('<svg', $body); } + + public function testPostUnsuspendRejectsNonSuspendedSaleWithoutClearingActiveCart(): void + { + $employeeId = $this->createReportsSalesEmployee(); + $itemId = $this->createTestItem(HAS_NO_STOCK); + $notSuspendedSaleId = $this->createSale($employeeId); + $this->loginAs($employeeId); + $this->seedCartLine(1, '1.00', $itemId); + $this->withSession(array_merge($this->session, ['sale_id' => NEW_ENTRY])); + + $this->post('/sales/unsuspend', [ + 'suspended_sale_id' => (string) $notSuspendedSaleId, + ]); + + $cart = Services::session()->get('sales_cart'); + $this->assertNotEmpty($cart); + $this->assertArrayHasKey(1, $cart); + $this->assertSame($itemId, $cart[1]['item_id']); + $this->assertSame(NEW_ENTRY, Services::session()->get('sale_id')); + } + + public function testPostUnsuspendReplacesCartForValidSuspendedSale(): void + { + $employeeId = $this->createReportsSalesEmployee(); + $itemId = $this->createTestItem(HAS_NO_STOCK); + $suspendedSaleId = $this->createSuspendedSale($employeeId); + $this->loginAs($employeeId); + $this->seedCartLine(1, '1.00', $itemId); + + $this->post('/sales/unsuspend', [ + 'suspended_sale_id' => (string) $suspendedSaleId, + ]); + + $this->assertSame($suspendedSaleId, Services::session()->get('sale_id')); + $cart = Services::session()->get('sales_cart'); + $this->assertNotEmpty($cart); + $this->assertNotSame($itemId, array_values($cart)[0]['item_id']); + } } diff --git a/tests/Support/SaleFixtureTrait.php b/tests/Support/SaleFixtureTrait.php new file mode 100644 index 000000000..6b29600a6 --- /dev/null +++ b/tests/Support/SaleFixtureTrait.php @@ -0,0 +1,65 @@ +table('items')->insert([ + 'name' => "Test Item $unique", + 'category' => 'Test', + 'description' => 'Test item', + 'cost_price' => 1, + 'unit_price' => 1, + 'item_number' => "TEST-$unique", + ]); + $itemId = (int) $db->insertID(); + + $db->table('sales')->insert([ + 'sale_time' => date('Y-m-d H:i:s'), + 'customer_id' => null, + 'employee_id' => $employeeId, + 'comment' => 'test sale', + 'invoice_number' => null, + ]); + $saleId = (int) $db->insertID(); + + $db->table('sales_items')->insert([ + 'sale_id' => $saleId, + 'item_id' => $itemId, + 'line' => 1, + 'quantity_purchased' => 1, + 'item_cost_price' => 1, + 'item_unit_price' => 1, + 'item_location' => 1, + ]); + + return $saleId; + } + + /** + * Same as createSale(), but flips the sale to SUSPENDED afterward so + * postUnsuspend's status check can be exercised. + */ + protected function createSuspendedSale(int $employeeId): int + { + $saleId = $this->createSale($employeeId); + + model(Sale::class)->update_sale_status($saleId, SUSPENDED); + + return $saleId; + } +}