Files
opensourcepos/app/Language/el/Sales.php
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

<?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" => "Δωροκάρτα",
"giftcard_balance" => "Υπόλοιπο Δωροκάρτας",
"giftcard_filter" => "",
"giftcard_number" => "Αριθμός Δωροκάρτας",
"group_by_category" => "Ομαδοποίηση ανά Κατηγορία",
"group_by_type" => "Ομαδοποίηση ανά Είδος",
"hsn" => "HSN",
"id" => "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" => "Προσαρμοσμένο Τιμολόγιο (custom_invoice.php)",
"invoice_type_custom_tax_invoice" => "Προσαρμοσμένο Φορολογικό Τιμολόγιο (custom_tax_invoice.php)",
"invoice_type_invoice" => "Τιμολόγιο (invoice.php)",
"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" => "Ο Αριθμός της Δωροκάρτας πρέπει να είναι αριθμός.",
"new_customer" => "Νέος Πελάτης",
"new_item" => "Νέο Είδος",
"no_description" => "Δεν έχει περιγραφή",
"no_filter" => "Όλα",
"no_items_in_cart" => "Δεν υπάρχουν είδη στο καλάθι.",
"no_sales_to_display" => "Δεν υπάρχουν Πωλήσεις προς προβολή.",
"none_selected" => "Δεν έχετε επιλέξει Πώληση/σεις για διαγραφή.",
"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" => "Υπόλοιπο Πόντων Ανταμοιβής",
"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" => "Πληκτρολογήστε το είδος ή σκανάρετε το Barcode...",
"stock" => "Απόθεμα",
"stock_location" => "Τοποθεσία Αποθέματος",
"sub_total" => "Υποσύνολο",
"successfully_deleted" => "Έχετε διαγράψει επιτυχώς",
"successfully_restored" => "Έχετε επαναφέρει επιτυχώς",
"successfully_suspended_sale" => "Αναμονή Πώλησης επιτυχής.",
"successfully_updated" => "Ενημέρωση Πώλησης επιτυχής.",
"suspend_sale" => "Αναμονή",
"suspended_doc_id" => "Έγγραφο",
"suspended_sale_id" => "ID",
"suspended_sales" => "Ανεστάλη",
"table" => "Πίνακας",
"takings" => "Ημερήσιες Πωλήσεις",
"tax" => "Φόρος",
"tax_id" => "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" => "Ενέργεια",
"update" => "Ενημέρωση",
"upi" => "UPI",
"visa" => "",
"wholesale" => "",
"work_order" => "Παραγγελία Εργασίας",
"work_order_number" => "Αριθμός Παραγγελίας Εργασίας",
"work_order_number_duplicate" => "Ο Αριθμός της Παραγγελίας Εργασίας πρέπει να είναι μοναδικός.",
"work_order_sent" => "Εντολή Εργασίας απεστάλη σε",
"work_order_unsent" => "Ανεπιτυχής αποστολή Εντολής Εργασίας",
];