Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

6 ajout dun objet prix sur chaque produit #10

Draft
wants to merge 15 commits into
base: master
Choose a base branch
from
81 changes: 77 additions & 4 deletions src/views/products/ProductForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,26 @@
<InputSupplier v-model="product.supplier_id" />
</div>

<!-- Unit Price -->
<div class="p-field">
<label>Unit Price</label>
Focus-Pacifique marked this conversation as resolved.
Show resolved Hide resolved
<div class="p-inputgroup">
<InputNumber v-model="productPriceValue"
placeholder="Unit Price"
:maxFractionDigits="2" />
<span class="p-inputgroup-addon" style="width: 6rem;">€ / {{ product.unit
}}</span>
</div>
</div>

<!-- Price History -->
<div class="p-field">
<label>Price History</label>
<Button icon=" pi pi-history" class="p-button-text"
Focus-Pacifique marked this conversation as resolved.
Show resolved Hide resolved
v-if="product.id && product.prices && product.prices.length > 0"
@click="$refs.productsPriceHistoryForm.show(this.product)" />
</div>

<div class="p-field">
<label>Packaging Name / Reference</label>
<InputText v-model="product.packaging_reference" placeholder="Packaging Name / Reference" />
Expand All @@ -38,15 +58,18 @@

<div class="p-field-checkbox w-100 mb-3" v-if="product.packaging_conditioning">
<Checkbox id="convert" v-model="product.packaging_convert_to_piece" :binary="true" />
<label for="convert" class="ms-2">Convert "{{ product.packaging_conditioning }}{{ product.unit
}}" to 1 piece in orders</label>
<label for="convert" class="ms-2">Convert "{{ product.packaging_conditioning }}{{
product.unit
}}" to 1 piece in orders</label>
</div>

<div class="p-field w-100 mt-0">
<div class="p-field w-100 mt-0 mb-3">
<label>Storage Areas</label>
<InputCategory type="StorageArea" :multiple="true" v-model="product.storage_area_ids"
placeholder="Storage Areas" />
</div>


</div>

<template #footer>
Expand All @@ -55,6 +78,9 @@
@click="saveProduct" />
</template>
</Dialog>

<ProductsPriceHistory @updatedPrices="handleUpdatedPrices" ref="productsPriceHistoryForm">
</ProductsPriceHistory>
</template>

<script>
Expand All @@ -65,25 +91,33 @@ import Checkbox from 'primevue/checkbox'
import InputUnit from '@/components/InputUnit.vue'
import InputSupplier from '@/components/InputSupplier.vue'
import InputCategory from '@/components/InputCategory.vue'
import Calendar from 'primevue/calendar';
import ProductsPriceHistory from './ProductsPriceHistory.vue'


export default {
components: {
InputUnit, InputSupplier, InputNumber, InputCategory, Divider, Checkbox,
InputUnit, InputSupplier, InputNumber, InputCategory, Divider, Checkbox, Calendar, ProductsPriceHistory,
},
data() {
return {
visible: false,
loading: false,
product: {},
productPriceValue: null,
}
},
methods: {
show(object = {}) {
this.product = { ...object }
this.visible = true
this.productPriceValue = this.getLastPriceValue(this.product)
},
async saveProduct() {
if (this.product.name) {
// prepare product.prices
this.savePrice()
Focus-Pacifique marked this conversation as resolved.
Show resolved Hide resolved

if (this.product.id) {
this.dbUpdate('products', this.product)
} else {
Expand All @@ -94,6 +128,45 @@ export default {
this.product = {}
}
},
savePrice() {
if (this.productPriceValue && this.productPriceValue !== 0) {
const newPrice = {
date: new Date().toISOString(),
value: this.productPriceValue
};

// if there is already a list of prices
if (this.product.prices) {
this.product.prices.push(newPrice)

// filter empty prices and order list
this.product.prices = this.product.prices.filter((p) => p.date && p.value).sort((a, b) => new Date(b.date) - new Date(a.date));

} else {
this.product.prices = []
this.product.prices.push(newPrice)
}
}
},
handleUpdatedPrices(updatedProductData) {
this.visible = false
Focus-Pacifique marked this conversation as resolved.
Show resolved Hide resolved
this.product = {}
},
getProductLastPrice(prices) {
Focus-Pacifique marked this conversation as resolved.
Show resolved Hide resolved
if (!prices || prices.length === 0) {
return null;
}

const lastPrice = prices.reduce((latest, current) => {
return new Date(current.date) > new Date(latest.date) ? current : latest;
});

return lastPrice;
},
getLastPriceValue(product) {
const lastPrice = this.getProductLastPrice(product.prices);
return lastPrice ? lastPrice.value : null;
}
},
watch: {
'product.packaging_conditioning': function (newVal, oldVal) {
Expand Down
29 changes: 27 additions & 2 deletions src/views/products/ProductsIndex.vue
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@
</template>
</Column>

<!-- Price -->
<Column field="price" header="Unit Price" style="max-width: 14rem">
<template #body="{ data }">
<InputText :value="getLastPriceValue(data)" disabled
Focus-Pacifique marked this conversation as resolved.
Show resolved Hide resolved
:maxFractionDigits="2" />
</template>
</Column>


<!-- Actions -->
<Column class="text-end" style="max-width: 40px" header="Actions">
<template #body="{ data }">
Expand Down Expand Up @@ -90,14 +99,15 @@
<script>
import { FilterMatchMode } from 'primevue/api'
import Chip from 'primevue/chip'
import InputText from 'primevue/inputtext'
import ProductForm from './ProductForm.vue'
import InputSupplier from '@/components/InputSupplier.vue'
import InputCategory from '@/components/InputCategory.vue'
import RecipieForm from '@/views/recipies/RecipieForm.vue'

export default {
components: {
ProductForm, RecipieForm, InputSupplier, InputCategory, Chip,
ProductForm, RecipieForm, InputSupplier, InputCategory, Chip, InputText,
},
data() {
return {
Expand Down Expand Up @@ -148,7 +158,22 @@ export default {
recipiesUsingProduct(product) {
return this.$root.recipiesArray.filter((r) => r.products.some((p) => p.id == product.id))
},
},
getProductLastPrice(prices) {
if (!prices || prices.length === 0) {
return null;
}

const lastPrice = prices.reduce((latest, current) => {
return new Date(current.date) > new Date(latest.date) ? current : latest;
});

return lastPrice;
},
getLastPriceValue(product) {
const lastPrice = this.getProductLastPrice(product.prices);
return lastPrice ? lastPrice.value + "€/" + product.unit : null;
}
}
Focus-Pacifique marked this conversation as resolved.
Show resolved Hide resolved
}
</script>

Expand Down
127 changes: 127 additions & 0 deletions src/views/products/ProductsPriceHistory.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
<template>
<Dialog v-model:visible="visible" :style="{ width: '600px' }" header="Price History"
position="top" :modal="true" class="p-fluid">

<div class="p-field">
<InputText id="name" v-model="product.name" placeholder="Name"
autofocus />
</div>

<div class="prices my-4 py-2">
<div v-for="price in product.prices" class="d-flex mb-2" :key="price">
<div class="p-inputgroup">
<Calendar v-model="price.date" showIcon iconDisplay="input"
Focus-Pacifique marked this conversation as resolved.
Show resolved Hide resolved
dateFormat="dd/mm/yy" class="w-50" />
<InputNumber v-model="price.value" :maxFractionDigits="2"
placeholder="Value"
inputClass="border-start-0 input-amount" />
<span class="p-inputgroup-addon" style="width: 6rem;">€ / {{ product.unit
}}</span>
</div>
<Button icon="pi pi-times" class="p-button-text p-button-danger"
@click="removeRow(price)" />
</div>
<Button icon="pi pi-plus" class="p-button-primary p-button-sm w-auto mt-2"
label="Price"
@click="newRow"></Button>
</div>

<template #footer>
<Button label="Cancel" icon="pi pi-times" class="p-button-text"
@click="visible = false" />
<Button label="Save" icon="pi pi-check" class="p-button-text" :loading="loading"
@click="savePrice" />
</template>
</Dialog>
</template>

<script>

import InputNumber from 'primevue/inputnumber'
import Calendar from 'primevue/calendar';

export default {
components: {
InputNumber, Calendar,
},
data() {
return {
visible: false,
loading: false,
product: {},
}
},
methods: {
show(object = {}) {
this.product = {
...object,
prices: Array.isArray(object.prices) ? [...object.prices] : [{}]
};
this.visible = true
},
newRow(event) {
this.product.prices.push({})
},
async savePrice() {
if (this.product.prices) {
// filter empty prices and order
this.product.prices = this.product.prices.filter((p) => p.date && p.value).sort((a, b) => new Date(b.date) - new Date(a.date));

if (this.product.id) {
this.dbUpdate('products', this.product)
}
this.visible = false
this.product.prices = [{}]
this.product = {}
this.$emit('updatedPrices', this.updatedProductData);
}
},
removeRow(price) {
this.product.prices = this.product.prices.filter((p) => p.date !== price.date)
},
formatDate(dateString) {
const date = new Date(dateString);
return new Intl.DateTimeFormat('default', { dateStyle: 'long' }).format(date);
},
},
}
</script>

<style lang="scss">
.prices {
.input-product-wrapper {
width: 20% !important;
}

.p-inputgroup {
&:hover>.btn-edit-product {
border-color: var(--primary-color);
}

.btn-edit-product {
border-radius: 0 !important;
background-color: transparent;
border-color: #ced4da;
border-left: none !important;
width: 2.5rem !important;
justify-content: flex-start;
padding-left: .25rem !important;
color: var(--text-color);

.pi {
font-size: .9rem;
}

&:hover {
background-color: transparent !important;
color: var(--primary-color);
border-color: #ced4da;
}
}
}

.input-product {
border-right: none;
}
}
</style>