Эх сурвалжийг харах

feat: adiciona listagem de contrato, e resource

ebagabee 1 сар өмнө
parent
commit
04f38a07cf

+ 20 - 0
src/api/studentContract.js

@@ -0,0 +1,20 @@
+import api from "src/api";
+
+export const getStudentContracts = async (studentId) => {
+  const { data } = await api.get("/student-contract", { params: { student_id: studentId } });
+  return data.payload;
+};
+
+export const createStudentContract = async (payload) => {
+  const { data } = await api.post("/student-contract", payload);
+  return data.payload;
+};
+
+export const updateStudentContract = async (id, payload) => {
+  const { data } = await api.put(`/student-contract/${id}`, payload);
+  return data.payload;
+};
+
+export const deleteStudentContract = async (id) => {
+  await api.delete(`/student-contract/${id}`);
+};

+ 74 - 52
src/pages/students/components/CreateContractDialog.vue

@@ -4,7 +4,7 @@
       class="q-dialog-plugin overflow-hidden"
       style="width: 100%; max-width: 1100px"
     >
-      <DefaultDialogHeader title="Novo Contrato" @close="onDialogCancel" />
+      <DefaultDialogHeader :title="props.contract ? 'Editar Contrato' : 'Novo Contrato'" @close="onDialogCancel" />
 
       <q-card-section class="q-pt-sm" style="height: 65vh; overflow-y: auto">
         <div class="text-subtitle1 q-mb-md">Dados do Aluno</div>
@@ -43,27 +43,17 @@
           </div>
 
           <div class="col-4">
-            <DefaultInput
+            <DefaultInputDatePicker
               v-model="form.signature_date"
               label="Data Assinatura"
-              :mask="masks.Brasil.date"
-            >
-              <template #append>
-                <q-icon name="mdi-calendar" />
-              </template>
-            </DefaultInput>
+            />
           </div>
 
           <div class="col-4">
-            <DefaultInput
+            <DefaultInputDatePicker
               v-model="form.end_date"
               label="Data Encerramento"
-              :mask="masks.Brasil.date"
-            >
-              <template #append>
-                <q-icon name="mdi-calendar" />
-              </template>
-            </DefaultInput>
+            />
           </div>
 
           <div class="col-5">
@@ -164,15 +154,10 @@
 
         <div class="row q-col-gutter-sm">
           <div class="col-4">
-            <DefaultInput
+            <DefaultInputDatePicker
               v-model="form.due_date"
               label="Vencimento"
-              :mask="masks.Brasil.date"
-            >
-              <template #append>
-                <q-icon name="mdi-calendar" />
-              </template>
-            </DefaultInput>
+            />
           </div>
 
           <div class="col-4">
@@ -193,10 +178,9 @@
           </div>
 
           <div class="col-3">
-            <DefaultInput
+            <DefaultCurrencyInput
               v-model="form.down_payment"
               label="Entrada"
-              type="number"
             />
           </div>
 
@@ -221,10 +205,9 @@
           </div>
 
           <div class="col-3">
-            <DefaultInput
+            <DefaultCurrencyInput
               v-model="form.material_value"
               label="Valor dos Materiais"
-              type="number"
             />
           </div>
 
@@ -297,17 +280,22 @@ import DefaultDialogHeader from "src/components/defaults/DefaultDialogHeader.vue
 import DefaultInput from "src/components/defaults/DefaultInput.vue";
 import DefaultSelect from "src/components/defaults/DefaultSelect.vue";
 import DefaultCurrencyInput from "src/components/defaults/DefaultCurrencyInput.vue";
+import DefaultInputDatePicker from "src/components/defaults/DefaultInputDatePicker.vue";
 import { useSubmitHandler } from "src/composables/useSubmitHandler";
 import { useFormUpdateTracker } from "src/composables/useFormUpdateTracker";
-import { formatDateYMDtoDMY } from "src/helpers/utils";
-import masks from "src/helpers/masks";
+import { formatDateYMDtoDMY, formatDateDMYtoYMD } from "src/helpers/utils";
 import { getUnitPackages } from "src/api/package";
+import { createStudentContract, updateStudentContract } from "src/api/studentContract";
 
 const props = defineProps({
   student: {
     type: Object,
     required: true,
   },
+  contract: {
+    type: Object,
+    default: null,
+  },
 });
 
 defineEmits([...useDialogPluginComponent.emits]);
@@ -315,29 +303,31 @@ defineEmits([...useDialogPluginComponent.emits]);
 const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } =
   useDialogPluginComponent();
 
+const trimTime = (t) => (t ? t.slice(0, 5) : null);
+
 const { form } = useFormUpdateTracker({
-  protocol: null,
-  signature_date: null,
-  end_date: null,
-  package_id: null,
-  class_quantity: null,
-  weekday: null,
-  start_time: null,
-  end_time: null,
-  second_weekday: null,
-  second_start_time: null,
-  second_end_time: null,
-  due_date: null,
-  enrollment_fee: null,
-  total_classes: null,
-  down_payment: null,
-  installments: null,
-  early_payment_discount: null,
-  material_value: null,
-  material_installments: null,
-  interest_rate: null,
-  payment_method: null,
-  late_fee: null,
+  protocol:               props.contract?.protocol ?? null,
+  signature_date:         props.contract?.signature_date ?? null,
+  end_date:               props.contract?.end_date ?? null,
+  package_id:             props.contract?.class_package_unit_id ?? null,
+  class_quantity:         props.contract?.class_quantity ?? null,
+  weekday:                props.contract?.weekday ?? null,
+  start_time:             trimTime(props.contract?.start_time),
+  end_time:               trimTime(props.contract?.end_time),
+  second_weekday:         props.contract?.second_weekday ?? null,
+  second_start_time:      trimTime(props.contract?.second_start_time),
+  second_end_time:        trimTime(props.contract?.second_end_time),
+  due_date:               props.contract?.due_date ?? 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,
+  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) => ({
@@ -382,11 +372,43 @@ const formattedBirthDate = computed(() =>
   props.student.birth_date ? formatDateYMDtoDMY(props.student.birth_date) : "",
 );
 
-const { loading: saving } = useSubmitHandler({
+const { loading: saving, execute } = useSubmitHandler({
   onSuccess: () => onDialogOK(true),
 });
 
+function buildPayload() {
+  return {
+    student_id:              props.student.id,
+    protocol:                form.protocol,
+    signature_date:          form.signature_date ? formatDateDMYtoYMD(form.signature_date) : null,
+    end_date:                form.end_date ? formatDateDMYtoYMD(form.end_date) : null,
+    class_package_unit_id:   form.package_id,
+    class_quantity:          form.class_quantity,
+    weekday:                 form.weekday,
+    start_time:              form.start_time,
+    end_time:                form.end_time,
+    second_weekday:          form.second_weekday,
+    second_start_time:       form.second_start_time,
+    second_end_time:         form.second_end_time,
+    due_date:                form.due_date ? formatDateDMYtoYMD(form.due_date) : null,
+    tax_register:            form.enrollment_fee,
+    down_payment:            form.down_payment ?? 0,
+    installments:            form.installments,
+    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,
+  };
+}
+
 async function handleSave() {
-  console.log("Save contract", form);
+  const payload = buildPayload();
+  await execute(() =>
+    props.contract
+      ? updateStudentContract(props.contract.id, payload)
+      : createStudentContract(payload),
+  );
 }
 </script>

+ 43 - 20
src/pages/students/tabs/ContractTab.vue

@@ -12,7 +12,7 @@
       @on-add-item="handleAdd"
     >
       <template #body-cell-period="{ row }">
-        <q-td>{{ row.started_date }} — {{ row.end_date }}</q-td>
+        <q-td>{{ row.signature_date }} — {{ row.end_date }}</q-td>
       </template>
 
       <template #body-cell-status="{ row }">
@@ -24,23 +24,38 @@
         </q-td>
       </template>
 
-      <template #body-cell-actions>
+      <template #body-cell-actions="{ row }">
         <q-td auto-width>
-          <q-item-section class="no-wrap" style="flex-direction: row">
+          <q-item-section class="no-wrap" style="flex-direction: row; gap: 4px">
             <q-btn
               outline
               icon="mdi-pencil-outline"
               style="width: 36px"
-              class="q-mr-sm"
-              @click.prevent.stop="() => {}"
+              @click.prevent.stop="handleEdit(row)"
             />
             <q-btn
               outline
-              icon="mdi-trash-can-outline"
+              icon="mdi-paperclip"
               style="width: 36px"
-              class="q-mr-sm"
               @click.prevent.stop="() => {}"
             />
+            <q-btn
+              outline
+              icon="mdi-dots-vertical"
+              style="width: 36px"
+              @click.prevent.stop
+            >
+              <q-menu>
+                <q-list style="min-width: 150px">
+                  <q-item v-close-popup clickable @click="() => {}">
+                    <q-item-section>Editar</q-item-section>
+                  </q-item>
+                  <q-item v-close-popup clickable @click="() => {}">
+                    <q-item-section>Anexos</q-item-section>
+                  </q-item>
+                </q-list>
+              </q-menu>
+            </q-btn>
           </q-item-section>
         </q-td>
       </template>
@@ -49,10 +64,11 @@
 </template>
 
 <script setup>
-import { ref } from "vue";
+import { ref, onMounted } from "vue";
 import { useQuasar } from "quasar";
 import DefaultTable from "src/components/defaults/DefaultTable.vue";
 import CreateContractDialog from "src/pages/students/components/CreateContractDialog.vue";
+import { getStudentContracts } from "src/api/studentContract";
 
 const props = defineProps({
   student: {
@@ -64,24 +80,31 @@ const props = defineProps({
 const $q = useQuasar();
 const rows = ref([]);
 
-function handleAdd() {
+async function loadContracts() {
+  rows.value = await getStudentContracts(props.student.id);
+}
+
+onMounted(loadContracts);
+
+function openDialog(contract = null) {
   $q.dialog({
     component: CreateContractDialog,
-    componentProps: { student: props.student },
-  }).onOk(() => {
-    console.log("Contract created");
-  });
+    componentProps: { student: props.student, contract },
+  }).onOk(loadContracts);
+}
+
+function handleAdd() {
+  openDialog();
+}
+
+function handleEdit(contract) {
+  openDialog(contract);
 }
 
 const columns = ref([
   { name: "contract", label: "Contrato", field: "protocol", align: "left" },
-  { name: "period", label: "Data Inicial - Final", field: null, align: "left" },
-  {
-    name: "status",
-    label: "Status Contrato",
-    field: "status",
-    align: "center",
-  },
+  { name: "period", label: "Data Assinatura - Encerramento", field: null, align: "left" },
+  { name: "status", label: "Status", field: "status", align: "center" },
   { name: "actions", label: "Ações", field: null, align: "center" },
 ]);
 </script>