diff --git a/backend/alembic/versions/7c8d9e0f1a2b_add_annex30_duration_days.py b/backend/alembic/versions/7c8d9e0f1a2b_add_annex30_duration_days.py new file mode 100644 index 00000000..ec565c31 --- /dev/null +++ b/backend/alembic/versions/7c8d9e0f1a2b_add_annex30_duration_days.py @@ -0,0 +1,29 @@ +"""add annex30_duration_days to company_certification + +Revision ID: 7c8d9e0f1a2b +Revises: c8d9e0f1a2b3 +Create Date: 2026-04-24 16:50:00.000000 + +""" + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '7c8d9e0f1a2b' +down_revision = 'c8d9e0f1a2b3' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + op.add_column( + "company_certification", + sa.Column("annex30_duration_days", sa.Integer(), nullable=True), + schema="a76", + ) + + +def downgrade() -> None: + op.drop_column("company_certification", "annex30_duration_days", schema="a76") diff --git a/backend/api/v1/modules/a76/general_catalogs/company/dto.py b/backend/api/v1/modules/a76/general_catalogs/company/dto.py index 97421872..39f71b25 100644 --- a/backend/api/v1/modules/a76/general_catalogs/company/dto.py +++ b/backend/api/v1/modules/a76/general_catalogs/company/dto.py @@ -99,6 +99,7 @@ class CompanyCreateDTO(BaseModel): annex30_certification_date: Optional[date] = None annex30_certification_number: Optional[str] = Field(None, max_length=50) annex30_modality: Optional[str] = Field(None, max_length=3) + annex30_duration_days: Optional[int] = Field(None, description="Modality duration in days") annex30_company_type: Optional[str] = Field(None, max_length=50) annex30_renewal_date: Optional[date] = None annex30_final_certification_date: Optional[date] = None @@ -328,6 +329,7 @@ class CompanyResponseDTO(BaseModel): annex30_certification_date: Optional[date] = None annex30_certification_number: Optional[str] = None annex30_modality: Optional[str] = None + annex30_duration_days: Optional[int] = None annex30_company_type: Optional[str] = None annex30_renewal_date: Optional[date] = None annex30_final_certification_date: Optional[date] = None diff --git a/backend/api/v1/modules/a76/general_catalogs/company/service.py b/backend/api/v1/modules/a76/general_catalogs/company/service.py index 962292d8..0c55a9d5 100644 --- a/backend/api/v1/modules/a76/general_catalogs/company/service.py +++ b/backend/api/v1/modules/a76/general_catalogs/company/service.py @@ -136,7 +136,7 @@ class CompanyService: "is_certified_company", "certified_company_registration", "certified_company_start_date", "certified_company_end_date", "annex30_certification_date", "annex30_certification_number", - "annex30_modality", "annex30_company_type", "annex30_renewal_date", + "annex30_modality", "annex30_duration_days", "annex30_company_type", "annex30_renewal_date", "annex30_final_certification_date", "is_seciit_company", "is_oea_company", "ctpat_svi", "trusted_exporter_number", "neec_company" ] @@ -251,7 +251,7 @@ class CompanyService: "is_certified_company", "certified_company_registration", "certified_company_start_date", "certified_company_end_date", "annex30_certification_date", "annex30_certification_number", - "annex30_modality", "annex30_company_type", "annex30_renewal_date", + "annex30_modality", "annex30_duration_days", "annex30_company_type", "annex30_renewal_date", "annex30_final_certification_date", "is_seciit_company", "is_oea_company", "ctpat_svi", "trusted_exporter_number", "neec_company" ] diff --git a/backend/api/v1/modules/a76/general_catalogs/company/submodels/certification.py b/backend/api/v1/modules/a76/general_catalogs/company/submodels/certification.py index ee70040a..7ca28af4 100644 --- a/backend/api/v1/modules/a76/general_catalogs/company/submodels/certification.py +++ b/backend/api/v1/modules/a76/general_catalogs/company/submodels/certification.py @@ -37,6 +37,7 @@ class CompanyCertification(Base, TimestampMixin): annex30_certification_date: Mapped[Optional[date]] = mapped_column(Date) annex30_certification_number: Mapped[Optional[str]] = mapped_column(String(50)) annex30_modality: Mapped[Optional[str]] = mapped_column(String(3)) + annex30_duration_days: Mapped[Optional[int]] = mapped_column(Integer) annex30_company_type: Mapped[Optional[str]] = mapped_column(String(50)) annex30_renewal_date: Mapped[Optional[date]] = mapped_column(Date) annex30_final_certification_date: Mapped[Optional[date]] = mapped_column(Date) diff --git a/frontend/src/routes/dashboard/general_catalogs/company_information/edit/[[id]]/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/company_information/edit/[[id]]/+page.svelte index b2faeef1..61b19a4d 100644 --- a/frontend/src/routes/dashboard/general_catalogs/company_information/edit/[[id]]/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/company_information/edit/[[id]]/+page.svelte @@ -112,6 +112,7 @@ annex30_certification_date: '', annex30_certification_number: '', annex30_modality: '', + annex30_duration_days: 0, annex30_company_type: '', annex30_renewal_date: '', annex30_final_certification_date: '', @@ -300,6 +301,7 @@ annex30_certification_date: toInputDate(item.annex30_certification_date), annex30_certification_number: item.annex30_certification_number || '', annex30_modality: item.annex30_modality || '', + annex30_duration_days: item.annex30_duration_days || 0, annex30_company_type: item.annex30_company_type || '', annex30_renewal_date: toInputDate(item.annex30_renewal_date), annex30_final_certification_date: toInputDate(item.annex30_final_certification_date), @@ -531,6 +533,36 @@ loading = false; } } + + // Auto-cálculo de duración y fecha de renovación del Anexo 30 + $effect(() => { + const modality = formData.annex30_modality; + const certDateStr = formData.annex30_certification_date; + + // 1. Mapear modalidad a días + const modalityDaysMap: Record = { + 'A': 365, + 'AA': 730, + 'AAA': 1095 + }; + + if (modality && modalityDaysMap[modality]) { + formData.annex30_duration_days = modalityDaysMap[modality]; + } else if (!modality) { + formData.annex30_duration_days = 0; + } + + // 2. Calcular fecha de renovación + if (certDateStr && formData.annex30_duration_days > 0) { + // Usamos el formato ISO para evitar problemas de zona horaria al crear el objeto Date + const certDate = new Date(certDateStr + 'T00:00:00'); + if (!isNaN(certDate.getTime())) { + const renewalDate = new Date(certDate); + renewalDate.setDate(certDate.getDate() + formData.annex30_duration_days); + formData.annex30_renewal_date = renewalDate.toISOString().split('T')[0]; + } + } + }); async function handleSubmit() { error = null; @@ -598,6 +630,7 @@ annex30_certification_date: toDbDate(formData.annex30_certification_date), annex30_certification_number: clean(formData.annex30_certification_number), annex30_modality: clean(formData.annex30_modality), + annex30_duration_days: Number(formData.annex30_duration_days) || 0, annex30_company_type: clean(formData.annex30_company_type), annex30_renewal_date: toDbDate(formData.annex30_renewal_date), annex30_final_certification_date: toDbDate(formData.annex30_final_certification_date), @@ -1035,6 +1068,16 @@ +
+ + +