Explorar el Código

refactor: remove ExclusiveCheckboxPair component and related logic; simplify pricing input handling in AddEditContractDialog and ProposalPricingTab

alvesantos hace 2 semanas
padre
commit
6c3a9d2f12

+ 6 - 32
src/pages/packages/components/AddEditPackageDialog.vue

@@ -20,11 +20,12 @@
           >
             <q-card-section class="q-pt-sm">
               <div class="row q-col-gutter-sm">
-                <CustomTabComponent
-                  v-model:active-tab="currentTab"
-                  class="col-12 q-mb-md"
-                  :tabs="tabs"
-                />
+                <div class="col-12 q-mb-md">
+                  <CustomTabComponent
+                    v-model:active-tab="currentTab"
+                    :tabs="tabs"
+                  />
+                </div>
 
                 <div
                   v-show="currentTab === 'dados'"
@@ -194,19 +195,10 @@ const tabs = [
 
 const defaultPricingBlock = (withCondition = false) => ({
   classes_discount_percentage: null,
-  classes_included_in_course: false,
-  classes_installments_allowed: false,
-  classes_max_installments: 13,
   classes_value: null,
 
   materials: [{ price: null, product_id: null, quantity: 1 }],
-  materials_included_in_course: false,
-  materials_installments_allowed: false,
-  materials_max_installments: 13,
 
-  registration_included_in_course: false,
-  registration_installments_allowed: false,
-  registration_max_installments: 13,
   registration_value: null,
 
   total_max_installments: 13,
@@ -243,9 +235,6 @@ const {
 
 const mapPricingBlockFromApi = (data, existingMaterials) => ({
   classes_discount_percentage: data.classes_discount_percentage,
-  classes_included_in_course: data.classes_included_in_course,
-  classes_installments_allowed: data.classes_installments_allowed,
-  classes_max_installments: data.classes_max_installments,
   classes_value: data.classes_value,
 
   materials: data.materials?.length
@@ -255,13 +244,7 @@ const mapPricingBlockFromApi = (data, existingMaterials) => ({
         quantity: material.quantity,
       }))
     : existingMaterials,
-  materials_included_in_course: data.materials_included_in_course,
-  materials_installments_allowed: data.materials_installments_allowed,
-  materials_max_installments: data.materials_max_installments,
 
-  registration_included_in_course: data.registration_included_in_course,
-  registration_installments_allowed: data.registration_installments_allowed,
-  registration_max_installments: data.registration_max_installments,
   registration_value: data.registration_value,
 
   total_max_installments: data.total_max_installments,
@@ -276,9 +259,6 @@ const numOrNull = (value) =>
 const toPricingPayload = (block, { withCondition = false } = {}) => {
   const payload = {
     classes_discount_percentage: numOrNull(block.classes_discount_percentage),
-    classes_included_in_course: block.classes_included_in_course,
-    classes_installments_allowed: block.classes_installments_allowed,
-    classes_max_installments: Number(block.classes_max_installments) || 13,
     classes_value: numOrNull(block.classes_value),
 
     materials: block.materials
@@ -288,13 +268,7 @@ const toPricingPayload = (block, { withCondition = false } = {}) => {
         product_id: material.product_id,
         quantity: Number(material.quantity),
       })),
-    materials_included_in_course: block.materials_included_in_course,
-    materials_installments_allowed: block.materials_installments_allowed,
-    materials_max_installments: Number(block.materials_max_installments) || 13,
 
-    registration_included_in_course: block.registration_included_in_course,
-    registration_installments_allowed: block.registration_installments_allowed,
-    registration_max_installments: Number(block.registration_max_installments) || 13,
     registration_value: numOrNull(block.registration_value),
 
     total_max_installments: Number(block.total_max_installments) || 13,

+ 0 - 44
src/pages/packages/components/ExclusiveCheckboxPair.vue

@@ -1,44 +0,0 @@
-<template>
-  <div class="row q-col-gutter-md">
-    <div class="col-6">
-      <q-checkbox
-        color="primary"
-        label="Incluso no valor do curso"
-        :model-value="included"
-        @update:model-value="onToggle('included', $event)"
-      />
-    </div>
-
-    <div class="col-6">
-      <q-checkbox
-        color="primary"
-        label="Permite Parcelar"
-        :model-value="installments"
-        @update:model-value="onToggle('installments', $event)"
-      />
-    </div>
-  </div>
-</template>
-
-<script setup>
-defineProps({
-  included: {
-    default: false,
-    type: Boolean,
-  },
-  installments: {
-    default: false,
-    type: Boolean,
-  },
-});
-
-const emit = defineEmits(["update:included", "update:installments"]);
-
-// Comportam-se como um par exclusivo (um dos dois é sempre obrigatório):
-// marcar um desmarca o outro; desmarcar direto é ignorado.
-const onToggle = (which, value) => {
-  if (!value) return;
-
-  emit(which === "included" ? "update:included" : "update:installments", true);
-};
-</script>

+ 11 - 141
src/pages/packages/components/ProposalPricingTab.vue

@@ -16,32 +16,6 @@
       label="Valor da Matrícula"
     />
 
-    <ExclusiveCheckboxPair
-      class="col-12"
-      :included="modelValue.registration_included_in_course"
-      :installments="modelValue.registration_installments_allowed"
-      @update:included="setExclusive('registration', 'included')"
-      @update:installments="setExclusive('registration', 'installments')"
-    />
-
-    <div v-if="sectionError('registration')" class="col-12 text-negative text-caption">
-      {{ sectionError('registration') }}
-    </div>
-
-    <template v-if="modelValue.registration_installments_allowed">
-      <DefaultInput
-        v-model="modelValue.registration_max_installments"
-        class="col-6"
-        label="Quantidade de Parcelas Máximas"
-        min="1"
-        type="number"
-      />
-
-      <div class="col-6 installment-hint">
-        Valor da Parcela: {{ formatInstallment(registrationInstallmentValue) }}
-      </div>
-    </template>
-
     <q-separator class="col-12" />
 
     <!-- Aulas -->
@@ -51,41 +25,15 @@
       label="Valor de Aulas"
     />
 
-    <ExclusiveCheckboxPair
+    <DefaultInput
+      v-model="modelValue.classes_discount_percentage"
       class="col-12"
-      :included="modelValue.classes_included_in_course"
-      :installments="modelValue.classes_installments_allowed"
-      @update:included="setExclusive('classes', 'included')"
-      @update:installments="setExclusive('classes', 'installments')"
+      label="Desconto (%)"
+      max="100"
+      min="0"
+      type="number"
     />
 
-    <div v-if="sectionError('classes')" class="col-12 text-negative text-caption">
-      {{ sectionError('classes') }}
-    </div>
-
-    <template v-if="modelValue.classes_installments_allowed">
-      <DefaultInput
-        v-model="modelValue.classes_max_installments"
-        class="col-4"
-        label="Quantidade de Parcelas Máximas"
-        min="1"
-        type="number"
-      />
-
-      <div class="col-4 installment-hint">
-        Valor da Parcela: {{ formatInstallment(classesInstallmentValue) }}
-      </div>
-
-      <DefaultInput
-        v-model="modelValue.classes_discount_percentage"
-        class="col-4"
-        label="Desconto (%)"
-        max="100"
-        min="0"
-        type="number"
-      />
-    </template>
-
     <q-separator class="col-12" />
 
     <!-- Materiais -->
@@ -144,32 +92,6 @@
       </div>
     </div>
 
-    <ExclusiveCheckboxPair
-      class="col-12"
-      :included="modelValue.materials_included_in_course"
-      :installments="modelValue.materials_installments_allowed"
-      @update:included="setExclusive('materials', 'included')"
-      @update:installments="setExclusive('materials', 'installments')"
-    />
-
-    <div v-if="sectionError('materials')" class="col-12 text-negative text-caption">
-      {{ sectionError('materials') }}
-    </div>
-
-    <template v-if="modelValue.materials_installments_allowed">
-      <DefaultInput
-        v-model="modelValue.materials_max_installments"
-        class="col-6"
-        label="Quantidade de Parcelas Máximas"
-        min="1"
-        type="number"
-      />
-
-      <div class="col-6 installment-hint">
-        Valor da Parcela: {{ formatInstallment(materialsInstallmentValue) }}
-      </div>
-    </template>
-
     <q-separator class="col-12" />
 
     <!-- Valor Total do Curso -->
@@ -179,6 +101,7 @@
       v-model="modelValue.total_value"
       class="col-12"
       label="Valor Total do Curso"
+      readonly
     />
 
     <DefaultInput
@@ -216,7 +139,6 @@ import { computed, watch } from "vue";
 import { formatToBRLCurrency } from "src/helpers/utils";
 import { useInputRules } from "src/composables/useInputRules";
 
-import ExclusiveCheckboxPair from "./ExclusiveCheckboxPair.vue";
 import DefaultCurrencyInput from "src/components/defaults/DefaultCurrencyInput.vue";
 import DefaultInput from "src/components/defaults/DefaultInput.vue";
 import DefaultSelect from "src/components/defaults/DefaultSelect.vue";
@@ -249,9 +171,6 @@ const props = defineProps({
   },
 });
 
-const sectionError = (section) =>
-  props.validationErrors[`${props.fieldPrefix}.${section}_included_in_course`];
-
 const materialsTotalValue = computed(() =>
   modelValue.value.materials.reduce(
     (sum, material) =>
@@ -260,27 +179,6 @@ const materialsTotalValue = computed(() =>
   ),
 );
 
-const registrationInstallmentValue = computed(() =>
-  installmentValue(
-    modelValue.value.registration_value,
-    modelValue.value.registration_max_installments,
-  ),
-);
-
-const classesInstallmentValue = computed(() =>
-  installmentValue(
-    modelValue.value.classes_value,
-    modelValue.value.classes_max_installments,
-  ),
-);
-
-const materialsInstallmentValue = computed(() =>
-  installmentValue(
-    materialsTotalValue.value,
-    modelValue.value.materials_max_installments,
-  ),
-);
-
 const totalInstallmentValue = computed(() =>
   installmentValue(
     modelValue.value.total_value,
@@ -288,25 +186,12 @@ const totalInstallmentValue = computed(() =>
   ),
 );
 
-// Soma sugerida do Valor Total, considerando só as seções marcadas como
-// "incluso no valor do curso". O campo continua editável: só reaplicamos a
-// sugestão enquanto o usuário não tiver digitado um valor diferente dela.
-let lastSuggestedTotal = null;
-
 const suggestedTotal = computed(() => {
   let total = 0;
 
-  if (modelValue.value.registration_included_in_course) {
-    total += Number(modelValue.value.registration_value) || 0;
-  }
-
-  if (modelValue.value.classes_included_in_course) {
-    total += Number(modelValue.value.classes_value) || 0;
-  }
-
-  if (modelValue.value.materials_included_in_course) {
-    total += materialsTotalValue.value;
-  }
+  total += Number(modelValue.value.registration_value) || 0;
+  total += Number(modelValue.value.classes_value) || 0;
+  total += materialsTotalValue.value;
 
   return total;
 });
@@ -314,26 +199,11 @@ const suggestedTotal = computed(() => {
 watch(
   suggestedTotal,
   (newTotal) => {
-    if (
-      modelValue.value.total_value === null ||
-      modelValue.value.total_value === lastSuggestedTotal
-    ) {
-      modelValue.value.total_value = newTotal;
-    }
-
-    lastSuggestedTotal = newTotal;
+    modelValue.value.total_value = newTotal;
   },
   { immediate: true },
 );
 
-const setExclusive = (section, option) => {
-  const includedKey = `${section}_included_in_course`;
-  const installmentsKey = `${section}_installments_allowed`;
-
-  modelValue.value[includedKey] = option === "included";
-  modelValue.value[installmentsKey] = option === "installments";
-};
-
 const addMaterial = () => {
   modelValue.value.materials.push({
     price: null,

+ 0 - 274
src/pages/students/components/AddEditContractDialog.vue

@@ -311,153 +311,6 @@
                 </div>
               </div>
 
-              <div class="text-subtitle2 q-mt-md q-mb-sm text-grey-8">
-                Matrícula
-              </div>
-
-              <div class="row q-col-gutter-sm">
-                <div :class="registrationIncluded ? 'col-12' : 'col-3'">
-                  <DefaultCurrencyInput
-                    v-model="form.enrollment_fee"
-                    v-model:error="validationErrors.tax_register"
-                    label="Valor da Matrícula"
-                    :disable="registrationIncluded || !props.contract"
-                  />
-                </div>
-
-                <template v-if="!registrationIncluded">
-                  <div class="col-3">
-                    <DefaultSelect
-                      v-model="form.installments"
-                      v-model:error="validationErrors.installments"
-                      emit-value
-                      label="Qtde Parcelas"
-                      map-options
-                      option-label="label"
-                      option-value="value"
-                      :options="enrollmentInstallmentOptions"
-                      :rules="[inputRules.integerRange(1, 12)]"
-                    />
-                  </div>
-
-                  <div class="col-3">
-                    <DefaultCurrencyInput
-                      v-model:error="validationErrors.installments"
-                      :model-value="enrollmentInstallmentValue"
-                      disable
-                      label="Valor da Parcela"
-                    />
-                  </div>
-
-                  <div class="col-3">
-                    <DefaultInputDatePicker
-                      v-model="form.enrollment_due_date"
-                      v-model:error="validationErrors.enrollment_due_date"
-                      label="Data Vencimento"
-                      :rules="[inputRules.date]"
-                    />
-                  </div>
-                </template>
-              </div>
-
-              <div class="text-subtitle2 q-mt-md q-mb-sm text-grey-8">
-                Aulas
-              </div>
-
-              <div class="row q-col-gutter-sm">
-                <div :class="classesIncluded ? 'col-12' : 'col-3'">
-                  <DefaultCurrencyInput
-                    v-model="form.package_value"
-                    v-model:error="validationErrors.package_value"
-                    label="Valor das Aulas"
-                    :disable="classesIncluded || !props.contract"
-                  />
-                </div>
-
-                <template v-if="!classesIncluded">
-                  <div class="col-3">
-                    <DefaultSelect
-                      v-model="form.package_installments"
-                      v-model:error="validationErrors.package_installments"
-                      emit-value
-                      label="Qtde Parcelas"
-                      map-options
-                      option-label="label"
-                      option-value="value"
-                      :options="packageInstallmentOptions"
-                      :rules="[inputRules.integerRange(1, 13)]"
-                    />
-                  </div>
-
-                  <div class="col-3">
-                    <DefaultCurrencyInput
-                      v-model:error="validationErrors.package_installments"
-                      :model-value="packageInstallmentValue"
-                      disable
-                      label="Valor da Parcela"
-                    />
-                  </div>
-
-                  <div class="col-3">
-                    <DefaultInputDatePicker
-                      v-model="form.package_due_date"
-                      v-model:error="validationErrors.package_due_date"
-                      label="Data 1ª Parcela"
-                      :rules="[inputRules.date]"
-                    />
-                  </div>
-                </template>
-              </div>
-
-              <div class="text-subtitle2 q-mt-md q-mb-sm text-grey-8">
-                Materiais
-              </div>
-
-              <div class="row q-col-gutter-sm">
-                <div :class="materialsIncluded ? 'col-12' : 'col-3'">
-                  <DefaultCurrencyInput
-                    v-model="form.materials_value"
-                    v-model:error="validationErrors.materials_value"
-                    label="Valor dos Materiais"
-                    :disable="materialsIncluded || !props.contract"
-                  />
-                </div>
-
-                <template v-if="!materialsIncluded">
-                  <div class="col-3">
-                    <DefaultSelect
-                      v-model="form.materials_installments"
-                      v-model:error="validationErrors.materials_installments"
-                      emit-value
-                      label="Qtde Parcelas"
-                      map-options
-                      option-label="label"
-                      option-value="value"
-                      :options="packageInstallmentOptions"
-                      :rules="[inputRules.integerRange(1, 13)]"
-                    />
-                  </div>
-
-                  <div class="col-3">
-                    <DefaultCurrencyInput
-                      v-model:error="validationErrors.materials_installments"
-                      :model-value="materialsInstallmentValue"
-                      disable
-                      label="Valor da Parcela"
-                    />
-                  </div>
-
-                  <div class="col-3">
-                    <DefaultInputDatePicker
-                      v-model="form.materials_due_date"
-                      v-model:error="validationErrors.materials_due_date"
-                      label="Data 1ª Parcela"
-                      :rules="[inputRules.date]"
-                    />
-                  </div>
-                </template>
-              </div>
-
               <div class="text-subtitle2 q-mt-md q-mb-sm text-grey-8">
                 Total do Curso
               </div>
@@ -668,38 +521,12 @@ const dialogCardStyle = computed(() => ({
   width: "100%",
 }));
 
-const enrollmentInstallmentValue = computed(() => {
-  if (!form.enrollment_fee || !form.installments) {
-    return null;
-  }
-
-  return Number((form.enrollment_fee / form.installments).toFixed(2));
-});
-
 const formattedBirthDate = computed(() =>
   currentStudent.value?.birth_date
     ? formatDateYMDtoDMY(currentStudent.value.birth_date)
     : "",
 );
 
-const packageInstallmentValue = computed(() => {
-  if (!form.package_value || !form.package_installments) {
-    return null;
-  }
-
-  return Number((form.package_value / form.package_installments).toFixed(2));
-});
-
-const materialsInstallmentValue = computed(() => {
-  if (!form.materials_value || !form.materials_installments) {
-    return null;
-  }
-
-  return Number(
-    (form.materials_value / form.materials_installments).toFixed(2),
-  );
-});
-
 const totalInstallmentValue = computed(() => {
   if (!form.total_value || !form.total_installments) {
     return null;
@@ -726,29 +553,6 @@ const modalityOptions = computed(() => {
   return options;
 });
 
-const selectedModality = computed(() => {
-  const selectedPackage = packages.value.find(
-    (item) => item.id === form.package_id,
-  );
-
-  return form.pricing_mode === "irrecusavel"
-    ? selectedPackage?.irrecusavel
-    : selectedPackage?.pavao;
-});
-
-// Item "incluso no valor do curso" não gera cobrança separada — só o campo
-// de valor aparece (informativo, desabilitado); parcelas/vencimento somem.
-const registrationIncluded = computed(() =>
-  Boolean(selectedModality.value?.registration_included_in_course),
-);
-
-const classesIncluded = computed(() =>
-  Boolean(selectedModality.value?.classes_included_in_course),
-);
-
-const materialsIncluded = computed(() =>
-  Boolean(selectedModality.value?.materials_included_in_course),
-);
 
 const completeDatePattern = /^\d{2}\/\d{2}\/\d{4}$/;
 
@@ -763,11 +567,6 @@ const defaultContractDates = (() => {
   };
 })();
 
-const enrollmentInstallmentOptions = Array.from({ length: 12 }, (_, index) => ({
-  label: `${index + 1}x`,
-  value: index + 1,
-}));
-
 const packageInstallmentOptions = Array.from({ length: 13 }, (_, index) => ({
   label: `${index + 1}x`,
   value: index + 1,
@@ -829,24 +628,11 @@ const { form, getUpdatedFields } = useForm({
 
   end_time: trimTime(props.contract?.end_time),
 
-  enrollment_due_date: props.contract?.enrollment_due_date ?? null,
-
-  enrollment_fee: props.contract?.tax_register ?? null,
-  installments: props.contract?.installments ?? null,
   late_fee: props.contract?.fine_cancelled ?? null,
-  package_due_date: props.contract?.package_due_date ?? null,
-
   package_id: props.contract?.class_package_unit_id ?? null,
 
-  package_installments: props.contract?.package_installments ?? null,
-
-  package_value: props.contract?.package_value ?? null,
   payment_method: props.contract?.payment_method ?? null,
 
-  materials_due_date: props.contract?.materials_due_date ?? null,
-  materials_installments: props.contract?.materials_installments ?? null,
-  materials_value: props.contract?.materials_value ?? null,
-
   pricing_mode: props.contract?.pricing_mode ?? null,
   protocol: props.contract?.protocol ?? null,
 
@@ -919,25 +705,7 @@ const buildPayload = () => ({
 
   end_time: form.end_time,
 
-  enrollment_due_date: form.enrollment_due_date
-    ? formatDateDMYtoYMD(form.enrollment_due_date)
-    : null,
-
   fine_cancelled: form.late_fee,
-  installments: form.installments,
-
-  materials_due_date: form.materials_due_date
-    ? formatDateDMYtoYMD(form.materials_due_date)
-    : null,
-  materials_installments: form.materials_installments,
-  materials_value: form.materials_value,
-
-  package_due_date: form.package_due_date
-    ? formatDateDMYtoYMD(form.package_due_date)
-    : null,
-
-  package_installments: form.package_installments,
-  package_value: form.package_value,
   payment_method: form.payment_method,
   pricing_mode: form.pricing_mode,
   protocol: form.protocol,
@@ -951,8 +719,6 @@ const buildPayload = () => ({
 
   start_time: form.start_time,
   student_id: currentStudent.value?.id ?? null,
-  tax_register: form.enrollment_fee,
-
   total_due_date: form.total_due_date
     ? formatDateDMYtoYMD(form.total_due_date)
     : null,
@@ -1007,7 +773,6 @@ const handleSave = async () => {
     const updatePayload = {};
 
     const fieldMap = {
-      enrollment_fee: "tax_register",
       late_fee: "fine_cancelled",
       package_id: "class_package_unit_id",
       total_classes: "class_quantity",
@@ -1022,13 +787,8 @@ const handleSave = async () => {
       "second_weekday",
       "second_start_time",
       "second_end_time",
-      "installments",
-      "package_value",
-      "package_installments",
       "payment_method",
       "pricing_mode",
-      "materials_value",
-      "materials_installments",
       "total_value",
       "total_installments",
     ]) {
@@ -1046,9 +806,6 @@ const handleSave = async () => {
     for (const key of [
       "signature_date",
       "end_date",
-      "enrollment_due_date",
-      "package_due_date",
-      "materials_due_date",
       "total_due_date",
     ]) {
       if (key in changedFields) {
@@ -1238,45 +995,14 @@ watch(
         : selectedPackage?.pavao;
 
     if (!modality) {
-      form.enrollment_fee = null;
-      form.installments = null;
-      form.package_value = null;
-      form.package_installments = null;
-      form.materials_value = null;
-      form.materials_installments = null;
       form.total_value = null;
       form.total_installments = null;
 
       return;
     }
 
-    // O valor aparece sempre (informativo); parcelas só existem pro que não
-    // estiver incluso no curso (é o que vira cobrança separada).
-    form.enrollment_fee = modality.registration_value;
-
-    form.installments = modality.registration_included_in_course
-      ? null
-      : modality.registration_max_installments;
-
-    form.package_value = modality.classes_value;
-
-    form.package_installments = modality.classes_included_in_course
-      ? null
-      : modality.classes_max_installments;
-
-    form.materials_value = modality.materials_total_value;
-
-    form.materials_installments = modality.materials_included_in_course
-      ? null
-      : modality.materials_max_installments;
-
     form.total_value = modality.total_value;
     form.total_installments = modality.total_max_installments;
-
-    // Vencimento só faz sentido pro que gera cobrança separada.
-    if (modality.registration_included_in_course) form.enrollment_due_date = null;
-    if (modality.classes_included_in_course) form.package_due_date = null;
-    if (modality.materials_included_in_course) form.materials_due_date = null;
   },
 );
 

+ 0 - 40
src/pages/students/components/ViewContractDialog.vue

@@ -227,14 +227,6 @@
                 />
               </div>
 
-              <div class="col-4">
-                <DefaultCurrencyInput
-                  :model-value="contract.tax_register"
-                  disable
-                  label="Taxa de Matrícula"
-                />
-              </div>
-
               <div class="col-4">
                 <DefaultInput
                   :model-value="contract.class_quantity"
@@ -243,38 +235,6 @@
                 />
               </div>
 
-              <div class="col-3">
-                <DefaultInput
-                  :model-value="
-                    contract.installments
-                      ? `${contract.installments}x`
-                      : null
-                  "
-                  disable
-                  label="Parcelas"
-                />
-              </div>
-
-              <div class="col-3">
-                <DefaultCurrencyInput
-                  :model-value="contract.materials_value"
-                  disable
-                  label="Valor dos Materiais"
-                />
-              </div>
-
-              <div class="col-3">
-                <DefaultInput
-                  :model-value="
-                    contract.materials_installments
-                      ? `${contract.materials_installments}x`
-                      : null
-                  "
-                  disable
-                  label="Parcelas"
-                />
-              </div>
-
               <div class="col-3">
                 <DefaultCurrencyInput
                   :model-value="contract.total_value"