Files
opensourcepos/app/Language/bg/Sales.php
Nozomu Sasaki (Paul) 85c7ce2da4 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>
2026-04-03 14:49:42 +04:00

232 lines
17 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
return [
"customers_available_points" => "Налични точки",
"rewards_package" => "Награди",
"rewards_remaining_balance" => "Оставащата стойност на точките за награда е ",
"account_number" => "Номер на акаунт",
"add_payment" => "Добавяне на плащане",
"amount_due" => "Дължима сума",
"amount_tendered" => "Предоставена сума",
"authorized_signature" => "Оторизиран подпис",
"cancel_sale" => "Отказ",
"cash" => "В брой",
"cash_1" => "",
"cash_2" => "",
"cash_3" => "",
"cash_4" => "",
"cash_adjustment" => "Корекция на пари в брой",
"cash_deposit" => "Депозит в брой",
"cash_filter" => "В брой",
"change_due" => "Промяна на дължимото",
"change_price" => "Промяна на продажната цена",
"check" => "Проверка",
"check_balance" => "Проверете остатъка",
"check_filter" => "Проверка",
"close" => "",
"comment" => "Коментар",
"comments" => "Коментари",
"company_name" => "",
"complete" => "",
"complete_sale" => "Завършен",
"confirm_cancel_sale" => "Сигурни ли сте, че искате да изчистите тази продажба? Всичко ще бъде изтрито.",
"confirm_delete" => "Наистина ли искате да изтриете избраната Продажба (и)?",
"confirm_restore" => "Наистина ли искате да възстановите избраната Продажба (и)?",
"credit" => "Кредитна карта",
"credit_deposit" => "Кредитен депозит",
"credit_filter" => "Кредитна карта",
"current_table" => "",
"customer" => "Име",
"customer_address" => "Адрес",
"customer_discount" => "Намаление",
"customer_email" => "Електронна поща",
"customer_location" => "Местоположение",
"customer_mailchimp_status" => "Състояние на Mailchimp",
"customer_optional" => "(Незадължително)",
"customer_required" => "(Задължително)",
"customer_total" => "Обща сума",
"customer_total_spent" => "",
"daily_sales" => "",
"date" => "Дата на продажба",
"date_range" => "Период от време",
"date_required" => "Трябва да въведете правилна дата.",
"date_type" => "Датата е задължително поле.",
"debit" => "Дебитна карта",
"debit_filter" => "",
"delete" => "Разреши изтриване",
"delete_confirmation" => "Наистина ли искате да изтриете тази продажба? Това действие не може да бъде отменено.",
"delete_entire_sale" => "Изтриване на цялата продажба",
"delete_successful" => "Продажбата е изтрита успешно.",
"delete_unsuccessful" => "Изтриването на продажба не бе успешно.",
"description_abbrv" => "Описание.",
"discard" => "Разпродажба",
"discard_quote" => "",
"discount" => "Намаление%",
"discount_included" => "% Отстъпка",
"discount_short" => "%",
"due" => "Дължимото",
"due_filter" => "Дължимо",
"edit" => "Редактиране",
"edit_item" => "Редактиране на елемент",
"edit_sale" => "Редактиране на продажбата",
"email_receipt" => "Електронна разписка",
"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 Карта",
"giftcard_balance" => "Gift Card Баланс",
"giftcard_filter" => "",
"giftcard_number" => "Gift Card Номер",
"group_by_category" => "Групирайте по категория",
"group_by_type" => "Групиране по тип",
"hsn" => "HSN",
"id" => "Номер на продажба",
"include_prices" => "Включва цени?",
"invoice" => "Фактура",
"invoice_confirm" => "Тази фактура ще бъде изпратена до",
"invoice_enable" => "Създаване на фактура",
"invoice_filter" => "Фактури",
"invoice_no_email" => "Този клиент няма валиден имейл адрес.",
"invoice_number" => "Фактура #",
"invoice_number_duplicate" => "Номерът на фактурите трябва да е уникален.",
"invoice_sent" => "Фактура, изпратена до",
"invoice_total" => "Фактура общо",
"invoice_type_custom_invoice" => "Ръчна фактура",
"invoice_type_custom_tax_invoice" => "Фактура по избор(custom_tax_invoice.php)",
"invoice_type_invoice" => "Фактура",
"invoice_type_tax_invoice" => "Данъчна фактура (tax_invoice.php)",
"invoice_unsent" => "Фактурата не можа да бъде изпратена до",
"invoice_update" => "Преизчисляване",
"item_insufficient_of_stock" => "Елементът има недостатъчен запас.",
"item_name" => "Име на предмета",
"item_number" => "Предмет #",
"item_out_of_stock" => "Елементът е изчерпан.",
"key_browser" => "",
"key_cancel" => "Cancels Current Quote/Invoice/Sale",
"key_customer_search" => "Customer Search",
"key_finish_quote" => "Finish Quote/Invoice witdout payment",
"key_finish_sale" => "Add Payment and Complete Invoice/Sale",
"key_full" => "",
"key_function" => "Function",
"key_help" => "Shortcuts",
"key_help_modal" => "Open Shortcuts Window",
"key_in" => "",
"key_item_search" => "Item Search",
"key_out" => "",
"key_payment" => "Add Payment",
"key_print" => "",
"key_restore" => "",
"key_search" => "",
"key_suspend" => "Suspend Current Sale",
"key_suspended" => "Show Suspended Sales",
"key_system" => "",
"key_tendered" => "Edit Amount Tendered",
"key_title" => "Sales Keyboard Shortcuts",
"mc" => "",
"mode" => "Режим на регистрация",
"must_enter_numeric" => "Сумата Предложена трябва да е число.",
"must_enter_numeric_giftcard" => "Gift Card номера трябва да бъде число.",
"new_customer" => "Нов клиент",
"new_item" => "Нов продукт",
"no_description" => "Нито един",
"no_filter" => "Всичко",
"no_items_in_cart" => "В количката няма продукти.",
"no_sales_to_display" => "Няма продажби за показване .",
"none_selected" => "Не сте избрали каквито и да е Продажби за изтриване.",
"nontaxed_ind" => " sales nontaxed ind ",
"not_authorized" => "Това действие не е разрешено.",
"one_or_multiple" => "Продажба (и)",
"payment" => "Вид плащане",
"payment_amount" => "Количество",
"payment_not_cover_total" => "Сумата за плащане трябва да е по-голяма или равна на цялата сума.",
"payment_type" => "Тип",
"payments" => "",
"payments_total" => "Общо плащания",
"price" => "Цена",
"print_after_sale" => "Печат след продажбата",
"quantity" => "Количество",
"quantity_less_than_reorder_level" => "Предупреждение: Желаното количество е под нивото на зареждане за тази позиция.",
"quantity_less_than_zero" => "Предупреждение: Желаното количество е недостатъчно. Все още можете да обработвате продажбата, но одитирайте инвентара си.",
"quantity_of_items" => "Количество{0} елементи",
"quote" => "Цитат",
"quote_number" => "Номер на цитата",
"quote_number_duplicate" => "Номерът на Цитат трябва да е уникален.",
"quote_sent" => "Цитат изпратен до",
"quote_unsent" => "Цитатът не можа да бъде изпратен до",
"receipt" => "Касова бележка",
"receipt_no_email" => "Този клиент няма валиден имейл адрес.",
"receipt_number" => "Продажба #",
"receipt_sent" => "Разписката е изпратена до",
"receipt_unsent" => "Разписката не бе изпратена до",
"refund" => "Вид на въстановяването",
"register" => "Регистър на продажбите",
"remove_customer" => "Премахване на клиент",
"remove_discount" => "",
"return" => "Връщане",
"rewards" => "Наградни точки",
"rewards_balance" => "Reward Points Баланс",
"sale" => "Продажба",
"sale_by_invoice" => "Продажба по фактура",
"sale_for_customer" => "Клиент:",
"sale_time" => "Време",
"sales_tax" => "Данък върху продажбите",
"sales_total" => "",
"select_customer" => "Изберете клиент (по избор)",
"send_invoice" => "Изпратете фактура",
"send_quote" => "Изпрати цитат",
"send_receipt" => "Изпращане на разписка",
"send_work_order" => "Изпращане на поръчка за работа",
"serial" => "Сериен",
"service_charge" => "",
"show_due" => "",
"show_invoice" => "Показване на фактурата",
"show_receipt" => "Показване на разписката",
"start_typing_customer_name" => "Започнете да пишете подробности за клиента ...",
"start_typing_item_name" => "Започнете да въвеждате името на елемента или да сканирате баркод ...",
"stock" => "Наличност",
"stock_location" => "Местоположение на наличност",
"sub_total" => "Междинна сума",
"successfully_deleted" => "Вие успешно сте изтрили",
"successfully_restored" => "Вие успешно сте възстановили",
"successfully_suspended_sale" => "Успешно спиране на продажбата.",
"successfully_updated" => "Обновихте продажбата успешно.",
"suspend_sale" => "Задържане",
"suspended_doc_id" => "Документ",
"suspended_sale_id" => "Номер",
"suspended_sales" => "Преустановен",
"table" => "Маса",
"takings" => "Ежедневни продажби",
"tax" => "Данък",
"tax_id" => "Данъчен номер",
"tax_invoice" => "Данъчна фактура",
"tax_percent" => "Данък %",
"taxed_ind" => "",
"total" => "Обща сума",
"total_tax_exclusive" => "Без данък",
"transaction_failed" => "Продажната транзакция е неуспешна.",
"unable_to_add_item" => "Добавянето на продукта към продажбата не бе успешно",
"unsuccessfully_deleted" => "Изтриването на продажба (и) не бе успешно.",
"unsuccessfully_restored" => "Възстановяването на Продажбата (ите) не бе успешна.",
"unsuccessfully_suspended_sale" => "Преустановяването на продажбата бе неуспешно.",
"unsuccessfully_updated" => "Актуализацията на продажбата не бе успешна.",
"unsuspend" => "Възстановяване",
"unsuspend_and_delete" => "Action",
"update" => "Актуализация",
"upi" => "",
"visa" => "",
"wholesale" => "",
"work_order" => "Работна поръчка",
"work_order_number" => "Номер работна поръчка",
"work_order_number_duplicate" => "Номерът на работната поръчка трябва да е уникален.",
"work_order_sent" => "Работната поръчка е изпратена до",
"work_order_unsent" => "Работната поръчка не бе изпратена до",
];