diff --git a/src/plugins/pricelist/components/CalculationTable.vue b/src/plugins/pricelist/components/CalculationTable.vue index 82095e6..69ff0f1 100644 --- a/src/plugins/pricelist/components/CalculationTable.vue +++ b/src/plugins/pricelist/components/CalculationTable.vue @@ -3,7 +3,7 @@ v-model:pagination="pagination" title="Kalkulationstabelle" :columns="columns" - :data="drinks" + :rows="drinks" :visible-columns="visibleColumn" :dense="$q.screen.lt.md" row-key="id" @@ -237,8 +237,8 @@ {{ - drinks_props.row.cost_price_pro_volume.value - ? `${drinks_props.row.cost_price_pro_volume.value.toFixed(3)}€` + drinks_props.row.cost_price_pro_volume + ? `${drinks_props.row.cost_price_pro_volume.toFixed(3)}€` : 'o.A.' }} ingredient.drink_ingredient) ) " - v-model="drinks_props.row.cost_price_pro_volume.value" + v-model="drinks_props.row.cost_price_pro_volume" buttons label-cancel="Abbrechen" label-set="Speichern" @save="updateDrink(drinks_props.row)" > - {{ parseFloat(props.row.volume.value).toFixed(3) }}L + {{ parseFloat(props.row.volume).toFixed(3) }}L {{ min_price.percentage }}%
- {{ min_price.price.value.toFixed(3) }}€ + {{ min_price.price.toFixed(3) }}€
@@ -427,172 +427,6 @@ -
@@ -600,8 +434,9 @@ import { defineComponent, onBeforeMount, ref, ComputedRef, computed } from 'vue'; import PriceTable from 'src/plugins/pricelist/components/CalculationTable/PriceTable.vue'; import Ingredients from 'src/plugins/pricelist/components/CalculationTable/Ingredients.vue'; -import { StateInterface, useMainStore } from 'src/store'; -import { Store } from 'vuex'; +import { useMainStore } from 'src/store'; +import { Drink, DrinkPriceVolume, usePricelistStore } from 'src/plugins/pricelist/store'; + function sort(a: string | number, b: string | number) { if (a > b) return 1; @@ -613,9 +448,10 @@ export default defineComponent({ components: { PriceTable, Ingredients }, setup() { const mainStore = useMainStore(); + const store = usePricelistStore(); onBeforeMount(() => { - //store.actions.getPriceCalcColumn(user); + store.getPriceCalcColumn(user); }); const user = mainStore.currentUser.userid; @@ -684,7 +520,6 @@ export default defineComponent({ name: 'volume', label: 'Abgabe in l', field: 'volume', - format: (val: number) => `${val} L`, }, { name: 'min_prices', @@ -715,11 +550,10 @@ export default defineComponent({ field: 'public', }, ]; - /* const visibleColumn = computed({ - get: () => store.state.pricecalc_columns, + get: () => store.pricecalc_columns, set: (val) => { - store.actions.updatePriceCalcColumn(user, val); + store.updatePriceCalcColumn(user, val); }, }); const emptyVolume: DrinkPriceVolume = { @@ -736,7 +570,7 @@ export default defineComponent({ }; const newVolume = ref(emptyVolume); function addVolume(drink: Drink) { - store.actions.setVolume(>newVolume.value, drink); + store.setVolume(newVolume.value, drink); cancelAddVolume(); } function cancelAddVolume() { @@ -748,14 +582,15 @@ export default defineComponent({ } function updateVolume(volume: DrinkPriceVolume, drink: Drink) { console.log(volume); - store.actions.updateVolume(volume, drink); + store.updateVolume(volume, drink); } function deleteVolume(volume: FG.DrinkPriceVolume, drink: FG.Drink) { - store.actions.deleteVolume(volume, drink); + store.deleteVolume(volume, drink); } + // eslint-disable-next-line vue/return-in-computed-property const pagination = computed(() => { - rowsPerPage: store.state.drinks.length; + rowsPerPage: store.drinks.length; }); const emptyDrink: FG.Drink = { @@ -785,6 +620,7 @@ export default defineComponent({ ((newDrink.value.cost_price_package_netto || 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_price_pro_volume = Math.round(retVal * 1000) / 1000; } return newDrink.value.cost_price_pro_volume; @@ -794,24 +630,24 @@ export default defineComponent({ }, }); - const drinkTypes = computed(() => store.state.drinkTypes); + const drinkTypes = computed(() => store.drinkTypes); function addDrink() { - store.actions.setDrink(newDrink.value); + store.setDrink(newDrink.value); cancelAddDrink(); } function cancelAddDrink() { setTimeout(() => (newDrink.value = emptyDrink), 200); } function updateDrink(drink: Drink) { - store.actions.updateDrink(drink); + store.updateDrink(drink); } function deleteDrink(drink: Drink) { - store.actions.deleteDrink(drink); + store.deleteDrink(drink); } return { - drinks: computed(() => store.state.drinks), + drinks: computed(() => store.drinks), pagination, columns, column_calc, @@ -831,7 +667,7 @@ export default defineComponent({ updateDrink, deleteDrink, console, - };*/ + }; }, }); diff --git a/src/plugins/pricelist/components/CalculationTable/Ingredients.vue b/src/plugins/pricelist/components/CalculationTable/Ingredients.vue index 317bc13..7ee0657 100644 --- a/src/plugins/pricelist/components/CalculationTable/Ingredients.vue +++ b/src/plugins/pricelist/components/CalculationTable/Ingredients.vue @@ -146,7 +146,7 @@ diff --git a/src/plugins/pricelist/components/Drink.vue b/src/plugins/pricelist/components/Drink.vue deleted file mode 100644 index e3d9815..0000000 --- a/src/plugins/pricelist/components/Drink.vue +++ /dev/null @@ -1,160 +0,0 @@ - - - - - diff --git a/src/plugins/pricelist/components/ExtraIngredients.vue b/src/plugins/pricelist/components/ExtraIngredients.vue index a90af46..086c9e8 100644 --- a/src/plugins/pricelist/components/ExtraIngredients.vue +++ b/src/plugins/pricelist/components/ExtraIngredients.vue @@ -26,7 +26,7 @@ - + diff --git a/src/plugins/pricelist/routes/index.ts b/src/plugins/pricelist/routes/index.ts index 2978832..ebe7f4a 100644 --- a/src/plugins/pricelist/routes/index.ts +++ b/src/plugins/pricelist/routes/index.ts @@ -6,7 +6,7 @@ const mainRoutes: FG_Plugin.PluginRouteConfig[] = [ route: { path: 'drinks', name: 'drinks', - redirect: { name: 'drinks-pricelist' }, + redirect: { name: 'drinks-pricelist' } }, permissions: ['user'], children: [ @@ -18,22 +18,22 @@ const mainRoutes: FG_Plugin.PluginRouteConfig[] = [ route: { path: 'pricelist', name: 'drinks-pricelist', - component: () => import('../pages/PricelistP.vue'), - }, + component: () => import('../pages/PricelistP.vue') + } }, { title: 'Einstellungen', icon: 'mdi-coffee-to-go', shortcut: false, - permissions: ['pricelist_settings'], + permissions: ['user'], route: { path: 'settings', name: 'drinks-settings', - component: () => import('../pages/Settings.vue'), - }, - }, - ], - }, + component: () => import('../pages/Settings.vue') + } + } + ] + } ]; export default mainRoutes; diff --git a/src/plugins/pricelist/store.ts b/src/plugins/pricelist/store.ts index feb5648..b36729f 100644 --- a/src/plugins/pricelist/store.ts +++ b/src/plugins/pricelist/store.ts @@ -1,12 +1,154 @@ import { api } from 'src/boot/axios'; import { defineStore } from 'pinia'; +import { AxiosResponse } from 'axios'; +import { computed, WritableComputedRef } from 'vue'; + +interface MinPrice extends Omit { + price: WritableComputedRef | null; +} +interface DrinkPriceVolume extends Omit, 'min_prices'> { + _volume: number; + volume: WritableComputedRef | null; + min_prices: MinPrice[]; +} +interface Drink extends Omit, 'volumes'> { + volumes: DrinkPriceVolume[]; + cost_price_pro_volume: WritableComputedRef; + _cost_price_pro_volume?: number; +} + +class DrinkPriceVolume { + constructor({ id, volume, min_prices, prices, ingredients }: FG.DrinkPriceVolume, drink: Drink) { + this.id = id; + this._volume = volume; + this.prices = prices; + this.ingredients = ingredients; + this.min_prices = [ + { + percentage: 100, + price: create_min_prices(drink, this, 100), + }, + { + percentage: 250, + price: create_min_prices(drink, this, 250), + }, + { + percentage: 300, + price: create_min_prices(drink, this, 300), + }, + ]; + this.volume = computed({ + 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), + }); + } +} + +class Drink { + constructor({ + id, + article_id, + package_size, + name, + volume, + cost_price_pro_volume, + cost_price_package_netto, + tags, + type, + volumes, + }: FG.Drink) { + this.id = id; + this.article_id = article_id; + this.package_size = package_size; + this.name = name; + this.volume = volume; + this.cost_price_package_netto = cost_price_package_netto; + this._cost_price_pro_volume = cost_price_pro_volume; + this.cost_price_pro_volume = computed({ + get: () => { + if (!!this.volume && !!this.package_size && !!this.cost_price_package_netto) { + const retVal = + ((this.cost_price_package_netto || 0) / + ((this.volume || 0) * (this.package_size || 0))) * + 1.19; + this._cost_price_pro_volume = Math.round(retVal * 1000) / 1000; + } + + return this._cost_price_pro_volume; + }, + set: (val) => (this._cost_price_pro_volume = val), + }); + this.tags = tags; + this.type = type; + this.volumes = []; + //volumes.forEach(volume => { + // this.volumes.push(new DrinkPriceVolume(volume, this)); + //}); + } +} + +function create_min_prices(drink: Drink, volume: DrinkPriceVolume, percentage: number) { + if (drink.cost_price_pro_volume?.value) { + if (volume.ingredients.every((ingredient) => !!ingredient.drink_ingredient)) { + return computed(() => { + let retVal = (drink.cost_price_pro_volume?.value || 0) * (volume.volume?.value || 0); + volume.ingredients.forEach((ingredient) => { + if (ingredient.extra_ingredient) { + retVal += ingredient.extra_ingredient.price; + } + }); + retVal = (retVal * percentage) / 100; + return retVal; + }); + } else { + return computed( + () => + ((drink.cost_price_pro_volume?.value || 0) * (volume.volume?.value || 0) * percentage) / + 100 + ); + } + } else { + return computed(() => { + let retVal = 0; + volume.ingredients.forEach((ingredient) => { + if (ingredient.drink_ingredient) { + const _drink = usePricelistStore().drinks.find( + (a) => a.id === ingredient.drink_ingredient?.drink_ingredient_id + ); + retVal += + ingredient.drink_ingredient.volume * (_drink?.cost_price_pro_volume?.value || 0); + } + if (ingredient.extra_ingredient) { + retVal += ingredient.extra_ingredient.price; + } + }); + console.log(volume); + return (retVal * percentage) / 100; + }); + } +} export const usePricelistStore = defineStore({ id: 'pricelist', state: () => ({ drinkTypes: [] as Array, - drinks: [] as Array, + drinks: [] as Array, + extraIngredients: [] as Array, + pricecalc_columns: [] as Array, }), actions: { @@ -31,16 +173,212 @@ export const usePricelistStore = defineStore({ const itm = this.drinkTypes.filter((val) => val.id == drinkType.id); if (itm.length > 0) itm[0].name = drinkType.name; }, - async getDrinks(force = false) { + async getExtraIngredients() { + const { data } = await api.get>( + 'pricelist/ingredients/extraIngredients' + ); + this.extraIngredients = data; + }, + async setExtraIngredient(ingredient: FG.ExtraIngredient) { + const { data } = await api.post( + 'pricelist/ingredients/extraIngredients', + ingredient + ); + this.extraIngredients.push(data); + }, + async updateExtraIngredient(ingredient: FG.ExtraIngredient) { + const { data } = await api.put( + `pricelist/ingredients/extraIngredients/${ingredient.id}`, + ingredient + ); + const index = this.extraIngredients.findIndex((a) => a.id === ingredient.id); + if (index > -1) { + this.extraIngredients[index] = data; + } else { + this.extraIngredients.push(data); + } + }, + async deleteExtraIngredient(ingredient: FG.ExtraIngredient) { + await api.delete(`pricelist/ingredients/extraIngredients/${ingredient.id}`); + const index = this.extraIngredients.findIndex((a) => a.id === ingredient.id); + if (index > -1) { + this.extraIngredients.splice(index, 1); + } + }, + /*async getDrinks(force = false) { if (force || this.drinks.length == 0) { const { data } = await api.get>('/pricelist/drinks'); this.drinks = data; } return this.drinks; + },*/ + getDrinks() { + api + .get('pricelist/drinks') + .then((response: AxiosResponse) => { + this.drinks = []; + response.data.forEach((drink) => { + this.drinks.push(new Drink(drink)); + }); + this.drinks.forEach((drink) => { + const _drink = response.data.find((a) => a.id === drink.id); + _drink?.volumes.forEach((volume) => { + drink.volumes.push(new DrinkPriceVolume(volume, drink)); + }); + }); + console.log(this.drinks); + }) + .catch((err) => console.warn(err)); }, - async createDrink(drink: FG.Drink) { - await api.post('/pricelist/drinks', drink); - this.drinks.push(drink); + setPrice(price: FG.DrinkPrice, volume: DrinkPriceVolume) { + api + .post(`pricelist/volumes/${volume.id}/prices`, price) + .then((response: AxiosResponse) => { + volume.prices.push(response.data); + this.sortPrices(volume); + }) + .catch((err) => console.warn(err)); + }, + sortPrices(volume: DrinkPriceVolume) { + volume.prices.sort((a, b) => { + if (a.price > b.price) return 1; + if (b.price > a.price) return -1; + return 0; + }); + }, + deletePrice(price: FG.DrinkPrice, volume: FG.DrinkPriceVolume) { + 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)); + }, + updatePrice(price: FG.DrinkPrice, volume: DrinkPriceVolume) { + api + .put(`pricelist/prices/${price.id}`, price) + .then((response: AxiosResponse) => { + const index = volume.prices.findIndex((a) => a.id === price.id); + if (index > -1) { + this.sortPrices(volume); + } + }) + .catch((err) => console.log(err)); + }, + setVolume(volume: DrinkPriceVolume, drink: Drink) { + console.log(volume); + api + .post(`pricelist/drinks/${drink.id}/volumes`, { + ...volume, + volume: volume.volume, + }) + .then((response: AxiosResponse) => { + drink.volumes.push(new DrinkPriceVolume(response.data, drink)); + }) + .catch((err) => console.warn(err)); + }, + updateVolume(volume: DrinkPriceVolume, drink: Drink) { + api + .put(`pricelist/volumes/${volume.id}`, { + ...volume, + volume: volume.volume?.value, + }) + .catch((err) => console.warn(err)); + }, + deleteVolume(volume: FG.DrinkPriceVolume, drink: FG.Drink) { + api + .delete(`pricelist/volumes/${volume.id}`) + .then(() => { + const index = drink.volumes.findIndex((a) => a.id === volume.id); + if (index > -1) { + drink.volumes.splice(index, 1); + } + }) + .catch((err) => console.warn(err)); + }, + setIngredient(ingredient: FG.Ingredient, volume: DrinkPriceVolume) { + api + .post(`pricelist/volumes/${volume.id}/ingredients`, ingredient) + .then((response: AxiosResponse) => { + volume.ingredients.push(response.data); + }) + .catch((err) => console.warn(err)); + }, + updateIngredient(ingredient: FG.Ingredient, volume: DrinkPriceVolume) { + api + .put(`pricelist/ingredients/${ingredient.id}`, ingredient) + .then((response: AxiosResponse) => { + //const index = volume.ingredients.findIndex(a => a.id === response.data.id); + //if (index > -1) { + // volume.ingredients[index] = response.data; + //} + }) + .catch((err) => console.warn(err)); + }, + deleteIngredient(ingredient: FG.Ingredient, volume: DrinkPriceVolume) { + 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)); + }, + setDrink(drink: FG.Drink) { + api + .post('pricelist/drinks', drink) + .then((response: AxiosResponse) => { + this.drinks.push(new Drink(response.data)); + const drink = this.drinks.find((a) => a.id === response.data.id); + response.data.volumes.forEach((volume) => { + drink?.volumes.push(new DrinkPriceVolume(volume, drink)); + }); + }) + .catch((err) => console.warn(err)); + }, + updateDrink(drink: Drink) { + api + .put(`pricelist/drinks/${drink.id}`, { + ...drink, + cost_price_pro_volume: drink.cost_price_pro_volume?.value, + }) + .catch((err) => console.warn(err)); + }, + deleteDrink(drink: Drink) { + api + .delete(`pricelist/drinks/${drink.id}`) + .then(() => { + const index = this.drinks.findIndex((a) => a.id === drink.id); + if (index > -1) { + this.drinks.splice(index, 1); + } + }) + .catch((err) => console.warn(err)); + }, + getPriceCalcColumn(userid: string) { + api + .get(`pricelist/users/${userid}/pricecalc_columns`) + .then(({ data }: AxiosResponse>) => { + if (data.length > 0) { + this.pricecalc_columns = data; + } + }) + .catch((err) => console.log(err)); + }, + updatePriceCalcColumn(userid: string, data: Array) { + api + .put(`pricelist/users/${userid}/pricecalc_columns`, data) + .then(() => { + this.pricecalc_columns = data; + }) + .catch((err) => console.log(err)); }, }, }); + +export { create_min_prices, DrinkPriceVolume, MinPrice, Drink };