feat(safety): price comparison on order detail
Add ROA price comparison to order detail modal — operators can now see if GoMag prices match Oracle before invoicing. Eliminates the #1 risk of invoicing with wrong prices. Backend: - New get_prices_for_order() in validation_service.py — batch Oracle query with dual-policy routing (sales/production by cont 341/345), PRETURI_CU_TVA handling, kit total calculation - Extend GET /api/sync/order/{orderNumber} with per-item pret_roa and order-level price_check summary - GET /api/dashboard/orders returns price_match=null (lightweight) Frontend: - Modal: price check badge (green/red/grey), "Pret GoMag" + "Pret ROA" columns, match dot per row, mismatch rows highlighted - Dashboard: price dot column (₽) in orders table - Mobile: inline mismatch indicator Cache-bust: shared.js?v=16, dashboard.js?v=28 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,7 @@ from pydantic import BaseModel
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from ..services import sync_service, scheduler_service, sqlite_service, invoice_service
|
||||
from ..services import sync_service, scheduler_service, sqlite_service, invoice_service, validation_service
|
||||
from .. import database
|
||||
|
||||
router = APIRouter(tags=["sync"])
|
||||
@@ -405,8 +405,26 @@ async def order_detail(order_number: str):
|
||||
"direct": True
|
||||
}]
|
||||
|
||||
# Price comparison against ROA Oracle
|
||||
app_settings = await sqlite_service.get_app_settings()
|
||||
try:
|
||||
price_data = await asyncio.to_thread(
|
||||
validation_service.get_prices_for_order, items, app_settings
|
||||
)
|
||||
price_items = price_data.get("items", {})
|
||||
for idx, item in enumerate(items):
|
||||
pi = price_items.get(idx)
|
||||
if pi:
|
||||
item["pret_roa"] = pi.get("pret_roa")
|
||||
item["price_match"] = pi.get("match")
|
||||
order_price_check = price_data.get("summary", {})
|
||||
except Exception as e:
|
||||
logger.warning(f"Price comparison failed for order {order_number}: {e}")
|
||||
order_price_check = {"mismatches": 0, "checked": 0, "oracle_available": False}
|
||||
|
||||
# Enrich with invoice data
|
||||
order = detail.get("order", {})
|
||||
order["price_check"] = order_price_check
|
||||
if order.get("factura_numar") and order.get("factura_data"):
|
||||
order["invoice"] = {
|
||||
"facturat": True,
|
||||
@@ -445,8 +463,7 @@ async def order_detail(order_number: str):
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
pass
|
||||
|
||||
# Add settings for receipt display
|
||||
app_settings = await sqlite_service.get_app_settings()
|
||||
# Add settings for receipt display (app_settings already fetched above)
|
||||
order["transport_vat"] = app_settings.get("transport_vat") or "21"
|
||||
order["transport_codmat"] = app_settings.get("transport_codmat") or ""
|
||||
order["discount_codmat"] = app_settings.get("discount_codmat") or ""
|
||||
@@ -484,6 +501,7 @@ async def dashboard_orders(page: int = 1, per_page: int = 50,
|
||||
# Enrich orders with invoice data — prefer SQLite cache, fallback to Oracle
|
||||
all_orders = result["orders"]
|
||||
for o in all_orders:
|
||||
o["price_match"] = None # Populated when order detail is opened
|
||||
if o.get("factura_numar") and o.get("factura_data"):
|
||||
# Use cached invoice data from SQLite (only if complete)
|
||||
o["invoice"] = {
|
||||
|
||||
Reference in New Issue
Block a user