[pricelist][calculation] can add new drink

This commit is contained in:
Tim Gröger 2021-04-11 23:11:43 +02:00
parent 06256f651a
commit b40b1064e7
6 changed files with 123 additions and 203 deletions

View File

@ -11,14 +11,6 @@
grid grid
:rows-per-page-options="[0]" :rows-per-page-options="[0]"
> >
<template #header="props">
<q-tr :props="props">
<q-th auto-width />
<q-th v-for="col in props.cols" :key="col.name" :props="props">
{{ col.label }}
</q-th>
</q-tr>
</template>
<template #top-right> <template #top-right>
<div class="row justify-end q-gutter-sm"> <div class="row justify-end q-gutter-sm">
<search-input v-model="search" :keys="search_keys" /> <search-input v-model="search" :keys="search_keys" />
@ -27,11 +19,6 @@
<min-price-setting /> <min-price-setting />
</q-menu> </q-menu>
</q-btn> </q-btn>
<q-btn label="neues Getränk" color="positive" icon-right="mdi-plus">
<q-menu v-model="showNewDrink" anchor="center middle" self="center middle" persistent>
<new-drink @close="showNewDrink = false" />
</q-menu>
</q-btn>
<q-select <q-select
v-model="visibleColumn" v-model="visibleColumn"
multiple multiple
@ -45,6 +32,12 @@
option-value="name" option-value="name"
options-cover options-cover
/> />
<q-btn color="primary" round icon="mdi-plus" @click="newDrink">
<!--<q-menu v-model="showNewDrink" anchor="center middle" self="center middle" persistent>
<new-drink @close="showNewDrink = false" />
</q-menu>-->
<q-tooltip> Neues Getränk </q-tooltip>
</q-btn>
</div> </div>
</template> </template>
<template #item="props"> <template #item="props">
@ -145,7 +138,12 @@
</template> </template>
</q-table> </q-table>
<q-dialog :model-value="editDrink !== undefined" persistent> <q-dialog :model-value="editDrink !== undefined" persistent>
<drink-modify :drink="editDrink" @save="editing_drink" @cancel="editDrink = undefined" /> <drink-modify
:drink="editDrink"
@save="editing_drink"
@cancel="editDrink = undefined"
@delete="deleteDrink"
/>
</q-dialog> </q-dialog>
</template> </template>
@ -154,7 +152,6 @@ import { defineComponent, onBeforeMount, ComputedRef, computed, ref } from 'vue'
import { useMainStore } from 'src/stores'; import { useMainStore } from 'src/stores';
import { Drink, usePricelistStore, DrinkPriceVolume } from 'src/plugins/pricelist/store'; import { Drink, usePricelistStore, DrinkPriceVolume } from 'src/plugins/pricelist/store';
import MinPriceSetting from 'src/plugins/pricelist/components/MinPriceSetting.vue'; import MinPriceSetting from 'src/plugins/pricelist/components/MinPriceSetting.vue';
import NewDrink from 'src/plugins/pricelist/components/CalculationTable/NewDrink.vue';
import SearchInput from './SearchInput.vue'; import SearchInput from './SearchInput.vue';
import DrinkPriceVolumes from 'src/plugins/pricelist/components/CalculationTable/DrinkPriceVolumes.vue'; import DrinkPriceVolumes from 'src/plugins/pricelist/components/CalculationTable/DrinkPriceVolumes.vue';
import DrinkModify from './DrinkModify.vue'; import DrinkModify from './DrinkModify.vue';
@ -168,7 +165,6 @@ export default defineComponent({
components: { components: {
SearchInput, SearchInput,
MinPriceSetting, MinPriceSetting,
NewDrink,
DrinkPriceVolumes, DrinkPriceVolumes,
DrinkModify, DrinkModify,
}, },
@ -349,8 +345,11 @@ export default defineComponent({
void store.updateDrink(drink); void store.updateDrink(drink);
} }
function deleteDrink(drink: Drink) { function deleteDrink() {
store.deleteDrink(drink); if (editDrink.value) {
store.deleteDrink(editDrink.value);
}
editDrink.value = undefined;
} }
const showNewDrink = ref(false); const showNewDrink = ref(false);
@ -390,7 +389,26 @@ export default defineComponent({
key: '', key: '',
label: '', label: '',
}); });
const editDrink = ref();
const emptyDrink: Drink = {
id: -1,
article_id: undefined,
package_size: undefined,
name: '',
volume: undefined,
cost_per_volume: undefined,
cost_per_package: undefined,
tags: [],
type: undefined,
volumes: [],
uuid: '',
};
function newDrink() {
editDrink.value = Object.assign({}, emptyDrink);
}
const editDrink = ref<Drink>();
async function editing_drink( async function editing_drink(
drink: Drink, drink: Drink,
@ -409,14 +427,13 @@ export default defineComponent({
await store.deleteVolume(volume, drink); await store.deleteVolume(volume, drink);
} }
console.log(drink); console.log(drink);
if (drink.id > 0) {
await store.updateDrink(drink); await store.updateDrink(drink);
if (deletePic || drinkPic) {
let loading = imageloading.value.find((a) => a.id === drink.id);
if (loading) {
loading.loading = true;
} else { } else {
loading = { id: drink.id, loading: true }; const _drink = await store.setDrink(drink);
imageloading.value.push(loading); if (editDrink.value) {
editDrink.value.id = _drink.id;
}
} }
if (deletePic) { if (deletePic) {
await deletePicture(); await deletePicture();
@ -424,8 +441,6 @@ export default defineComponent({
if (drinkPic instanceof File) { if (drinkPic instanceof File) {
await savePicture(drinkPic); await savePicture(drinkPic);
} }
loading.loading = false;
}
editDrink.value = undefined; editDrink.value = undefined;
notLoading.value = true; notLoading.value = true;
} }
@ -469,6 +484,7 @@ export default defineComponent({
get_volumes, get_volumes,
notLoading, notLoading,
getImageLoading, getImageLoading,
newDrink,
}; };
}, },
}); });

View File

@ -20,8 +20,8 @@
/> />
</div> </div>
<div v-if="editable" class="full-width row q-gutter-sm justify-between"> <div v-if="editable" class="full-width row q-gutter-sm justify-between">
<q-input v-model="newStep" filled label="Arbeitsschritt" /> <q-input v-model="newStep" filled label="Arbeitsschritt" dense />
<q-btn label="Schritt hinzufügen" @click="addStep" /> <q-btn label="Schritt hinzufügen" dense @click="addStep" />
</div> </div>
</template> </template>

View File

@ -1,143 +0,0 @@
<template>
<div class="q-pa-sm">
<div class="q-table__title q-pa-sm">Neues Getränk</div>
<q-form @submit="addDrink" @reset="cancelAddDrink">
<q-input
v-model="newDrink.name"
class="col-sm-4 col-xs-6 q-pa-sm"
filled
label="Getränkname"
lazy-rules
:rules="[notEmpty]"
/>
<q-input
v-model="newDrink.article_id"
class="col-sm-4 col-xs-6 q-pa-sm"
filled
label="Artikelnummer"
/>
<q-select
v-model="newDrink.type"
class="col-sm-4 col-xs-6 q-pa-sm"
filled
label="Kategorie"
:options="drinkTypes"
option-label="name"
lazy-rules
:rules="[notEmpty]"
/>
<q-input
v-model.number="newDrink.volume"
class="col-sm-4 col-xs-6 q-pa-sm"
filled
label="Inhalt in L/Gebinde"
type="number"
step="0.01"
min="0"
/>
<q-input
v-model.number="newDrink.package_size"
class="col-sm-4 col-xs-6 q-pa-sm"
filled
label="Gebindegröße"
type="number"
/>
<q-input
v-model.number="newDrink.cost_per_package"
class="col-sm-4 col-xs-6 q-pa-sm"
filled
label="Preis Netto/Gebinde"
type="number"
step="0.01"
min="0"
/>
<q-input
v-model.number="cost_per_volume"
class="col-sm-4 col-xs-6 q-pa-sm"
filled
label="Preis mit 19%/Liter"
:disable="calc_price_pro_volume"
type="number"
step="0.01"
min="0"
/>
<div class="row justify-between">
<q-btn v-close-popup label="Abbrechen" type="reset" />
<q-btn label="Speichern" type="submit" />
</div>
</q-form>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, ref } from 'vue';
import { usePricelistStore } from 'src/plugins/pricelist/store';
import { notEmpty } from 'src/utils/validators';
export default defineComponent({
name: 'NewDrink',
emits: { close: () => true },
setup(_, { emit }) {
const store = usePricelistStore();
const emptyDrink: FG.Drink = {
id: -1,
article_id: undefined,
package_size: undefined,
name: '',
volume: undefined,
cost_per_volume: undefined,
cost_per_package: undefined,
tags: [],
type: undefined,
volumes: [],
uuid: '',
};
const calc_price_pro_volume = computed(
() =>
!!newDrink.value.cost_per_package &&
!!newDrink.value.volume &&
!!newDrink.value.package_size
);
const cost_per_volume = computed({
get: () => {
if (calc_price_pro_volume.value) {
const retVal =
((newDrink.value.cost_per_package || 0) /
((newDrink.value.volume || 0) * (newDrink.value.package_size || 0))) *
1.19;
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
newDrink.value.cost_per_volume = Math.round(retVal * 1000) / 1000;
}
return newDrink.value.cost_per_volume;
},
set: (val) => {
newDrink.value.cost_per_volume = val;
},
});
async function addDrink() {
// Maybe try catch and handle error (e.g. name used...)
await store.setDrink(newDrink.value);
cancelAddDrink();
emit('close');
}
function cancelAddDrink() {
newDrink.value = emptyDrink;
}
const newDrink = ref<FG.Drink>(emptyDrink);
return {
drinkTypes: computed(() => store.drinkTypes),
newDrink,
calc_price_pro_volume,
cost_per_volume,
addDrink,
cancelAddDrink,
notEmpty,
};
},
});
</script>
<style scoped></style>

View File

@ -3,6 +3,26 @@
<q-card-section> <q-card-section>
<div class="text-h6">Getränk Bearbeiten</div> <div class="text-h6">Getränk Bearbeiten</div>
</q-card-section> </q-card-section>
<q-card-section>
<div class="full-width row">
<q-input
v-model="edit_drink.name"
class="col-xs-12 col-sm-6 q-pa-sm"
filled
label="Name"
dense
/>
<q-select
v-model="edit_drink.type"
class="col-xs-12 col-sm-6 q-pa-sm"
filled
label="Kategorie"
dense
:options="types"
option-label="name"
/>
</div>
</q-card-section>
<q-card-section> <q-card-section>
<q-img :src="image" style="max-height: 256px" fit="contain" /> <q-img :src="image" style="max-height: 256px" fit="contain" />
<div class="full-width row"> <div class="full-width row">
@ -90,9 +110,11 @@
dense dense
/> />
<q-input <q-input
v-model="edit_drink.cost_per_volume" v-model="cost_per_volume"
class="col-xs-12 col-sm-6 q-pa-sm q-pb-lg" class="col-xs-12 col-sm-6 q-pa-sm q-pb-lg"
filled :outlined="auto_cost_per_volume"
:filled="!auto_cost_per_volume"
:readonly="auto_cost_per_volume"
label="Preis pro L" label="Preis pro L"
hint="Inkl. 19% Mehrwertsteuer" hint="Inkl. 19% Mehrwertsteuer"
suffix="€" suffix="€"
@ -115,6 +137,7 @@
</q-card-section> </q-card-section>
<q-card-actions class="justify-around"> <q-card-actions class="justify-around">
<q-btn label="Abbrechen" @click="cancel" /> <q-btn label="Abbrechen" @click="cancel" />
<q-btn v-if="can_delete" label="Löschen" color="negative" @click="delete_drink" />
<q-btn label="Speichern" color="primary" @click="save" /> <q-btn label="Speichern" color="primary" @click="save" />
</q-card-actions> </q-card-actions>
</q-card> </q-card>
@ -123,7 +146,7 @@
import { defineComponent, PropType, ref, onBeforeMount, computed } from 'vue'; import { defineComponent, PropType, ref, onBeforeMount, computed } from 'vue';
import { Drink, DrinkPriceVolume, usePricelistStore } from '../store'; import { Drink, DrinkPriceVolume, usePricelistStore } from '../store';
import DrinkPriceVolumes from './CalculationTable/DrinkPriceVolumes.vue'; import DrinkPriceVolumes from './CalculationTable/DrinkPriceVolumes.vue';
import { clone, calc_min_prices, DeleteObjects } from '../utils/utils'; import { clone, calc_min_prices, DeleteObjects, calc_cost_per_volume } from '../utils/utils';
import BuildManual from 'src/plugins/pricelist/components/CalculationTable/BuildManual.vue'; import BuildManual from 'src/plugins/pricelist/components/CalculationTable/BuildManual.vue';
import config from 'src/config'; import config from 'src/config';
export default defineComponent({ export default defineComponent({
@ -141,7 +164,8 @@ export default defineComponent({
toDeleteObjects: DeleteObjects, toDeleteObjects: DeleteObjects,
drinkPic: File | undefined, drinkPic: File | undefined,
deletePic: boolean deletePic: boolean
) => drink && toDeleteObjects || drinkPic || deletePic, ) => (drink && toDeleteObjects) || drinkPic || deletePic,
delete: () => true,
cancel: () => true, cancel: () => true,
}, },
setup(props, { emit }) { setup(props, { emit }) {
@ -235,6 +259,42 @@ export default defineComponent({
return 'no-image.svg'; return 'no-image.svg';
}); });
const can_delete = computed(() => {
if (edit_drink.value) {
if (edit_drink.value.id < 0) {
return false;
}
const _edit_drink = edit_drink.value;
const test = _edit_drink.volumes ? _edit_drink.volumes.length === 0 : true;
console.log(test);
return test;
}
return false;
});
function delete_drink() {
emit('delete');
}
const auto_cost_per_volume = computed(
() =>
!!(
edit_drink.value?.cost_per_package &&
edit_drink.value?.package_size &&
edit_drink.value?.volume
)
);
const cost_per_volume = computed({
get: () => {
if (auto_cost_per_volume.value) {
return <number>calc_cost_per_volume(<Drink>edit_drink.value);
}
return <number>(<Drink>edit_drink.value).cost_per_volume;
},
set: (val: number) => ((<Drink>edit_drink.value).cost_per_volume = val),
});
return { return {
edit_drink, edit_drink,
save, save,
@ -251,6 +311,11 @@ export default defineComponent({
drinkPic, drinkPic,
imagePreview, imagePreview,
delete_pic, delete_pic,
types: computed(() => store.drinkTypes),
can_delete,
delete_drink,
auto_cost_per_volume,
cost_per_volume,
}; };
}, },
}); });

View File

@ -147,15 +147,6 @@ export const usePricelistStore = defineStore({
}); });
}, },
async deletePrice(price: FG.DrinkPrice) { async deletePrice(price: FG.DrinkPrice) {
/*api
.delete(`pricelist/prices/${price.id}`)
.then(() => {
const index = volume.prices.findIndex((a) => a.id == price.id);
if (index > -1) {
volume.prices.splice(index, 1);
}
})
.catch((err) => console.warn(err));*/
await api.delete(`pricelist/prices/${price.id}`); await api.delete(`pricelist/prices/${price.id}`);
}, },
async deleteVolume(volume: DrinkPriceVolume, drink: Drink) { async deleteVolume(volume: DrinkPriceVolume, drink: Drink) {
@ -166,19 +157,9 @@ export const usePricelistStore = defineStore({
} }
}, },
async deleteIngredient(ingredient: FG.Ingredient) { async deleteIngredient(ingredient: FG.Ingredient) {
/*api
.delete(`pricelist/ingredients/${ingredient.id}`)
.then(() => {
const index = volume.ingredients.findIndex((a) => a.id === ingredient.id);
if (index > -1) {
volume.ingredients.splice(index, 1);
}
})
.catch((err) => console.warn(err));
*/
await api.delete(`pricelist/ingredients/${ingredient.id}`); await api.delete(`pricelist/ingredients/${ingredient.id}`);
}, },
async setDrink(drink: FG.Drink) { async setDrink(drink: Drink) {
const { data } = await api.post<FG.Drink>('pricelist/drinks', { const { data } = await api.post<FG.Drink>('pricelist/drinks', {
...drink, ...drink,
}); });
@ -189,6 +170,7 @@ export const usePricelistStore = defineStore({
}); });
this.drinks.push(_drink); this.drinks.push(_drink);
calc_all_min_prices(this.drinks, this.min_prices); calc_all_min_prices(this.drinks, this.min_prices);
return _drink;
}, },
async updateDrink(drink: Drink) { async updateDrink(drink: Drink) {
const { data } = await api.put<FG.Drink>(`pricelist/drinks/${drink.id}`, { const { data } = await api.put<FG.Drink>(`pricelist/drinks/${drink.id}`, {