release v2.0.0 #4

Merged
crimsen merged 481 commits from develop into master 2024-01-18 15:15:08 +00:00
8 changed files with 323 additions and 148 deletions
Showing only changes of commit 7a3a151688 - Show all commits

View File

@ -371,8 +371,13 @@
props.row.uuid ? `/api/pricelist/picture/${props.row.uuid}?size=256` : 'no-image.svg' props.row.uuid ? `/api/pricelist/picture/${props.row.uuid}?size=256` : 'no-image.svg'
" "
> >
<div class='absolute-top-right justify-end' style='background-color: transparent;'> <div class="absolute-top-right justify-end" style="background-color: transparent">
<q-btn @click="console.log('hallo')" round icon='mdi-pencil' style='background-color: rgba(0,0,0,0.5)'/> <q-btn
round
icon="mdi-pencil"
style="background-color: rgba(0, 0, 0, 0.5)"
@click="editDrink = props.row"
/>
</div> </div>
<div class="absolute-bottom-right justify-end"> <div class="absolute-bottom-right justify-end">
<div class="text-subtitle1 text-right"> <div class="text-subtitle1 text-right">
@ -447,14 +452,20 @@
/> />
</div> </div>
</q-card-section> </q-card-section>
<q-card-section v-if="props.row.volumes.length > 0"> <q-card-section v-if="props.row.volumes.length > 0">
<drink-price-volumes :props="props.row" /> <drink-price-volumes v-model="props.row.volumes" />
</q-card-section> </q-card-section>
</q-card> </q-card>
</div> </div>
</template> </template>
</q-table> </q-table>
<q-dialog :model-value="editDrink !== undefined" persistent>
<drink-modify
:drink="editDrink"
@save="editDrink = undefined"
@cancel="editDrink = undefined"
/>
</q-dialog>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -467,6 +478,7 @@ import NewDrink from 'src/plugins/pricelist/components/CalculationTable/NewDrink
import BuildManual from 'src/plugins/pricelist/components/CalculationTable/BuildManual.vue'; import BuildManual from 'src/plugins/pricelist/components/CalculationTable/BuildManual.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 { filter, Search } from '../utils/filter'; import { filter, Search } from '../utils/filter';
import { Notify } from 'quasar'; import { Notify } from 'quasar';
import { sort } from '../utils/sort'; import { sort } from '../utils/sort';
@ -480,6 +492,7 @@ export default defineComponent({
BuildManual, BuildManual,
DrinkPriceVolumesTable, DrinkPriceVolumesTable,
DrinkPriceVolumes, DrinkPriceVolumes,
DrinkModify,
}, },
setup() { setup() {
const mainStore = useMainStore(); const mainStore = useMainStore();
@ -715,6 +728,7 @@ export default defineComponent({
label: '', label: '',
}); });
const grid = ref(true); const grid = ref(true);
const editDrink = ref();
return { return {
drinks: computed(() => store.drinks), drinks: computed(() => store.drinks),
pagination, pagination,
@ -737,6 +751,7 @@ export default defineComponent({
search_keys, search_keys,
grid, grid,
tags: computed(() => store.tags), tags: computed(() => store.tags),
editDrink,
}; };
}, },
}); });

View File

@ -37,7 +37,7 @@ export default defineComponent({
const emptyVolume: DrinkPriceVolume = { const emptyVolume: DrinkPriceVolume = {
id: -1, id: -1,
_volume: 0, _volume: 0,
min_prices: [{ percentage: 100 }, { percentage: 250 }, { percentage: 300 }], min_prices: [],
prices: [], prices: [],
ingredients: [], ingredients: [],
}; };

View File

@ -9,17 +9,20 @@
navigation navigation
arrows arrows
> >
<q-carousel-slide v-for="volume in props.volumes" :key="volume.id" :name="volume.id"> <q-carousel-slide v-for="volume in volumes" :key="volume.id" :name="volume.id">
<q-input <q-input
v-model.number="volume.volume"
class="q-pa-sm" class="q-pa-sm"
:model-value="volume.volume" :outlined="!editable"
outlined :filled="editable"
readonly :readonly="!editable"
dense dense
label="Inhalt" label="Inhalt"
mask="#.###" mask="#.###"
fill-mask="0" fill-mask="0"
suffix="L" suffix="L"
min="0"
step="0.001"
/> />
<div class="full-width row q-gutter-sm q-pa-sm justify-around"> <div class="full-width row q-gutter-sm q-pa-sm justify-around">
<div v-for="(min_price, index) in volume.min_prices" :key="index"> <div v-for="(min_price, index) in volume.min_prices" :key="index">
@ -30,58 +33,104 @@
<div class="q-pa-sm"> <div class="q-pa-sm">
<div v-for="(price, index) in volume.prices" :key="price.id"> <div v-for="(price, index) in volume.prices" :key="price.id">
<div class="fit row justify-around q-py-sm"> <div class="fit row justify-around q-py-sm">
<div class="text-body1 col-xs-12 col-md-4">{{ price.price.toFixed(2) }}</div> <div v-if="!editable" class="text-body1 col-xs-12 col-md-3">
<div class="text-body1 col-xs-12 col-md-4"> {{ price.price.toFixed(2) }}
</div>
<q-input
v-else
v-model.number="price.price"
class="col-xs-12 col-md-3"
type="number"
min="0"
step="0.01"
suffix="€"
filled
dense
label="Preis"
/>
<div class="text-body1 col-xs-12 col-md-2">
<q-toggle <q-toggle
:model-value="price.public" v-model="price.public"
disable :disable="!editable"
checked-icon="mdi-earth" checked-icon="mdi-earth"
unchecked-icon="mdi-earth-off" unchecked-icon="mdi-earth-off"
/> />
</div> </div>
<div class="text-body1 col-xs-12 col-md-4"> <div v-if="!editable" class="text-body1 col-xs-12 col-md-5">
{{ price.description }} {{ price.description }}
</div> </div>
<q-input
v-else
v-model="price.description"
class="col-xs-12 col-md-5"
filled
dense
label="Beschreibung"
/>
</div> </div>
<q-separator v-if="index < volume.prices.length - 1" /> <q-separator v-if="index < volume.prices.length - 1" />
</div> </div>
</div> </div>
<div class="q-pa-sm"> <div class="q-pa-sm">
<ingredients :ingredients="volume.ingredients" :volume="volume" /> <ingredients v-model="volume.ingredients" :editable="editable" />
</div> </div>
</q-carousel-slide> </q-carousel-slide>
</q-carousel> </q-carousel>
<q-btn-toggle v-model="volume" :options="options" />
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, PropType, ref } from 'vue'; import { computed, defineComponent, PropType, ref, onBeforeMount } from 'vue';
import { Drink } from 'src/plugins/pricelist/store'; import { DrinkPriceVolume } from 'src/plugins/pricelist/store';
import Ingredients from 'src/plugins/pricelist/components/CalculationTable/Ingredients.vue'; import Ingredients from 'src/plugins/pricelist/components/CalculationTable/Ingredients.vue';
export default defineComponent({ export default defineComponent({
name: 'DrinkPriceVolume', name: 'DrinkPriceVolume',
components: { Ingredients }, components: { Ingredients },
props: { props: {
props: { modelValue: {
type: Object as PropType<Drink>, type: Array as PropType<Array<DrinkPriceVolume>>,
required: true, required: true,
}, },
editable: {
type: Boolean,
default: false,
},
}, },
setup(props) { emits: {
const _volume = ref<number|undefined>(); 'update:modelValue': (val: Array<DrinkPriceVolume>) => val,
const volume = computed<number|undefined>({ },
setup(props, { emit }) {
onBeforeMount(() => {
volumes.value = <Array<DrinkPriceVolume>>[...props.modelValue];
});
const volumes = ref<Array<DrinkPriceVolume>>([]);
const _volume = ref<number | undefined>();
const volume = computed<number | undefined>({
get: () => { get: () => {
if (_volume.value !== undefined) { if (_volume.value !== undefined) {
return _volume.value; return _volume.value;
} }
if (props.props.volumes.length > 0) { if (volumes.value.length > 0) {
return props.props.volumes[0].id; return volumes.value[0].id;
} }
return undefined; return undefined;
}, },
set: (val: number|undefined) => (_volume.value = val), set: (val: number | undefined) => (_volume.value = val),
}); });
return { volume }; const options = computed<Array<{ label: string; value: number }>>(() => {
const retVal: Array<{ label: string; value: number }> = [];
volumes.value.forEach((volume: DrinkPriceVolume) => {
retVal.push({ label: `${<number>volume.volume}L`, value: volume.id });
});
return retVal;
});
function updateVolume() {
emit('update:modelValue', volumes.value);
}
return { volumes, volume, options, updateVolume };
}, },
}); });
</script> </script>

View File

@ -1,8 +1,8 @@
<template> <template>
<div class="full-width"> <div class="full-width">
<div <div
v-for="ingredient in ingredients" v-for="ingredient in edit_ingredients"
:key="`volume:${volume.id},ingredient:${ingredient.id}`" :key="`ingredient:${ingredient.id}`"
class="full-width row justify-evenly q-py-xs" class="full-width row justify-evenly q-py-xs"
> >
<div class="full-width row justify-evenly"> <div class="full-width row justify-evenly">
@ -11,14 +11,16 @@
<div class="col"> <div class="col">
{{ get_drink_ingredient_name(ingredient.drink_ingredient.ingredient_id) }} {{ get_drink_ingredient_name(ingredient.drink_ingredient.ingredient_id) }}
<q-popup-edit <q-popup-edit
v-if="editable"
v-slot="scope"
v-model="ingredient.drink_ingredient.ingredient_id" v-model="ingredient.drink_ingredient.ingredient_id"
buttons buttons
label-cancel="Abbrechen" label-cancel="Abbrechen"
label-set="Speichern" label-set="Speichern"
@save="updateDrink" @save="updateValue"
> >
<q-select <q-select
v-model="ingredient.drink_ingredient.ingredient_id" v-model="scope.ingredient_id"
class="col q-px-sm" class="col q-px-sm"
label="Getränk" label="Getränk"
filled filled
@ -34,14 +36,16 @@
<div class="col"> <div class="col">
{{ ingredient.drink_ingredient.volume.toFixed(3) }}L {{ ingredient.drink_ingredient.volume.toFixed(3) }}L
<q-popup-edit <q-popup-edit
v-if="editable"
v-slot="scope"
v-model="ingredient.drink_ingredient.volume" v-model="ingredient.drink_ingredient.volume"
buttons buttons
label-cancel="Abbrechen" label-cancel="Abbrechen"
label-set="Speichern" label-set="Speichern"
@save="updateDrink" @save="updateValue"
> >
<q-input <q-input
v-model.number="ingredient.drink_ingredient.volume" v-model.number="scope.value"
class="col q-px-sm" class="col q-px-sm"
label="Volume" label="Volume"
type="number" type="number"
@ -63,11 +67,12 @@
<div class="col">{{ ingredient.extra_ingredient.price.toFixed(3) }}</div> <div class="col">{{ ingredient.extra_ingredient.price.toFixed(3) }}</div>
</div> </div>
<q-popup-edit <q-popup-edit
v-if="editable"
v-model="ingredient.extra_ingredient" v-model="ingredient.extra_ingredient"
buttons buttons
label-cancel="Abbrechen" label-cancel="Abbrechen"
label-set="Speichern" label-set="Speichern"
@save="updateDrink" @save="updateValue"
> >
<q-select <q-select
v-model="ingredient.extra_ingredient" v-model="ingredient.extra_ingredient"
@ -78,19 +83,19 @@
/> />
</q-popup-edit> </q-popup-edit>
</div> </div>
<div class="col-1 row justify-end q-pa-xs"> <div v-if="editable" class="col-1 row justify-end q-pa-xs">
<q-btn <q-btn
icon="mdi-delete" icon="mdi-delete"
round round
size="xs" size="xs"
color="negative" color="negative"
@click="deleteIngredient(ingredient, volume)" @click="deleteIngredient(ingredient)"
/> />
</div> </div>
</div> </div>
<q-separator /> <q-separator />
</div> </div>
<div class="full-width row justify-end q-py-xs"> <div v-if="editable" class="full-width row justify-end q-py-xs">
<q-btn size="sm" icon-right="mdi-plus" color="positive" label="Zutat hinzufügen"> <q-btn size="sm" icon-right="mdi-plus" color="positive" label="Zutat hinzufügen">
<q-menu anchor="center middle" self="center middle"> <q-menu anchor="center middle" self="center middle">
<div class="full-width row justify-around q-gutter-sm q-pa-sm"> <div class="full-width row justify-around q-gutter-sm q-pa-sm">
@ -133,12 +138,7 @@
</div> </div>
<div class="full-width row jusitfy-between q-gutter-sm q-pa-sm"> <div class="full-width row jusitfy-between q-gutter-sm q-pa-sm">
<q-btn v-close-popup label="Abbrechen" @click="cancelAddIngredient" /> <q-btn v-close-popup label="Abbrechen" @click="cancelAddIngredient" />
<q-btn <q-btn v-close-popup label="Speichern" color="positive" @click="addIngredient" />
v-close-popup
label="Speichern"
color="positive"
@click="addIngredient(volume)"
/>
</div> </div>
</q-menu> </q-menu>
</q-btn> </q-btn>
@ -147,34 +147,39 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, PropType, ref } from 'vue'; import { computed, defineComponent, PropType, ref, onBeforeMount } from 'vue';
import { DrinkPriceVolume, usePricelistStore } from '../../store'; import { usePricelistStore } from '../../store';
export default defineComponent({ export default defineComponent({
name: 'Ingredients', name: 'Ingredients',
props: { props: {
ingredients: { modelValue: {
type: Array as PropType<FG.Ingredient[]>, type: Object as PropType<Array<FG.Ingredient>>,
required: true, required: true,
}, },
volume: { editable: {
type: Object /*as PropType<DrinkPriceVolume>*/, type: Boolean,
required: true, default: false,
}, },
}, },
emits: { emits: {
updateDrink: () => true, 'update:modelValue': (val: Array<FG.Ingredient>) => val,
addIngredient: (val: FG.Ingredient, volume: DrinkPriceVolume) =>
(val.drink_ingredient || val.extra_ingredient) && volume,
deleteIngredient: (ingredient: FG.Ingredient, volume: DrinkPriceVolume) =>
(ingredient.drink_ingredient || ingredient.extra_ingredient) && volume,
}, },
setup(_, { emit }) { setup(props, { emit }) {
onBeforeMount(() => {
edit_ingredients.value = [];
props.modelValue.forEach((a) => {
edit_ingredients.value.push(Object.assign({}, a));
});
console.log(edit_ingredients);
});
const store = usePricelistStore(); const store = usePricelistStore();
const edit_ingredients = ref<Array<FG.Ingredient>>([]);
const newIngredient = ref<FG.Drink | FG.ExtraIngredient>(); const newIngredient = ref<FG.Drink | FG.ExtraIngredient>();
const newIngredientVolume = ref<number>(0); const newIngredientVolume = ref<number>(0);
function addIngredient(volume: DrinkPriceVolume) { function addIngredient() {
let _ingredient: FG.Ingredient; let _ingredient: FG.Ingredient;
if ((<FG.Drink>newIngredient.value)?.volume && newIngredient.value) { if ((<FG.Drink>newIngredient.value)?.volume && newIngredient.value) {
_ingredient = { _ingredient = {
@ -193,20 +198,27 @@ export default defineComponent({
extra_ingredient: <FG.ExtraIngredient>newIngredient.value, extra_ingredient: <FG.ExtraIngredient>newIngredient.value,
}; };
} }
emit('addIngredient', _ingredient, volume); edit_ingredients.value.push(_ingredient);
emit('update:modelValue', edit_ingredients.value);
cancelAddIngredient(); cancelAddIngredient();
} }
function updateDrink() {
console.log('updateDrink from Ingredients'); function updateValue(value: number, initValue: number) {
emit('updateDrink'); console.log('updateValue', value, initValue);
emit('update:modelValue', edit_ingredients.value);
} }
function cancelAddIngredient() { function cancelAddIngredient() {
setTimeout(() => { setTimeout(() => {
(newIngredient.value = undefined), (newIngredientVolume.value = 0); (newIngredient.value = undefined), (newIngredientVolume.value = 0);
}, 200); }, 200);
} }
function deleteIngredient(ingredient: FG.Ingredient, volume: DrinkPriceVolume) { function deleteIngredient(ingredient: FG.Ingredient) {
emit('deleteIngredient', ingredient, volume); const index = edit_ingredients.value.findIndex((a) => a.id === ingredient.id);
if (index > -1) {
edit_ingredients.value.splice(index, 1);
}
emit('update:modelValue', edit_ingredients.value);
} }
const drinks = computed(() => const drinks = computed(() =>
store.drinks.filter((drink) => { store.drinks.filter((drink) => {
@ -227,9 +239,10 @@ export default defineComponent({
newIngredient, newIngredient,
newIngredientVolume, newIngredientVolume,
cancelAddIngredient, cancelAddIngredient,
updateDrink, updateValue,
deleteIngredient, deleteIngredient,
get_drink_ingredient_name, get_drink_ingredient_name,
edit_ingredients,
}; };
}, },
}); });

View File

@ -0,0 +1,94 @@
<template>
<q-card>
<q-card-section>
<div class="text-h6">Getränk Bearbeiten</div>
</q-card-section>
<q-card-section>
<div class="fit row">
<q-input
v-model="edit_drink.article_id"
class="col-xs-12 col-sm-6 q-pa-sm"
filled
label="Artikelnummer"
dense
/>
<q-input
v-model="edit_drink.volume"
class="col-xs-12 col-sm-6 q-pa-sm"
filled
label="Inhalt"
dense
suffix="L"
/>
<q-input
v-model="edit_drink.package_size"
class="col-xs-12 col-sm-6 q-pa-sm"
filled
label="Gebindegröße"
dense
/>
<q-input
v-model="edit_drink.cost_per_package"
class="col-xs-12 col-sm-6 q-pa-sm"
filled
label="Preis Gebinde"
suffix="€"
dense
/>
<q-input
v-model="edit_drink.cost_per_volume"
class="col-xs-12 col-sm-6 q-pa-sm q-pb-lg"
filled
label="Preis pro L"
hint="Inkl. 19% Mehrwertsteuer"
suffix="€"
dense
/>
</div>
</q-card-section>
<q-card-section>
<drink-price-volumes v-model="edit_drink.volumes" editable />
</q-card-section>
<q-card-actions class="justify-around">
<q-btn label="Abbrechen" @click="cancel" />
<q-btn label="Speichern" color="primary" @click="save" />
</q-card-actions>
</q-card>
</template>
<script lang="ts">
import { defineComponent, PropType, ref, onBeforeMount } from 'vue';
import { Drink, DrinkPriceVolume } from '../store';
import DrinkPriceVolumes from './CalculationTable/DrinkPriceVolumes.vue';
import { calc_volume } from 'src/plugins/pricelist/utils/utils';
export default defineComponent({
name: 'DrinkModify',
components: { DrinkPriceVolumes },
props: {
drink: {
type: Object as PropType<Drink>,
required: true,
},
},
emits: { save: () => true, cancel: () => true },
setup(props, { emit }) {
onBeforeMount(() => {
edit_drink.value = Object.assign({}, props.drink);
});
const edit_drink = ref<Drink>();
function save() {
emit('save');
}
function cancel() {
emit('cancel');
}
function updateVolume(volume: DrinkPriceVolume) {
if (volume) {
console.log('edit_volume', volume);
volume.volume = calc_volume(volume);
}
}
return { edit_drink, save, cancel, updateVolume };
},
});
</script>

View File

@ -27,7 +27,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, onBeforeMount, ref } from 'vue'; import { defineComponent, onBeforeMount, ref } from 'vue';
import Ingredients from 'src/plugins/pricelist/components/CalculationTable/Ingredients.vue'; import Ingredients from 'src/plugins/pricelist/components/CalculationTable/Ingredients.vue';
import { DrinkPriceVolume, usePricelistStore } from 'src/plugins/pricelist/store'; import { DrinkPriceVolume, usePricelistStore } from 'src/plugins/pricelist/store';
export default defineComponent({ export default defineComponent({
@ -39,7 +39,7 @@ export default defineComponent({
store.min_prices.forEach((min_price) => { store.min_prices.forEach((min_price) => {
(<DrinkPriceVolume>volume.value).min_prices.push({ (<DrinkPriceVolume>volume.value).min_prices.push({
percentage: min_price, percentage: min_price,
price: computed<number>(() => { price: /*computed<number>(() => {
let retVal = 0; let retVal = 0;
let extraIngredientPrice = 0; let extraIngredientPrice = 0;
volume.value.ingredients.forEach((ingredient) => { volume.value.ingredients.forEach((ingredient) => {
@ -55,7 +55,7 @@ export default defineComponent({
} }
}); });
return (retVal * min_price) / 100 + extraIngredientPrice; return (retVal * min_price) / 100 + extraIngredientPrice;
}), }) */ 0,
}); });
}); });
}); });

View File

@ -1,21 +1,20 @@
import { api } from 'src/boot/axios'; import { api } from 'src/boot/axios';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { AxiosResponse } from 'axios'; import { AxiosResponse } from 'axios';
import { computed, ComputedRef, WritableComputedRef } from 'vue'; import {
calc_volume,
calc_cost_per_volume,
calc_all_min_prices,
} from 'src/plugins/pricelist/utils/utils';
interface MinPrice extends Omit<FG.MinPrices, 'price'> { interface DrinkPriceVolume extends Omit<FG.DrinkPriceVolume, 'volume'> {
price?: WritableComputedRef<number>;
}
interface DrinkPriceVolume extends Omit<Omit<FG.DrinkPriceVolume, 'volume'>, 'min_prices'> {
_volume: number; _volume: number;
volume?: WritableComputedRef<number>; volume?: number;
min_prices: MinPrice[];
} }
interface Drink extends Omit<Omit<FG.Drink, 'cost_per_volume'>, 'volumes'> { interface Drink extends Omit<Omit<FG.Drink, 'cost_per_volume'>, 'volumes'> {
volumes: DrinkPriceVolume[]; volumes: DrinkPriceVolume[];
cost_per_volume: WritableComputedRef<number | undefined>; cost_per_volume?: number;
_cost_per_volume?: number; _cost_per_volume?: number;
} }
@ -26,23 +25,7 @@ class DrinkPriceVolume implements DrinkPriceVolume {
this.prices = prices; this.prices = prices;
this.ingredients = ingredients; this.ingredients = ingredients;
this.min_prices = []; this.min_prices = [];
this.volume = computed<number>({ this.volume = calc_volume(this);
get: () => {
if (this.ingredients.some((ingredient) => !!ingredient.drink_ingredient)) {
let retVal = 0;
this.ingredients.forEach((ingredient) => {
if (ingredient.drink_ingredient?.volume) {
retVal += ingredient.drink_ingredient.volume;
}
});
this._volume = retVal;
return retVal;
} else {
return this._volume;
}
},
set: (val) => (this._volume = val),
});
} }
} }
@ -67,18 +50,7 @@ class Drink {
this.volume = volume; this.volume = volume;
this.cost_per_package = cost_per_package; this.cost_per_package = cost_per_package;
this._cost_per_volume = cost_per_volume; this._cost_per_volume = cost_per_volume;
this.cost_per_volume = computed({ this.cost_per_volume = calc_cost_per_volume(this);
get: () => {
if (!!this.volume && !!this.package_size && !!this.cost_per_package) {
const retVal =
((this.cost_per_package || 0) / ((this.volume || 0) * (this.package_size || 0))) * 1.19;
this._cost_per_volume = Math.round(retVal * 1000) / 1000;
}
return this._cost_per_volume;
},
set: (val) => (this._cost_per_volume = val),
});
this.tags = tags; this.tags = tags;
this.type = type; this.type = type;
this.volumes = []; this.volumes = [];
@ -164,7 +136,7 @@ export const usePricelistStore = defineStore({
}); });
this.drinks.push(_drink); this.drinks.push(_drink);
}); });
this.create_min_prices(); calc_all_min_prices(this.drinks, this.min_prices);
console.log(this.drinks); console.log(this.drinks);
}, },
sortPrices(volume: DrinkPriceVolume) { sortPrices(volume: DrinkPriceVolume) {
@ -217,7 +189,7 @@ export const usePricelistStore = defineStore({
_drink.volumes.push(_volume); _drink.volumes.push(_volume);
}); });
this.drinks.push(_drink); this.drinks.push(_drink);
this.create_min_prices(); calc_all_min_prices(this.drinks, this.min_prices);
}, },
async updateDrink(drink: Drink) { async updateDrink(drink: Drink) {
console.log(drink); console.log(drink);
@ -234,7 +206,7 @@ export const usePricelistStore = defineStore({
}); });
this.drinks[index] = _drink; this.drinks[index] = _drink;
} }
this.create_min_prices(); calc_all_min_prices(this.drinks, this.min_prices);
}, },
deleteDrink(drink: Drink) { deleteDrink(drink: Drink) {
api api
@ -271,46 +243,7 @@ export const usePricelistStore = defineStore({
}, },
async set_min_prices() { async set_min_prices() {
await api.post<Array<number>>('pricelist/settings/min_prices', this.min_prices); await api.post<Array<number>>('pricelist/settings/min_prices', this.min_prices);
this.create_min_prices(); calc_all_min_prices(this.drinks, this.min_prices);
},
create_min_prices() {
this.drinks.forEach((drink) => {
drink.volumes.forEach((volume) => {
volume.min_prices = [];
this.min_prices.forEach((min_price) => {
let computedMinPrice: ComputedRef;
if (drink.cost_per_volume) {
computedMinPrice = computed<number>(
() =>
(<number>(<unknown>drink.cost_per_volume) *
<number>(<unknown>volume.volume) *
min_price) /
100
);
} else {
computedMinPrice = computed<number>(() => {
let retVal = 0;
let extraIngredientPrice = 0;
volume.ingredients.forEach((ingredient) => {
if (ingredient.drink_ingredient) {
const _drink = usePricelistStore().drinks.find(
(a) => a.id === ingredient.drink_ingredient?.ingredient_id
);
retVal +=
ingredient.drink_ingredient.volume *
<number>(<unknown>_drink?.cost_per_volume);
}
if (ingredient.extra_ingredient) {
extraIngredientPrice += ingredient.extra_ingredient.price;
}
});
return (retVal * min_price) / 100 + extraIngredientPrice;
});
}
volume.min_prices.push({ percentage: min_price, price: computedMinPrice });
});
});
});
}, },
async upload_drink_picture(drink: Drink, file: File) { async upload_drink_picture(drink: Drink, file: File) {
const formData = new FormData(); const formData = new FormData();
@ -351,4 +284,4 @@ export const usePricelistStore = defineStore({
}, },
}); });
export { DrinkPriceVolume, MinPrice, Drink }; export { DrinkPriceVolume, Drink };

View File

@ -0,0 +1,71 @@
import { Drink, DrinkPriceVolume, usePricelistStore } from 'src/plugins/pricelist/store';
function calc_volume(volume: DrinkPriceVolume) {
if (volume.ingredients.some((ingredient) => !!ingredient.drink_ingredient)) {
let retVal = 0;
volume.ingredients.forEach((ingredient) => {
if (ingredient.drink_ingredient?.volume) {
retVal += ingredient.drink_ingredient.volume;
}
});
return retVal;
} else {
return volume._volume;
}
}
function calc_cost_per_volume(drink: Drink) {
let retVal = drink._cost_per_volume;
if (!!drink.volume && !!drink.package_size && !!drink.cost_per_package) {
retVal =
((drink.cost_per_package || 0) / ((drink.volume || 0) * (drink.package_size || 0))) * 1.19;
}
return retVal ? Math.round(retVal * 1000) / 1000 : retVal;
}
function calc_all_min_prices(drinks: Array<Drink>, min_prices: Array<number>) {
drinks.forEach((drink) => {
drink.volumes.forEach((volume) => {
volume.min_prices = calc_min_prices(volume, drink.cost_per_volume, min_prices);
});
});
}
function helper(volume: DrinkPriceVolume, min_price: number) {
let retVal = 0;
let extraIngredientPrice = 0;
volume.ingredients.forEach((ingredient) => {
if (ingredient.drink_ingredient) {
const _drink = usePricelistStore().drinks.find(
(a) => a.id === ingredient.drink_ingredient?.ingredient_id
);
retVal += ingredient.drink_ingredient.volume * <number>(<unknown>_drink?.cost_per_volume);
}
if (ingredient.extra_ingredient) {
extraIngredientPrice += ingredient.extra_ingredient.price;
}
});
return (retVal * min_price) / 100 + extraIngredientPrice;
}
function calc_min_prices(
volume: DrinkPriceVolume,
cost_per_volume: number | undefined,
min_prices: Array<number>
) {
const retVal: Array<FG.MinPrices> = [];
volume.min_prices = [];
min_prices.forEach((min_price) => {
let computedMinPrice: number;
if (cost_per_volume) {
computedMinPrice = (cost_per_volume * <number>volume.volume * min_price) / 100;
} else {
computedMinPrice = helper(volume, min_price);
}
retVal.push({ percentage: min_price, price: computedMinPrice });
});
return retVal;
}
export { calc_volume, calc_cost_per_volume, calc_all_min_prices, calc_min_prices };