mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-09-13 05:47:23 -04:00
Merge remote-tracking branch 'OpensourcePOS/master' into plugin-system-fresh
This commit is contained in:
commit
e581cecdd8
53 files changed
+297
-126
No files matched your search
+22
-12
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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.',
|
||||
|
||||
@@ -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.',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => 'จำนวนไม่สามารถเป็นค่าติดลบได้',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -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' => '',
|
||||
|
||||
@@ -147,7 +147,7 @@ class Barcode_lib
|
||||
$barcode = $this->generate_barcode($item, $barcode_config);
|
||||
$display_table = '<table>';
|
||||
$display_table .= '<tr><td style="text-align: center;">' . $this->manageDisplayLayout($barcode_config['barcode_first_row'], $item, $barcode_config) . '</td></tr>';
|
||||
$display_table .= '<tr><td style="text-align: center;"><div class="barcode">'.$barcode.'</div></td></tr>';
|
||||
$display_table .= '<tr><td style="text-align: center;"><div class="barcode">' . $barcode . '</div></td></tr>';
|
||||
$display_table .= '<tr><td style="text-align: center;">' . $this->manageDisplayLayout($barcode_config['barcode_second_row'], $item, $barcode_config) . '</td></tr>';
|
||||
$display_table .= '<tr><td style="text-align: center;">' . $this->manageDisplayLayout($barcode_config['barcode_third_row'], $item, $barcode_config) . '</td></tr>';
|
||||
$display_table .= '</table>';
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+5
-3
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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('<svg onload', $body);
|
||||
$this->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']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Support;
|
||||
|
||||
use App\Models\Sale;
|
||||
use Config\Database;
|
||||
|
||||
trait SaleFixtureTrait
|
||||
{
|
||||
/**
|
||||
* Inserts a minimal completed sale row directly, bypassing Sale::save_value()
|
||||
* (which requires a full cart/inventory/tax pipeline unrelated to authorization
|
||||
* checks). 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user