|
|
@@ -65,16 +65,27 @@
|
|
|
>
|
|
|
<div class="row q-col-gutter-sm items-center">
|
|
|
<DefaultSelect
|
|
|
- v-model="material.type"
|
|
|
+ v-model="material.product_id"
|
|
|
label="Material"
|
|
|
class="col"
|
|
|
- :options="[]"
|
|
|
+ :options="productOptions"
|
|
|
+ emit-value
|
|
|
+ map-options
|
|
|
+ @update:model-value="onProductSelected(material)"
|
|
|
+ />
|
|
|
+
|
|
|
+ <DefaultInput
|
|
|
+ v-model="material.quantity"
|
|
|
+ label="Qtd"
|
|
|
+ class="col-2"
|
|
|
+ type="number"
|
|
|
+ min="1"
|
|
|
/>
|
|
|
|
|
|
<DefaultCurrencyInput
|
|
|
- v-model="material.value"
|
|
|
- label="R$ 000,00"
|
|
|
- class="col-4"
|
|
|
+ v-model="material.price"
|
|
|
+ label="R$ Unitário"
|
|
|
+ class="col-3"
|
|
|
/>
|
|
|
|
|
|
<div class="col-auto">
|
|
|
@@ -86,7 +97,15 @@
|
|
|
style="border-radius: 8px; height: 40px; width: 40px"
|
|
|
@click="addMaterial"
|
|
|
/>
|
|
|
- <div v-else style="width: 40px" />
|
|
|
+ <q-btn
|
|
|
+ v-else
|
|
|
+ flat
|
|
|
+ round
|
|
|
+ dense
|
|
|
+ icon="mdi-delete-outline"
|
|
|
+ color="negative"
|
|
|
+ @click="removeMaterial(index)"
|
|
|
+ />
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -246,6 +265,7 @@ import DefaultCurrencyInput from "src/components/defaults/DefaultCurrencyInput.v
|
|
|
|
|
|
import { getUnitsForSelect } from "src/api/unit";
|
|
|
import { getPackage, createPackage, updatePackage } from "src/api/package";
|
|
|
+import { getProductsForSelect } from "src/api/product";
|
|
|
|
|
|
defineEmits([...useDialogPluginComponent.emits]);
|
|
|
|
|
|
@@ -269,20 +289,42 @@ const tabs = [
|
|
|
{ name: "unidades", label: "Unidades" },
|
|
|
];
|
|
|
|
|
|
+const products = ref([]);
|
|
|
+
|
|
|
+const productOptions = computed(() =>
|
|
|
+ products.value.map((p) => ({ label: p.name, value: p.id, price_sale: p.price_sale }))
|
|
|
+);
|
|
|
+
|
|
|
const form = ref({
|
|
|
name: props.package?.name ?? null,
|
|
|
quantity_classes: props.package?.quantity_classes ?? null,
|
|
|
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,
|
|
|
- contract_material_value: props.package?.contract_material_value ?? null,
|
|
|
- materials: [{ type: null, value: null }],
|
|
|
+ materials: [{ product_id: null, quantity: 1, price: null }],
|
|
|
});
|
|
|
|
|
|
+const onProductSelected = (material) => {
|
|
|
+ const option = productOptions.value.find((o) => o.value === material.product_id);
|
|
|
+ if (option) material.price = option.price_sale;
|
|
|
+};
|
|
|
+
|
|
|
const addMaterial = () => {
|
|
|
- form.value.materials.push({ type: null, value: null });
|
|
|
+ form.value.materials.push({ product_id: null, quantity: 1, price: null });
|
|
|
};
|
|
|
|
|
|
+const removeMaterial = (index) => {
|
|
|
+ form.value.materials.splice(index, 1);
|
|
|
+};
|
|
|
+
|
|
|
+const contractMaterialValue = computed(() =>
|
|
|
+ form.value.materials.reduce((sum, m) => {
|
|
|
+ const qty = Number(m.quantity) || 0;
|
|
|
+ const price = Number(m.price) || 0;
|
|
|
+ return sum + qty * price;
|
|
|
+ }, 0)
|
|
|
+);
|
|
|
+
|
|
|
// Unidades tab
|
|
|
const unitSearch = ref("");
|
|
|
const units = ref([]);
|
|
|
@@ -302,14 +344,28 @@ const setAllVisible = (visible) => {
|
|
|
onMounted(async () => {
|
|
|
loadingUnits.value = true;
|
|
|
try {
|
|
|
- const allUnits = await getUnitsForSelect();
|
|
|
+ const [allUnits, allProducts] = await Promise.all([
|
|
|
+ getUnitsForSelect(),
|
|
|
+ getProductsForSelect(),
|
|
|
+ ]);
|
|
|
+
|
|
|
+ products.value = allProducts;
|
|
|
|
|
|
let visibilityMap = {};
|
|
|
+ let savedMaterials = null;
|
|
|
+
|
|
|
if (props.package?.id) {
|
|
|
const pkg = await getPackage(props.package.id);
|
|
|
(pkg.unit_visibilities ?? []).forEach((uv) => {
|
|
|
visibilityMap[uv.unit_id] = uv.visible;
|
|
|
});
|
|
|
+ if (pkg.materials?.length) {
|
|
|
+ savedMaterials = pkg.materials.map((m) => ({
|
|
|
+ product_id: m.product_id,
|
|
|
+ quantity: m.quantity,
|
|
|
+ price: m.price,
|
|
|
+ }));
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
units.value = allUnits.map((u) => ({
|
|
|
@@ -317,6 +373,10 @@ onMounted(async () => {
|
|
|
fantasy_name: u.fantasy_name,
|
|
|
visible: visibilityMap[u.id] ?? true,
|
|
|
}));
|
|
|
+
|
|
|
+ if (savedMaterials) {
|
|
|
+ form.value.materials = savedMaterials;
|
|
|
+ }
|
|
|
} finally {
|
|
|
loadingUnits.value = false;
|
|
|
}
|
|
|
@@ -325,17 +385,23 @@ onMounted(async () => {
|
|
|
const onOKClick = async () => {
|
|
|
loading.value = true;
|
|
|
try {
|
|
|
+ const validMaterials = form.value.materials.filter((m) => m.product_id);
|
|
|
+
|
|
|
const payload = {
|
|
|
name: form.value.name,
|
|
|
quantity_classes: form.value.quantity_classes,
|
|
|
contract_value: form.value.contract_value,
|
|
|
- contract_material_value: form.value.contract_material_value,
|
|
|
contract_register_value: form.value.contract_register_value,
|
|
|
contrat_discount_value: form.value.contrat_discount_value,
|
|
|
unit_visibilities: units.value.map((u) => ({
|
|
|
unit_id: u.id,
|
|
|
visible: u.visible,
|
|
|
})),
|
|
|
+ materials: validMaterials.map((m) => ({
|
|
|
+ product_id: m.product_id,
|
|
|
+ quantity: Number(m.quantity),
|
|
|
+ price: Number(m.price),
|
|
|
+ })),
|
|
|
};
|
|
|
|
|
|
const result = props.package?.id
|