|
|
@@ -1,145 +1,103 @@
|
|
|
<template>
|
|
|
<q-dialog ref="dialogRef" @hide="onDialogHide">
|
|
|
- <q-card
|
|
|
- class="q-dialog-plugin dialog-form-card"
|
|
|
- :style="dialogCardStyle"
|
|
|
- >
|
|
|
+ <q-card class="q-dialog-plugin dialog-form-card" :style="dialogCardStyle">
|
|
|
<DefaultDialogHeader
|
|
|
:title="props.contract ? 'Editar Contrato' : 'Novo Contrato'"
|
|
|
@close="onDialogCancel"
|
|
|
/>
|
|
|
|
|
|
- <template v-if="props.contract">
|
|
|
- <q-tabs
|
|
|
- v-model="activeTab"
|
|
|
- active-color="primary"
|
|
|
- align="left"
|
|
|
- class="q-px-md text-grey-7"
|
|
|
- dense
|
|
|
- indicator-color="primary"
|
|
|
- >
|
|
|
- <q-tab
|
|
|
- label="Dados do Contrato"
|
|
|
- name="dados"
|
|
|
- />
|
|
|
-
|
|
|
- <q-tab
|
|
|
- label="Mídias do Contrato"
|
|
|
- name="midias"
|
|
|
- />
|
|
|
- </q-tabs>
|
|
|
-
|
|
|
- <q-separator />
|
|
|
- </template>
|
|
|
-
|
|
|
- <DefaultForm
|
|
|
- ref="formRef"
|
|
|
- @submit="handleSave"
|
|
|
- >
|
|
|
- <q-scroll-area
|
|
|
- ref="scrollAreaRef"
|
|
|
- class="dialog-form-scroll"
|
|
|
- >
|
|
|
+ <DefaultForm ref="formRef" @submit="handleSave">
|
|
|
+ <q-scroll-area ref="scrollAreaRef" class="dialog-form-scroll">
|
|
|
<q-card-section class="q-pt-sm">
|
|
|
- <div v-show="activeTab === 'dados'">
|
|
|
- <DefaultInput
|
|
|
- :model-value="store.user?.name"
|
|
|
- class="q-mb-md"
|
|
|
- label="Franqueado operador"
|
|
|
- readonly
|
|
|
- />
|
|
|
-
|
|
|
- <div class="text-subtitle1 q-mb-md">
|
|
|
- Dados da Unidade
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="row q-col-gutter-sm">
|
|
|
+ <div>
|
|
|
+ <template v-if="!props.contract">
|
|
|
<DefaultInput
|
|
|
- v-model:error="validationErrors.unit_id"
|
|
|
- :model-value="unitDetails.name"
|
|
|
- class="col-12 col-md-6"
|
|
|
- label="Nome da Unidade"
|
|
|
+ :model-value="store.user?.name"
|
|
|
+ class="q-mb-md"
|
|
|
+ label="Franqueado operador"
|
|
|
readonly
|
|
|
/>
|
|
|
|
|
|
- <DefaultInput
|
|
|
- v-model:error="validationErrors.unit_id"
|
|
|
- :model-value="unitDetails.cnpj"
|
|
|
- :mask="masks.Brasil.cnpj"
|
|
|
- class="col-12 col-md-6"
|
|
|
- label="CNPJ"
|
|
|
- readonly
|
|
|
- />
|
|
|
- </div>
|
|
|
+ <div class="text-subtitle1 q-mb-md">Dados da Unidade</div>
|
|
|
|
|
|
- <div class="text-subtitle1 q-mt-lg q-mb-md">
|
|
|
- Dados do Aluno
|
|
|
- </div>
|
|
|
+ <div class="row q-col-gutter-sm">
|
|
|
+ <DefaultInput
|
|
|
+ v-model:error="validationErrors.unit_id"
|
|
|
+ :model-value="unitDetails.name"
|
|
|
+ class="col-12 col-md-6"
|
|
|
+ label="Nome da Unidade"
|
|
|
+ readonly
|
|
|
+ />
|
|
|
|
|
|
- <div class="row q-col-gutter-sm">
|
|
|
- <div
|
|
|
- v-if="props.selectStudent"
|
|
|
- class="col-12"
|
|
|
- >
|
|
|
- <div class="row items-start no-wrap q-col-gutter-sm" @keydown.enter.prevent>
|
|
|
- <DefaultSelect
|
|
|
- v-model="selectedStudent"
|
|
|
- v-model:error="validationErrors.student_id"
|
|
|
- class="col"
|
|
|
- dropdown-icon="mdi-magnify"
|
|
|
- fill-input
|
|
|
- hide-selected
|
|
|
- input-debounce="0"
|
|
|
- label="Aluno"
|
|
|
- option-label="name"
|
|
|
- use-input
|
|
|
- :options="filteredStudents"
|
|
|
- :rules="[inputRules.required]"
|
|
|
- @filter="filterStudents"
|
|
|
- />
|
|
|
+ <DefaultInput
|
|
|
+ v-model:error="validationErrors.unit_id"
|
|
|
+ :model-value="unitDetails.cnpj"
|
|
|
+ :mask="masks.Brasil.cnpj"
|
|
|
+ class="col-12 col-md-6"
|
|
|
+ label="CNPJ"
|
|
|
+ readonly
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="text-subtitle1 q-mt-lg q-mb-md">Dados do Aluno</div>
|
|
|
|
|
|
+ <div class="row q-col-gutter-sm">
|
|
|
+ <div v-if="props.selectStudent" class="col-12">
|
|
|
<div
|
|
|
- v-if="canAddStudents"
|
|
|
- class="col-auto"
|
|
|
+ class="row items-start no-wrap q-col-gutter-sm"
|
|
|
+ @keydown.enter.prevent
|
|
|
>
|
|
|
- <q-btn
|
|
|
- aria-label="Cadastrar novo aluno"
|
|
|
- color="primary"
|
|
|
- icon="mdi-plus"
|
|
|
- round
|
|
|
- unelevated
|
|
|
- @click="openCreateStudent"
|
|
|
- >
|
|
|
- <q-tooltip>
|
|
|
- Cadastrar novo aluno
|
|
|
- </q-tooltip>
|
|
|
- </q-btn>
|
|
|
+ <DefaultSelect
|
|
|
+ v-model="selectedStudent"
|
|
|
+ v-model:error="validationErrors.student_id"
|
|
|
+ class="col"
|
|
|
+ dropdown-icon="mdi-magnify"
|
|
|
+ fill-input
|
|
|
+ hide-selected
|
|
|
+ input-debounce="0"
|
|
|
+ label="Aluno"
|
|
|
+ option-label="name"
|
|
|
+ use-input
|
|
|
+ :options="filteredStudents"
|
|
|
+ :rules="[inputRules.required]"
|
|
|
+ @filter="filterStudents"
|
|
|
+ />
|
|
|
+
|
|
|
+ <div v-if="canAddStudents" class="col-auto">
|
|
|
+ <q-btn
|
|
|
+ aria-label="Cadastrar novo aluno"
|
|
|
+ color="primary"
|
|
|
+ icon="mdi-plus"
|
|
|
+ round
|
|
|
+ unelevated
|
|
|
+ @click="openCreateStudent"
|
|
|
+ >
|
|
|
+ <q-tooltip> Cadastrar novo aluno </q-tooltip>
|
|
|
+ </q-btn>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
|
|
|
- <div
|
|
|
- v-if="!props.selectStudent"
|
|
|
- class="col-12"
|
|
|
- >
|
|
|
- <DefaultInput
|
|
|
- v-model:error="validationErrors.student_id"
|
|
|
- :model-value="currentStudent?.name"
|
|
|
- :rules="[inputRules.required]"
|
|
|
- disable
|
|
|
- label="Aluno"
|
|
|
- />
|
|
|
- </div>
|
|
|
+ <div v-if="!props.selectStudent" class="col-12">
|
|
|
+ <DefaultInput
|
|
|
+ v-model:error="validationErrors.student_id"
|
|
|
+ :model-value="currentStudent?.name"
|
|
|
+ :rules="[inputRules.required]"
|
|
|
+ disable
|
|
|
+ label="Aluno"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
|
|
|
- <div class="col-12">
|
|
|
- <DefaultInput
|
|
|
- v-model:error="validationErrors.birth_date"
|
|
|
- :model-value="formattedBirthDate"
|
|
|
- disable
|
|
|
- label="Data de Nascimento"
|
|
|
- />
|
|
|
+ <div class="col-12">
|
|
|
+ <DefaultInput
|
|
|
+ v-model:error="validationErrors.birth_date"
|
|
|
+ :model-value="formattedBirthDate"
|
|
|
+ disable
|
|
|
+ label="Data de Nascimento"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
+ </template>
|
|
|
|
|
|
<div class="text-subtitle1 q-mt-lg q-mb-md">
|
|
|
Dados do Contrato
|
|
|
@@ -159,8 +117,9 @@
|
|
|
<DefaultInputDatePicker
|
|
|
v-model="form.signature_date"
|
|
|
v-model:error="validationErrors.signature_date"
|
|
|
- label="Data Assinatura"
|
|
|
+ :disable="!!props.contract"
|
|
|
:rules="[inputRules.date]"
|
|
|
+ label="Data de Início"
|
|
|
/>
|
|
|
</div>
|
|
|
|
|
|
@@ -169,7 +128,18 @@
|
|
|
v-model="form.end_date"
|
|
|
v-model:error="validationErrors.end_date"
|
|
|
label="Data Encerramento"
|
|
|
- :rules="[inputRules.date]"
|
|
|
+ reactive-rules
|
|
|
+ :lazy-rules="false"
|
|
|
+ :rules="[
|
|
|
+ inputRules.date,
|
|
|
+ props.contract
|
|
|
+ ? inputRules.renewalEndDate(
|
|
|
+ () => props.contract?.end_date,
|
|
|
+ )
|
|
|
+ : inputRules.dateMaxYearsFrom(
|
|
|
+ () => form.signature_date,
|
|
|
+ ),
|
|
|
+ ]"
|
|
|
/>
|
|
|
</div>
|
|
|
|
|
|
@@ -183,7 +153,7 @@
|
|
|
option-label="name"
|
|
|
option-value="id"
|
|
|
:options="packages"
|
|
|
- :rules="[inputRules.required]"
|
|
|
+ :rules="props.contract ? [] : [inputRules.required]"
|
|
|
/>
|
|
|
</div>
|
|
|
|
|
|
@@ -198,6 +168,22 @@
|
|
|
/>
|
|
|
</div>
|
|
|
|
|
|
+ <div class="col-6">
|
|
|
+ <DefaultCurrencyInput
|
|
|
+ :model-value="form.package_value"
|
|
|
+ disable
|
|
|
+ label="Total do Contrato"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="col-6">
|
|
|
+ <DefaultInput
|
|
|
+ :model-value="contractWeeks"
|
|
|
+ disable
|
|
|
+ label="Total de Semanas"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
<div class="col-4">
|
|
|
<DefaultSelect
|
|
|
v-model="form.weekday"
|
|
|
@@ -308,8 +294,8 @@
|
|
|
<DefaultCurrencyInput
|
|
|
v-model="form.enrollment_fee"
|
|
|
v-model:error="validationErrors.tax_register"
|
|
|
- disable
|
|
|
label="Valor da Matrícula"
|
|
|
+ :disable="!props.contract"
|
|
|
/>
|
|
|
</div>
|
|
|
|
|
|
@@ -355,8 +341,8 @@
|
|
|
<DefaultCurrencyInput
|
|
|
v-model="form.package_value"
|
|
|
v-model:error="validationErrors.package_value"
|
|
|
- disable
|
|
|
label="Valor do Pacote"
|
|
|
+ :disable="!props.contract"
|
|
|
/>
|
|
|
</div>
|
|
|
|
|
|
@@ -400,10 +386,7 @@
|
|
|
v-model:error="validationErrors.early_payment_discount"
|
|
|
label="Desconto até o vencimento (%)"
|
|
|
type="number"
|
|
|
- :rules="[
|
|
|
- inputRules.minValue(0),
|
|
|
- inputRules.maxValue(100),
|
|
|
- ]"
|
|
|
+ :rules="[inputRules.minValue(0), inputRules.maxValue(100)]"
|
|
|
/>
|
|
|
</div>
|
|
|
|
|
|
@@ -418,11 +401,7 @@
|
|
|
option-value="value"
|
|
|
:options="paymentMethods"
|
|
|
:rules="[
|
|
|
- inputRules.oneOf([
|
|
|
- 'pix',
|
|
|
- 'credit_card',
|
|
|
- 'debit_card',
|
|
|
- ]),
|
|
|
+ inputRules.oneOf(['pix', 'credit_card', 'debit_card']),
|
|
|
]"
|
|
|
/>
|
|
|
</div>
|
|
|
@@ -443,61 +422,15 @@
|
|
|
v-model:error="validationErrors.fine_cancelled"
|
|
|
label="Multa (%)"
|
|
|
type="number"
|
|
|
- :rules="[
|
|
|
- inputRules.minValue(0),
|
|
|
- inputRules.maxValue(100),
|
|
|
- ]"
|
|
|
+ :rules="[inputRules.minValue(0), inputRules.maxValue(100)]"
|
|
|
/>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
-
|
|
|
- <div
|
|
|
- v-if="props.contract"
|
|
|
- v-show="activeTab === 'midias'"
|
|
|
- >
|
|
|
- <DefaultTable
|
|
|
- v-model:rows="medias"
|
|
|
- :columns="mediaColumns"
|
|
|
- :feminino="true"
|
|
|
- :loading="loadingMedias"
|
|
|
- :show-search-field="false"
|
|
|
- descricao="mídias"
|
|
|
- no-api-call
|
|
|
- title="Mídias"
|
|
|
- >
|
|
|
- <template #body-cell-actions="{ row }">
|
|
|
- <q-td align="center">
|
|
|
- <q-item-section
|
|
|
- class="no-wrap"
|
|
|
- style="flex-direction: row; gap: 4px"
|
|
|
- >
|
|
|
- <q-btn
|
|
|
- icon="mdi-eye-outline"
|
|
|
- outline
|
|
|
- style="width: 36px"
|
|
|
- @click.prevent.stop="openFile(row.file_url)"
|
|
|
- />
|
|
|
-
|
|
|
- <q-btn
|
|
|
- color="negative"
|
|
|
- icon="mdi-trash-can-outline"
|
|
|
- outline
|
|
|
- style="width: 36px"
|
|
|
- @click.prevent.stop="handleDeleteMedia(row)"
|
|
|
- />
|
|
|
- </q-item-section>
|
|
|
- </q-td>
|
|
|
- </template>
|
|
|
- </DefaultTable>
|
|
|
- </div>
|
|
|
</q-card-section>
|
|
|
</q-scroll-area>
|
|
|
|
|
|
- <q-card-actions
|
|
|
- align="right"
|
|
|
- class="q-px-md q-pb-md"
|
|
|
- >
|
|
|
+ <q-card-actions align="right" class="q-px-md q-pb-md">
|
|
|
<q-btn
|
|
|
color="primary"
|
|
|
label="Cancelar"
|
|
|
@@ -507,7 +440,6 @@
|
|
|
/>
|
|
|
|
|
|
<q-btn
|
|
|
- v-if="activeTab === 'dados'"
|
|
|
color="primary"
|
|
|
label="Salvar"
|
|
|
no-caps
|
|
|
@@ -521,32 +453,21 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { addYears, format } from "date-fns";
|
|
|
+import {
|
|
|
+ addYears,
|
|
|
+ differenceInCalendarDays,
|
|
|
+ format,
|
|
|
+ isValid,
|
|
|
+ parse,
|
|
|
+} from "date-fns";
|
|
|
|
|
|
import {
|
|
|
createStudentContract,
|
|
|
updateStudentContract,
|
|
|
} from "src/api/studentContract";
|
|
|
|
|
|
-import {
|
|
|
- computed,
|
|
|
- nextTick,
|
|
|
- onMounted,
|
|
|
- ref,
|
|
|
- useTemplateRef,
|
|
|
- watch,
|
|
|
-} from "vue";
|
|
|
-
|
|
|
-import {
|
|
|
- deleteContractMedia,
|
|
|
- getContractMedias,
|
|
|
-} from "src/api/student_media";
|
|
|
-
|
|
|
-import {
|
|
|
- formatDateDMYtoYMD,
|
|
|
- formatDateYMDtoDMY,
|
|
|
-} from "src/helpers/utils";
|
|
|
-
|
|
|
+import { computed, nextTick, onMounted, ref, useTemplateRef, watch } from "vue";
|
|
|
+import { formatDateDMYtoYMD, formatDateYMDtoDMY } from "src/helpers/utils";
|
|
|
import { getFinancialMe } from "src/api/unit_financial";
|
|
|
import { getStudentsForSelect } from "src/api/student";
|
|
|
import { getUnitMe } from "src/api/unit";
|
|
|
@@ -567,7 +488,6 @@ import DefaultForm from "src/components/defaults/DefaultForm.vue";
|
|
|
import DefaultInput from "src/components/defaults/DefaultInput.vue";
|
|
|
import DefaultInputDatePicker from "src/components/defaults/DefaultInputDatePicker.vue";
|
|
|
import DefaultSelect from "src/components/defaults/DefaultSelect.vue";
|
|
|
-import DefaultTable from "src/components/defaults/DefaultTable.vue";
|
|
|
import AddEditStudentDialog from "src/pages/students/components/AddEditStudentDialog.vue";
|
|
|
|
|
|
defineEmits([...useDialogPluginComponent.emits]);
|
|
|
@@ -600,12 +520,9 @@ const store = userStore();
|
|
|
const formRef = useTemplateRef("formRef");
|
|
|
const scrollAreaRef = useTemplateRef("scrollAreaRef");
|
|
|
|
|
|
-const activeTab = ref("dados");
|
|
|
const dateConfirmationOpen = ref(false);
|
|
|
const dateOverrideConfirmed = ref(false);
|
|
|
const filteredStudents = ref([]);
|
|
|
-const loadingMedias = ref(false);
|
|
|
-const medias = ref([]);
|
|
|
const packages = ref([]);
|
|
|
const restoringDefaultDates = ref(false);
|
|
|
const selectedStudent = ref(props.student);
|
|
|
@@ -622,9 +539,25 @@ const canViewFinancial = computed(() =>
|
|
|
permissions.getAccess("franchisee_financial", "view"),
|
|
|
);
|
|
|
|
|
|
-const currentStudent = computed(
|
|
|
- () => selectedStudent.value ?? props.student,
|
|
|
-);
|
|
|
+const currentStudent = computed(() => selectedStudent.value ?? props.student);
|
|
|
+
|
|
|
+const contractWeeks = computed(() => {
|
|
|
+ if (!form.signature_date || !form.end_date) return null;
|
|
|
+
|
|
|
+ const startDate = parse(form.signature_date, "dd/MM/yyyy", new Date());
|
|
|
+
|
|
|
+ const endDate = parse(form.end_date, "dd/MM/yyyy", new Date());
|
|
|
+
|
|
|
+ if (!isValid(startDate) || !isValid(endDate)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ const days = differenceInCalendarDays(endDate, startDate);
|
|
|
+
|
|
|
+ if (days < 0) return null;
|
|
|
+
|
|
|
+ return Math.max(1, Math.round(days / 7));
|
|
|
+});
|
|
|
|
|
|
const dialogCardStyle = computed(() => ({
|
|
|
height: props.selectStudent ? "95vh" : "auto",
|
|
|
@@ -638,9 +571,7 @@ const enrollmentInstallmentValue = computed(() => {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- return Number(
|
|
|
- (form.enrollment_fee / form.installments).toFixed(2),
|
|
|
- );
|
|
|
+ return Number((form.enrollment_fee / form.installments).toFixed(2));
|
|
|
});
|
|
|
|
|
|
const formattedBirthDate = computed(() =>
|
|
|
@@ -654,12 +585,7 @@ const packageInstallmentValue = computed(() => {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- return Number(
|
|
|
- (
|
|
|
- form.package_value /
|
|
|
- form.package_installments
|
|
|
- ).toFixed(2),
|
|
|
- );
|
|
|
+ return Number((form.package_value / form.package_installments).toFixed(2));
|
|
|
});
|
|
|
|
|
|
const completeDatePattern = /^\d{2}\/\d{2}\/\d{4}$/;
|
|
|
@@ -675,36 +601,15 @@ const defaultContractDates = (() => {
|
|
|
};
|
|
|
})();
|
|
|
|
|
|
-const enrollmentInstallmentOptions = Array.from(
|
|
|
- { length: 12 },
|
|
|
- (_, index) => ({
|
|
|
- label: `${index + 1}x`,
|
|
|
- value: index + 1,
|
|
|
- }),
|
|
|
-);
|
|
|
-
|
|
|
-const mediaColumns = [
|
|
|
- {
|
|
|
- align: "left",
|
|
|
- field: "created_at",
|
|
|
- label: "Data de Anexo",
|
|
|
- name: "created_at",
|
|
|
- },
|
|
|
- {
|
|
|
- align: "center",
|
|
|
- field: null,
|
|
|
- label: "Ações",
|
|
|
- name: "actions",
|
|
|
- },
|
|
|
-];
|
|
|
+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,
|
|
|
- }),
|
|
|
-);
|
|
|
+const packageInstallmentOptions = Array.from({ length: 13 }, (_, index) => ({
|
|
|
+ label: `${index + 1}x`,
|
|
|
+ value: index + 1,
|
|
|
+}));
|
|
|
|
|
|
const paymentMethods = [
|
|
|
{
|
|
|
@@ -752,25 +657,19 @@ const weekdays = [
|
|
|
},
|
|
|
];
|
|
|
|
|
|
-const trimTime = (time) =>
|
|
|
- time ? time.slice(0, 5) : null;
|
|
|
+const trimTime = (time) => (time ? time.slice(0, 5) : null);
|
|
|
|
|
|
const { form, getUpdatedFields } = useForm({
|
|
|
class_quantity: props.contract?.class_quantity ?? null,
|
|
|
- due_day: props.contract?.recurring_day ?? null,
|
|
|
+ due_day: props.contract?.due_day ?? null,
|
|
|
|
|
|
- early_payment_discount:
|
|
|
- props.contract?.early_payment_discount ?? null,
|
|
|
+ early_payment_discount: props.contract?.early_payment_discount ?? null,
|
|
|
|
|
|
- end_date:
|
|
|
- props.contract?.end_date ??
|
|
|
- defaultContractDates?.end_date ??
|
|
|
- null,
|
|
|
+ end_date: props.contract?.end_date ?? defaultContractDates?.end_date ?? null,
|
|
|
|
|
|
end_time: trimTime(props.contract?.end_time),
|
|
|
|
|
|
- enrollment_due_date:
|
|
|
- props.contract?.enrollment_due_date ?? null,
|
|
|
+ enrollment_due_date: props.contract?.enrollment_due_date ?? null,
|
|
|
|
|
|
enrollment_fee: props.contract?.tax_register ?? null,
|
|
|
installments: props.contract?.installments ?? null,
|
|
|
@@ -778,26 +677,19 @@ const { form, getUpdatedFields } = useForm({
|
|
|
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_id: props.contract?.class_package_unit_id ?? null,
|
|
|
|
|
|
- package_installments:
|
|
|
- props.contract?.package_installments ?? null,
|
|
|
+ package_installments: props.contract?.package_installments ?? null,
|
|
|
|
|
|
package_value: props.contract?.package_value ?? null,
|
|
|
payment_method: props.contract?.payment_method ?? null,
|
|
|
protocol: props.contract?.protocol ?? null,
|
|
|
|
|
|
- second_end_time: trimTime(
|
|
|
- props.contract?.second_end_time,
|
|
|
- ),
|
|
|
+ second_end_time: trimTime(props.contract?.second_end_time),
|
|
|
|
|
|
- second_start_time: trimTime(
|
|
|
- props.contract?.second_start_time,
|
|
|
- ),
|
|
|
+ second_start_time: trimTime(props.contract?.second_start_time),
|
|
|
|
|
|
- second_weekday:
|
|
|
- props.contract?.second_weekday ?? null,
|
|
|
+ second_weekday: props.contract?.second_weekday ?? null,
|
|
|
|
|
|
signature_date:
|
|
|
props.contract?.signature_date ??
|
|
|
@@ -833,9 +725,7 @@ const buildDateFromDay = (day) => {
|
|
|
const nextMonthIndex = (now.getMonth() + 1) % 12;
|
|
|
|
|
|
const nextYear =
|
|
|
- now.getMonth() === 11
|
|
|
- ? now.getFullYear() + 1
|
|
|
- : now.getFullYear();
|
|
|
+ now.getMonth() === 11 ? now.getFullYear() + 1 : now.getFullYear();
|
|
|
|
|
|
const lastDayOfNextMonth = new Date(
|
|
|
nextYear,
|
|
|
@@ -843,10 +733,7 @@ const buildDateFromDay = (day) => {
|
|
|
0,
|
|
|
).getDate();
|
|
|
|
|
|
- const safeDay = Math.min(
|
|
|
- parsedDay,
|
|
|
- lastDayOfNextMonth,
|
|
|
- );
|
|
|
+ const safeDay = Math.min(parsedDay, lastDayOfNextMonth);
|
|
|
|
|
|
return `${String(safeDay).padStart(2, "0")}/${String(
|
|
|
nextMonthIndex + 1,
|
|
|
@@ -857,15 +744,11 @@ const buildPayload = () => ({
|
|
|
class_package_unit_id: form.package_id,
|
|
|
class_quantity: form.class_quantity,
|
|
|
|
|
|
- due_day: form.due_day
|
|
|
- ? Number.parseInt(form.due_day)
|
|
|
- : null,
|
|
|
+ due_day: form.due_day ? Number.parseInt(form.due_day) : null,
|
|
|
|
|
|
early_payment_discount: form.early_payment_discount,
|
|
|
|
|
|
- end_date: form.end_date
|
|
|
- ? formatDateDMYtoYMD(form.end_date)
|
|
|
- : null,
|
|
|
+ end_date: form.end_date ? formatDateDMYtoYMD(form.end_date) : null,
|
|
|
|
|
|
end_time: form.end_time,
|
|
|
|
|
|
@@ -899,94 +782,36 @@ const buildPayload = () => ({
|
|
|
weekday: form.weekday,
|
|
|
});
|
|
|
|
|
|
-const calculateEndTime = (
|
|
|
- startTime,
|
|
|
- durationMinutes = 120,
|
|
|
-) => {
|
|
|
+const calculateEndTime = (startTime, durationMinutes = 120) => {
|
|
|
if (!/^\d{2}:\d{2}$/.test(startTime ?? "")) {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- const [hours, minutes] = startTime
|
|
|
- .split(":")
|
|
|
- .map(Number);
|
|
|
+ const [hours, minutes] = startTime.split(":").map(Number);
|
|
|
|
|
|
if (hours > 23 || minutes > 59) {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- const endMinutes =
|
|
|
- (hours * 60 + minutes + durationMinutes) %
|
|
|
- (24 * 60);
|
|
|
+ const endMinutes = (hours * 60 + minutes + durationMinutes) % (24 * 60);
|
|
|
|
|
|
- return `${String(
|
|
|
- Math.floor(endMinutes / 60),
|
|
|
- ).padStart(2, "0")}:${String(
|
|
|
+ return `${String(Math.floor(endMinutes / 60)).padStart(2, "0")}:${String(
|
|
|
endMinutes % 60,
|
|
|
).padStart(2, "0")}`;
|
|
|
};
|
|
|
|
|
|
-const fetchMedias = async () => {
|
|
|
- if (!props.contract) return;
|
|
|
-
|
|
|
- loadingMedias.value = true;
|
|
|
-
|
|
|
- try {
|
|
|
- medias.value = await getContractMedias(
|
|
|
- props.contract.id,
|
|
|
- );
|
|
|
- } finally {
|
|
|
- loadingMedias.value = false;
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
const filterStudents = (value, update) => {
|
|
|
update(() => {
|
|
|
- const search = value
|
|
|
- .trim()
|
|
|
- .toLocaleLowerCase("pt-BR");
|
|
|
+ const search = value.trim().toLocaleLowerCase("pt-BR");
|
|
|
|
|
|
filteredStudents.value = search
|
|
|
? students.value.filter((student) =>
|
|
|
- student.name
|
|
|
- .toLocaleLowerCase("pt-BR")
|
|
|
- .includes(search),
|
|
|
+ student.name.toLocaleLowerCase("pt-BR").includes(search),
|
|
|
)
|
|
|
: students.value;
|
|
|
});
|
|
|
};
|
|
|
|
|
|
-const handleDeleteMedia = (media) => {
|
|
|
- $q.dialog({
|
|
|
- cancel: {
|
|
|
- color: "primary",
|
|
|
- label: "Cancelar",
|
|
|
- outline: true,
|
|
|
- },
|
|
|
- message: "Deseja excluir esta mídia permanentemente?",
|
|
|
- ok: {
|
|
|
- color: "negative",
|
|
|
- label: "Excluir",
|
|
|
- },
|
|
|
- title: "Excluir mídia",
|
|
|
- }).onOk(async () => {
|
|
|
- try {
|
|
|
- await deleteContractMedia(media.id);
|
|
|
-
|
|
|
- medias.value = medias.value.filter(
|
|
|
- (item) => item.id !== media.id,
|
|
|
- );
|
|
|
- } catch (error) {
|
|
|
- console.error(error);
|
|
|
-
|
|
|
- $q.notify({
|
|
|
- message: "Erro ao excluir mídia.",
|
|
|
- type: "negative",
|
|
|
- });
|
|
|
- }
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
const handleSave = async () => {
|
|
|
const payload = buildPayload();
|
|
|
|
|
|
@@ -997,9 +822,7 @@ const handleSave = async () => {
|
|
|
|
|
|
const changedFields = getUpdatedFields.value;
|
|
|
|
|
|
- const updatePayload = {
|
|
|
- student_id: currentStudent.value?.id ?? null,
|
|
|
- };
|
|
|
+ const updatePayload = {};
|
|
|
|
|
|
const fieldMap = {
|
|
|
enrollment_fee: "tax_register",
|
|
|
@@ -1029,9 +852,7 @@ const handleSave = async () => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- for (const [source, target] of Object.entries(
|
|
|
- fieldMap,
|
|
|
- )) {
|
|
|
+ for (const [source, target] of Object.entries(fieldMap)) {
|
|
|
if (source in changedFields) {
|
|
|
updatePayload[target] = payload[target];
|
|
|
}
|
|
|
@@ -1052,10 +873,7 @@ const handleSave = async () => {
|
|
|
updatePayload.due_day = payload.due_day;
|
|
|
}
|
|
|
|
|
|
- return updateStudentContract(
|
|
|
- props.contract.id,
|
|
|
- updatePayload,
|
|
|
- );
|
|
|
+ return updateStudentContract(props.contract.id, updatePayload);
|
|
|
});
|
|
|
};
|
|
|
|
|
|
@@ -1069,16 +887,11 @@ const openCreateStudent = () => {
|
|
|
filteredStudents.value = unitStudents;
|
|
|
|
|
|
selectedStudent.value =
|
|
|
- unitStudents.find(
|
|
|
- (student) => student.id === createdStudent?.id,
|
|
|
- ) ?? createdStudent;
|
|
|
+ unitStudents.find((student) => student.id === createdStudent?.id) ??
|
|
|
+ createdStudent;
|
|
|
});
|
|
|
};
|
|
|
|
|
|
-const openFile = (url) => {
|
|
|
- window.open(url, "_blank");
|
|
|
-};
|
|
|
-
|
|
|
const restoreDefaultContractDates = () => {
|
|
|
restoringDefaultDates.value = true;
|
|
|
|
|
|
@@ -1105,17 +918,14 @@ watch(
|
|
|
}
|
|
|
|
|
|
const datesAreStillDefault =
|
|
|
- signatureDate ===
|
|
|
- defaultContractDates.signature_date &&
|
|
|
+ signatureDate === defaultContractDates.signature_date &&
|
|
|
endDate === defaultContractDates.end_date;
|
|
|
|
|
|
if (datesAreStillDefault) return;
|
|
|
|
|
|
const datesAreComplete =
|
|
|
- (!signatureDate ||
|
|
|
- completeDatePattern.test(signatureDate)) &&
|
|
|
- (!endDate ||
|
|
|
- completeDatePattern.test(endDate));
|
|
|
+ (!signatureDate || completeDatePattern.test(signatureDate)) &&
|
|
|
+ (!endDate || completeDatePattern.test(endDate));
|
|
|
|
|
|
if (!datesAreComplete) return;
|
|
|
|
|
|
@@ -1169,14 +979,9 @@ watch(
|
|
|
|
|
|
if (!dateString || dateString.length < 8) return;
|
|
|
|
|
|
- const day = Number.parseInt(
|
|
|
- dateString.split("/")[0],
|
|
|
- );
|
|
|
+ const day = Number.parseInt(dateString.split("/")[0]);
|
|
|
|
|
|
- if (
|
|
|
- !Number.isNaN(day) &&
|
|
|
- day !== Number.parseInt(form.due_day)
|
|
|
- ) {
|
|
|
+ if (!Number.isNaN(day) && day !== Number.parseInt(form.due_day)) {
|
|
|
syncingFromDate.value = true;
|
|
|
form.due_day = day;
|
|
|
|
|
|
@@ -1187,50 +992,33 @@ watch(
|
|
|
},
|
|
|
);
|
|
|
|
|
|
-watch(activeTab, (tab) => {
|
|
|
- if (tab === "midias") {
|
|
|
- fetchMedias();
|
|
|
- }
|
|
|
-});
|
|
|
-
|
|
|
watch(
|
|
|
() => form.package_id,
|
|
|
(id) => {
|
|
|
- const selectedPackage = packages.value.find(
|
|
|
- (item) => item.id === id,
|
|
|
- );
|
|
|
+ const selectedPackage = packages.value.find((item) => item.id === id);
|
|
|
|
|
|
if (!selectedPackage) return;
|
|
|
|
|
|
- form.class_quantity =
|
|
|
- selectedPackage.quantity_classes;
|
|
|
+ form.class_quantity = selectedPackage.quantity_classes;
|
|
|
|
|
|
- form.total_classes =
|
|
|
- selectedPackage.quantity_classes;
|
|
|
+ form.total_classes = selectedPackage.quantity_classes;
|
|
|
|
|
|
- form.enrollment_fee =
|
|
|
- selectedPackage.contract_register_value;
|
|
|
+ form.enrollment_fee = selectedPackage.contract_register_value;
|
|
|
|
|
|
- form.package_value =
|
|
|
- selectedPackage.contract_value;
|
|
|
+ form.package_value = selectedPackage.contract_value;
|
|
|
|
|
|
form.weekday = selectedPackage.weekday ?? null;
|
|
|
|
|
|
- form.start_time = trimTime(
|
|
|
- selectedPackage.start_time,
|
|
|
- );
|
|
|
+ form.start_time = trimTime(selectedPackage.start_time);
|
|
|
|
|
|
form.end_time = calculateEndTime(
|
|
|
form.start_time,
|
|
|
selectedPackage.class_duration_minutes ?? 120,
|
|
|
);
|
|
|
|
|
|
- form.second_weekday =
|
|
|
- selectedPackage.second_weekday ?? null;
|
|
|
+ form.second_weekday = selectedPackage.second_weekday ?? null;
|
|
|
|
|
|
- form.second_start_time = trimTime(
|
|
|
- selectedPackage.second_start_time,
|
|
|
- );
|
|
|
+ form.second_start_time = trimTime(selectedPackage.second_start_time);
|
|
|
|
|
|
form.second_end_time = calculateEndTime(
|
|
|
form.second_start_time,
|
|
|
@@ -1277,33 +1065,23 @@ watch(
|
|
|
|
|
|
onMounted(async () => {
|
|
|
const unitRequest = getUnitMe().catch((error) => {
|
|
|
- console.error(
|
|
|
- "Falha ao carregar os dados da unidade:",
|
|
|
- error,
|
|
|
- );
|
|
|
+ console.error("Falha ao carregar os dados da unidade:", error);
|
|
|
|
|
|
return store.selectedUnit;
|
|
|
});
|
|
|
|
|
|
- const requests = [
|
|
|
- getUnitPackagesForSelect(),
|
|
|
- unitRequest,
|
|
|
- ];
|
|
|
+ const requests = [getUnitPackagesForSelect(), unitRequest];
|
|
|
|
|
|
if (props.selectStudent) {
|
|
|
requests.push(getStudentsForSelect());
|
|
|
}
|
|
|
|
|
|
- const [
|
|
|
- unitPackages,
|
|
|
- unitData,
|
|
|
- unitStudents = [],
|
|
|
- ] = await Promise.all(requests);
|
|
|
+ const [unitPackages, unitData, unitStudents = []] =
|
|
|
+ await Promise.all(requests);
|
|
|
|
|
|
packages.value = unitPackages;
|
|
|
|
|
|
- unitDetails.value =
|
|
|
- unitData ?? store.selectedUnit ?? {};
|
|
|
+ unitDetails.value = unitData ?? store.selectedUnit ?? {};
|
|
|
|
|
|
students.value = unitStudents;
|
|
|
filteredStudents.value = unitStudents;
|
|
|
@@ -1315,13 +1093,11 @@ onMounted(async () => {
|
|
|
if (!financial) return;
|
|
|
|
|
|
if (financial.default_discount != null) {
|
|
|
- form.early_payment_discount =
|
|
|
- financial.default_discount;
|
|
|
+ form.early_payment_discount = financial.default_discount;
|
|
|
}
|
|
|
|
|
|
if (financial.default_interest != null) {
|
|
|
- form.interest_rate =
|
|
|
- financial.default_interest;
|
|
|
+ form.interest_rate = financial.default_interest;
|
|
|
}
|
|
|
|
|
|
if (financial.default_fine != null) {
|