from typing import Any, Dict, Optional def resolver_location(store_config: Dict[str, Any], location_id: Any) -> Optional[Dict[str, Any]]: """Config (is_store/warehouse_code) para un location_id de Shopify, o None si no está mapeado.""" return store_config["sap"]["locations"].get(str(location_id)) def es_tienda(store_config: Dict[str, Any], location_id: Any) -> bool: """ True si este location_id es una tienda física (genera StockTransfer + Delivery además de la ITR); False si es un CD (solo ITR). """ location = resolver_location(store_config, location_id) return bool(location and location.get("is_store")) def construir_inventory_transfer_request( order: Dict[str, Any], fulfillment: Dict[str, Any], store_config: Dict[str, Any], warehouse_code: str, invoice: Dict[str, Any], ) -> Dict[str, Any]: """ Arma el JSON para POST InventoryTransferRequests: una solicitud por cada fulfillment, moviendo stock desde la bodega real del location_id hacia la bodega virtual usada en el Invoice (default_warehouse_invoice). Usa los line_items propios del fulfillment (no los de toda la orden), ya que una orden puede tener varios fulfillments con distintos ítems/cantidades. CardCode/CardName se toman del Invoice; Comments lleva el "name" de Shopify para poder ubicarla fácil. """ to_warehouse = store_config["sap"]["default_warehouse_invoice"] series = store_config["sap"]["numbering_series"]["INVENTORY_TRANSFER_REQUEST"] doc_date = order["created_at"][:10] document_lines = [ { "ItemCode": item["sku"], "Quantity": item["quantity"], "FromWarehouseCode": warehouse_code, "WarehouseCode": to_warehouse, } for item in fulfillment.get("line_items", []) if item.get("sku") ] return { "CardCode": invoice["CardCode"], "CardName": invoice["CardName"], "Comments": order.get("name"), "DocDate": doc_date, "DueDate": doc_date, "Series": series, "FromWarehouse": warehouse_code, "ToWarehouse": to_warehouse, "U_ShopifyOrderId": order["id"], "U_ShopifyStore": store_config["store_code"], "StockTransferLines": document_lines, }