Fix negative price/quantity/discount validation (GHSA-wv3j-pp8r-7q43) (#4450)

* Fix business logic vulnerability allowing negative sale totals (GHSA-wv3j-pp8r-7q43)

Add server-side validation in postEditItem() to reject negative prices,
quantities, and discounts, as well as percentage discounts exceeding 100%
and fixed discounts exceeding the item total. Also block sale completion
with negative totals in non-return mode to prevent fraud/theft.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix: exempt return mode from negative quantity validation

Return mode legitimately stores items with negative quantities.
The quantity validation now skips the non-negative check in return mode,
consistent with the existing return mode exemption in postComplete().
Also use abs() for fixed discount comparison to handle return quantities.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Refactor: use $rules + validate() pattern per review feedback

Address review comments from jekkos on PR #4450:

1. Use CI4 $rules variable with custom non_negative_decimal validation
   rule instead of manual if-checks for price/discount validation.

2. Add validation error strings to all 44 non-English language files
   (English fallback values used until translations are contributed).

3. Use validate() method with $messages array for localized error
   display, maintaining the existing controller pattern.

Additional improvements:
- Add non_negative_decimal rule to OSPOSRules.php (leverages
  parse_decimals() for locale-aware decimal parsing)
- Preserve manual checks for business logic (return mode quantity
  exemption, discount bounds via bccomp)
- Fix PHP 8.1+ compatibility: avoid passing method return to reset()
- Explicit empty discount handling for bc-math safety

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix: rename to nonNegativeDecimal (PSR), clear non-English translation strings

- Rename validation rule method non_negative_decimal → nonNegativeDecimal in
  OSPOSRules.php and all $rules/$messages references in Sales.php (PSR naming
  per @objecttothis review)
- Replace English fallback text with "" in 43 non-English language files so
  CI4 falls back to the base language string; weblate will handle translations
  (per @jekkos and @objecttothis agreement)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Paul <morimori-dev@github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: objecttothis <17935339+objecttothis@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2026-04-03 14:49:42 +04:00
1 parent e723e2ddf4
commit 85c7ce2da4
47 files changed
+323 -5

No files matched your search

+15
View File
@@ -135,4 +135,19 @@ class OSPOSRules
{
return parse_decimals($candidate) !== false;
}
/**
* Validates that a locale-aware decimal value is non-negative (>= 0).
*
* @param string $candidate
* @param string|null $error
* @return bool
* @noinspection PhpUnused
*/
public function nonNegativeDecimal(string $candidate, ?string &$error = null): bool
{
$value = parse_decimals($candidate);
return $value !== false && $value >= 0;
}
}
+38 -5
View File
@@ -582,12 +582,21 @@ class Sales extends Secure_Controller
$data = [];
$rules = [
'price' => 'trim|required|decimal_locale',
'price' => 'trim|required|decimal_locale|nonNegativeDecimal',
'quantity' => 'trim|required|decimal_locale',
'discount' => 'trim|permit_empty|decimal_locale',
'discount' => 'trim|permit_empty|decimal_locale|nonNegativeDecimal',
];
if ($this->validate($rules)) {
$messages = [
'price' => [
'nonNegativeDecimal' => lang('Sales.negative_price_invalid'),
],
'discount' => [
'nonNegativeDecimal' => lang('Sales.negative_discount_invalid'),
],
];
if ($this->validate($rules, $messages)) {
$description = $this->request->getPost('description', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
$serialnumber = $this->request->getPost('serialnumber', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
$price = parse_decimals($this->request->getPost('price'));
@@ -596,20 +605,38 @@ class Sales extends Secure_Controller
$discount = $discount_type
? parse_quantity($this->request->getPost('discount'))
: parse_decimals($this->request->getPost('discount'));
$discount = $discount ?: 0;
// Return mode legitimately uses negative quantities for refunds
if ($this->sale_lib->get_mode() != 'return' && $quantity < 0) {
$data['error'] = lang('Sales.negative_quantity_invalid');
return $this->_reload($data);
}
// Business logic: discount bounds depend on discount_type and item values
if ($discount_type == PERCENT && $discount > 100) {
$data['error'] = lang('Sales.discount_percent_exceeds_100');
return $this->_reload($data);
}
if ($discount_type == FIXED && bccomp((string)$discount, bcmul((string)abs($quantity), (string)$price, 2), 2) > 0) {
$data['error'] = lang('Sales.discount_exceeds_item_total');
return $this->_reload($data);
}
$item_location = $this->request->getPost('location', FILTER_SANITIZE_NUMBER_INT);
$discounted_total = $this->request->getPost('discounted_total') != ''
? parse_decimals($this->request->getPost('discounted_total') ?? '')
: null;
$this->sale_lib->edit_item($line, $description, $serialnumber, $quantity, $discount, $discount_type, $price, $discounted_total);
$this->sale_lib->empty_payments();
$data['warning'] = $this->sale_lib->out_of_stock($this->sale_lib->get_item_id($line), $item_location);
} else {
$data['error'] = lang('Sales.error_editing_item');
$errors = $this->validator->getErrors();
$data['error'] = $errors ? reset($errors) : lang('Sales.error_editing_item');
}
return $this->_reload($data);
@@ -723,6 +750,12 @@ class Sales extends Secure_Controller
$data['cash_amount_due'] = $totals['cash_amount_due'];
$data['non_cash_amount_due'] = $totals['amount_due'];
// Prevent negative total sales (fraud/theft vector) - returns can have negative totals for legitimate refunds
if ($this->sale_lib->get_mode() != 'return' && bccomp($totals['total'], '0') < 0) {
$data['error'] = lang('Sales.negative_total_invalid');
return $this->_reload($data);
}
if ($data['cash_mode']) { // TODO: Convert this to ternary notation
$data['amount_due'] = $totals['cash_amount_due'];
} else {
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "الموظف",
"entry" => "ادخال",
"error_editing_item" => "خطاء فى تحرير الصنف",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "بحث/مسح باركود صنف",
"find_or_scan_item_or_receipt" => "بحث/مسح باركود صنف أو ايصال",
"giftcard" => "بطاقة هدية",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "الموظف",
"entry" => "ادخال",
"error_editing_item" => "خطاء فى تعديل المادة",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "بحث/مسح باركود المادة",
"find_or_scan_item_or_receipt" => "بحث/مسح باركود المادة أو الايصال",
"giftcard" => "بطاقة هدية",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Əməkdaş",
"entry" => "Daxil",
"error_editing_item" => "XƏTA Malın redaktəsində",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Malın axtarışı",
"find_or_scan_item_or_receipt" => "Tapmaq skan etmək və ya kvitansiya",
"giftcard" => "Hədiyyə Kartı",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Служител",
"entry" => "Вход",
"error_editing_item" => "Грешка при редактирането на елемента",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Намерете или сканирайте елемента",
"find_or_scan_item_or_receipt" => "Намерете или сканирайте елемент или разпис",
"giftcard" => "Gift Карта",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Zaposlenik",
"entry" => "Ulaz",
"error_editing_item" => "Greška pri uređivanju artikla",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Pronađi/Skeniraj artikal",
"find_or_scan_item_or_receipt" => "Pronađi/Skeniraj artikal ili priznanicu",
"giftcard" => "Poklon kartica",
+6
View File
@@ -73,6 +73,12 @@ return [
'employee' => "فەرمانبەر",
'entry' => "تۆمار",
'error_editing_item' => "هەڵە لە دەستکاریکردنی ئایتم",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
'find_or_scan_item' => "دۆزینەوە یان سکانکردنی ئایتم",
'find_or_scan_item_or_receipt' => "دۆزینەوە یان سکانکردنی ئایتم یان پسوڵە",
'giftcard' => "کارتی دیاری",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Prodávající",
"entry" => "Záznam",
"error_editing_item" => "Chyba při úpravě položky",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Najít nebo skenovat položku",
"find_or_scan_item_or_receipt" => "Najít nebo skenovat položku či účtenku",
"giftcard" => "Dárkový poukaz",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "",
"entry" => "",
"error_editing_item" => "",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "",
"find_or_scan_item_or_receipt" => "",
"giftcard" => "Gavekort",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Mitarbeiter",
"entry" => "",
"error_editing_item" => "Fehler beim Ändern des Artikels",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Finde/Scanne Artikel",
"find_or_scan_item_or_receipt" => "Finde/Scanne Artikel oder Quittung",
"giftcard" => "Gutschein",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Mitarbeiter",
"entry" => "Eintrag",
"error_editing_item" => "Fehler beim Ändern des Artikels",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Finde/Scanne Artikel",
"find_or_scan_item_or_receipt" => "Finde/Scanne Artikel oder Quittung",
"giftcard" => "Gutschein",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Υπάλληλος",
"entry" => "Εγγραφή",
"error_editing_item" => "Σφάλμα επεξεργασίας είδους",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Εύρεση ή Σκανάρισμα Είδους",
"find_or_scan_item_or_receipt" => "Εύρεση ή Σκανάρισμα είδους ή Απόδειξης",
"giftcard" => "Δωροκάρτα",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Employee",
"entry" => "Entry",
"error_editing_item" => "Error editing item",
"negative_price_invalid" => "Price cannot be negative.",
"negative_quantity_invalid" => "Quantity cannot be negative.",
"negative_discount_invalid" => "Discount cannot be negative.",
"discount_percent_exceeds_100" => "Percentage discount cannot exceed 100%.",
"discount_exceeds_item_total" => "Discount cannot exceed the item total.",
"negative_total_invalid" => "Sale total cannot be negative. Check item discounts and quantities.",
"find_or_scan_item" => "Find or Scan Item",
"find_or_scan_item_or_receipt" => "Find or Scan Item or Receipt",
"giftcard" => "Gift Card",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Employee",
"entry" => "Entry",
"error_editing_item" => "Error editing item",
"negative_price_invalid" => "Price cannot be negative.",
"negative_quantity_invalid" => "Quantity cannot be negative.",
"negative_discount_invalid" => "Discount cannot be negative.",
"discount_percent_exceeds_100" => "Percentage discount cannot exceed 100%.",
"discount_exceeds_item_total" => "Discount cannot exceed the item total.",
"negative_total_invalid" => "Sale total cannot be negative. Check item discounts and quantities.",
"find_or_scan_item" => "Find or Scan Item",
"find_or_scan_item_or_receipt" => "Find or Scan Item or Receipt",
"giftcard" => "Gift Card",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Empleado",
"entry" => "Entrada",
"error_editing_item" => "Error editando artículo",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Encontrar/Escanear Artículo",
"find_or_scan_item_or_receipt" => "Encontrar/Escanear Artículo o Entrada",
"giftcard" => "Tarjeta de Regalo",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Empleado",
"entry" => "Entrada",
"error_editing_item" => "Error editando el artículo",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Buscar o escanear artículo",
"find_or_scan_item_or_receipt" => "Buscar o escanear artículo o recibo",
"giftcard" => "Tarjeta de regalo",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "کارمند",
"entry" => "ورود",
"error_editing_item" => "خطا در ویرایش مورد",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "یافتن یا اسکن کردن مورد",
"find_or_scan_item_or_receipt" => "یافتن یا اسکن کردن مورد یا رسید",
"giftcard" => "کارت هدیه",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Employé",
"entry" => "Entrée",
"error_editing_item" => "Érreur lors de l'édition",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Trouver/Scanner Article",
"find_or_scan_item_or_receipt" => "Trouver/Scanner Article OU Reçu",
"giftcard" => "Carte Cadeau",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "עובד",
"entry" => "ערך",
"error_editing_item" => "שגיאה בעריכת פריט",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "חיפוש או סריקה של פריט",
"find_or_scan_item_or_receipt" => "חיפוש או סריקה של פריט או קבלה",
"giftcard" => "כרטיס מתנה",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Radnik",
"entry" => "",
"error_editing_item" => "Greška kod uređivanja artikla",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Pronađi/Skaniraj artikal",
"find_or_scan_item_or_receipt" => "Pronađi/Skaniraj artikal ili račun",
"giftcard" => "Poklon bon",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Dolgozó",
"entry" => "",
"error_editing_item" => "Termék módositási hiba",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Termék keresés/scan",
"find_or_scan_item_or_receipt" => "Termék keresése",
"giftcard" => "Ajándék utalvány",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "",
"entry" => "",
"error_editing_item" => "",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "",
"find_or_scan_item_or_receipt" => "",
"giftcard" => "",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Karyawan",
"entry" => "Entri",
"error_editing_item" => "mengubah item salah",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Cari/Scan Item",
"find_or_scan_item_or_receipt" => "Temukan atau pindai Item atau Faktur",
"giftcard" => "Kartu Hadiah",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Impiegato",
"entry" => "Voce",
"error_editing_item" => "Errore modificando un articolo",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Scansiona o Cerca Articolo",
"find_or_scan_item_or_receipt" => "Scansiona o Cerca Articolo o Scontrino",
"giftcard" => "Carta Regalo",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "បុគ្គលិក",
"entry" => "បញ្ចូល",
"error_editing_item" => "មានកំហុស ក្នុងការកែប្រែទំនិញ",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "ស្វែងរក ឬស្កេនទំនិញ",
"find_or_scan_item_or_receipt" => "ស្វែងរក ឬ​ស្កេនទំនិញ ឬ វិក័យបត្រ",
"giftcard" => "កាតអំណោយ",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Employee",
"entry" => "Entry",
"error_editing_item" => "Error editing item",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Find or Scan Item",
"find_or_scan_item_or_receipt" => "Find or Scan Item or Receipt",
"giftcard" => "Gift Card",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "",
"entry" => "",
"error_editing_item" => "",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "",
"find_or_scan_item_or_receipt" => "",
"giftcard" => "",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "",
"entry" => "",
"error_editing_item" => "",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "",
"find_or_scan_item_or_receipt" => "",
"giftcard" => "",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Werknemer",
"entry" => "Rij",
"error_editing_item" => "Fout bij bewerken",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Zoek/Scan Product",
"find_or_scan_item_or_receipt" => "Zoek/Scan Product of Ticket",
"giftcard" => "Cadeaubon",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Werknemer",
"entry" => "Vermelding",
"error_editing_item" => "Fout bij artikel bewerken",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Artikel zoeken of scannen",
"find_or_scan_item_or_receipt" => "Artikel of kassabon vinden of scannen",
"giftcard" => "Cadeaubon",
+6
View File
@@ -73,6 +73,12 @@ return [
'employee' => "",
'entry' => "",
'error_editing_item' => "",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
'find_or_scan_item' => "",
'find_or_scan_item_or_receipt' => "",
'giftcard' => "Karta Podarunkowa",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Empregado",
"entry" => "Entrada",
"error_editing_item" => "Erro editando item",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Pesquisar Item",
"find_or_scan_item_or_receipt" => "Produto",
"giftcard" => "Cupom",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Salariat",
"entry" => "Intrare",
"error_editing_item" => "Eroare editare articol",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Gaseste sau scaneaza Articol",
"find_or_scan_item_or_receipt" => "Gaseste sau scaneaza Articol sau Chitanta",
"giftcard" => "Card Cadou",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Сотрудник",
"entry" => "Запись",
"error_editing_item" => "Ошибка при редактировании товара",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Найти/Сканировать товар",
"find_or_scan_item_or_receipt" => "Найти/Сканировать товара или квитанцию",
"giftcard" => "Подарочная карта",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Anställd",
"entry" => "Post",
"error_editing_item" => "Ändra artikel misslyckades",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Hitta eller skanna artikel",
"find_or_scan_item_or_receipt" => "Hitta eller skanna artikel eller kvitto",
"giftcard" => "Presentkort",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Mfanyakazi",
"entry" => "Ingizo",
"error_editing_item" => "Hitilafu katika kuhariri bidhaa",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Tafuta au Changanua Bidhaa",
"find_or_scan_item_or_receipt" => "Tafuta au Changanua Bidhaa au Risiti",
"giftcard" => "Kadi ya Zawadi",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Mfanyakazi",
"entry" => "Ingizo",
"error_editing_item" => "Hitilafu katika kuhariri bidhaa",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Tafuta au Changanua Bidhaa",
"find_or_scan_item_or_receipt" => "Tafuta au Changanua Bidhaa au Risiti",
"giftcard" => "Kadi ya Zawadi",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "ஊழியர்",
"entry" => "உள்ளீடு",
"error_editing_item" => "பொருளை திருத்துவதில் பிழை",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "பொருளைக் தேடு அல்லது ஸ்கேன் செய்யுங்கள்",
"find_or_scan_item_or_receipt" => "தேடு அல்லது பொருளை வருடு அல்லது ரசீது",
"giftcard" => "பரிசு அட்டை",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "พนักงาน",
"entry" => "การนำเข้า",
"error_editing_item" => "แก้ไขสินค้าล้มเหลว",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "ค้นหาสินค้า",
"find_or_scan_item_or_receipt" => "ค้นหา หรือ แสกนรายการ หรือ ใบเสร็จ",
"giftcard" => "บัตรของขวัญ",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Employee",
"entry" => "Entry",
"error_editing_item" => "Error editing item",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Find or Scan Item",
"find_or_scan_item_or_receipt" => "Find or Scan Item or Receipt",
"giftcard" => "Gift Card",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Personel",
"entry" => "Girdi",
"error_editing_item" => "Ürün düzenleme hatası",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Ürün Bul/Oku",
"find_or_scan_item_or_receipt" => "Ürün yada Fiş Bul/Oku",
"giftcard" => "Hediye Çeki",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Працівник",
"entry" => "Вхід",
"error_editing_item" => "Помилка редагування товару",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Знайти/Сканувати товар",
"find_or_scan_item_or_receipt" => "Знайти/Сканувати товар або квитанцію",
"giftcard" => "Подарункова карта",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "",
"entry" => "",
"error_editing_item" => "",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "",
"find_or_scan_item_or_receipt" => "",
"giftcard" => "",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "Nhân viên",
"entry" => "Mục nhập",
"error_editing_item" => "Lỗi sửa hàng hóa",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "Tìm hay quét Hàng hóa",
"find_or_scan_item_or_receipt" => "Tìm hay quét Hàng hóa hay Biên lai",
"giftcard" => "Thẻ quà tặng",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "員工",
"entry" => "",
"error_editing_item" => "編輯產品錯誤",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "查找/掃描商品",
"find_or_scan_item_or_receipt" => "查找/掃描產品或收貨單",
"giftcard" => "禮金券",
+6
View File
@@ -73,6 +73,12 @@ return [
"employee" => "員工",
"entry" => "加入項目",
"error_editing_item" => "編輯產品錯誤",
"negative_price_invalid" => "",
"negative_quantity_invalid" => "",
"negative_discount_invalid" => "",
"discount_percent_exceeds_100" => "",
"discount_exceeds_item_total" => "",
"negative_total_invalid" => "",
"find_or_scan_item" => "查找/掃描商品",
"find_or_scan_item_or_receipt" => "查找/掃描產品或收貨單",
"giftcard" => "禮金券",