|
|
@@ -143,7 +143,7 @@
|
|
|
/>
|
|
|
</div>
|
|
|
|
|
|
- <div class="col-5">
|
|
|
+ <div class="col-4">
|
|
|
<DefaultSelect
|
|
|
v-model="form.package_id"
|
|
|
v-model:error="validationErrors.class_package_unit_id"
|
|
|
@@ -157,7 +157,25 @@
|
|
|
/>
|
|
|
</div>
|
|
|
|
|
|
- <div class="col-7">
|
|
|
+ <div class="col-3">
|
|
|
+ <DefaultSelect
|
|
|
+ v-model="form.pricing_mode"
|
|
|
+ v-model:error="validationErrors.pricing_mode"
|
|
|
+ emit-value
|
|
|
+ label="Modalidade"
|
|
|
+ map-options
|
|
|
+ option-label="label"
|
|
|
+ option-value="value"
|
|
|
+ :options="modalityOptions"
|
|
|
+ :rules="
|
|
|
+ modalityOptions.length
|
|
|
+ ? [inputRules.required]
|
|
|
+ : []
|
|
|
+ "
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="col-5">
|
|
|
<DefaultInput
|
|
|
v-model="form.class_quantity"
|
|
|
v-model:error="validationErrors.class_quantity"
|
|
|
@@ -170,7 +188,7 @@
|
|
|
|
|
|
<div class="col-6">
|
|
|
<DefaultCurrencyInput
|
|
|
- :model-value="form.package_value"
|
|
|
+ :model-value="form.total_value"
|
|
|
disable
|
|
|
label="Total do Contrato"
|
|
|
/>
|
|
|
@@ -379,6 +397,100 @@
|
|
|
</div>
|
|
|
</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="col-3">
|
|
|
+ <DefaultCurrencyInput
|
|
|
+ v-model="form.materials_value"
|
|
|
+ v-model:error="validationErrors.materials_value"
|
|
|
+ label="Valor dos Materiais"
|
|
|
+ :disable="!props.contract"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <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>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="text-subtitle2 q-mt-md q-mb-sm text-grey-8">
|
|
|
+ Total do Curso
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="row q-col-gutter-sm">
|
|
|
+ <div class="col-3">
|
|
|
+ <DefaultCurrencyInput
|
|
|
+ v-model="form.total_value"
|
|
|
+ v-model:error="validationErrors.total_value"
|
|
|
+ label="Valor Total do Curso"
|
|
|
+ :disable="!props.contract"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="col-3">
|
|
|
+ <DefaultSelect
|
|
|
+ v-model="form.total_installments"
|
|
|
+ v-model:error="validationErrors.total_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.total_installments"
|
|
|
+ :model-value="totalInstallmentValue"
|
|
|
+ disable
|
|
|
+ label="Valor da Parcela"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="col-3">
|
|
|
+ <DefaultInputDatePicker
|
|
|
+ v-model="form.total_due_date"
|
|
|
+ v-model:error="validationErrors.total_due_date"
|
|
|
+ label="Data 1ª Parcela"
|
|
|
+ :rules="[inputRules.date]"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
<div class="row q-col-gutter-sm q-mt-xs">
|
|
|
<div class="col-6">
|
|
|
<DefaultInput
|
|
|
@@ -588,6 +700,42 @@ const packageInstallmentValue = computed(() => {
|
|
|
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;
|
|
|
+ }
|
|
|
+
|
|
|
+ return Number((form.total_value / form.total_installments).toFixed(2));
|
|
|
+});
|
|
|
+
|
|
|
+const modalityOptions = computed(() => {
|
|
|
+ const selectedPackage = packages.value.find(
|
|
|
+ (item) => item.id === form.package_id,
|
|
|
+ );
|
|
|
+
|
|
|
+ if (!selectedPackage) return [];
|
|
|
+
|
|
|
+ const options = [];
|
|
|
+
|
|
|
+ if (selectedPackage.pavao) options.push({ label: "Pavão", value: "pavao" });
|
|
|
+
|
|
|
+ if (selectedPackage.irrecusavel) {
|
|
|
+ options.push({ label: "Irrecusável", value: "irrecusavel" });
|
|
|
+ }
|
|
|
+
|
|
|
+ return options;
|
|
|
+});
|
|
|
+
|
|
|
const completeDatePattern = /^\d{2}\/\d{2}\/\d{4}$/;
|
|
|
|
|
|
const defaultContractDates = (() => {
|
|
|
@@ -683,8 +831,18 @@ const { form, getUpdatedFields } = useForm({
|
|
|
|
|
|
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,
|
|
|
|
|
|
+ total_due_date: props.contract?.total_due_date ?? null,
|
|
|
+ total_installments: props.contract?.total_installments ?? null,
|
|
|
+ total_value: props.contract?.total_value ?? null,
|
|
|
+
|
|
|
second_end_time: trimTime(props.contract?.second_end_time),
|
|
|
|
|
|
second_start_time: trimTime(props.contract?.second_start_time),
|
|
|
@@ -760,6 +918,12 @@ const buildPayload = () => ({
|
|
|
installments: form.installments,
|
|
|
interest_rate: form.interest_rate,
|
|
|
|
|
|
+ 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,
|
|
|
@@ -767,6 +931,7 @@ const buildPayload = () => ({
|
|
|
package_installments: form.package_installments,
|
|
|
package_value: form.package_value,
|
|
|
payment_method: form.payment_method,
|
|
|
+ pricing_mode: form.pricing_mode,
|
|
|
protocol: form.protocol,
|
|
|
second_end_time: form.second_end_time,
|
|
|
second_start_time: form.second_start_time,
|
|
|
@@ -779,6 +944,13 @@ 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,
|
|
|
+ total_installments: form.total_installments,
|
|
|
+ total_value: form.total_value,
|
|
|
+
|
|
|
weekday: form.weekday,
|
|
|
});
|
|
|
|
|
|
@@ -846,6 +1018,11 @@ const handleSave = async () => {
|
|
|
"early_payment_discount",
|
|
|
"interest_rate",
|
|
|
"payment_method",
|
|
|
+ "pricing_mode",
|
|
|
+ "materials_value",
|
|
|
+ "materials_installments",
|
|
|
+ "total_value",
|
|
|
+ "total_installments",
|
|
|
]) {
|
|
|
if (key in changedFields) {
|
|
|
updatePayload[key] = payload[key];
|
|
|
@@ -863,6 +1040,8 @@ const handleSave = async () => {
|
|
|
"end_date",
|
|
|
"enrollment_due_date",
|
|
|
"package_due_date",
|
|
|
+ "materials_due_date",
|
|
|
+ "total_due_date",
|
|
|
]) {
|
|
|
if (key in changedFields) {
|
|
|
updatePayload[key] = payload[key];
|
|
|
@@ -1003,10 +1182,6 @@ watch(
|
|
|
|
|
|
form.total_classes = selectedPackage.quantity_classes;
|
|
|
|
|
|
- form.enrollment_fee = selectedPackage.contract_register_value;
|
|
|
-
|
|
|
- form.package_value = selectedPackage.contract_value;
|
|
|
-
|
|
|
form.weekday = selectedPackage.weekday ?? null;
|
|
|
|
|
|
form.start_time = trimTime(selectedPackage.start_time);
|
|
|
@@ -1024,6 +1199,72 @@ watch(
|
|
|
form.second_start_time,
|
|
|
selectedPackage.class_duration_minutes ?? 120,
|
|
|
);
|
|
|
+
|
|
|
+ // Escolhe automaticamente a modalidade quando só há uma disponível;
|
|
|
+ // se a proposta ainda não tem Pavão nem Irrecusável, limpa a escolha.
|
|
|
+ if (selectedPackage.pavao) {
|
|
|
+ form.pricing_mode = "pavao";
|
|
|
+ } else if (selectedPackage.irrecusavel) {
|
|
|
+ form.pricing_mode = "irrecusavel";
|
|
|
+ } else {
|
|
|
+ form.pricing_mode = null;
|
|
|
+ }
|
|
|
+ },
|
|
|
+);
|
|
|
+
|
|
|
+// Os valores do contrato vêm da modalidade escolhida na proposta comercial:
|
|
|
+// o que estiver marcado "incluso no valor do curso" não é cobrado à parte
|
|
|
+// (só entra no Total do Curso); o que "permite parcelar" vira cobrança
|
|
|
+// separada com o próprio valor/parcelas daquele item.
|
|
|
+watch(
|
|
|
+ [() => form.package_id, () => form.pricing_mode],
|
|
|
+ ([id, mode]) => {
|
|
|
+ const selectedPackage = packages.value.find((item) => item.id === id);
|
|
|
+
|
|
|
+ const modality =
|
|
|
+ mode === "irrecusavel"
|
|
|
+ ? selectedPackage?.irrecusavel
|
|
|
+ : 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ form.enrollment_fee = modality.registration_included_in_course
|
|
|
+ ? null
|
|
|
+ : modality.registration_value;
|
|
|
+
|
|
|
+ form.installments = modality.registration_included_in_course
|
|
|
+ ? null
|
|
|
+ : modality.registration_max_installments;
|
|
|
+
|
|
|
+ form.package_value = modality.classes_included_in_course
|
|
|
+ ? null
|
|
|
+ : modality.classes_value;
|
|
|
+
|
|
|
+ form.package_installments = modality.classes_included_in_course
|
|
|
+ ? null
|
|
|
+ : modality.classes_max_installments;
|
|
|
+
|
|
|
+ form.materials_value = modality.materials_included_in_course
|
|
|
+ ? null
|
|
|
+ : 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;
|
|
|
},
|
|
|
);
|
|
|
|