| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- from typing import List, Optional, Tuple
- from uuid import uuid4
- from logging import getLogger
- from pydantic import BaseModel
- import toteat.toteat as toteat
- from models.sales import ItemWeb, OrderWeb
- from models.items import Product
- from models.user import User
- from services.toteat_service import add_order_item
- from services.data_service import DataServiceFactory
- logger = getLogger(__name__)
- _user_svc = DataServiceFactory.get_user_service()
- _product_svc = DataServiceFactory.get_product_service()
- _sale_svc = DataServiceFactory.get_sales_service()
- PROMO_PRODUCT_TYPE = "Cervezas"
- REWARD_POINTS_PER_BEER = 10
- class ComparePricesResponse(BaseModel):
- product: Product
- oldPrice: int
- newPrice: int
- isAvailable: bool
- def compare_prices(products: List[Product], items: List[ItemWeb]) -> list:
- """Detecta diferencias de precio o productos inactivos entre el carrito y la BD."""
- result = []
- for product, item in zip(products, items):
- if product.status == 0:
- result.append(ComparePricesResponse(
- product=product, oldPrice=item.price,
- newPrice=product.price, isAvailable=False
- ))
- elif product.price != item.price:
- result.append(ComparePricesResponse(
- product=product, oldPrice=item.price,
- newPrice=product.price, isAvailable=True
- ))
- return [r.model_dump() for r in result]
- async def fetch_sorted_products(items: List[ItemWeb]) -> List[Product]:
- """Obtiene productos de la BD ordenados igual que los items del carrito."""
- products = await _product_svc.get_products([item.id for item in items])
- return sorted(products, key=lambda x: x.id)
- def push_items_to_toteat(
- items: List[ItemWeb],
- products: List[Product],
- table: int,
- user_name: str,
- ) -> Tuple[List[str], int]:
- """
- Registra cada item en Toteat POS.
- Retorna (errores, cervezas_para_promo).
- Lanza excepción si toteat.get_token() falla — el handler la captura como error fatal.
- """
- toteat.get_token()
- errors: List[str] = []
- beers = 0
- for item, product in zip(items, products):
- try:
- if product.type == PROMO_PRODUCT_TYPE and user_name != "Guest":
- beers += item.quantity
- result = add_order_item(item.id, item.quantity, table)
- if not result:
- errors.append(f"Error adding product {item.id} to table {table}.")
- except Exception as e:
- errors.append(f"Error processing product {item.id}: {e}")
- return errors, beers
- def get_active_sale_id(table: int) -> Optional[str]:
- """Devuelve el ID de la venta activa de la mesa en Toteat, o None si no hay."""
- sale = toteat.get_active_sale(toteat.get_table(table))
- return sale['id'] if sale else None
- def update_reward_progress(user: User, beers: int) -> int:
- """
- Actualiza puntos de fidelización del usuario.
- No lanza excepción — un fallo aquí no bloquea el pedido.
- """
- new_progress = user.reward_progress + beers * REWARD_POINTS_PER_BEER
- try:
- _user_svc.set_reward_progress(user.id, new_progress)
- logger.info(f"Reward progress updated for user {user.email}: {user.reward_progress} -> {new_progress}")
- except Exception as e:
- logger.error(f"Error updating reward progress for user {user.id}: {e}")
- new_progress = user.reward_progress
- return new_progress
- def create_sale_record(order: OrderWeb, active_sale_id: str, items: List[ItemWeb]) -> int:
- """Persiste la venta en PostgreSQL. Retorna el ID o -1 si falló."""
- return _sale_svc.create(
- order.customerId,
- active_sale_id or uuid4().hex,
- order.totalAmount,
- order.table,
- [item.id for item in items],
- [item.quantity for item in items],
- )
|