|
|
@@ -10,6 +10,12 @@
|
|
|
@close="onDialogCancel"
|
|
|
/>
|
|
|
|
|
|
+ <CustomTabComponent
|
|
|
+ v-model:active-tab="activeTab"
|
|
|
+ class="q-mx-md q-mb-sm"
|
|
|
+ :tabs="tabs"
|
|
|
+ />
|
|
|
+
|
|
|
<DefaultForm
|
|
|
ref="formRef"
|
|
|
@submit="onOKClick"
|
|
|
@@ -18,7 +24,13 @@
|
|
|
ref="scrollAreaRef"
|
|
|
class="dialog-form-scroll"
|
|
|
>
|
|
|
- <q-card-section class="q-pt-sm">
|
|
|
+ <!-- Tab: Pacote (class_package_units) -->
|
|
|
+
|
|
|
+ <q-card-section
|
|
|
+ v-show="activeTab === 'pacote'"
|
|
|
+ ref="pacotePanelRef"
|
|
|
+ class="q-pt-sm"
|
|
|
+ >
|
|
|
<div class="row q-col-gutter-sm">
|
|
|
<DefaultInput
|
|
|
v-model="form.name"
|
|
|
@@ -58,29 +70,6 @@
|
|
|
necessário. É possível configurar no máximo dois dias.
|
|
|
</div>
|
|
|
|
|
|
- <DefaultCurrencyInput
|
|
|
- v-model="form.contract_register_value"
|
|
|
- v-model:error="validationErrors.contract_register_value"
|
|
|
- class="col-4"
|
|
|
- label="R$ Matrícula"
|
|
|
- />
|
|
|
-
|
|
|
- <DefaultCurrencyInput
|
|
|
- v-model="form.contract_value"
|
|
|
- v-model:error="validationErrors.contract_value"
|
|
|
- class="col-4"
|
|
|
- label="R$ Total do Contrato"
|
|
|
- />
|
|
|
-
|
|
|
- <DefaultInput
|
|
|
- v-model="form.contrat_discount_value"
|
|
|
- class="col-4"
|
|
|
- label="Desconto em %"
|
|
|
- max="100"
|
|
|
- min="0"
|
|
|
- type="number"
|
|
|
- />
|
|
|
-
|
|
|
<div
|
|
|
v-for="(material, index) in form.materials"
|
|
|
:key="index"
|
|
|
@@ -157,6 +146,227 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
</q-card-section>
|
|
|
+
|
|
|
+ <!-- Tabs: Propostas (class_package_unit_variations) -->
|
|
|
+
|
|
|
+ <q-card-section
|
|
|
+ v-for="(variation, index) in form.variations"
|
|
|
+ v-show="activeTab === variation.type"
|
|
|
+ :key="variation.type"
|
|
|
+ :ref="(el) => setVariationPanelRef(variation.type, el)"
|
|
|
+ class="q-pt-sm"
|
|
|
+ >
|
|
|
+ <div class="row q-col-gutter-sm">
|
|
|
+ <div class="col-12 variation-section-title">
|
|
|
+ Matrícula
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <DefaultCurrencyInput
|
|
|
+ v-model="variation.register_value"
|
|
|
+ v-model:error="
|
|
|
+ validationErrors[`variations.${index}.register_value`]
|
|
|
+ "
|
|
|
+ class="col-4"
|
|
|
+ label="R$ Matrícula"
|
|
|
+ :rules="[inputRules.required]"
|
|
|
+ />
|
|
|
+
|
|
|
+ <DefaultInput
|
|
|
+ v-model="variation.register_installments_min"
|
|
|
+ v-model:error="
|
|
|
+ validationErrors[
|
|
|
+ `variations.${index}.register_installments_min`
|
|
|
+ ]
|
|
|
+ "
|
|
|
+ class="col-4"
|
|
|
+ label="Parcelas Mín."
|
|
|
+ max="60"
|
|
|
+ min="1"
|
|
|
+ type="number"
|
|
|
+ :rules="[
|
|
|
+ inputRules.required,
|
|
|
+ inputRules.integerRange(1, 60),
|
|
|
+ ]"
|
|
|
+ />
|
|
|
+
|
|
|
+ <DefaultInput
|
|
|
+ v-model="variation.register_installments_max"
|
|
|
+ v-model:error="
|
|
|
+ validationErrors[
|
|
|
+ `variations.${index}.register_installments_max`
|
|
|
+ ]
|
|
|
+ "
|
|
|
+ class="col-4"
|
|
|
+ label="Parcelas Máx."
|
|
|
+ max="60"
|
|
|
+ min="1"
|
|
|
+ type="number"
|
|
|
+ :rules="[
|
|
|
+ inputRules.required,
|
|
|
+ inputRules.integerRange(1, 60),
|
|
|
+ gteInstallmentsMin(
|
|
|
+ () => variation.register_installments_min,
|
|
|
+ ),
|
|
|
+ ...(variation.type === 'irrecusavel'
|
|
|
+ ? [
|
|
|
+ ltePavaoInstallmentsMax(
|
|
|
+ () =>
|
|
|
+ form.variations[0]
|
|
|
+ .register_installments_max,
|
|
|
+ ),
|
|
|
+ ]
|
|
|
+ : []),
|
|
|
+ ]"
|
|
|
+ />
|
|
|
+
|
|
|
+ <div class="col-12 variation-section-title">
|
|
|
+ Pacote
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <DefaultCurrencyInput
|
|
|
+ v-model="variation.package_value"
|
|
|
+ v-model:error="
|
|
|
+ validationErrors[`variations.${index}.package_value`]
|
|
|
+ "
|
|
|
+ class="col-4"
|
|
|
+ label="R$ Pacote"
|
|
|
+ :rules="[
|
|
|
+ inputRules.required,
|
|
|
+ ...(variation.type === 'irrecusavel'
|
|
|
+ ? [irrecusavelTotalMenorQuePavao]
|
|
|
+ : []),
|
|
|
+ ]"
|
|
|
+ />
|
|
|
+
|
|
|
+ <DefaultInput
|
|
|
+ v-model="variation.package_installments_min"
|
|
|
+ v-model:error="
|
|
|
+ validationErrors[
|
|
|
+ `variations.${index}.package_installments_min`
|
|
|
+ ]
|
|
|
+ "
|
|
|
+ class="col-4"
|
|
|
+ label="Parcelas Mín."
|
|
|
+ max="60"
|
|
|
+ min="1"
|
|
|
+ type="number"
|
|
|
+ :rules="[
|
|
|
+ inputRules.required,
|
|
|
+ inputRules.integerRange(1, 60),
|
|
|
+ ]"
|
|
|
+ />
|
|
|
+
|
|
|
+ <DefaultInput
|
|
|
+ v-model="variation.package_installments_max"
|
|
|
+ v-model:error="
|
|
|
+ validationErrors[
|
|
|
+ `variations.${index}.package_installments_max`
|
|
|
+ ]
|
|
|
+ "
|
|
|
+ class="col-4"
|
|
|
+ label="Parcelas Máx."
|
|
|
+ max="60"
|
|
|
+ min="1"
|
|
|
+ type="number"
|
|
|
+ :rules="[
|
|
|
+ inputRules.required,
|
|
|
+ inputRules.integerRange(1, 60),
|
|
|
+ gteInstallmentsMin(
|
|
|
+ () => variation.package_installments_min,
|
|
|
+ ),
|
|
|
+ ...(variation.type === 'irrecusavel'
|
|
|
+ ? [
|
|
|
+ ltePavaoInstallmentsMax(
|
|
|
+ () =>
|
|
|
+ form.variations[0]
|
|
|
+ .package_installments_max,
|
|
|
+ ),
|
|
|
+ ]
|
|
|
+ : []),
|
|
|
+ ]"
|
|
|
+ />
|
|
|
+
|
|
|
+ <DefaultInput
|
|
|
+ v-model="variation.discount_value"
|
|
|
+ v-model:error="
|
|
|
+ validationErrors[`variations.${index}.discount_value`]
|
|
|
+ "
|
|
|
+ class="col-4"
|
|
|
+ label="Desconto em %"
|
|
|
+ max="100"
|
|
|
+ min="0"
|
|
|
+ type="number"
|
|
|
+ :rules="[
|
|
|
+ inputRules.minValue(0),
|
|
|
+ inputRules.maxValue(100),
|
|
|
+ ]"
|
|
|
+ />
|
|
|
+
|
|
|
+ <div class="col-12 variation-section-title">
|
|
|
+ Material
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <DefaultInput
|
|
|
+ class="col-4"
|
|
|
+ label="R$ Material"
|
|
|
+ :model-value="formatToBRLCurrency(materialsTotal)"
|
|
|
+ readonly
|
|
|
+ />
|
|
|
+
|
|
|
+ <DefaultInput
|
|
|
+ v-model="variation.material_installments_min"
|
|
|
+ v-model:error="
|
|
|
+ validationErrors[
|
|
|
+ `variations.${index}.material_installments_min`
|
|
|
+ ]
|
|
|
+ "
|
|
|
+ class="col-4"
|
|
|
+ label="Parcelas Mín."
|
|
|
+ max="60"
|
|
|
+ min="1"
|
|
|
+ type="number"
|
|
|
+ :rules="[
|
|
|
+ inputRules.required,
|
|
|
+ inputRules.integerRange(1, 60),
|
|
|
+ ]"
|
|
|
+ />
|
|
|
+
|
|
|
+ <DefaultInput
|
|
|
+ v-model="variation.material_installments_max"
|
|
|
+ v-model:error="
|
|
|
+ validationErrors[
|
|
|
+ `variations.${index}.material_installments_max`
|
|
|
+ ]
|
|
|
+ "
|
|
|
+ class="col-4"
|
|
|
+ label="Parcelas Máx."
|
|
|
+ max="60"
|
|
|
+ min="1"
|
|
|
+ type="number"
|
|
|
+ :rules="[
|
|
|
+ inputRules.required,
|
|
|
+ inputRules.integerRange(1, 60),
|
|
|
+ gteInstallmentsMin(
|
|
|
+ () => variation.material_installments_min,
|
|
|
+ ),
|
|
|
+ ...(variation.type === 'irrecusavel'
|
|
|
+ ? [
|
|
|
+ ltePavaoInstallmentsMax(
|
|
|
+ () =>
|
|
|
+ form.variations[0]
|
|
|
+ .material_installments_max,
|
|
|
+ ),
|
|
|
+ ]
|
|
|
+ : []),
|
|
|
+ ]"
|
|
|
+ />
|
|
|
+
|
|
|
+ <div class="col-12 package-duration-hint">
|
|
|
+ O valor do material é a soma dos materiais do pacote e não
|
|
|
+ pode ser alterado na proposta.
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </q-card-section>
|
|
|
</q-scroll-area>
|
|
|
|
|
|
<q-card-actions
|
|
|
@@ -172,11 +382,38 @@
|
|
|
/>
|
|
|
|
|
|
<q-btn
|
|
|
+ v-if="!props.package && activeTab !== tabOrder[0]"
|
|
|
+ color="primary"
|
|
|
+ label="Voltar"
|
|
|
+ no-caps
|
|
|
+ outline
|
|
|
+ @click="goToTab(-1)"
|
|
|
+ />
|
|
|
+
|
|
|
+ <q-btn
|
|
|
+ v-if="
|
|
|
+ !props.package &&
|
|
|
+ activeTab !== tabOrder[tabOrder.length - 1]
|
|
|
+ "
|
|
|
+ color="primary"
|
|
|
+ label="Avançar"
|
|
|
+ no-caps
|
|
|
+ :disable="
|
|
|
+ tabs[tabOrder.indexOf(activeTab) + 1]?.disable
|
|
|
+ "
|
|
|
+ @click="goToTab(1)"
|
|
|
+ />
|
|
|
+
|
|
|
+ <q-btn
|
|
|
+ v-show="
|
|
|
+ !!props.package ||
|
|
|
+ activeTab === tabOrder[tabOrder.length - 1]
|
|
|
+ "
|
|
|
color="primary"
|
|
|
label="Salvar"
|
|
|
no-caps
|
|
|
- type="submit"
|
|
|
:loading="loading"
|
|
|
+ @click="onOKClick"
|
|
|
/>
|
|
|
</q-card-actions>
|
|
|
</DefaultForm>
|
|
|
@@ -188,6 +425,7 @@
|
|
|
<script setup>
|
|
|
import {
|
|
|
computed,
|
|
|
+ nextTick,
|
|
|
onMounted,
|
|
|
ref,
|
|
|
useTemplateRef,
|
|
|
@@ -205,7 +443,9 @@ import { useForm } from "src/composables/useForm";
|
|
|
import { useInputRules } from "src/composables/useInputRules";
|
|
|
import { useScroll } from "src/composables/useScroll";
|
|
|
import { useSubmitHandler } from "src/composables/useSubmitHandler";
|
|
|
+import { formatToBRLCurrency } from "src/helpers/utils";
|
|
|
|
|
|
+import CustomTabComponent from "src/components/shared/CustomTabComponent.vue";
|
|
|
import DefaultCurrencyInput from "src/components/defaults/DefaultCurrencyInput.vue";
|
|
|
import DefaultDialogHeader from "src/components/defaults/DefaultDialogHeader.vue";
|
|
|
import DefaultForm from "src/components/defaults/DefaultForm.vue";
|
|
|
@@ -229,28 +469,25 @@ const { scrollToComponent } = useScroll();
|
|
|
|
|
|
const formRef = useTemplateRef("formRef");
|
|
|
const scrollAreaRef = useTemplateRef("scrollAreaRef");
|
|
|
-
|
|
|
-const products = ref([]);
|
|
|
-
|
|
|
-const productOptions = computed(() =>
|
|
|
- products.value.map((product) => ({
|
|
|
- label: product.name,
|
|
|
- price_sale: product.price_sale,
|
|
|
- value: product.id,
|
|
|
- })),
|
|
|
-);
|
|
|
+const pacotePanelRef = useTemplateRef("pacotePanelRef");
|
|
|
+
|
|
|
+const defaultVariation = (type) => ({
|
|
|
+ type,
|
|
|
+ register_value: null,
|
|
|
+ register_installments_min: 1,
|
|
|
+ register_installments_max: 1,
|
|
|
+ package_value: null,
|
|
|
+ package_installments_min: 1,
|
|
|
+ package_installments_max: 1,
|
|
|
+ discount_value: null,
|
|
|
+ material_installments_min: 1,
|
|
|
+ material_installments_max: 1,
|
|
|
+});
|
|
|
|
|
|
const { form, getUpdatedFields } = useForm({
|
|
|
- class_duration_hours:
|
|
|
+ class_duration_hours: String(
|
|
|
(props.package?.class_duration_minutes ?? 120) / 60,
|
|
|
-
|
|
|
- contract_register_value:
|
|
|
- props.package?.contract_register_value ?? null,
|
|
|
-
|
|
|
- contract_value: props.package?.contract_value ?? null,
|
|
|
-
|
|
|
- contrat_discount_value:
|
|
|
- props.package?.contrat_discount_value ?? null,
|
|
|
+ ),
|
|
|
|
|
|
materials: [
|
|
|
{
|
|
|
@@ -261,9 +498,34 @@ const { form, getUpdatedFields } = useForm({
|
|
|
],
|
|
|
|
|
|
name: props.package?.name ?? null,
|
|
|
- quantity_classes: props.package?.quantity_classes ?? null,
|
|
|
+ quantity_classes:
|
|
|
+ props.package?.quantity_classes != null
|
|
|
+ ? String(props.package.quantity_classes)
|
|
|
+ : null,
|
|
|
+
|
|
|
+ variations: [
|
|
|
+ defaultVariation("pavao"),
|
|
|
+ defaultVariation("irrecusavel"),
|
|
|
+ ],
|
|
|
});
|
|
|
|
|
|
+// scrollFn customizado: antes de rolar ate o campo com erro,
|
|
|
+// descobre em qual tab ele esta e troca para ela
|
|
|
+
|
|
|
+const tabScrollFn = async (errorElement, containerRef, options) => {
|
|
|
+ const tab = tabOrder.find((name) =>
|
|
|
+ getPanelElement(name)?.contains(errorElement),
|
|
|
+ );
|
|
|
+
|
|
|
+ if (tab && tab !== activeTab.value) {
|
|
|
+ activeTab.value = tab;
|
|
|
+
|
|
|
+ await nextTick();
|
|
|
+ }
|
|
|
+
|
|
|
+ return scrollToComponent(errorElement, containerRef, options);
|
|
|
+};
|
|
|
+
|
|
|
const {
|
|
|
loading,
|
|
|
validationErrors,
|
|
|
@@ -274,9 +536,66 @@ const {
|
|
|
onSuccess: (result) => {
|
|
|
onDialogOK(result);
|
|
|
},
|
|
|
- scrollFn: scrollToComponent,
|
|
|
+ scrollFn: tabScrollFn,
|
|
|
});
|
|
|
|
|
|
+const activeTab = ref("pacote");
|
|
|
+const products = ref([]);
|
|
|
+const variationPanelRefs = ref({});
|
|
|
+
|
|
|
+const tabOrder = ["pacote", "pavao", "irrecusavel"];
|
|
|
+
|
|
|
+const materialsTotal = computed(() =>
|
|
|
+ form.materials.reduce(
|
|
|
+ (total, material) =>
|
|
|
+ material.product_id
|
|
|
+ ? total +
|
|
|
+ Number(material.quantity || 0) * Number(material.price || 0)
|
|
|
+ : total,
|
|
|
+ 0,
|
|
|
+ ),
|
|
|
+);
|
|
|
+
|
|
|
+// uma tab so fica disponivel quando tudo da tab anterior esta preenchido
|
|
|
+
|
|
|
+const hasValue = (value) =>
|
|
|
+ value !== null && value !== undefined && value !== "";
|
|
|
+
|
|
|
+const pacoteFilled = computed(
|
|
|
+ () =>
|
|
|
+ hasValue(form.name) &&
|
|
|
+ hasValue(form.quantity_classes) &&
|
|
|
+ hasValue(form.class_duration_hours),
|
|
|
+);
|
|
|
+
|
|
|
+const productOptions = computed(() =>
|
|
|
+ products.value.map((product) => ({
|
|
|
+ label: product.name,
|
|
|
+ price_sale: product.price_sale,
|
|
|
+ value: product.id,
|
|
|
+ })),
|
|
|
+);
|
|
|
+
|
|
|
+const variationFilled = (variation) =>
|
|
|
+ hasValue(variation.register_value) &&
|
|
|
+ hasValue(variation.package_value);
|
|
|
+
|
|
|
+const tabs = computed(() => [
|
|
|
+ { name: "pacote", label: "Pacote" },
|
|
|
+ {
|
|
|
+ name: "pavao",
|
|
|
+ label: "Proposta Pavão",
|
|
|
+ disable: !pacoteFilled.value,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "irrecusavel",
|
|
|
+ label: "Proposta Irrecusável",
|
|
|
+ disable:
|
|
|
+ !pacoteFilled.value ||
|
|
|
+ !variationFilled(form.variations[0]),
|
|
|
+ },
|
|
|
+]);
|
|
|
+
|
|
|
const addMaterial = () => {
|
|
|
form.materials.push({
|
|
|
price: null,
|
|
|
@@ -285,6 +604,92 @@ const addMaterial = () => {
|
|
|
});
|
|
|
};
|
|
|
|
|
|
+const buildVariationPayload = (variation) => ({
|
|
|
+ type: variation.type,
|
|
|
+ register_value: variation.register_value ?? 0,
|
|
|
+ register_installments_min: Number(
|
|
|
+ variation.register_installments_min,
|
|
|
+ ),
|
|
|
+ register_installments_max: Number(
|
|
|
+ variation.register_installments_max,
|
|
|
+ ),
|
|
|
+ package_value: variation.package_value ?? 0,
|
|
|
+ package_installments_min: Number(
|
|
|
+ variation.package_installments_min,
|
|
|
+ ),
|
|
|
+ package_installments_max: Number(
|
|
|
+ variation.package_installments_max,
|
|
|
+ ),
|
|
|
+ discount_value:
|
|
|
+ variation.discount_value === null ||
|
|
|
+ variation.discount_value === ""
|
|
|
+ ? null
|
|
|
+ : Number(variation.discount_value),
|
|
|
+ material_installments_min: Number(
|
|
|
+ variation.material_installments_min,
|
|
|
+ ),
|
|
|
+ material_installments_max: Number(
|
|
|
+ variation.material_installments_max,
|
|
|
+ ),
|
|
|
+});
|
|
|
+
|
|
|
+const irrecusavelTotalMenorQuePavao = () =>
|
|
|
+ variationTotal(form.variations[1]) <
|
|
|
+ variationTotal(form.variations[0]) ||
|
|
|
+ "O total da proposta irrecusável deve ser menor que o total da proposta pavão";
|
|
|
+
|
|
|
+const ltePavaoInstallmentsMax = (getPavaoMax) => (value) =>
|
|
|
+ Number(value) <= Number(getPavaoMax()) ||
|
|
|
+ "Não pode ser maior que o máximo de parcelas da proposta pavão";
|
|
|
+
|
|
|
+const getPanelElement = (tab) => {
|
|
|
+ const panel =
|
|
|
+ tab === "pacote"
|
|
|
+ ? pacotePanelRef.value
|
|
|
+ : variationPanelRefs.value[tab];
|
|
|
+
|
|
|
+ return panel?.$el ?? panel ?? null;
|
|
|
+};
|
|
|
+
|
|
|
+const goToTab = (direction) => {
|
|
|
+ const index = tabOrder.indexOf(activeTab.value);
|
|
|
+
|
|
|
+ activeTab.value = tabOrder[index + direction];
|
|
|
+};
|
|
|
+
|
|
|
+const gteInstallmentsMin = (getMin) => (value) =>
|
|
|
+ Number(value) >= Number(getMin()) ||
|
|
|
+ "Deve ser maior ou igual ao mínimo de parcelas";
|
|
|
+
|
|
|
+const setVariationPanelRef = (type, el) => {
|
|
|
+ if (el) {
|
|
|
+ variationPanelRefs.value[type] = el;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const variationTotal = (variation) =>
|
|
|
+ Number(variation.register_value || 0) +
|
|
|
+ Number(variation.package_value || 0) +
|
|
|
+ materialsTotal.value;
|
|
|
+
|
|
|
+//
|
|
|
+
|
|
|
+const onProductSelected = (material) => {
|
|
|
+ const option = productOptions.value.find(
|
|
|
+ (product) => product.value === material.product_id,
|
|
|
+ );
|
|
|
+
|
|
|
+ if (option) {
|
|
|
+ material.price = option.price_sale;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const removeMaterial = (index) => {
|
|
|
+ form.materials.splice(index, 1);
|
|
|
+};
|
|
|
+
|
|
|
+//
|
|
|
+
|
|
|
const onOKClick = async () => {
|
|
|
const validMaterials = form.materials.filter(
|
|
|
(material) => material.product_id,
|
|
|
@@ -295,14 +700,6 @@ const onOKClick = async () => {
|
|
|
Number(form.class_duration_hours) * 60,
|
|
|
),
|
|
|
|
|
|
- contract_register_value:
|
|
|
- form.contract_register_value,
|
|
|
-
|
|
|
- contract_value: form.contract_value,
|
|
|
-
|
|
|
- contrat_discount_value:
|
|
|
- form.contrat_discount_value,
|
|
|
-
|
|
|
materials: validMaterials.map((material) => ({
|
|
|
price: Number(material.price),
|
|
|
product_id: material.product_id,
|
|
|
@@ -311,6 +708,8 @@ const onOKClick = async () => {
|
|
|
|
|
|
name: form.name,
|
|
|
quantity_classes: form.quantity_classes,
|
|
|
+
|
|
|
+ variations: form.variations.map(buildVariationPayload),
|
|
|
};
|
|
|
|
|
|
await execute(() => {
|
|
|
@@ -321,13 +720,7 @@ const onOKClick = async () => {
|
|
|
const changedFields = getUpdatedFields.value;
|
|
|
const updatePayload = {};
|
|
|
|
|
|
- const directKeys = [
|
|
|
- "name",
|
|
|
- "quantity_classes",
|
|
|
- "contract_value",
|
|
|
- "contract_register_value",
|
|
|
- "contrat_discount_value",
|
|
|
- ];
|
|
|
+ const directKeys = ["name", "quantity_classes"];
|
|
|
|
|
|
for (const key of directKeys) {
|
|
|
if (key in changedFields) {
|
|
|
@@ -344,6 +737,10 @@ const onOKClick = async () => {
|
|
|
updatePayload.materials = payload.materials;
|
|
|
}
|
|
|
|
|
|
+ if ("variations" in changedFields) {
|
|
|
+ updatePayload.variations = payload.variations;
|
|
|
+ }
|
|
|
+
|
|
|
return updateUnitPackage(
|
|
|
props.package.id,
|
|
|
updatePayload,
|
|
|
@@ -351,20 +748,6 @@ const onOKClick = async () => {
|
|
|
});
|
|
|
};
|
|
|
|
|
|
-const onProductSelected = (material) => {
|
|
|
- const option = productOptions.value.find(
|
|
|
- (product) => product.value === material.product_id,
|
|
|
- );
|
|
|
-
|
|
|
- if (option) {
|
|
|
- material.price = option.price_sale;
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-const removeMaterial = (index) => {
|
|
|
- form.materials.splice(index, 1);
|
|
|
-};
|
|
|
-
|
|
|
onMounted(async () => {
|
|
|
const productsResponse = await getProductsForSelect();
|
|
|
|
|
|
@@ -376,18 +759,54 @@ onMounted(async () => {
|
|
|
props.package.id,
|
|
|
);
|
|
|
|
|
|
- form.class_duration_hours =
|
|
|
- (packageData.class_duration_minutes ?? 120) / 60;
|
|
|
+ form.class_duration_hours = String(
|
|
|
+ (packageData.class_duration_minutes ?? 120) / 60,
|
|
|
+ );
|
|
|
|
|
|
if (packageData.materials?.length) {
|
|
|
form.materials = packageData.materials.map(
|
|
|
(material) => ({
|
|
|
price: material.price,
|
|
|
product_id: material.product_id,
|
|
|
- quantity: material.quantity,
|
|
|
+ quantity: String(material.quantity),
|
|
|
}),
|
|
|
);
|
|
|
}
|
|
|
+
|
|
|
+ for (const variation of form.variations) {
|
|
|
+ const existing = packageData.variations?.find(
|
|
|
+ (item) => item.type === variation.type,
|
|
|
+ );
|
|
|
+
|
|
|
+ if (existing) {
|
|
|
+ Object.assign(variation, {
|
|
|
+ register_value: existing.register_value,
|
|
|
+ register_installments_min: String(
|
|
|
+ existing.register_installments_min,
|
|
|
+ ),
|
|
|
+ register_installments_max: String(
|
|
|
+ existing.register_installments_max,
|
|
|
+ ),
|
|
|
+ package_value: existing.package_value,
|
|
|
+ package_installments_min: String(
|
|
|
+ existing.package_installments_min,
|
|
|
+ ),
|
|
|
+ package_installments_max: String(
|
|
|
+ existing.package_installments_max,
|
|
|
+ ),
|
|
|
+ discount_value:
|
|
|
+ existing.discount_value != null
|
|
|
+ ? String(existing.discount_value)
|
|
|
+ : null,
|
|
|
+ material_installments_min: String(
|
|
|
+ existing.material_installments_min,
|
|
|
+ ),
|
|
|
+ material_installments_max: String(
|
|
|
+ existing.material_installments_max,
|
|
|
+ ),
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
});
|
|
|
</script>
|
|
|
|
|
|
@@ -399,4 +818,12 @@ onMounted(async () => {
|
|
|
font-size: 12px;
|
|
|
line-height: 1.35;
|
|
|
}
|
|
|
+
|
|
|
+.variation-section-title {
|
|
|
+ padding-top: 8px;
|
|
|
+ padding-bottom: 2px;
|
|
|
+ color: #424242;
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
</style>
|