release v2.0.0 #4
|
@ -11,14 +11,6 @@
|
|||
grid
|
||||
: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>
|
||||
<div class="row justify-end q-gutter-sm">
|
||||
<search-input v-model="search" :keys="search_keys" />
|
||||
|
@ -27,11 +19,6 @@
|
|||
<min-price-setting />
|
||||
</q-menu>
|
||||
</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
|
||||
v-model="visibleColumn"
|
||||
multiple
|
||||
|
@ -45,6 +32,12 @@
|
|||
option-value="name"
|
||||
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>
|
||||
</template>
|
||||
<template #item="props">
|
||||
|
@ -145,7 +138,12 @@
|
|||
</template>
|
||||
</q-table>
|
||||
<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>
|
||||
</template>
|
||||
|
||||
|
@ -154,7 +152,6 @@ import { defineComponent, onBeforeMount, ComputedRef, computed, ref } from 'vue'
|
|||
import { useMainStore } from 'src/stores';
|
||||
import { Drink, usePricelistStore, DrinkPriceVolume } from 'src/plugins/pricelist/store';
|
||||
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 DrinkPriceVolumes from 'src/plugins/pricelist/components/CalculationTable/DrinkPriceVolumes.vue';
|
||||
import DrinkModify from './DrinkModify.vue';
|
||||
|
@ -168,7 +165,6 @@ export default defineComponent({
|
|||
components: {
|
||||
SearchInput,
|
||||
MinPriceSetting,
|
||||
NewDrink,
|
||||
DrinkPriceVolumes,
|
||||
DrinkModify,
|
||||
},
|
||||
|
@ -349,8 +345,11 @@ export default defineComponent({
|
|||
void store.updateDrink(drink);
|
||||
}
|
||||
|
||||
function deleteDrink(drink: Drink) {
|
||||
store.deleteDrink(drink);
|
||||
function deleteDrink() {
|
||||
if (editDrink.value) {
|
||||
store.deleteDrink(editDrink.value);
|
||||
}
|
||||
editDrink.value = undefined;
|
||||
}
|
||||
|
||||
const showNewDrink = ref(false);
|
||||
|
@ -390,7 +389,26 @@ export default defineComponent({
|
|||
key: '',
|
||||
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(
|
||||
drink: Drink,
|
||||
|
@ -409,22 +427,19 @@ export default defineComponent({
|
|||
await store.deleteVolume(volume, drink);
|
||||
}
|
||||
console.log(drink);
|
||||
await store.updateDrink(drink);
|
||||
if (deletePic || drinkPic) {
|
||||
let loading = imageloading.value.find((a) => a.id === drink.id);
|
||||
if (loading) {
|
||||
loading.loading = true;
|
||||
} else {
|
||||
loading = { id: drink.id, loading: true };
|
||||
imageloading.value.push(loading);
|
||||
if (drink.id > 0) {
|
||||
await store.updateDrink(drink);
|
||||
} else {
|
||||
const _drink = await store.setDrink(drink);
|
||||
if (editDrink.value) {
|
||||
editDrink.value.id = _drink.id;
|
||||
}
|
||||
if (deletePic) {
|
||||
await deletePicture();
|
||||
}
|
||||
if (drinkPic instanceof File) {
|
||||
await savePicture(drinkPic);
|
||||
}
|
||||
loading.loading = false;
|
||||
}
|
||||
if (deletePic) {
|
||||
await deletePicture();
|
||||
}
|
||||
if (drinkPic instanceof File) {
|
||||
await savePicture(drinkPic);
|
||||
}
|
||||
editDrink.value = undefined;
|
||||
notLoading.value = true;
|
||||
|
@ -469,6 +484,7 @@ export default defineComponent({
|
|||
get_volumes,
|
||||
notLoading,
|
||||
getImageLoading,
|
||||
newDrink,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
/>
|
||||
</div>
|
||||
<div v-if="editable" class="full-width row q-gutter-sm justify-between">
|
||||
<q-input v-model="newStep" filled label="Arbeitsschritt" />
|
||||
<q-btn label="Schritt hinzufügen" @click="addStep" />
|
||||
<q-input v-model="newStep" filled label="Arbeitsschritt" dense />
|
||||
<q-btn label="Schritt hinzufügen" dense @click="addStep" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -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>
|
|
@ -3,6 +3,26 @@
|
|||
<q-card-section>
|
||||
<div class="text-h6">Getränk Bearbeiten</div>
|
||||
</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-img :src="image" style="max-height: 256px" fit="contain" />
|
||||
<div class="full-width row">
|
||||
|
@ -90,9 +110,11 @@
|
|||
dense
|
||||
/>
|
||||
<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"
|
||||
filled
|
||||
:outlined="auto_cost_per_volume"
|
||||
:filled="!auto_cost_per_volume"
|
||||
:readonly="auto_cost_per_volume"
|
||||
label="Preis pro L"
|
||||
hint="Inkl. 19% Mehrwertsteuer"
|
||||
suffix="€"
|
||||
|
@ -115,6 +137,7 @@
|
|||
</q-card-section>
|
||||
<q-card-actions class="justify-around">
|
||||
<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-card-actions>
|
||||
</q-card>
|
||||
|
@ -123,7 +146,7 @@
|
|||
import { defineComponent, PropType, ref, onBeforeMount, computed } from 'vue';
|
||||
import { Drink, DrinkPriceVolume, usePricelistStore } from '../store';
|
||||
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 config from 'src/config';
|
||||
export default defineComponent({
|
||||
|
@ -141,7 +164,8 @@ export default defineComponent({
|
|||
toDeleteObjects: DeleteObjects,
|
||||
drinkPic: File | undefined,
|
||||
deletePic: boolean
|
||||
) => drink && toDeleteObjects || drinkPic || deletePic,
|
||||
) => (drink && toDeleteObjects) || drinkPic || deletePic,
|
||||
delete: () => true,
|
||||
cancel: () => true,
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
|
@ -235,6 +259,42 @@ export default defineComponent({
|
|||
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 {
|
||||
edit_drink,
|
||||
save,
|
||||
|
@ -251,6 +311,11 @@ export default defineComponent({
|
|||
drinkPic,
|
||||
imagePreview,
|
||||
delete_pic,
|
||||
types: computed(() => store.drinkTypes),
|
||||
can_delete,
|
||||
delete_drink,
|
||||
auto_cost_per_volume,
|
||||
cost_per_volume,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -147,15 +147,6 @@ export const usePricelistStore = defineStore({
|
|||
});
|
||||
},
|
||||
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}`);
|
||||
},
|
||||
async deleteVolume(volume: DrinkPriceVolume, drink: Drink) {
|
||||
|
@ -166,19 +157,9 @@ export const usePricelistStore = defineStore({
|
|||
}
|
||||
},
|
||||
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}`);
|
||||
},
|
||||
async setDrink(drink: FG.Drink) {
|
||||
async setDrink(drink: Drink) {
|
||||
const { data } = await api.post<FG.Drink>('pricelist/drinks', {
|
||||
...drink,
|
||||
});
|
||||
|
@ -189,6 +170,7 @@ export const usePricelistStore = defineStore({
|
|||
});
|
||||
this.drinks.push(_drink);
|
||||
calc_all_min_prices(this.drinks, this.min_prices);
|
||||
return _drink;
|
||||
},
|
||||
async updateDrink(drink: Drink) {
|
||||
const { data } = await api.put<FG.Drink>(`pricelist/drinks/${drink.id}`, {
|
||||
|
|
Loading…
Reference in New Issue