Translate UI and user-facing messages to Ukrainian (#5)
- All frontend pages, labels, notices and errors; html lang=uk, uk-UA money format - Brand "Assistant System" in the top bar and page title - Backend error details returned to the UI (auth, orders, receipts, cash registers, Checkbox/CRM/NP errors) and CLI output - Tests updated for the new messages Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -133,7 +133,7 @@ def build_goods(order: Order, tax_codes: list[Any]) -> tuple[list[dict[str, Any]
|
||||
price = to_kopecks(good["price"])
|
||||
quantity = to_thousandths(good["quantity"])
|
||||
if quantity <= 0:
|
||||
raise ReceiptValidationError(f"Товар «{good['name']}»: количество должно быть больше 0")
|
||||
raise ReceiptValidationError(f"Товар «{good['name']}»: кількість має бути більшою за 0")
|
||||
gross = _line_sum(price, quantity)
|
||||
# `amount` — сумма строки после скидки CRM; скидку выводим из неё,
|
||||
# а не из discount_amount/percent, чтобы не расходиться с итогом CRM.
|
||||
@@ -141,7 +141,7 @@ def build_goods(order: Order, tax_codes: list[Any]) -> tuple[list[dict[str, Any]
|
||||
discount = gross - net
|
||||
if discount < 0:
|
||||
raise ReceiptValidationError(
|
||||
f"Товар «{good['name']}»: сумма строки больше цены × количество"
|
||||
f"Товар «{good['name']}»: сума рядка більша за ціну × кількість"
|
||||
)
|
||||
|
||||
payload: dict[str, Any] = {
|
||||
@@ -168,7 +168,7 @@ def build_ettn_body(
|
||||
order_discount = goods_total - amounts.total_kopecks
|
||||
if order_discount < 0:
|
||||
raise ReceiptValidationError(
|
||||
"Сумма товаров меньше суммы заказа — проверьте заказ в CRM"
|
||||
"Сума товарів менша за суму замовлення — перевірте замовлення в CRM"
|
||||
)
|
||||
# Предоплата и скидка заказа — одной обычной скидкой «Знижка», как в чеках из
|
||||
# портала Checkbox. Тип `PRE_PAYMENT` для ЕТТН не годится: Checkbox отвечает
|
||||
@@ -185,7 +185,7 @@ def build_ettn_body(
|
||||
receipt_total = goods_total - order_discount - amounts.prepayment_kopecks
|
||||
if receipt_total != amounts.cod_kopecks:
|
||||
raise ReceiptValidationError(
|
||||
f"Сумма чека {receipt_total / 100:.2f} ₴ ≠ наложка {amounts.cod_kopecks / 100:.2f} ₴"
|
||||
f"Сума чека {receipt_total / 100:.2f} ₴ ≠ післяплата {amounts.cod_kopecks / 100:.2f} ₴"
|
||||
)
|
||||
|
||||
receipt_body: dict[str, Any] = {
|
||||
@@ -222,30 +222,30 @@ def resolve_amounts(order: Order, prepayment_kopecks: int | None) -> ReceiptAmou
|
||||
`prepayment_kopecks=None` — взять разницу между суммой заказа и наложкой.
|
||||
"""
|
||||
if order.is_deleted:
|
||||
raise ReceiptValidationError("Заказ удалён")
|
||||
raise ReceiptValidationError("Замовлення видалено")
|
||||
if not order.waybill_number:
|
||||
raise ReceiptValidationError("У заказа нет ТТН")
|
||||
raise ReceiptValidationError("У замовлення немає ТТН")
|
||||
if not order.np_cod_amount_kopecks:
|
||||
raise ReceiptValidationError("По ТТН нет суммы контроля оплаты (наложки)")
|
||||
raise ReceiptValidationError("За ТТН немає суми контролю оплати (післяплати)")
|
||||
if order.np_status_code in NP_FINAL_STATUS_CODES:
|
||||
raise ReceiptValidationError(
|
||||
f"Посылка уже не в пути ({order.np_status or order.np_status_code}) — "
|
||||
"ЕТТН-чек создать нельзя"
|
||||
f"Посилка вже не в дорозі ({order.np_status or order.np_status_code}) — "
|
||||
"ЕТТН-чек створити неможливо"
|
||||
)
|
||||
if not order.goods:
|
||||
raise ReceiptValidationError("В заказе нет товаров")
|
||||
raise ReceiptValidationError("У замовленні немає товарів")
|
||||
|
||||
total = order.total_amount_kopecks
|
||||
cod = order.np_cod_amount_kopecks
|
||||
prepayment = total - cod if prepayment_kopecks is None else prepayment_kopecks
|
||||
if prepayment < 0:
|
||||
raise ReceiptValidationError(
|
||||
f"Наложка {cod / 100:.2f} ₴ больше суммы заказа {total / 100:.2f} ₴"
|
||||
f"Післяплата {cod / 100:.2f} ₴ більша за суму замовлення {total / 100:.2f} ₴"
|
||||
)
|
||||
if total - prepayment != cod:
|
||||
raise ReceiptValidationError(
|
||||
f"Сумма заказа {total / 100:.2f} ₴ − предоплата {prepayment / 100:.2f} ₴ "
|
||||
f"≠ наложка {cod / 100:.2f} ₴"
|
||||
f"Сума замовлення {total / 100:.2f} ₴ − передоплата {prepayment / 100:.2f} ₴ "
|
||||
f"≠ післяплата {cod / 100:.2f} ₴"
|
||||
)
|
||||
return ReceiptAmounts(total_kopecks=total, prepayment_kopecks=prepayment, cod_kopecks=cod)
|
||||
|
||||
@@ -306,7 +306,7 @@ async def request_receipts(
|
||||
registers = await _active_registers(session)
|
||||
if not registers:
|
||||
for order_id, _ in items:
|
||||
result.errors[order_id] = "Не настроена касса Checkbox"
|
||||
result.errors[order_id] = "Не налаштовано касу Checkbox"
|
||||
return result
|
||||
|
||||
order_ids = [order_id for order_id, _ in items]
|
||||
@@ -319,16 +319,16 @@ async def request_receipts(
|
||||
for order_id, prepayment in items:
|
||||
order = orders.get(order_id)
|
||||
if order is None:
|
||||
result.errors[order_id] = "Заказ не найден"
|
||||
result.errors[order_id] = "Замовлення не знайдено"
|
||||
continue
|
||||
if order_id in busy:
|
||||
result.errors[order_id] = "По заказу уже есть чек"
|
||||
result.errors[order_id] = "За замовленням уже є чек"
|
||||
continue
|
||||
register = registers.get(order.cash_register_id) if order.cash_register_id else None
|
||||
if register is None:
|
||||
result.errors[order_id] = (
|
||||
"Касса не определена: ТТН не найдена ни одним ключом Новой Почты "
|
||||
"активных касс"
|
||||
"Касу не визначено: ТТН не знайдено жодним ключем Нової Пошти "
|
||||
"активних кас"
|
||||
)
|
||||
continue
|
||||
try:
|
||||
@@ -485,7 +485,7 @@ async def cancel_receipt(
|
||||
if receipt is None:
|
||||
return None
|
||||
if receipt.status not in (ReceiptStatus.CREATED, ReceiptStatus.RECEIPT_ERROR):
|
||||
raise ReceiptStateError(f"Чек в статусе «{receipt.status}» отменить нельзя")
|
||||
raise ReceiptStateError(f"Чек у статусі «{receipt.status}» скасувати неможливо")
|
||||
|
||||
if receipt.checkbox_ettn_id:
|
||||
register = await session.get(CashRegister, receipt.cash_register_id)
|
||||
|
||||
Reference in New Issue
Block a user