Sfoglia il codice sorgente

feat: add down payment and demonstrative values to contract dialog

Adiciona Taxa de Contratação/Entrada + Data do Valor, que abate do
Total do Curso na hora de calcular a parcela; e mostra Valor da Aula
e Valor dos Materiais (só demonstrativo, vindos da modalidade do
pacote selecionado). Um único componente já cobre atalhos rápidos e
aluno -> contrato, então não precisou duplicar nada.
alvesantos 2 giorni fa
parent
commit
2a21324974
1 ha cambiato i file con 78 aggiunte e 1 eliminazioni
  1. 78 1
      src/pages/students/components/AddEditContractDialog.vue

+ 78 - 1
src/pages/students/components/AddEditContractDialog.vue

@@ -329,6 +329,45 @@
               </div>
 
               <div class="row q-col-gutter-sm">
+                <div class="col-3">
+                  <DefaultCurrencyInput
+                    :model-value="form.classes_value"
+                    disable
+                    label="Valor da Aula"
+                  />
+                </div>
+
+                <div class="col-3">
+                  <DefaultCurrencyInput
+                    :model-value="form.materials_total_value"
+                    disable
+                    label="Valor dos Materiais"
+                  />
+                </div>
+
+                <div class="col-3">
+                  <DefaultCurrencyInput
+                    v-model="form.down_payment_value"
+                    v-model:error="validationErrors.down_payment_value"
+                    label="Taxa de Contratação / Entrada"
+                  />
+                </div>
+
+                <div class="col-3">
+                  <DefaultInputDatePicker
+                    v-model="form.down_payment_date"
+                    v-model:error="validationErrors.down_payment_date"
+                    label="Data do Valor"
+                    :rules="
+                      form.down_payment_value
+                        ? [inputRules.required, inputRules.date]
+                        : [inputRules.date]
+                    "
+                  />
+                </div>
+              </div>
+
+              <div class="row q-col-gutter-sm q-mt-xs">
                 <div class="col-3">
                   <DefaultCurrencyInput
                     v-model="form.total_value"
@@ -548,7 +587,10 @@ const totalInstallmentValue = computed(() => {
     return null;
   }
 
-  return Number((form.total_value / form.total_installments).toFixed(2));
+  const downPayment = Number(form.down_payment_value) || 0;
+  const remaining = Math.max(0, form.total_value - downPayment);
+
+  return Number((remaining / form.total_installments).toFixed(2));
 });
 
 const modalityOptions = computed(() => {
@@ -638,13 +680,18 @@ const trimTime = (time) => (time ? time.slice(0, 5) : null);
 
 const { form, getUpdatedFields } = useForm({
   class_quantity: props.contract?.class_quantity ?? null,
+  classes_value: null,
   due_day: props.contract?.due_day ?? null,
 
+  down_payment_date: props.contract?.down_payment_date ?? null,
+  down_payment_value: props.contract?.down_payment_value ?? null,
+
   end_date: props.contract?.end_date ?? defaultContractDates?.end_date ?? null,
 
   end_time: trimTime(props.contract?.end_time),
 
   late_fee: props.contract?.fine_cancelled ?? null,
+  materials_total_value: props.contract?.materials_value ?? null,
   package_id: props.contract?.class_package_unit_id ?? null,
 
   payment_method: props.contract?.payment_method ?? null,
@@ -715,6 +762,11 @@ const buildPayload = () => ({
   class_package_unit_id: form.package_id,
   class_quantity: form.class_quantity,
 
+  down_payment_date: form.down_payment_date
+    ? formatDateDMYtoYMD(form.down_payment_date)
+    : null,
+  down_payment_value: form.down_payment_value,
+
   due_day: form.due_day ? Number.parseInt(form.due_day) : null,
 
   end_date: form.end_date ? formatDateDMYtoYMD(form.end_date) : null,
@@ -807,6 +859,7 @@ const handleSave = async () => {
       "pricing_mode",
       "total_value",
       "total_installments",
+      "down_payment_value",
     ]) {
       if (key in changedFields) {
         updatePayload[key] = payload[key];
@@ -823,6 +876,7 @@ const handleSave = async () => {
       "signature_date",
       "end_date",
       "total_due_date",
+      "down_payment_date",
     ]) {
       if (key in changedFields) {
         updatePayload[key] = payload[key];
@@ -1048,12 +1102,16 @@ watch(
     if (!modality) {
       form.total_value = null;
       form.total_installments = null;
+      form.classes_value = null;
+      form.materials_total_value = null;
 
       return;
     }
 
     form.total_value = modality.total_value;
     form.total_installments = modality.total_max_installments;
+    form.classes_value = modality.classes_value;
+    form.materials_total_value = modality.materials_total_value;
   },
 );
 
@@ -1141,6 +1199,25 @@ onMounted(async () => {
 
   packages.value = unitPackages;
 
+  // Num contrato existente o pacote já vem selecionado, então o watch de
+  // package_id/pricing_mode não dispara sozinho — busca a modalidade aqui
+  // pra preencher os campos demonstrativos (Valor da Aula/Materiais).
+  if (props.contract) {
+    const selectedPackage = packages.value.find(
+      (item) => item.id === form.package_id,
+    );
+
+    const modality =
+      form.pricing_mode === "irrecusavel"
+        ? selectedPackage?.irrecusavel
+        : selectedPackage?.pavao;
+
+    if (modality) {
+      form.classes_value = modality.classes_value;
+      form.materials_total_value ??= modality.materials_total_value;
+    }
+  }
+
   unitDetails.value = unitData ?? store.selectedUnit ?? {};
 
   isAutomaticProtocol.value = unitDetails.value?.automatic_protocol ?? true;