Agregar flujo de inmovilización/liberación de lotes (Inmovilizar, Liberar y Confirmar Liberación Lote)
- Inmovilizar Lotes: selección múltiple de almacén origen con cantidad editable, genera Solicitud de Transferencia hacia un almacén de inmovilizados. - Liberar Lotes: inversa de la anterior, con almacenes/campos de usuario propios (U_SIS_MOVINV, U_EXX_TIPOOPER, U_SIS_TIPDESP, U_SIS_MOTALM). - Confirmar Liberación Lote: lista las Solicitudes abiertas pendientes (U_SIS_MOTALM=108) y, por cada lote, resuelve contra el historial de transferencias en HANA a qué almacén(es) debe volver, repartiendo la cantidad entre orígenes; permite editar cantidad, almacén destino, y agregar/quitar líneas antes de actualizar la Solicitud en SAP. - Backend: nuevo endpoint /api/batch/lot-source-warehouse (HANA) para resolver el origen histórico de un lote; endpoint genérico /api/Catalogs/UdfValidValues (Service Layer) para valores válidos de un UDF; PATCH genérico ahora reenvía cualquier header B1S-* que mande el frontend en vez de decidirlos en el backend. - Registro de rutas, menú y permisos para las tres pantallas nuevas. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d900b62f33
commit
7e0a646853
19 files changed
+2830
-5
No files matched your search
@@ -113,11 +113,21 @@ def make_crud_router(
|
||||
@router.patch(f"/api/{resource}/{{key}}", status_code=204, name=f"update_{resource}")
|
||||
async def update_resource(key: str, request: Request):
|
||||
data = await request.json()
|
||||
# Las cabeceras de Service Layer (B1S-*) las decide quien llama
|
||||
# (el frontend), no el backend: cualquier header "B1S-*" que
|
||||
# venga en el request se reenvía tal cual a SAP. Ej.:
|
||||
# B1S-ReplaceCollectionsOnPatch para reemplazar una colección
|
||||
# hija (StockTransferLines) en vez de mergearla por LineNum,
|
||||
# necesario solo cuando ese PATCH agrega o quita líneas.
|
||||
headers = dict(patch_headers or {})
|
||||
headers.update(
|
||||
{k: v for k, v in request.headers.items() if k.lower().startswith("b1s-")}
|
||||
)
|
||||
forward_to_sapb1(
|
||||
method="PATCH",
|
||||
endpoint_path=key_expr(key),
|
||||
json_data=data,
|
||||
extra_headers=patch_headers,
|
||||
extra_headers=headers or None,
|
||||
)
|
||||
|
||||
return router
|
||||
@@ -0,0 +1,4 @@
|
||||
# Objeto Service Layer para la Solicitud de Transferencia de Inventario
|
||||
# (BoObjectTypes "1250000001"). Centralizado acá para que el router de
|
||||
# routers/inventory_transfer_requests.py no repita el nombre del endpoint.
|
||||
INVENTORY_TRANSFER_REQUESTS_RESOURCE = "InventoryTransferRequests"
|
||||
@@ -0,0 +1,51 @@
|
||||
import logging
|
||||
from typing import List, Optional
|
||||
|
||||
from core.sap import forward_to_sapb1
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_default_series(document_type: str) -> Optional[int]:
|
||||
"""
|
||||
Consulta a Service Layer (SeriesService_GetDefaultSeries) la serie activa
|
||||
por defecto para un tipo de documento de SAP B1 (código BoObjectTypes,
|
||||
ej. "1250000001" para Solicitud de Transferencia). Si la llamada falla o
|
||||
la respuesta no trae el campo esperado, se registra en el log y se
|
||||
devuelve None; quien llama decide cómo seguir sin una serie por defecto.
|
||||
"""
|
||||
try:
|
||||
response = forward_to_sapb1(
|
||||
method="POST",
|
||||
endpoint_path="SeriesService_GetDefaultSeries",
|
||||
json_data={"DocumentTypeParams": {"Document": document_type}},
|
||||
)
|
||||
except Exception as exc:
|
||||
logger.warning(
|
||||
f"No se pudo obtener la serie por defecto de SAP (documento {document_type}): {exc}"
|
||||
)
|
||||
return None
|
||||
|
||||
data = response.json()
|
||||
series = data.get("Series")
|
||||
if series is None:
|
||||
logger.warning(
|
||||
f"SeriesService_GetDefaultSeries no devolvió 'Series' (documento {document_type}): {data}"
|
||||
)
|
||||
return series
|
||||
|
||||
|
||||
def get_active_series(document_type: str) -> List[dict]:
|
||||
"""
|
||||
Lista las series no bloqueadas de un tipo de documento de SAP B1, vía
|
||||
SeriesService_GetDocumentSeries. Confirmado contra el HANA/Service Layer
|
||||
real de tagumedica: la respuesta viene en "value", cada item con
|
||||
"Series" (código) y "Name"; "Locked" en "tYES"/"tNO".
|
||||
"""
|
||||
response = forward_to_sapb1(
|
||||
method="POST",
|
||||
endpoint_path="SeriesService_GetDocumentSeries",
|
||||
json_data={"DocumentTypeParams": {"Document": document_type}},
|
||||
)
|
||||
series_list = response.json().get("value", [])
|
||||
return [s for s in series_list if str(s.get("Locked", "")).lower() != "tyes"]
|
||||
Reference in new issue
Block a user