From cdc3788a05b2f4561635b28ec484a17e37041a9e Mon Sep 17 00:00:00 2001 From: acazares Date: Mon, 24 Nov 2025 09:58:24 -0600 Subject: [PATCH] feat: update company API endpoint, refine pedimento dates model, and adjust Keycloak mapper creation --- .../a76/pedmientos/dtos/pedimento_dates.py | 19 +-- .../a76/pedmientos/models/pedimento_dates.py | 18 +-- .../code_pedimento_regimens/routes.py | 5 + .../pedimentos/edit/general-tab-form.svelte | 44 ++++--- frontend/src/lib/stores/company.svelte.ts | 2 +- .../pedimentos/edit/[id]/+page.svelte | 15 ++- scripts/init_first_time.sh | 113 +++++++++--------- 7 files changed, 114 insertions(+), 102 deletions(-) diff --git a/backend/api/v1/modules/a76/pedmientos/dtos/pedimento_dates.py b/backend/api/v1/modules/a76/pedmientos/dtos/pedimento_dates.py index c83cebbc..101b58b0 100644 --- a/backend/api/v1/modules/a76/pedmientos/dtos/pedimento_dates.py +++ b/backend/api/v1/modules/a76/pedmientos/dtos/pedimento_dates.py @@ -7,9 +7,8 @@ from pydantic import BaseModel, ConfigDict, Field class PedimentoDatesBase(BaseModel): """Base schema for Pedimento Dates""" - entry_date: Optional[datetime] = Field(None, description="Entry date") - pedimento_date: Optional[datetime] = Field(None, description="Pedimento date") - payment_date: Optional[datetime] = Field(None, description="Payment date") + entry_date: Optional[datetime] = Field(None, description="Entry date") + payment_date: datetime = Field(None, description="Payment date") rectification_payment_date: Optional[datetime] = Field( None, description="Rectification payment date" ) @@ -19,16 +18,13 @@ class PedimentoDatesBase(BaseModel): original_date: Optional[datetime] = Field(None, description="Original date") start_date: Optional[datetime] = Field(None, description="Start date") end_date: Optional[datetime] = Field(None, description="End date") - capture_date: Optional[datetime] = Field(None, description="Capture date") - capture_time: Optional[time] = Field(None, description="Capture time") class PedimentoDatesCreate(BaseModel): """Schema for creating a new Pedimento Dates - pedimento_id and tenant_id are set by backend""" - entry_date: Optional[datetime] = Field(None, description="Entry date") - pedimento_date: Optional[datetime] = Field(None, description="Pedimento date") - payment_date: Optional[datetime] = Field(None, description="Payment date") + entry_date: Optional[datetime] = Field(None, description="Entry date") + payment_date: datetime = Field(..., description="Payment date") rectification_payment_date: Optional[datetime] = Field(None, description="Rectification payment date") extraction_date: Optional[datetime] = Field(None, description="Extraction date") submission_date: Optional[datetime] = Field(None, description="Submission date") @@ -36,15 +32,12 @@ class PedimentoDatesCreate(BaseModel): original_date: Optional[datetime] = Field(None, description="Original date") start_date: Optional[datetime] = Field(None, description="Start date") end_date: Optional[datetime] = Field(None, description="End date") - capture_date: Optional[datetime] = Field(None, description="Capture date") - capture_time: Optional[time] = Field(None, description="Capture time") class PedimentoDatesUpdate(BaseModel): """Schema for updating a Pedimento Dates""" - entry_date: Optional[datetime] = None - pedimento_date: Optional[datetime] = None + entry_date: Optional[datetime] = None payment_date: Optional[datetime] = None rectification_payment_date: Optional[datetime] = None extraction_date: Optional[datetime] = None @@ -53,8 +46,6 @@ class PedimentoDatesUpdate(BaseModel): original_date: Optional[datetime] = None start_date: Optional[datetime] = None end_date: Optional[datetime] = None - capture_date: Optional[datetime] = None - capture_time: Optional[time] = None class PedimentoDatesResponse(PedimentoDatesBase): diff --git a/backend/api/v1/modules/a76/pedmientos/models/pedimento_dates.py b/backend/api/v1/modules/a76/pedmientos/models/pedimento_dates.py index a6f1958b..cea9f34d 100644 --- a/backend/api/v1/modules/a76/pedmientos/models/pedimento_dates.py +++ b/backend/api/v1/modules/a76/pedmientos/models/pedimento_dates.py @@ -1,6 +1,6 @@ from datetime import datetime from datetime import time as datetime_time -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Optional from api.v1.common.base_models import TenantScopedMixin, TimestampMixin from core.database import Base @@ -48,16 +48,16 @@ class PedimentoDates(Base, TenantScopedMixin, TimestampMixin): id: Mapped[int] = mapped_column(Integer) pedimento_id: Mapped[int] = mapped_column(Integer, nullable=False) - entry_date: Mapped[datetime] = mapped_column(DateTime) + entry_date: Mapped[Optional[datetime]] = mapped_column(DateTime) pedimento_date: Mapped[datetime] = mapped_column(DateTime) payment_date: Mapped[datetime] = mapped_column(DateTime) - rectification_payment_date: Mapped[datetime] = mapped_column(DateTime) - extraction_date: Mapped[datetime] = mapped_column(DateTime) - submission_date: Mapped[datetime] = mapped_column(DateTime) - eucan_date: Mapped[datetime] = mapped_column(DateTime) - original_date: Mapped[datetime] = mapped_column(DateTime) - start_date: Mapped[datetime] = mapped_column(DateTime) - end_date: Mapped[datetime] = mapped_column(DateTime) + rectification_payment_date: Mapped[Optional[datetime]] = mapped_column(DateTime) + extraction_date: Mapped[Optional[datetime]] = mapped_column(DateTime) + submission_date: Mapped[Optional[datetime]] = mapped_column(DateTime) + eucan_date: Mapped[Optional[datetime]] = mapped_column(DateTime) + original_date: Mapped[Optional[datetime]] = mapped_column(DateTime) + start_date: Mapped[Optional[datetime]] = mapped_column(DateTime) + end_date: Mapped[Optional[datetime]] = mapped_column(DateTime) capture_date: Mapped[datetime] = mapped_column(DateTime) capture_time: Mapped[datetime_time] = mapped_column(Time) diff --git a/backend/api/v1/modules/public/reference_data/code_pedimento_regimens/routes.py b/backend/api/v1/modules/public/reference_data/code_pedimento_regimens/routes.py index de7fc176..93d2ed7c 100644 --- a/backend/api/v1/modules/public/reference_data/code_pedimento_regimens/routes.py +++ b/backend/api/v1/modules/public/reference_data/code_pedimento_regimens/routes.py @@ -15,11 +15,16 @@ router = APIRouter(prefix="/code-pedimento-regimens") def list_code_pedimento_regimens( page: int = Query(1, ge=1, description="Número de página"), page_size: int = Query(50, ge=1, le=100, description="Tamaño de página"), + code: str = Query(None, description="Filter by code"), db: Session = Depends(get_core_db), current_user: dict = Depends(get_current_user), ): skip = (page - 1) * page_size query = db.query(CodePedimentoRegimen) + + if code is not None: + query = query.filter(CodePedimentoRegimen.pedimento_code == code) + items = query.offset(skip).limit(page_size).all() total = query.count() return { diff --git a/frontend/src/lib/components/dashboard/pedimentos/edit/general-tab-form.svelte b/frontend/src/lib/components/dashboard/pedimentos/edit/general-tab-form.svelte index 7f8fed59..bc488ea7 100644 --- a/frontend/src/lib/components/dashboard/pedimentos/edit/general-tab-form.svelte +++ b/frontend/src/lib/components/dashboard/pedimentos/edit/general-tab-form.svelte @@ -176,24 +176,32 @@ /> - -
- - formData.pedimento_code = v ?? ''} - > - - {pedimentoCodes.find(o => o.code === formData.pedimento_code)?.description || 'Seleccionar...'} - - - {#each pedimentoCodes as code} - - {/each} - - -
+ +
+ + formData.pedimento_code = v ?? ''} + > + + + {pedimentoCodes.find(o => o.code === formData.pedimento_code)?.code || 'Seleccionar...'} + + + + {#each pedimentoCodes as code} + + + {code.code} - {code.description} + + + {/each} + + +
+ +
(data.pedimentoId); + let pedimentoId = $state(data.pedimentoId ?? null); // Referencias a los componentes de formulario para obtener sus datos let generalFormData = $state(null); diff --git a/scripts/init_first_time.sh b/scripts/init_first_time.sh index 591a52ac..223908ab 100755 --- a/scripts/init_first_time.sh +++ b/scripts/init_first_time.sh @@ -22,7 +22,7 @@ # se actualiza con el ID real del tenant creado en PostgreSQL. ############################################################################### -set -e # Salir si hay algún error +# set -e # Comentado para permitir que el script continúe aunque algunos comandos fallen (ej: mapper ya existe) # Colores para output RED='\033[0;31m' @@ -309,87 +309,84 @@ echo -e "\n${YELLOW}[5/8] Configurando mappers para tenant_id...${NC}" if [ -n "$BACKEND_CLIENT_ID" ]; then echo "Configurando mapper para Backend..." - # Obtener el dedicated scope del cliente backend - BACKEND_SCOPES=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${BACKEND_CLIENT_ID}/optional-client-scopes" \ + # Verificar si el mapper tenant_id ya existe en el cliente + MAPPER_TENANT_EXISTS=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${BACKEND_CLIENT_ID}/protocol-mappers/models" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ - -H "Content-Type: application/json") + -H "Content-Type: application/json" | grep -o "\"name\":\"tenant-id-mapper\"") - # Buscar el scope dedicado - BACKEND_DEDICATED_SCOPE_ID=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/client-scopes" \ - -H "Authorization: Bearer ${ACCESS_TOKEN}" \ - -H "Content-Type: application/json" | grep -o "\"id\":\"[^\"]*\",\"name\":\"anexo76-backend-dedicated\"" | grep -o "\"id\":\"[^\"]*" | sed 's/"id":"//') - - if [ -n "$BACKEND_DEDICATED_SCOPE_ID" ]; then - # Verificar si el mapper tenant_id ya existe - MAPPER_TENANT_EXISTS=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/client-scopes/${BACKEND_DEDICATED_SCOPE_ID}/protocol-mappers/models" \ + if [ -z "$MAPPER_TENANT_EXISTS" ]; then + # Crear mapper para tenant_id directamente en el cliente + CREATE_MAPPER_RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${BACKEND_CLIENT_ID}/protocol-mappers/models" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ - -H "Content-Type: application/json" | grep -o "\"name\":\"tenant-id-mapper\"") + -H "Content-Type: application/json" \ + -d '{ + "name": "tenant-id-mapper", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "config": { + "user.attribute": "tenant_id", + "claim.name": "tenant_id", + "jsonType.label": "String", + "id.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + }') - if [ -z "$MAPPER_TENANT_EXISTS" ]; then - # Crear mapper para tenant_id - curl -s -X POST "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/client-scopes/${BACKEND_DEDICATED_SCOPE_ID}/protocol-mappers/models" \ - -H "Authorization: Bearer ${ACCESS_TOKEN}" \ - -H "Content-Type: application/json" \ - -d '{ - "name": "tenant-id-mapper", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "config": { - "user.attribute": "tenant_id", - "claim.name": "tenant_id", - "jsonType.label": "String", - "id.token.claim": "true", - "access.token.claim": "true", - "userinfo.token.claim": "true" - } - }' + HTTP_CODE=$(echo "$CREATE_MAPPER_RESPONSE" | tail -n1) + if [ "$HTTP_CODE" = "201" ]; then echo -e "${GREEN}✓ Mapper tenant_id creado para Backend${NC}" else - echo -e "${YELLOW}⚠ Mapper tenant_id ya existe para Backend${NC}" + echo -e "${YELLOW}⚠ Error al crear mapper para Backend (HTTP ${HTTP_CODE})${NC}" + echo "Respuesta: $(echo "$CREATE_MAPPER_RESPONSE" | head -n -1)" fi + else + echo -e "${YELLOW}⚠ Mapper tenant_id ya existe para Backend${NC}" fi fi + # 4.2 Configurar mapper para Frontend if [ -n "$FRONTEND_CLIENT_ID" ]; then echo "Configurando mapper para Frontend..." - # Buscar el scope dedicado del frontend - FRONTEND_DEDICATED_SCOPE_ID=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/client-scopes" \ + # Verificar si el mapper tenant_id ya existe en el cliente + MAPPER_TENANT_EXISTS=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${FRONTEND_CLIENT_ID}/protocol-mappers/models" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ - -H "Content-Type: application/json" | grep -o "\"id\":\"[^\"]*\",\"name\":\"anexo76-frontend-dedicated\"" | grep -o "\"id\":\"[^\"]*" | sed 's/"id":"//') + -H "Content-Type: application/json" | grep -o "\"name\":\"tenant-id-mapper\"") - if [ -n "$FRONTEND_DEDICATED_SCOPE_ID" ]; then - # Verificar si el mapper tenant_id ya existe - MAPPER_TENANT_EXISTS=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/client-scopes/${FRONTEND_DEDICATED_SCOPE_ID}/protocol-mappers/models" \ + if [ -z "$MAPPER_TENANT_EXISTS" ]; then + # Crear mapper para tenant_id directamente en el cliente + CREATE_MAPPER_RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${FRONTEND_CLIENT_ID}/protocol-mappers/models" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ - -H "Content-Type: application/json" | grep -o "\"name\":\"tenant-id-mapper\"") + -H "Content-Type: application/json" \ + -d '{ + "name": "tenant-id-mapper", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "config": { + "user.attribute": "tenant_id", + "claim.name": "tenant_id", + "jsonType.label": "String", + "id.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + }') - if [ -z "$MAPPER_TENANT_EXISTS" ]; then - # Crear mapper para tenant_id - curl -s -X POST "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/client-scopes/${FRONTEND_DEDICATED_SCOPE_ID}/protocol-mappers/models" \ - -H "Authorization: Bearer ${ACCESS_TOKEN}" \ - -H "Content-Type: application/json" \ - -d '{ - "name": "tenant-id-mapper", - "protocol": "openid-connect", - "protocolMapper": "oidc-usermodel-attribute-mapper", - "config": { - "user.attribute": "tenant_id", - "claim.name": "tenant_id", - "jsonType.label": "String", - "id.token.claim": "true", - "access.token.claim": "true", - "userinfo.token.claim": "true" - } - }' + HTTP_CODE=$(echo "$CREATE_MAPPER_RESPONSE" | tail -n1) + if [ "$HTTP_CODE" = "201" ]; then echo -e "${GREEN}✓ Mapper tenant_id creado para Frontend${NC}" else - echo -e "${YELLOW}⚠ Mapper tenant_id ya existe para Frontend${NC}" + echo -e "${YELLOW}⚠ Error al crear mapper para Frontend (HTTP ${HTTP_CODE})${NC}" + echo "Respuesta: $(echo "$CREATE_MAPPER_RESPONSE" | head -n -1)" fi + else + echo -e "${YELLOW}⚠ Mapper tenant_id ya existe para Frontend${NC}" fi fi + ############################################################################### # 6. Crear usuario demo en Keycloak ###############################################################################