update logic
This commit is contained in:
parent
20490ef9b6
commit
8d18e5838e
@ -1,6 +0,0 @@
|
|||||||
DB_SERVER=localhost
|
|
||||||
DB_NAME=inventur
|
|
||||||
DB_USER=inventur
|
|
||||||
DB_PASSWORD=inventur
|
|
||||||
|
|
||||||
NODE_ENV=production
|
|
||||||
192
app/js/App.vue
192
app/js/App.vue
@ -23,6 +23,8 @@
|
|||||||
<InventoryTable
|
<InventoryTable
|
||||||
ref="inventory"
|
ref="inventory"
|
||||||
:articles="articles"
|
:articles="articles"
|
||||||
|
:groups="groups"
|
||||||
|
:dimensions="dimensions"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -37,120 +39,11 @@
|
|||||||
id="article"
|
id="article"
|
||||||
class="col s12"
|
class="col s12"
|
||||||
>
|
>
|
||||||
<div
|
<ArticlesView
|
||||||
v-for="(a, index) in articles"
|
:articles="articles"
|
||||||
:key="'article_'+index"
|
:groups="groups"
|
||||||
class="card"
|
:dimensions="dimensions"
|
||||||
>
|
/>
|
||||||
<div class="card-content row">
|
|
||||||
<span class="card-title">{{ a.name }}</span>
|
|
||||||
<div class="input-field inline col s8">
|
|
||||||
<input
|
|
||||||
:id="'a_name_'+index"
|
|
||||||
v-model="a.name"
|
|
||||||
placeholder="Artikelname"
|
|
||||||
class="validate"
|
|
||||||
>
|
|
||||||
<label
|
|
||||||
:for="'a_name_'+index"
|
|
||||||
class="active"
|
|
||||||
>Name</label>
|
|
||||||
</div>
|
|
||||||
<div class="input-field inline col s4">
|
|
||||||
<input
|
|
||||||
:id="'a_short_'+index"
|
|
||||||
v-model="a.short"
|
|
||||||
placeholder="Kurzname"
|
|
||||||
class="validate"
|
|
||||||
>
|
|
||||||
<label
|
|
||||||
:for="'a_short_'+index"
|
|
||||||
class="active"
|
|
||||||
>Kürzel</label>
|
|
||||||
</div>
|
|
||||||
<div class="input-field col s8">
|
|
||||||
<input
|
|
||||||
:id="'a_csize_'+index"
|
|
||||||
v-model.number="a.content.size"
|
|
||||||
placeholder="Gesamtinhalt"
|
|
||||||
type="number"
|
|
||||||
class="validate"
|
|
||||||
step="0.01"
|
|
||||||
>
|
|
||||||
<label
|
|
||||||
:for="'a_csize_'+index"
|
|
||||||
class="active"
|
|
||||||
>Gesamtinhalt</label>
|
|
||||||
</div>
|
|
||||||
<div class="input-field col s4">
|
|
||||||
<input
|
|
||||||
:id="'a_dim_'+index"
|
|
||||||
v-model="a.dimension"
|
|
||||||
placeholder="Dimension"
|
|
||||||
class="validate"
|
|
||||||
max="5"
|
|
||||||
>
|
|
||||||
<label
|
|
||||||
:for="'a_dim_'+index"
|
|
||||||
class="active"
|
|
||||||
>Dimension</label>
|
|
||||||
<span class="helper-text">z.B. Liter(l), Stück(Stk.)</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="input-field col s4">
|
|
||||||
<input
|
|
||||||
:id="'a_psize_'+index"
|
|
||||||
v-model.number="a.portion.size"
|
|
||||||
placeholder="Gesamtinhalt"
|
|
||||||
type="number"
|
|
||||||
class="validate"
|
|
||||||
step="0.01"
|
|
||||||
max="5"
|
|
||||||
>
|
|
||||||
<label
|
|
||||||
:for="'a_psize_'+index"
|
|
||||||
class="active"
|
|
||||||
>Portionsinhalt</label>
|
|
||||||
</div>
|
|
||||||
<div class="input-field col s4">
|
|
||||||
<input
|
|
||||||
:id="'a_ptype_'+index"
|
|
||||||
v-model="a.portion.type"
|
|
||||||
placeholder="Art"
|
|
||||||
class="validate"
|
|
||||||
max="5"
|
|
||||||
>
|
|
||||||
<label
|
|
||||||
:for="'a_ptype_'+index"
|
|
||||||
class="active"
|
|
||||||
>Portionsbezeichnung</label>
|
|
||||||
</div>
|
|
||||||
<div class="input-field col s4">
|
|
||||||
<input
|
|
||||||
:id="'a_pprice_'+index"
|
|
||||||
v-model.number="a.portion.price"
|
|
||||||
placeholder="Preis"
|
|
||||||
type="number"
|
|
||||||
step="0.01"
|
|
||||||
class="validate"
|
|
||||||
>
|
|
||||||
<label
|
|
||||||
:for="'a_pprice_'+index"
|
|
||||||
class="active"
|
|
||||||
>Portionspreis in €</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col s12 right">
|
|
||||||
<span class="right">Gesamtpreis {{ a.ContentPrice }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-action">
|
|
||||||
<a
|
|
||||||
class
|
|
||||||
href="#"
|
|
||||||
>Artikel löschen</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
@ -165,17 +58,6 @@
|
|||||||
<i class="large material-icons">more_vert</i>
|
<i class="large material-icons">more_vert</i>
|
||||||
</a>
|
</a>
|
||||||
<ul>
|
<ul>
|
||||||
<li v-show="view == 'article'">
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
class="btn-floating tooltipped"
|
|
||||||
data-position="left"
|
|
||||||
data-tooltip="Artikelliste speichern"
|
|
||||||
@click="storeArticles"
|
|
||||||
>
|
|
||||||
<i class="material-icons">save</i>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li v-show="view == 'article'">
|
<li v-show="view == 'article'">
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
@ -217,20 +99,23 @@
|
|||||||
<script>
|
<script>
|
||||||
import Calculator from './components/Calculator';
|
import Calculator from './components/Calculator';
|
||||||
import InventoryTable from './components/InventoryTable';
|
import InventoryTable from './components/InventoryTable';
|
||||||
|
import ArticlesView from './components/ArticlesView';
|
||||||
import NavigationBar from './components/NavigationBar';
|
import NavigationBar from './components/NavigationBar';
|
||||||
import {Article, thawArticle} from './model/article';
|
import {Article, thawArticle} from './model/article';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "App",
|
name: "App",
|
||||||
components: { InventoryTable, NavigationBar, Calculator },
|
components: { InventoryTable, NavigationBar, Calculator, ArticlesView },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
articles: [],
|
articles: [],
|
||||||
|
dimensions: [],
|
||||||
|
groups: [],
|
||||||
bon: [],
|
bon: [],
|
||||||
ready: false,
|
|
||||||
caretPosition: 0,
|
caretPosition: 0,
|
||||||
fab: null,
|
fab: null,
|
||||||
view: "inventory",
|
view: "article",
|
||||||
|
location: 'fairwertbar'
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -245,9 +130,14 @@ export default {
|
|||||||
default:
|
default:
|
||||||
return "red";
|
return "red";
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
ready() {
|
||||||
|
return this.dimensions.length && this.groups.length;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created: function() {
|
created: function() {
|
||||||
|
this.loadDimensions();
|
||||||
|
this.loadGroups();
|
||||||
this.loadArticles();
|
this.loadArticles();
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -261,35 +151,59 @@ export default {
|
|||||||
addArticle: function() {
|
addArticle: function() {
|
||||||
this.articles.push(new Article());
|
this.articles.push(new Article());
|
||||||
},
|
},
|
||||||
storeArticles: function() {
|
loadDimensions: function() {
|
||||||
|
var app = this;
|
||||||
this.$http
|
this.$http
|
||||||
.post(
|
.get("api/dimension")
|
||||||
"/api/artikel",
|
|
||||||
JSON.stringify(this.articles)
|
|
||||||
)
|
|
||||||
.then(response => {
|
.then(response => {
|
||||||
this.$M.toast({ html: response.body });
|
return response.data;
|
||||||
|
})
|
||||||
|
.then(json => {
|
||||||
|
if (json != null) {
|
||||||
|
json.forEach(element => {
|
||||||
|
app.dimensions.push(element);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.$M.toast({ html: "Dimensionen wurden geladen." });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
loadGroups: function() {
|
||||||
|
var app = this;
|
||||||
|
this.$http
|
||||||
|
.get("api/group")
|
||||||
|
.then(response => {
|
||||||
|
return response.data;
|
||||||
|
})
|
||||||
|
.then(json => {
|
||||||
|
if (json != null) {
|
||||||
|
json.forEach(element => {
|
||||||
|
app.groups.push(element);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.$M.toast({ html: "Artikelgruppen wurden geladen." });
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
loadArticles: function() {
|
loadArticles: function() {
|
||||||
var app = this;
|
var app = this;
|
||||||
this.$http
|
this.$http
|
||||||
.get("api/artikel/theater")
|
.get("api/artikel")
|
||||||
.then(response => {
|
.then(response => {
|
||||||
return response.data;
|
return response.data;
|
||||||
})
|
})
|
||||||
.then(json => {
|
.then(json => {
|
||||||
console.log(json);
|
if (json != null) {
|
||||||
json.forEach(element => {
|
json.forEach(element => {
|
||||||
app.articles.push(thawArticle(element));
|
app.articles.push(thawArticle(element));
|
||||||
});
|
});
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.$M.toast({ html: "Artikel wurden geladen." });
|
this.$M.toast({ html: "Artikel wurden geladen." });
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
this.$M.updateTextFields();
|
this.$M.updateTextFields();
|
||||||
app.ready = true;
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
exportInventur() {
|
exportInventur() {
|
||||||
|
|||||||
315
app/js/components/ArticleCard.vue
Normal file
315
app/js/components/ArticleCard.vue
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="card"
|
||||||
|
>
|
||||||
|
<div class="card-content">
|
||||||
|
<span class="card-title">
|
||||||
|
{{ article.name }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-tabs">
|
||||||
|
<ul class="tabs tabs-fixed-width">
|
||||||
|
<li class="tab">
|
||||||
|
<a
|
||||||
|
:href="'#' + identifier + '_info'"
|
||||||
|
class="active"
|
||||||
|
>Info</a>
|
||||||
|
</li>
|
||||||
|
<li class="tab">
|
||||||
|
<a :href="'#' + identifier + '_variants'">Varianten</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-content">
|
||||||
|
<div
|
||||||
|
:id="identifier + '_info'"
|
||||||
|
class="row"
|
||||||
|
>
|
||||||
|
<div class="input-field inline col s8">
|
||||||
|
<input
|
||||||
|
:id="'a_name_' + article.id"
|
||||||
|
v-model="article.name"
|
||||||
|
placeholder="Artikelname"
|
||||||
|
class="validate"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
:for="'a_name_' + article.id"
|
||||||
|
class="active"
|
||||||
|
>Name</label>
|
||||||
|
</div>
|
||||||
|
<div class="input-field inline col s4">
|
||||||
|
<input
|
||||||
|
:id="'a_short_' + article.id"
|
||||||
|
v-model="article.short"
|
||||||
|
placeholder="Kurzname"
|
||||||
|
class="validate"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
:for="'a_short_' + article.id"
|
||||||
|
class="active"
|
||||||
|
>Kürzel</label>
|
||||||
|
</div>
|
||||||
|
<div class="input-field col s4">
|
||||||
|
<materialize-select
|
||||||
|
:id="'a_group_' + article.id"
|
||||||
|
v-model.number="article.group"
|
||||||
|
:value="article.group"
|
||||||
|
placeholder="Artikelgruppe"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
v-for="group in groups"
|
||||||
|
:key="group.id"
|
||||||
|
:value="group.id"
|
||||||
|
>
|
||||||
|
{{ group.name }}
|
||||||
|
</option>
|
||||||
|
</materialize-select>
|
||||||
|
<label :for="'a_group_' + article.id">Artikelgruppe</label>
|
||||||
|
</div>
|
||||||
|
<div class="input-field col s4">
|
||||||
|
<input
|
||||||
|
:id="'a_csize_' + article.id"
|
||||||
|
v-model.number="article.content.size"
|
||||||
|
placeholder="Gesamtinhalt"
|
||||||
|
type="number"
|
||||||
|
class="validate"
|
||||||
|
step="0.01"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
:for="'a_csize_' + article.id"
|
||||||
|
class="active"
|
||||||
|
>Gesamtinhalt</label>
|
||||||
|
</div>
|
||||||
|
<div class="input-field col s4">
|
||||||
|
<materialize-select
|
||||||
|
:id="'a_dim_' + article.id"
|
||||||
|
v-model.number="article.dimension"
|
||||||
|
:value="article.dimension"
|
||||||
|
placeholder="Dimension"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
v-for="dim in dimensions"
|
||||||
|
:key="dim.id"
|
||||||
|
:value="dim.id"
|
||||||
|
>
|
||||||
|
{{ dim.name }}
|
||||||
|
</option>
|
||||||
|
</materialize-select>
|
||||||
|
<label :for="'a_dim_' + article.id">Dimension</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-field col s4">
|
||||||
|
<input
|
||||||
|
:id="'a_psize_' + article.id"
|
||||||
|
v-model.number="article.portion.size"
|
||||||
|
placeholder="Gesamtinhalt"
|
||||||
|
type="number"
|
||||||
|
class="validate"
|
||||||
|
step="0.01"
|
||||||
|
max="5"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
:for="'a_psize_' + article.id"
|
||||||
|
class="active"
|
||||||
|
>Portionsinhalt</label>
|
||||||
|
</div>
|
||||||
|
<div class="input-field col s4">
|
||||||
|
<MaterializeSelect
|
||||||
|
:id="'a_ptype_' + article.id"
|
||||||
|
v-model.number="article.portion.type"
|
||||||
|
:value="article.portion.type"
|
||||||
|
placeholder="Art"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
v-for="dim in dimensions"
|
||||||
|
:key="dim.id"
|
||||||
|
:value="dim.id"
|
||||||
|
>
|
||||||
|
{{ dim.name }}
|
||||||
|
</option>
|
||||||
|
</MaterializeSelect>
|
||||||
|
<label :for="'a_ptype_' + article.id">Portionsbezeichnung</label>
|
||||||
|
</div>
|
||||||
|
<div class="input-field col s4">
|
||||||
|
<input
|
||||||
|
:id="'a_pprice_' + article.id"
|
||||||
|
v-model.number="article.portion.price"
|
||||||
|
placeholder="Preis"
|
||||||
|
type="number"
|
||||||
|
step="0.01"
|
||||||
|
class="validate"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
:for="'a_pprice_' + article.id"
|
||||||
|
class="active"
|
||||||
|
>Portionspreis in €</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col s12 right">
|
||||||
|
<span
|
||||||
|
class="right"
|
||||||
|
>Gesamtpreis
|
||||||
|
<TweenedNumber
|
||||||
|
:wert="article.ContentPrice"
|
||||||
|
:einheit="'€'"
|
||||||
|
:precision="2"
|
||||||
|
/></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
:id="identifier + '_variants'"
|
||||||
|
class="row"
|
||||||
|
>
|
||||||
|
<div class="col s12">
|
||||||
|
<ArticleVariant
|
||||||
|
v-for="(variant, index) in variants"
|
||||||
|
:key="'article_' + article.id + '_variant_' + index"
|
||||||
|
:identifier="'article_' + article.id + '_variant_' + index"
|
||||||
|
:variant="variant"
|
||||||
|
:article="article"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
@click="addVariant(article)"
|
||||||
|
>Variante hinzufügen</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-action">
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
@click="deleteArticle(article)"
|
||||||
|
>Artikel löschen</a>
|
||||||
|
<a
|
||||||
|
v-if="changed"
|
||||||
|
href="#"
|
||||||
|
@click="storeArticle(article)"
|
||||||
|
>Artikel speichern</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { Article, thawArticle } from '../model/article';
|
||||||
|
import MaterializeSelect from "./MaterializeSelect";
|
||||||
|
import TweenedNumber from "./TweenedNumber";
|
||||||
|
import ArticleVariant from "./ArticleVariant";
|
||||||
|
import { thawVariant, Variant } from '../model/variant';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Article",
|
||||||
|
components: {MaterializeSelect, TweenedNumber, ArticleVariant},
|
||||||
|
props: {
|
||||||
|
a: {
|
||||||
|
type: Object,
|
||||||
|
default() { return new Article(); }
|
||||||
|
},
|
||||||
|
dimensions: {
|
||||||
|
type: Array,
|
||||||
|
default() { return []; }
|
||||||
|
},
|
||||||
|
groups: {
|
||||||
|
type: Array,
|
||||||
|
default() { return []; }
|
||||||
|
},
|
||||||
|
identifier: {
|
||||||
|
type: String,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
changed: false,
|
||||||
|
article: null,
|
||||||
|
original: null,
|
||||||
|
variants: [],
|
||||||
|
tabs: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
article: {
|
||||||
|
handler(newValue, oldVal) {
|
||||||
|
this.changed = JSON.stringify(newValue) != this.original;
|
||||||
|
},
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.article = this.a;
|
||||||
|
this.original = JSON.stringify(this.a);
|
||||||
|
this.loadVariants(this.article);
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
var tabs = this.$el.getElementsByClassName("tabs")[0];
|
||||||
|
M.Tabs.init(tabs, {});
|
||||||
|
this.tabs = M.Tabs.getInstance(tabs);
|
||||||
|
this.$M.updateTextFields();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
storeArticle: function(article) {
|
||||||
|
this.$http
|
||||||
|
.post(
|
||||||
|
"/api/artikel" + (article.id > 0 ? '/' + article.id : ''),
|
||||||
|
JSON.stringify(article),
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then(response => {
|
||||||
|
this.$M.toast({ html: response.data + " Artikel aktualisiert." });
|
||||||
|
this.article = thawArticle(response.data);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.$M.toast({ html: response });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deleteArticle: function(article) {
|
||||||
|
this.$http
|
||||||
|
.delete(
|
||||||
|
"/api/artikel/" + article.id,
|
||||||
|
)
|
||||||
|
.then(response => {
|
||||||
|
this.$emit('delete-article', article);
|
||||||
|
this.$M.toast({ html: response.data + " Artikel gelöscht." });
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.$M.toast({ html: response });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
addVariant(article) {
|
||||||
|
var variant = new Variant();
|
||||||
|
variant.ArticleId = article.id;
|
||||||
|
this.variants.push(variant);
|
||||||
|
},
|
||||||
|
loadVariants: function(article) {
|
||||||
|
this.$http
|
||||||
|
.get(
|
||||||
|
"/api/artikel/" + article.id + '/varianten',
|
||||||
|
)
|
||||||
|
.then(response => {
|
||||||
|
return response.data;
|
||||||
|
})
|
||||||
|
.then(json => {
|
||||||
|
if (json != null) {
|
||||||
|
json.forEach(element => {
|
||||||
|
this.variants.push(thawVariant(element));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.$M.updateTextFields();
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.$M.toast({ html: error });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
100
app/js/components/ArticleVariant.vue
Normal file
100
app/js/components/ArticleVariant.vue
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<template>
|
||||||
|
<div class="row">
|
||||||
|
<div class="input-field col s4">
|
||||||
|
<input
|
||||||
|
:id="identifier + '_name'"
|
||||||
|
v-model="variant.name"
|
||||||
|
placeholder="Variantenbezeichnung"
|
||||||
|
type="text"
|
||||||
|
class="validate"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
:for="identifier + '_name'"
|
||||||
|
class="active"
|
||||||
|
>Variantenbezeichnung</label>
|
||||||
|
</div>
|
||||||
|
<div class="input-field col s4">
|
||||||
|
<input
|
||||||
|
:id="identifier + '_price'"
|
||||||
|
v-model.number="variant.price"
|
||||||
|
placeholder="Preis"
|
||||||
|
type="number"
|
||||||
|
class="validate"
|
||||||
|
step="0.01"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
:for="identifier + '_price'"
|
||||||
|
class="active"
|
||||||
|
>Preis</label>
|
||||||
|
</div>
|
||||||
|
<div class="input-field col s2">
|
||||||
|
<input
|
||||||
|
:value="article.PortionPrice + variant.Price"
|
||||||
|
class="validate"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="input-field col s2">
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
@click="storeVariant(variant)"
|
||||||
|
>Variante speichern</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { Article } from '../model/article';
|
||||||
|
import { thawVariant, Variant } from '../model/variant'
|
||||||
|
export default {
|
||||||
|
name: 'Variant',
|
||||||
|
props: {
|
||||||
|
variant: {
|
||||||
|
type: Object,
|
||||||
|
default() { return new Variant(); }
|
||||||
|
},
|
||||||
|
article: {
|
||||||
|
type: Object,
|
||||||
|
default() { return new Article(); }
|
||||||
|
},
|
||||||
|
identifier: {
|
||||||
|
type: String
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
storeVariant: function(variant) {
|
||||||
|
variant.ArticleId = this.article.id;
|
||||||
|
this.$http
|
||||||
|
.post(
|
||||||
|
"/api/varianten" + (variant.id > 0 ? '/' + variant.id : ''),
|
||||||
|
JSON.stringify(variant),
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then(response => {
|
||||||
|
this.$M.toast({ html: response.data + " Variante aktualisiert." });
|
||||||
|
this.variant = thawVariant(response.data);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.$M.toast({ html: error });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deleteVariant: function(variant) {
|
||||||
|
this.$http
|
||||||
|
.delete(
|
||||||
|
"/api/varianten/" + variant.id,
|
||||||
|
)
|
||||||
|
.then(response => {
|
||||||
|
this.$emit('delete-variant', variant);
|
||||||
|
this.$M.toast({ html: response.data + " Varianten gelöscht." });
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.$M.toast({ html: response });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
51
app/js/components/ArticlesView.vue
Normal file
51
app/js/components/ArticlesView.vue
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<ArticleCard
|
||||||
|
v-for="(a, index) in articles"
|
||||||
|
:key="'article_' + index"
|
||||||
|
:identifier="'article_' + index"
|
||||||
|
:a="a"
|
||||||
|
:dimensions="dimensions"
|
||||||
|
:groups="groups"
|
||||||
|
@delete-article="removeFromList(a)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ArticleCard from "./ArticleCard";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "ArticlesView",
|
||||||
|
components: {ArticleCard},
|
||||||
|
props: {
|
||||||
|
articles: {
|
||||||
|
type: Array,
|
||||||
|
default() { return []; }
|
||||||
|
},
|
||||||
|
groups: {
|
||||||
|
type: Array,
|
||||||
|
default() { return []; }
|
||||||
|
},
|
||||||
|
dimensions: {
|
||||||
|
type: Array,
|
||||||
|
default() { return []; }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
removeFromList(article) {
|
||||||
|
this.articles.splice(this.articles.indexOf(article),1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@ -39,7 +39,7 @@
|
|||||||
+'%,transparent 100%) 1'
|
+'%,transparent 100%) 1'
|
||||||
}"
|
}"
|
||||||
:wert="item.Sold"
|
:wert="item.Sold"
|
||||||
:einheit="item.article.PortionType"
|
:einheit="Dimension.short"
|
||||||
:precision="item.PortionPrecision"
|
:precision="item.PortionPrecision"
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
@ -74,6 +74,12 @@ export default {
|
|||||||
total: {
|
total: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0
|
default: 0
|
||||||
|
},
|
||||||
|
dimensions: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@ -89,6 +95,9 @@ export default {
|
|||||||
},
|
},
|
||||||
SaleAnimated() {
|
SaleAnimated() {
|
||||||
return this.tweenedSale.toFixed(2);
|
return this.tweenedSale.toFixed(2);
|
||||||
|
},
|
||||||
|
Dimension() {
|
||||||
|
return this.dimensions.find(element => element.id == this.item.article.PortionType)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|||||||
@ -29,6 +29,7 @@
|
|||||||
<InventoryItem
|
<InventoryItem
|
||||||
v-for="(item,index) in inventory"
|
v-for="(item,index) in inventory"
|
||||||
:key="'item-'+index"
|
:key="'item-'+index"
|
||||||
|
:dimensions="dimensions"
|
||||||
:item="item"
|
:item="item"
|
||||||
:total="sold"
|
:total="sold"
|
||||||
/>
|
/>
|
||||||
@ -68,6 +69,18 @@ export default {
|
|||||||
default() {
|
default() {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
groups: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dimensions: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
|||||||
75
app/js/components/MaterializeSelect.vue
Normal file
75
app/js/components/MaterializeSelect.vue
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<template>
|
||||||
|
<select :value="value">
|
||||||
|
<option
|
||||||
|
value=""
|
||||||
|
disabled
|
||||||
|
selected
|
||||||
|
>
|
||||||
|
Bitte wählen
|
||||||
|
</option>
|
||||||
|
<slot />
|
||||||
|
</select>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "MaterializeSelect",
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Component local variables
|
||||||
|
* @return {Object} data
|
||||||
|
* @return {undefined|FormSelect} data.instance
|
||||||
|
*/
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
instance: undefined,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
value() {
|
||||||
|
this.instance.destroy();
|
||||||
|
|
||||||
|
this.$nextTick(() => (this.instance = this.initializeSelect()));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.instance = this.initializeSelect();
|
||||||
|
|
||||||
|
this.$el.addEventListener("change", this.changeHandler);
|
||||||
|
},
|
||||||
|
|
||||||
|
destroyed() {
|
||||||
|
this.$el.removeEventListener("change", this.changeHandler);
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* @description Initialize a new Materialize select component
|
||||||
|
* @param {Object} options
|
||||||
|
* @return {FormSelect}
|
||||||
|
* @see https://materializecss.com/select.html#options
|
||||||
|
*/
|
||||||
|
initializeSelect(options = {}) {
|
||||||
|
return M.FormSelect.init(this.$el, options);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Send the proper input event to the parents components
|
||||||
|
* @param {Event} event
|
||||||
|
* @param {HTMLSelectElement} target
|
||||||
|
* @see https://developer.mozilla.org/fr/docs/Web/API/Event/target
|
||||||
|
*/
|
||||||
|
changeHandler({ target }) {
|
||||||
|
this.$emit("input", target.value);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@ -8,12 +8,13 @@
|
|||||||
<ul class="tabs tabs-transparent">
|
<ul class="tabs tabs-transparent">
|
||||||
<li class="tab">
|
<li class="tab">
|
||||||
<a
|
<a
|
||||||
class="active"
|
|
||||||
@click.stop.prevent="changeTab('inventory', $event)"
|
@click.stop.prevent="changeTab('inventory', $event)"
|
||||||
>Inventur</a>
|
>Inventur</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="tab">
|
<li class="tab">
|
||||||
<a
|
<a
|
||||||
|
class="active"
|
||||||
|
TweenedNumber
|
||||||
@click.stop.prevent="changeTab('article', $event)"
|
@click.stop.prevent="changeTab('article', $event)"
|
||||||
>Artikelliste</a>
|
>Artikelliste</a>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="tweened">
|
<span class="tweened">
|
||||||
<div>{{ intAnimated }}</div>
|
{{ intAnimated }}
|
||||||
<div v-if="precision>0">
|
<span v-if="precision>0">
|
||||||
,{{ deciAnimated }}
|
,{{ deciAnimated }}
|
||||||
</div>
|
</span>
|
||||||
<div v-else />
|
{{ einheit }}
|
||||||
<div>{{ einheit }}</div>
|
</span>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -31,7 +30,7 @@ export default {
|
|||||||
},
|
},
|
||||||
data(){
|
data(){
|
||||||
return {
|
return {
|
||||||
tweenedValue: 0,
|
tweenedValue: this.wert,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
export class Article{
|
export class Article{
|
||||||
constructor() {
|
constructor() {
|
||||||
|
this.id = 0;
|
||||||
this.name = "";
|
this.name = "";
|
||||||
this.short = "";
|
this.short = "";
|
||||||
this.dimension = "";
|
this.dimension = 0;
|
||||||
|
this.group = 0;
|
||||||
this.content = {
|
this.content = {
|
||||||
size : 0,
|
size : 0,
|
||||||
price: 0
|
price: 0
|
||||||
@ -10,7 +12,7 @@ export class Article{
|
|||||||
this.portion = {
|
this.portion = {
|
||||||
size : 0,
|
size : 0,
|
||||||
price : 0,
|
price : 0,
|
||||||
type : ""
|
type : 0
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
get Name() {
|
get Name() {
|
||||||
@ -55,6 +57,12 @@ export class Article{
|
|||||||
set PortionPrice(value) {
|
set PortionPrice(value) {
|
||||||
this.portion.price = value;
|
this.portion.price = value;
|
||||||
}
|
}
|
||||||
|
get Group() {
|
||||||
|
return this.group;
|
||||||
|
}
|
||||||
|
set Group(value) {
|
||||||
|
this.group = value;
|
||||||
|
}
|
||||||
get ContentPrice() {
|
get ContentPrice() {
|
||||||
return this.Portions * this.portion.price;
|
return this.Portions * this.portion.price;
|
||||||
}
|
}
|
||||||
@ -68,11 +76,13 @@ Article.thaw = function (json) {
|
|||||||
article.id = json.id;
|
article.id = json.id;
|
||||||
article.Name = json.name;
|
article.Name = json.name;
|
||||||
article.Short = json.short;
|
article.Short = json.short;
|
||||||
article.Dimension = json.dimension;
|
article.Dimension = json.content_dimension;
|
||||||
article.ContentSize = json.content.size;
|
article.ContentSize = json.content_size;
|
||||||
article.PortionPrice = json.portion.price;
|
article.PortionPrice = json.portion_price;
|
||||||
article.PortionSize = json.portion.size;
|
article.PortionSize = json.portion_size;
|
||||||
article.PortionType = json.portion.type;
|
article.PortionType = json.portion_dimension;
|
||||||
|
article.Group = json.group_id;
|
||||||
|
article.variants = json.variants;
|
||||||
|
|
||||||
return article;
|
return article;
|
||||||
};
|
};
|
||||||
|
|||||||
38
app/js/model/variant.js
Normal file
38
app/js/model/variant.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
export class Variant{
|
||||||
|
constructor() {
|
||||||
|
this.id = 0;
|
||||||
|
this.name = "";
|
||||||
|
this.article_id = 0;
|
||||||
|
this.price = 0;
|
||||||
|
}
|
||||||
|
get Name() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
set Name(value) {
|
||||||
|
this.name = value;
|
||||||
|
}
|
||||||
|
get ArticleId() {
|
||||||
|
return this.article_id;
|
||||||
|
}
|
||||||
|
set ArticleId(value) {
|
||||||
|
this.article_id = value;
|
||||||
|
}
|
||||||
|
get Price() {
|
||||||
|
return this.price;
|
||||||
|
}
|
||||||
|
set Price(value) {
|
||||||
|
this.price = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Variant.thaw = function (json) {
|
||||||
|
var variant = new Variant();
|
||||||
|
variant.id = json.id;
|
||||||
|
variant.Name = json.name;
|
||||||
|
variant.ArticleId = json.article_id;
|
||||||
|
variant.Price = json.price;
|
||||||
|
|
||||||
|
return variant;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const thawVariant = Variant.thaw;
|
||||||
@ -9,24 +9,18 @@
|
|||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"slim/slim": "^4.3",
|
"slim/slim": "^4.3",
|
||||||
"vlucas/phpdotenv": "^4.1",
|
"vlucas/phpdotenv": "^5.3",
|
||||||
"catfan/medoo": "^1.7",
|
"slim/psr7": "^1.4",
|
||||||
"slim/psr7": "^0.6.0",
|
|
||||||
"slim/php-view": "^2.2",
|
|
||||||
"slim/twig-view": "^3.0",
|
"slim/twig-view": "^3.0",
|
||||||
"php-di/php-di": "^6.0",
|
"php-di/php-di": "^6.0",
|
||||||
"symfony/webpack-encore-bundle": "^1.7",
|
"symfony/webpack-encore-bundle": "^1.7",
|
||||||
"illuminate/database": "^6.10",
|
"illuminate/database": "^7.3",
|
||||||
"phpoffice/phpspreadsheet": "^1.10",
|
"phpoffice/phpspreadsheet": "^1.10",
|
||||||
"monolog/monolog": "^2.0",
|
"monolog/monolog": "^2.0",
|
||||||
"illuminate/filesystem": "^6.12"
|
"illuminate/filesystem": "^7.3"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"config": {
|
||||||
"squizlabs/php_codesniffer": "^3.5",
|
"sort-packages": true
|
||||||
"doctrine/coding-standard": "^7.0",
|
|
||||||
"thecodingmachine/phpstan-strict-rules": "^0.12.0",
|
|
||||||
"thecodingmachine/safe": "^1.0",
|
|
||||||
"thecodingmachine/phpstan-safe-rule": "@dev"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"csfix": "phpcbf",
|
"csfix": "phpcbf",
|
||||||
@ -37,5 +31,9 @@
|
|||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Chrosey\\Inventur\\":"src"
|
"Chrosey\\Inventur\\":"src"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"laravel/tinker": "^2.6",
|
||||||
|
"symfony/var-dumper": "^5.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3489
composer.lock
generated
3489
composer.lock
generated
File diff suppressed because it is too large
Load Diff
63
database/migrations/2021_07_10_000000_add_bons.php
Normal file
63
database/migrations/2021_07_10_000000_add_bons.php
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||||
|
|
||||||
|
class AddBons extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
$builder = Capsule::schema();
|
||||||
|
|
||||||
|
$builder->table('articles', function($table) {
|
||||||
|
$table->softDeletes();
|
||||||
|
});
|
||||||
|
|
||||||
|
$builder->create(
|
||||||
|
'bons',
|
||||||
|
function ($table) {
|
||||||
|
$table->increments('id');
|
||||||
|
|
||||||
|
$table->timestamp('created_at')->useCurrent();
|
||||||
|
$table->timestamp('updated_at')->useCurrent();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$builder->create(
|
||||||
|
'bonitems',
|
||||||
|
function ($table) {
|
||||||
|
$table->increments('id');
|
||||||
|
|
||||||
|
$table->unsignedInteger('bon_id');
|
||||||
|
$table->foreign('bon_id')->references('id')->on('bons');
|
||||||
|
|
||||||
|
$table->unsignedInteger('article_id');
|
||||||
|
$table->foreign('article_id')->references('id')->on('articles');
|
||||||
|
|
||||||
|
$table->unsignedInteger('count');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
$builder = Capsule::schema();
|
||||||
|
|
||||||
|
$builder->table('articles', function($table) {
|
||||||
|
$table->dropSoftDeletes();
|
||||||
|
});
|
||||||
|
|
||||||
|
$builder->drop('bons');
|
||||||
|
$builder->drop('bonitems');
|
||||||
|
}
|
||||||
|
}
|
||||||
37
database/migrations/2021_07_10_000000_add_subarticles.php
Normal file
37
database/migrations/2021_07_10_000000_add_subarticles.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||||
|
|
||||||
|
class AddSubarticles extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
$builder = Capsule::schema();
|
||||||
|
|
||||||
|
$builder->table('articles', function($table) {
|
||||||
|
|
||||||
|
$table->unsignedInteger('main_article_id')->nullable();
|
||||||
|
$table->foreign('main_article_id')->references('id')->on('articles');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
$builder = Capsule::schema();
|
||||||
|
|
||||||
|
$builder->table('articles', function($table) {
|
||||||
|
$table->dropColum('main_article_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
45
database/migrations/2021_07_10_000000_article_variants.php
Normal file
45
database/migrations/2021_07_10_000000_article_variants.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||||
|
|
||||||
|
class ArticleVariants extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
$builder = Capsule::schema();
|
||||||
|
|
||||||
|
$builder->create(
|
||||||
|
'variants',
|
||||||
|
function ($table) {
|
||||||
|
$table->increments('id');
|
||||||
|
|
||||||
|
$table->unsignedInteger('article_id');
|
||||||
|
$table->foreign('article_id')->references('id')->on('articles');
|
||||||
|
|
||||||
|
$table->string('name');
|
||||||
|
$table->string('short');
|
||||||
|
$table->float('price', 8, 2);
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
$builder = Capsule::schema();
|
||||||
|
|
||||||
|
$builder->drop('variants');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1 +1 @@
|
|||||||
[{"name":"Edelpils","short":"Pils","dimension":"l","content":{"size":0.33000000000000002,"price":0},"portion":{"size":0.33000000000000002,"price":3.5,"type":"Fl."},"group":"Bier"},{"name":"Schwarzbier","short":"Sb","dimension":"l","content":{"size":0.33000000000000002,"price":0},"portion":{"size":0.33000000000000002,"price":3.5,"type":"Fl."},"group":"Bier"},{"name":"Sch\u00f6fferhofer","short":"Sch\u00f6","dimension":"l","content":{"size":0.33000000000000002,"price":0},"portion":{"size":0.33000000000000002,"price":3.5,"type":"Fl."},"group":"Bier"},{"name":"Bitburger af.","short":"0%","dimension":"l","content":{"size":0.33000000000000002,"price":0},"portion":{"size":0.33000000000000002,"price":3.5,"type":"Fl."},"group":"Bier"},{"name":"Kellerbier","short":"Keller","dimension":"l","content":{"size":0.33000000000000002,"price":0},"portion":{"size":0.33000000000000002,"price":3.5,"type":"Fl."},"group":"Bier"},{"name":"Weiswein","short":"WW","dimension":"l","content":{"size":1,"price":0},"portion":{"size":0.20000000000000001,"price":6,"type":"Gl."},"group":"Wein und Sekt"},{"name":"Ros\u00e9wein","short":"Ros\u00e9","dimension":"l","content":{"size":1,"price":0},"portion":{"size":0.20000000000000001,"price":6.5,"type":"Gl."},"group":"Wein und Sekt"},{"name":"Rotwein","short":"RW","dimension":"l","content":{"size":0.75,"price":0},"portion":{"size":0.20000000000000001,"price":6.5,"type":"Gl."},"group":"Wein und Sekt"},{"name":"Secco","short":"Sekt","dimension":"l","content":{"size":0.75,"price":0},"portion":{"size":0.10000000000000001,"price":6,"type":"Gl."},"group":"Wein und Sekt"},{"name":"B-Saft","short":"BS","dimension":"l","content":{"size":1,"price":0},"portion":{"size":0.20000000000000001,"price":3.5,"type":"Gl."},"group":"afG offen"},{"name":"K-Saft","short":"KS","dimension":"l","content":{"size":1,"price":0},"portion":{"size":0.20000000000000001,"price":3.5,"type":"Gl."},"group":"afG offen"},{"name":"O-Saft","short":"OS","dimension":"l","content":{"size":1,"price":0},"portion":{"size":0.20000000000000001,"price":3.5,"type":"Gl."},"group":"afG offen"},{"name":"M-Saft","short":"MS","dimension":"l","content":{"size":1,"price":0},"portion":{"size":0.20000000000000001,"price":3.5,"type":"Gl."},"group":"afG offen"},{"name":"Vita Cola","short":"Co","dimension":"l","content":{"size":1,"price":0},"portion":{"size":0.20000000000000001,"price":2.5,"type":"Gl."},"group":"afG offen"},{"name":"Vita Orange","short":"Fa","dimension":"l","content":{"size":1,"price":0},"portion":{"size":0.20000000000000001,"price":2.5,"type":"Gl."},"group":"afG offen"},{"name":"Vita Zitrone","short":"Spr","dimension":"l","content":{"size":1,"price":0},"portion":{"size":0.20000000000000001,"price":2.5,"type":"Gl."},"group":"afG offen"},{"name":"Tonic","short":"To","dimension":"l","content":{"size":0.25,"price":0},"portion":{"size":0.25,"price":3,"type":"Fl."},"group":"afG Gastro"},{"name":"Bitter Lemon","short":"BL","dimension":"l","content":{"size":0.25,"price":0},"portion":{"size":0.25,"price":3,"type":"Fl."},"group":"afG Gastro"},{"name":"Ginger Ale","short":"GA","dimension":"l","content":{"size":0.25,"price":0},"portion":{"size":0.25,"price":3,"type":"Fl."},"group":"afG Gastro"},{"name":"Apfelschorle","short":"AS","dimension":"l","content":{"size":0.25,"price":0},"portion":{"size":0.25,"price":3,"type":"Fl."},"group":"afG Gastro"},{"name":"Cola light","short":"Clight","dimension":"l","content":{"size":0.25,"price":0},"portion":{"size":0.25,"price":3,"type":"Fl."},"group":"afG Gastro"},{"name":"TWQ naturell","short":"W-","dimension":"l","content":{"size":0.25,"price":0},"portion":{"size":0.25,"price":2.5,"type":"Fl."},"group":"afG Gastro"},{"name":"TWQ medium","short":"W","dimension":"l","content":{"size":0.25,"price":0},"portion":{"size":0.25,"price":2.5,"type":"Fl."},"group":"afG Gastro"},{"name":"TWQ classic","short":"W+","dimension":"l","content":{"size":0.25,"price":0},"portion":{"size":0.25,"price":2.5,"type":"Fl."},"group":"afG Gastro"},{"name":"Kaffee","short":"TK","dimension":"T","content":{"size":1,"price":0},"portion":{"size":1,"price":2.5,"type":"T"},"group":"Hei\u00dfgetr\u00e4nke"},{"name":"Latte Macchiato","short":"LM","dimension":"Gl","content":{"size":1,"price":0},"portion":{"size":1,"price":3.5,"type":"Gl."},"group":"Hei\u00dfgetr\u00e4nke"},{"name":"dopp. Esp.","short":"dEsp","dimension":"T","content":{"size":1,"price":0},"portion":{"size":1,"price":3.5,"type":"T"},"group":"Hei\u00dfgetr\u00e4nke"},{"name":"Brezel","short":"Br","dimension":"stk","content":{"size":1,"price":0},"portion":{"size":1,"price":2.5,"type":"Stk."},"group":"Fingerfood"},{"name":"Schokoriegel","short":"Schoko","dimension":"stk","content":{"size":1,"price":0},"portion":{"size":1,"price":2,"type":"Stk."},"group":"Fingerfood"},{"name":"Duplo","short":"Duplo","dimension":"stk","content":{"size":1,"price":0},"portion":{"size":1,"price":1,"type":"Stk."},"group":"Fingerfood"}]
|
[{"name":"Edelpils","short":"Pils","dimension":"l","content":{"size":0.33000000000000002,"price":0},"portion":{"size":0.33000000000000002,"price":3.5,"type":"Fl."}},{"name":"Schwarzbier","short":"Sb","dimension":"l","content":{"size":0.33000000000000002,"price":0},"portion":{"size":0.33000000000000002,"price":3.5,"type":"Fl."}},{"name":"Sch\u00f6fferhofer","short":"Sch\u00f6","dimension":"l","content":{"size":0.33000000000000002,"price":0},"portion":{"size":0.33000000000000002,"price":3.5,"type":"Fl."}},{"name":"Bitburger af.","short":"0%","dimension":"l","content":{"size":0.33000000000000002,"price":0},"portion":{"size":0.33000000000000002,"price":3.5,"type":"Fl."}},{"name":"Weiswein","short":"WW","dimension":"l","content":{"size":1,"price":0},"portion":{"size":0.20000000000000001,"price":6,"type":"Gl."}},{"name":"Rotwein","short":"RW","dimension":"l","content":{"size":0.75,"price":0},"portion":{"size":0.20000000000000001,"price":6.5,"type":"Gl."}},{"name":"Secco","short":"Sekt","dimension":"l","content":{"size":0.75,"price":0},"portion":{"size":0.10000000000000001,"price":6,"type":"Gl."}},{"name":"B-Saft","short":"BS","dimension":"l","content":{"size":1,"price":0},"portion":{"size":0.20000000000000001,"price":3.5,"type":"Gl."}},{"name":"K-Saft","short":"KS","dimension":"l","content":{"size":1,"price":0},"portion":{"size":0.20000000000000001,"price":3.5,"type":"Gl."}},{"name":"O-Saft","short":"OS","dimension":"l","content":{"size":1,"price":0},"portion":{"size":0.20000000000000001,"price":3.5,"type":"Gl."}},{"name":"G-Saft","short":"GS","dimension":"l","content":{"size":1,"price":0},"portion":{"size":0.20000000000000001,"price":3.5,"type":"Gl."}},{"name":"Vita Cola","short":"Co","dimension":"l","content":{"size":1,"price":0},"portion":{"size":0.20000000000000001,"price":2.5,"type":"Gl."}},{"name":"Vita Orange","short":"Fa","dimension":"l","content":{"size":1,"price":0},"portion":{"size":0.20000000000000001,"price":2.5,"type":"Gl."}},{"name":"Vita Zitrone","short":"Spr","dimension":"l","content":{"size":1,"price":0},"portion":{"size":0.20000000000000001,"price":2.5,"type":"Gl."}},{"name":"Tonic","short":"To","dimension":"l","content":{"size":0.25,"price":0},"portion":{"size":0.25,"price":3,"type":"Fl."}},{"name":"Bitter Lemon","short":"BL","dimension":"l","content":{"size":0.25,"price":0},"portion":{"size":0.25,"price":3,"type":"Fl."}},{"name":"Ginger Ale","short":"GA","dimension":"l","content":{"size":0.25,"price":0},"portion":{"size":0.25,"price":3,"type":"Fl."}},{"name":"Apfelschorle","short":"AS","dimension":"l","content":{"size":0.25,"price":0},"portion":{"size":0.25,"price":3,"type":"Fl."}},{"name":"TWQ naturell","short":"W-","dimension":"l","content":{"size":0.25,"price":0},"portion":{"size":0.25,"price":2.5,"type":"Fl."}},{"name":"TWQ medium","short":"W","dimension":"l","content":{"size":0.25,"price":0},"portion":{"size":0.25,"price":2.5,"type":"Fl."}},{"name":"TWQ classic","short":"W+","dimension":"l","content":{"size":0.25,"price":0},"portion":{"size":0.25,"price":2.5,"type":"Fl."}},{"name":"Kaffee","short":"TK","dimension":"Tasse","content":{"size":1,"price":0},"portion":{"size":1,"price":2.5,"type":"T"}},{"name":"Latte Macchiato","short":"LM","dimension":"Glas","content":{"size":1,"price":0},"portion":{"size":1,"price":3.5,"type":"Gl."}},{"name":"dopp. Esp.","short":"dEsp","dimension":"Tasse","content":{"size":1,"price":0},"portion":{"size":1,"price":3.5,"type":"T"}},{"name":"Brezel","short":"Br","dimension":"St\u00fcck","content":{"size":1,"price":0},"portion":{"size":1,"price":2.5,"type":"Stk."}},{"name":"Schokoriegel","short":"Schoko","dimension":"St\u00fcck","content":{"size":1,"price":0},"portion":{"size":1,"price":2,"type":"Stk."}}]
|
||||||
9
env.example
Normal file
9
env.example
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
DB_HOST=db
|
||||||
|
DB_NAME=db
|
||||||
|
DB_USER=db
|
||||||
|
DB_PASSWORD=db
|
||||||
|
DB_DRIVER=mysql
|
||||||
|
DB_CHARSET=utf8mb4
|
||||||
|
DB_COLLATION=utf8mb4_general_ci
|
||||||
|
|
||||||
|
NODE_ENV=production
|
||||||
3275
package-lock.json
generated
3275
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
2313
public/build/app.js
2313
public/build/app.js
File diff suppressed because one or more lines are too long
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"build/app.css": "/build/app.css",
|
|
||||||
"build/app.js": "/build/app.js",
|
"build/app.js": "/build/app.js",
|
||||||
"build/vendors~app.css": "/build/vendors~app.css",
|
"build/vendors~app.css": "/build/vendors~app.css",
|
||||||
"build/vendors~app.js": "/build/vendors~app.js"
|
"build/vendors~app.js": "/build/vendors~app.js",
|
||||||
|
"build/app.css": "/build/app.css"
|
||||||
}
|
}
|
||||||
File diff suppressed because one or more lines are too long
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
83
src/Controller/ArticleController.php
Normal file
83
src/Controller/ArticleController.php
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chrosey\Inventur\Controller;
|
||||||
|
|
||||||
|
use Chrosey\Inventur\Models\Article;
|
||||||
|
use Chrosey\Inventur\Models\Variant;
|
||||||
|
use Slim\Psr7\Request;
|
||||||
|
use Slim\Psr7\Response;
|
||||||
|
|
||||||
|
class ArticleController extends BaseController
|
||||||
|
{
|
||||||
|
public function create(Request $request, Response $response, $args)
|
||||||
|
{
|
||||||
|
$artikel = dump($request->getParsedBody());
|
||||||
|
|
||||||
|
$article = new Article([
|
||||||
|
'name' => $artikel['name'],
|
||||||
|
'short' => $artikel['short'],
|
||||||
|
'content_size' => $artikel['content']['size'],
|
||||||
|
'content_dimension' => $artikel['dimension'],
|
||||||
|
'portion_size' => $artikel['portion']['size'],
|
||||||
|
'portion_price' => $artikel['portion']['price'],
|
||||||
|
'portion_dimension' => $artikel['portion']['type'],
|
||||||
|
'group_id' => $artikel['group'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$article->save();
|
||||||
|
$response->getBody()->write(\json_encode($article));
|
||||||
|
return $response
|
||||||
|
->withHeader('Content-Type', 'application/json');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Request $request, Response $response, $args)
|
||||||
|
{
|
||||||
|
$artikel = dump($request->getParsedBody());
|
||||||
|
|
||||||
|
$table = $this->db->table('articles');
|
||||||
|
$updatedRowsCount = $table
|
||||||
|
->where('id','=', $artikel['id'])
|
||||||
|
->update([
|
||||||
|
'name' => $artikel['name'],
|
||||||
|
'short' => $artikel['short'],
|
||||||
|
'content_size' => $artikel['content']['size'],
|
||||||
|
'content_dimension' => $artikel['dimension'],
|
||||||
|
'portion_size' => $artikel['portion']['size'],
|
||||||
|
'portion_price' => $artikel['portion']['price'],
|
||||||
|
'portion_dimension' => $artikel['portion']['type'],
|
||||||
|
'group_id' => $artikel['group'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response->getBody()->write(\json_encode($updatedRowsCount));
|
||||||
|
return $response
|
||||||
|
->withHeader('Content-Type', 'application/json');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(Request $request, Response $response, $args)
|
||||||
|
{
|
||||||
|
$affectedRows = Article::where('id', $args['id'])->delete();
|
||||||
|
|
||||||
|
$response->getBody()->write(\json_encode($affectedRows));
|
||||||
|
return $response
|
||||||
|
->withHeader('Content-Type', 'application/json');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function list(Request $request, Response $response, $args)
|
||||||
|
{
|
||||||
|
$articles = Article::all();
|
||||||
|
|
||||||
|
foreach ($articles as $article) {
|
||||||
|
$variants = Variant::where('article_id', $article->id)->get();
|
||||||
|
$article->variants = $variants;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response->getBody()->write(\json_encode($articles));
|
||||||
|
return $response
|
||||||
|
->withHeader('Content-Type', 'application/json');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/Controller/ArticleGroupController.php
Normal file
42
src/Controller/ArticleGroupController.php
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chrosey\Inventur\Controller;
|
||||||
|
|
||||||
|
use Slim\Psr7\Request;
|
||||||
|
use Slim\Psr7\Response;
|
||||||
|
|
||||||
|
class ArticleGroupController extends BaseController
|
||||||
|
{
|
||||||
|
public function create(Request $request, Response $response, $args)
|
||||||
|
{
|
||||||
|
$dimension = dump($request->getParsedBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function list(Request $request, Response $response, $args)
|
||||||
|
{
|
||||||
|
$table = $this->db->table('groups');
|
||||||
|
|
||||||
|
|
||||||
|
$items = $table->get();
|
||||||
|
dump($items);
|
||||||
|
|
||||||
|
$response->getBody()->write(\json_encode($items));
|
||||||
|
return $response
|
||||||
|
->withHeader('Content-Type', 'application/json');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,12 +2,28 @@
|
|||||||
|
|
||||||
namespace Chrosey\Inventur\Controller;
|
namespace Chrosey\Inventur\Controller;
|
||||||
|
|
||||||
|
use Illuminate\Database\Capsule\Manager;
|
||||||
|
use Monolog\Logger;
|
||||||
use Psr\Container\ContainerInterface;
|
use Psr\Container\ContainerInterface;
|
||||||
|
|
||||||
class BaseController
|
class BaseController
|
||||||
{
|
{
|
||||||
protected $container;
|
protected $container;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database
|
||||||
|
*
|
||||||
|
* @var Manager
|
||||||
|
*/
|
||||||
|
protected $db;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logger
|
||||||
|
*
|
||||||
|
* @var Logger
|
||||||
|
*/
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
function __construct(ContainerInterface $container)
|
function __construct(ContainerInterface $container)
|
||||||
{
|
{
|
||||||
$this->container = $container;
|
$this->container = $container;
|
||||||
|
|||||||
42
src/Controller/DimensionController.php
Normal file
42
src/Controller/DimensionController.php
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chrosey\Inventur\Controller;
|
||||||
|
|
||||||
|
use Slim\Psr7\Request;
|
||||||
|
use Slim\Psr7\Response;
|
||||||
|
|
||||||
|
class DimensionController extends BaseController
|
||||||
|
{
|
||||||
|
public function create(Request $request, Response $response, $args)
|
||||||
|
{
|
||||||
|
$dimension = dump($request->getParsedBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function list(Request $request, Response $response, $args)
|
||||||
|
{
|
||||||
|
$table = $this->db->table('dimensions');
|
||||||
|
|
||||||
|
|
||||||
|
$dimensions = $table->get();
|
||||||
|
dump($dimensions);
|
||||||
|
|
||||||
|
$response->getBody()->write(\json_encode($dimensions));
|
||||||
|
return $response
|
||||||
|
->withHeader('Content-Type', 'application/json');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,7 +6,7 @@ use Illuminate\Database\Migrations\DatabaseMigrationRepository;
|
|||||||
use Illuminate\Database\Migrations\Migrator;
|
use Illuminate\Database\Migrations\Migrator;
|
||||||
use Illuminate\Filesystem\Filesystem;
|
use Illuminate\Filesystem\Filesystem;
|
||||||
|
|
||||||
class DatabaseController extends BaseController
|
class MigrationController extends BaseController
|
||||||
{
|
{
|
||||||
|
|
||||||
function migrate($request, $response, $args)
|
function migrate($request, $response, $args)
|
||||||
63
src/Controller/VariantController.php
Normal file
63
src/Controller/VariantController.php
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chrosey\Inventur\Controller;
|
||||||
|
|
||||||
|
use Chrosey\Inventur\Models\Variant;
|
||||||
|
use Slim\Psr7\Request;
|
||||||
|
use Slim\Psr7\Response;
|
||||||
|
|
||||||
|
class VariantController extends BaseController
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public function list(Request $request, Response $response, $args)
|
||||||
|
{
|
||||||
|
$items = Variant::where('article_id', $args['id'])->get();
|
||||||
|
dump($items);
|
||||||
|
|
||||||
|
$response->getBody()->write(\json_encode($items));
|
||||||
|
return $response
|
||||||
|
->withHeader('Content-Type', 'application/json');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create(Request $request, Response $response, $args)
|
||||||
|
{
|
||||||
|
$data = dump($request->getParsedBody());
|
||||||
|
|
||||||
|
$variant = new Variant([
|
||||||
|
'name' => $data['name'],
|
||||||
|
'short' => $data['short'] ?: $data['name'],
|
||||||
|
'price' => $data['price'],
|
||||||
|
'article_id' => $data['article_id'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$variant->save();
|
||||||
|
$response->getBody()->write(\json_encode($variant));
|
||||||
|
return $response
|
||||||
|
->withHeader('Content-Type', 'application/json');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Request $request, Response $response, $args)
|
||||||
|
{
|
||||||
|
$data = dump($request->getParsedBody());
|
||||||
|
|
||||||
|
$table = $this->db->table('variants');
|
||||||
|
$updatedRowsCount = $table
|
||||||
|
->where('id','=', $data['id'])
|
||||||
|
->update([
|
||||||
|
'name' => $data['name'],
|
||||||
|
'short' => $data['short'] ?: $data['name'],
|
||||||
|
'price' => $data['price'],
|
||||||
|
'article_id' => $data['article_id'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response->getBody()->write(\json_encode($updatedRowsCount));
|
||||||
|
return $response
|
||||||
|
->withHeader('Content-Type', 'application/json');
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/Middleware/JsonBodyParserMiddleware.php
Normal file
25
src/Middleware/JsonBodyParserMiddleware.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chrosey\Inventur\Middleware;
|
||||||
|
|
||||||
|
use Psr\Http\Message\ResponseInterface as Response;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||||
|
use Psr\Http\Server\MiddlewareInterface;
|
||||||
|
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
|
||||||
|
|
||||||
|
class JsonBodyParserMiddleware implements MiddlewareInterface
|
||||||
|
{
|
||||||
|
public function process(Request $request, RequestHandler $handler): Response
|
||||||
|
{
|
||||||
|
$contentType = $request->getHeaderLine('Content-Type');
|
||||||
|
|
||||||
|
if (strstr($contentType, 'application/json')) {
|
||||||
|
$contents = json_decode(file_get_contents('php://input'), true);
|
||||||
|
if (json_last_error() === JSON_ERROR_NONE) {
|
||||||
|
$request = $request->withParsedBody($contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $handler->handle($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/Models/Article.php
Normal file
20
src/Models/Article.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chrosey\Inventur\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
class Article extends Model
|
||||||
|
{
|
||||||
|
use SoftDeletes;
|
||||||
|
|
||||||
|
protected $fillable = ['name',
|
||||||
|
'short',
|
||||||
|
'content_size',
|
||||||
|
'content_dimension',
|
||||||
|
'portion_size',
|
||||||
|
'portion_price',
|
||||||
|
'portion_dimension',
|
||||||
|
'group_id'];
|
||||||
|
}
|
||||||
15
src/Models/Variant.php
Normal file
15
src/Models/Variant.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chrosey\Inventur\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
class Variant extends Model
|
||||||
|
{
|
||||||
|
|
||||||
|
protected $fillable = ['name',
|
||||||
|
'short',
|
||||||
|
'price',
|
||||||
|
'article_id'];
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Chrosey\Inventur\Middleware\JsonBodyParserMiddleware;
|
||||||
use DI\Container;
|
use DI\Container;
|
||||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||||
use Monolog\Handler\StreamHandler;
|
use Monolog\Handler\StreamHandler;
|
||||||
@ -9,6 +10,13 @@ use Monolog\Logger;
|
|||||||
use Slim\Factory\AppFactory;
|
use Slim\Factory\AppFactory;
|
||||||
use Slim\Views\Twig;
|
use Slim\Views\Twig;
|
||||||
use Slim\Views\TwigMiddleware;
|
use Slim\Views\TwigMiddleware;
|
||||||
|
use Symfony\Component\VarDumper\Cloner\VarCloner;
|
||||||
|
use Symfony\Component\VarDumper\Dumper\CliDumper;
|
||||||
|
use Symfony\Component\VarDumper\Dumper\ContextProvider\CliContextProvider;
|
||||||
|
use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider;
|
||||||
|
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
|
||||||
|
use Symfony\Component\VarDumper\Dumper\ServerDumper;
|
||||||
|
use Symfony\Component\VarDumper\VarDumper;
|
||||||
|
|
||||||
require __DIR__ . '/../vendor/autoload.php';
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
require __DIR__ . '/env.php';
|
require __DIR__ . '/env.php';
|
||||||
@ -23,14 +31,14 @@ $container->set('view', static function () {
|
|||||||
$container->set('db', static function () {
|
$container->set('db', static function () {
|
||||||
$capsule = new Capsule();
|
$capsule = new Capsule();
|
||||||
$capsule->addConnection([
|
$capsule->addConnection([
|
||||||
'driver' => getenv('DB_DRIVER'),
|
'driver' => $_ENV['DB_DRIVER'] ?: 'mysql',
|
||||||
'host' => getenv('DB_HOST'),
|
'host' => $_ENV['DB_HOST'] ?: 'localhost',
|
||||||
'database' => getenv('DB_NAME'),
|
'database' => $_ENV['DB_NAME'] ?: 'inventar',
|
||||||
'username' => getenv('DB_USER'),
|
'username' => $_ENV['DB_USER'] ?: 'dbuser',
|
||||||
'password' => getenv('DB_PASSWORD'),
|
'password' => $_ENV['DB_PASSWORD'] ?: 'password',
|
||||||
'charset' => getenv('DB_CHARSET'),
|
'charset' => $_ENV['DB_CHARSET'] ?: 'utf8',
|
||||||
'collation' => getenv('DB_COLLATION'),
|
'collation' => $_ENV['DB_COLLATION'] ?: 'utf8_general_ci',
|
||||||
'prefix' => getenv('DB_PREFIX'),
|
'prefix' => $_ENV['DB_PREFIX'] ?: '',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$capsule->setAsGlobal();
|
$capsule->setAsGlobal();
|
||||||
@ -49,10 +57,36 @@ $container->set('log', static function() {
|
|||||||
$container->set('upload_directory', __DIR__ . '/../data/uploads');
|
$container->set('upload_directory', __DIR__ . '/../data/uploads');
|
||||||
$container->set('data_directory', __DIR__ . '/../data/');
|
$container->set('data_directory', __DIR__ . '/../data/');
|
||||||
|
|
||||||
|
|
||||||
$app = AppFactory::create();
|
$app = AppFactory::create();
|
||||||
|
|
||||||
|
$app->addMiddleware(new JsonBodyParserMiddleware());
|
||||||
$app->add(TwigMiddleware::createFromContainer($app));
|
$app->add(TwigMiddleware::createFromContainer($app));
|
||||||
|
|
||||||
|
$cloner = new VarCloner();
|
||||||
|
$fallbackDumper = in_array(PHP_SAPI, ['cli', 'phpdbg']) ? new CliDumper() : new HtmlDumper();
|
||||||
|
$dumper = new ServerDumper('tcp://127.0.0.1:9912', $fallbackDumper, [
|
||||||
|
'cli' => new CliContextProvider(),
|
||||||
|
'source' => new SourceContextProvider(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
VarDumper::setHandler(function ($var) use ($cloner, $dumper) {
|
||||||
|
$dumper->dump($cloner->cloneVar($var));
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add Error Middleware
|
||||||
|
*
|
||||||
|
* @param bool $displayErrorDetails -> Should be set to false in production
|
||||||
|
* @param bool $logErrors -> Parameter is passed to the default ErrorHandler
|
||||||
|
* @param bool $logErrorDetails -> Display error details in error log
|
||||||
|
* @param LoggerInterface|null $logger -> Optional PSR-3 Logger
|
||||||
|
*
|
||||||
|
* Note: This middleware should be added last. It will not handle any exceptions/errors
|
||||||
|
* for middleware added after it.
|
||||||
|
*/
|
||||||
|
$errorMiddleware = $app->addErrorMiddleware(true, true, true, $container->get('log'));
|
||||||
|
|
||||||
require 'routes.php';
|
require 'routes.php';
|
||||||
|
|
||||||
return $app;
|
return $app;
|
||||||
|
|||||||
@ -2,41 +2,33 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
use Chrosey\Inventur\Controller\DatabaseController;
|
use Chrosey\Inventur\Controller\ArticleController;
|
||||||
|
use Chrosey\Inventur\Controller\ArticleGroupController;
|
||||||
|
use Chrosey\Inventur\Controller\MigrationController;
|
||||||
|
use Chrosey\Inventur\Controller\DimensionController;
|
||||||
use Psr\Http\Message\ResponseInterface as Response;
|
use Psr\Http\Message\ResponseInterface as Response;
|
||||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||||
use Slim\Psr7\Stream;
|
|
||||||
use Slim\Psr7\UploadedFile;
|
use Slim\Psr7\UploadedFile;
|
||||||
use Slim\Routing\RouteCollectorProxy;
|
use Slim\Routing\RouteCollectorProxy;
|
||||||
use Chrosey\Inventur\Controller\SpreadsheetController;
|
use Chrosey\Inventur\Controller\SpreadsheetController;
|
||||||
|
use Chrosey\Inventur\Controller\VariantController;
|
||||||
|
|
||||||
$app->get('/', function (Request $request, Response $response, $args) {
|
$app->get('/', function (Request $request, Response $response, $args) {
|
||||||
return $this->get('view')->render($response, 'frontend.html', []);
|
return $this->get('view')->render($response, 'frontend.html', []);
|
||||||
})->setName('frontend');
|
})->setName('frontend');
|
||||||
|
|
||||||
$app->group('/api', function (RouteCollectorProxy $group): void {
|
$app->group('/api', function (RouteCollectorProxy $group): void {
|
||||||
$group->post('/artikel', function (Request $request, Response $response, $args) {
|
$group->post('/artikel', ArticleController::class . ':create')->setName('article.create');
|
||||||
$directory = $this->get('upload_directory');
|
$group->post('/artikel/{id}', ArticleController::class . ':update')->setName('article.update');
|
||||||
$uploadedFile = $request->getUploadedFiles()['articles'];
|
$group->delete('/artikel/{id}', ArticleController::class . ':delete')->setName('article.delete');
|
||||||
|
$group->get('/artikel/{id}/varianten', VariantController::class . ':list')->setName('article.list.variants');
|
||||||
|
$group->post('/varianten', VariantController::class . ':create')->setName('variant.create');
|
||||||
|
$group->post('/varianten/{id}', VariantController::class . ':update')->setName('variant.update');
|
||||||
|
$group->delete('/varianten/{id}', VariantController::class . ':list')->setName('variant.delete');
|
||||||
|
$group->get('/artikel[/{location}]', ArticleController::class . ':list')->setName('article.list');
|
||||||
|
|
||||||
if ($uploadedFile->getError() === UPLOAD_ERR_OK) {
|
$group->get('/dimension', DimensionController::class . ':list')->setName('dimension.list');
|
||||||
$filename = moveUploadedFile($directory, $uploadedFile);
|
$group->get('/group', ArticleGroupController::class . ':list')->setName('group.list');
|
||||||
$response->write('uploaded ' . $filename . '<br/>');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
});
|
|
||||||
|
|
||||||
$group->get('/artikel/theater', function (Request $request, Response $response, $args) {
|
|
||||||
$file = __DIR__ . '/../data/articles.theater.json';
|
|
||||||
$fh = fopen($file, 'rb');
|
|
||||||
|
|
||||||
$stream = new Stream($fh);
|
|
||||||
|
|
||||||
return $response
|
|
||||||
->withHeader('Content-Type', 'application/json')
|
|
||||||
->withBody($stream);
|
|
||||||
});
|
|
||||||
|
|
||||||
$group->post('/inventur', function (Request $request, Response $response, $args) {
|
$group->post('/inventur', function (Request $request, Response $response, $args) {
|
||||||
$directory = $this->get('upload_directory');
|
$directory = $this->get('upload_directory');
|
||||||
@ -55,9 +47,9 @@ $app->group('/api', function (RouteCollectorProxy $group): void {
|
|||||||
$group->get('/excel/download', SpreadsheetController::class . ':download');
|
$group->get('/excel/download', SpreadsheetController::class . ':download');
|
||||||
});
|
});
|
||||||
|
|
||||||
$app->get('/migrate', DatabaseController::class . ':migrate')->setName('migrate');
|
$app->get('/migrate', MigrationController::class . ':migrate')->setName('migrate');
|
||||||
|
|
||||||
$app->get('/seed', DatabaseController::class . ':seed')->setName('seed');
|
$app->get('/seed', MigrationController::class . ':seed')->setName('seed');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move Uploaded File to Target Destination
|
* Move Uploaded File to Target Destination
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user