Просмотр исходного кода

feat: adiciona funcionalidade de criacao de contas a receber do aluno

ebagabee 3 недель назад
Родитель
Сommit
f409672494
1 измененных файлов с 126 добавлено и 37 удалено
  1. 126 37
      src/pages/students/components/AddEditContractDialog.vue

+ 126 - 37
src/pages/students/components/AddEditContractDialog.vue

@@ -179,33 +179,23 @@
               type="number"
             />
           </div>
+        </div>
 
-          <div class="col-4">
+        <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="col-3">
             <DefaultCurrencyInput
               v-model="form.enrollment_fee"
-              label="Taxa de Matrícula"
-              disable
-            />
-          </div>
-
-          <div class="col-4">
-            <DefaultInput
-              v-model="form.total_classes"
-              label="Total de Aulas"
-              type="number"
+              label="Valor da Matrícula"
               disable
             />
           </div>
 
-          <div class="col-3">
-            <DefaultCurrencyInput v-model="form.down_payment" label="Entrada" />
-          </div>
-
           <div class="col-3">
             <DefaultSelect
               v-model="form.installments"
-              label="Parcelas"
-              :options="installmentOptions"
+              label="Qtde Parcelas"
+              :options="enrollmentInstallmentOptions"
               option-value="value"
               option-label="label"
               emit-value
@@ -213,26 +203,37 @@
             />
           </div>
 
-          <div class="col-6">
-            <DefaultInput
-              v-model="form.early_payment_discount"
-              label="Desconto até o vencimento (%)"
-              type="number"
+          <div class="col-3">
+            <DefaultCurrencyInput
+              :model-value="enrollmentInstallmentValue"
+              label="Valor da Parcela"
+              disable
+            />
+          </div>
+
+          <div class="col-3">
+            <DefaultInputDatePicker
+              v-model="form.enrollment_due_date"
+              label="Data Vencimento"
             />
           </div>
+        </div>
 
+        <div class="text-subtitle2 q-mt-md q-mb-sm text-grey-8">Pacote</div>
+        <div class="row q-col-gutter-sm">
           <div class="col-3">
             <DefaultCurrencyInput
-              v-model="form.material_value"
-              label="Valor dos Materiais"
+              v-model="form.package_value"
+              label="Valor do Pacote"
+              disable
             />
           </div>
 
           <div class="col-3">
             <DefaultSelect
-              v-model="form.material_installments"
-              label="Parcelas"
-              :options="installmentOptions"
+              v-model="form.package_installments"
+              label="Qtde Parcelas"
+              :options="packageInstallmentOptions"
               option-value="value"
               option-label="label"
               emit-value
@@ -240,10 +241,27 @@
             />
           </div>
 
+          <div class="col-3">
+            <DefaultCurrencyInput
+              :model-value="packageInstallmentValue"
+              label="Valor da Parcela"
+              disable
+            />
+          </div>
+
+          <div class="col-3">
+            <DefaultInputDatePicker
+              v-model="form.package_due_date"
+              label="Data 1ª Parcela"
+            />
+          </div>
+        </div>
+
+        <div class="row q-col-gutter-sm q-mt-xs">
           <div class="col-6">
             <DefaultInput
-              v-model="form.interest_rate"
-              label="Juros (%) a.m"
+              v-model="form.early_payment_discount"
+              label="Desconto até o vencimento (%)"
               type="number"
             />
           </div>
@@ -260,6 +278,14 @@
             />
           </div>
 
+          <div class="col-6">
+            <DefaultInput
+              v-model="form.interest_rate"
+              label="Juros (%) a.m"
+              type="number"
+            />
+          </div>
+
           <div class="col-6">
             <DefaultInput
               v-model="form.late_fee"
@@ -326,7 +352,7 @@
 </template>
 
 <script setup>
-import { computed, ref, watch, onMounted } from "vue";
+import { computed, ref, watch, onMounted, nextTick } from "vue";
 import { useDialogPluginComponent, useQuasar } from "quasar";
 import DefaultDialogHeader from "src/components/defaults/DefaultDialogHeader.vue";
 import DefaultInput from "src/components/defaults/DefaultInput.vue";
@@ -382,21 +408,78 @@ const { form } = useFormUpdateTracker({
   due_day: props.contract?.recurring_day ?? null,
   enrollment_fee: props.contract?.tax_register ?? null,
   total_classes: props.contract?.class_quantity ?? null,
-  down_payment: props.contract?.down_payment ?? null,
   installments: props.contract?.installments ?? null,
+  enrollment_due_date: props.contract?.enrollment_due_date ?? null,
+  package_value: props.contract?.package_value ?? null,
+  package_installments: props.contract?.package_installments ?? null,
+  package_due_date: props.contract?.package_due_date ?? null,
   early_payment_discount: props.contract?.early_payment_discount ?? null,
-  material_value: props.contract?.material_value ?? null,
-  material_installments: props.contract?.material_installments ?? null,
   interest_rate: props.contract?.interest_rate ?? null,
   payment_method: props.contract?.payment_method ?? null,
   late_fee: props.contract?.fine_cancelled ?? null,
 });
 
-const installmentOptions = Array.from({ length: 12 }, (_, i) => ({
+const enrollmentInstallmentOptions = Array.from({ length: 12 }, (_, i) => ({
   value: i + 1,
   label: `${i + 1}x`,
 }));
 
+const packageInstallmentOptions = Array.from({ length: 13 }, (_, i) => ({
+  value: i + 1,
+  label: `${i + 1}x`,
+}));
+
+const enrollmentInstallmentValue = computed(() => {
+  if (!form.enrollment_fee || !form.installments) return null;
+  return parseFloat((form.enrollment_fee / form.installments).toFixed(2));
+});
+
+const packageInstallmentValue = computed(() => {
+  if (!form.package_value || !form.package_installments) return null;
+  return parseFloat((form.package_value / form.package_installments).toFixed(2));
+});
+
+// Two-way binding: due_day <-> package_due_date
+const _syncingFromDay = ref(false);
+const _syncingFromDate = ref(false);
+
+function buildDateFromDay(day) {
+  const d = parseInt(day);
+  if (!d || d < 1 || d > 31) return null;
+  const now = new Date();
+  const nextMonthIndex = (now.getMonth() + 1) % 12;
+  const nextYear = now.getMonth() === 11 ? now.getFullYear() + 1 : now.getFullYear();
+  const lastDayOfNextMonth = new Date(nextYear, nextMonthIndex + 1, 0).getDate();
+  const safeDay = Math.min(d, lastDayOfNextMonth);
+  return `${String(safeDay).padStart(2, '0')}/${String(nextMonthIndex + 1).padStart(2, '0')}/${nextYear}`;
+}
+
+watch(
+  () => form.due_day,
+  (day) => {
+    if (_syncingFromDate.value) return;
+    const dateStr = buildDateFromDay(day);
+    if (!dateStr) return;
+    _syncingFromDay.value = true;
+    form.package_due_date = dateStr;
+    nextTick(() => { _syncingFromDay.value = false; });
+  },
+);
+
+watch(
+  () => form.package_due_date,
+  (dateStr) => {
+    if (_syncingFromDay.value) return;
+    if (!dateStr || dateStr.length < 8) return;
+    const day = parseInt(dateStr.split('/')[0]);
+    if (!isNaN(day) && day !== parseInt(form.due_day)) {
+      _syncingFromDate.value = true;
+      form.due_day = day;
+      nextTick(() => { _syncingFromDate.value = false; });
+    }
+  },
+);
+
 const paymentMethods = [
   { value: "pix", label: "Pix" },
   { value: "credit_card", label: "Cartão de Crédito" },
@@ -467,6 +550,7 @@ watch(
     form.class_quantity = pkg.quantity_classes;
     form.total_classes = pkg.quantity_classes;
     form.enrollment_fee = pkg.contract_register_value;
+    form.package_value = pkg.contract_value;
   },
 );
 
@@ -496,11 +580,16 @@ function buildPayload() {
     second_end_time: form.second_end_time,
     due_day: form.due_day ? parseInt(form.due_day) : null,
     tax_register: form.enrollment_fee,
-    down_payment: form.down_payment ?? 0,
     installments: form.installments,
+    enrollment_due_date: form.enrollment_due_date
+      ? formatDateDMYtoYMD(form.enrollment_due_date)
+      : null,
+    package_value: form.package_value,
+    package_installments: form.package_installments,
+    package_due_date: form.package_due_date
+      ? formatDateDMYtoYMD(form.package_due_date)
+      : null,
     early_payment_discount: form.early_payment_discount,
-    material_value: form.material_value,
-    material_installments: form.material_installments,
     interest_rate: form.interest_rate,
     payment_method: form.payment_method,
     fine_cancelled: form.late_fee,