File: /home/slfopp7cb1df/www/inventorypacket.com/resources/src/views/app/pages/sales/change_to_sale.vue
<template>
<div class="main-content">
<breadcumb :page="$t('AddSale')" :folder="$t('ListSales')"/>
<div v-if="isLoading" class="loading_page spinner spinner-primary mr-3"></div>
<validation-observer ref="create_sale" v-if="!isLoading">
<b-form @submit.prevent="Submit_Sale">
<b-row>
<b-col lg="12" md="12" sm="12">
<b-card>
<b-row>
<b-modal hide-footer id="open_scan" size="md" title="Barcode Scanner">
<qrcode-scanner
:qrbox="250"
:fps="10"
style="width: 100%; height: calc(100vh - 56px);"
@result="onScan"
/>
</b-modal>
<!-- date -->
<b-col lg="4" md="4" sm="12" class="mb-3">
<validation-provider
name="date"
:rules="{ required: true}"
v-slot="validationContext"
>
<b-form-group :label="$t('date') + ' ' + '*'">
<b-form-input
:state="getValidationState(validationContext)"
aria-describedby="date-feedback"
type="date"
v-model="sale.date"
></b-form-input>
<b-form-invalid-feedback
id="OrderTax-feedback"
>{{ validationContext.errors[0] }}</b-form-invalid-feedback>
</b-form-group>
</validation-provider>
</b-col>
<!-- Customer -->
<b-col lg="4" md="4" sm="12" class="mb-3">
<validation-provider name="Customer" :rules="{ required: true}">
<b-form-group slot-scope="{ valid, errors }" :label="$t('Customer') + ' ' + '*'">
<v-select
:class="{'is-invalid': !!errors.length}"
:state="errors[0] ? false : (valid ? true : null)"
v-model="sale.client_id"
:reduce="label => label.value"
:placeholder="$t('Choose_Customer')"
:options="clients.map(clients => ({label: clients.name, value: clients.id}))"
/>
<b-form-invalid-feedback>{{ errors[0] }}</b-form-invalid-feedback>
</b-form-group>
</validation-provider>
</b-col>
<!-- warehouse -->
<b-col lg="4" md="4" sm="12" class="mb-3">
<validation-provider name="warehouse" :rules="{ required: true}">
<b-form-group slot-scope="{ valid, errors }" :label="$t('warehouse') + ' ' + '*'">
<v-select
:class="{'is-invalid': !!errors.length}"
:state="errors[0] ? false : (valid ? true : null)"
:disabled="details.length > 0"
@input="Selected_Warehouse"
v-model="sale.warehouse_id"
:reduce="label => label.value"
:placeholder="$t('Choose_Warehouse')"
:options="warehouses.map(warehouses => ({label: warehouses.name, value: warehouses.id}))"
/>
<b-form-invalid-feedback>{{ errors[0] }}</b-form-invalid-feedback>
</b-form-group>
</validation-provider>
</b-col>
<!-- Product -->
<b-col md="12" class="mb-5">
<h6>{{$t('ProductName')}}</h6>
<div id="autocomplete" class="autocomplete">
<div class="input-with-icon">
<img src="/assets_setup/scan.png" alt="Scan" class="scan-icon" @click="showModal">
<input
:placeholder="$t('Scan_Search_Product_by_Code_Name')"
@input='e => search_input = e.target.value'
@keyup="search(search_input)"
@focus="handleFocus"
@blur="handleBlur"
ref="product_autocomplete"
class="autocomplete-input" />
</div>
<ul class="autocomplete-result-list" v-show="focused">
<li class="autocomplete-result" v-for="product_fil in product_filter" @mousedown="SearchProduct(product_fil)">{{getResultValue(product_fil)}}</li>
</ul>
</div>
</b-col>
<!-- Order panel -->
<b-col md="12">
<h5>{{$t('order_products')}} *</h5>
<div class="table-responsive">
<table class="table table-hover">
<thead class="bg-gray-300">
<tr>
<th scope="col">#</th>
<th scope="col">{{$t('ProductName')}}</th>
<th scope="col">{{$t('Net_Unit_Price')}}</th>
<th scope="col">{{$t('CurrentStock')}}</th>
<th scope="col">{{$t('Qty')}}</th>
<th scope="col">{{$t('Discount')}}</th>
<th scope="col">{{$t('Tax')}}</th>
<th scope="col">{{$t('SubTotal')}}</th>
<th scope="col" class="text-center">
<i class="fa fa-trash"></i>
</th>
</tr>
</thead>
<tbody>
<tr v-if="details.length <=0">
<td colspan="9">{{$t('NodataAvailable')}}</td>
</tr>
<tr v-for="detail in details" :class="{'row_deleted': detail.quantity > detail.stock}">
<td>{{detail.detail_id}}</td>
<td>
<span>{{detail.code}}</span>
<br>
<span class="badge badge-success">{{detail.name}}</span>
</td>
<td>{{currentUser.currency}} {{formatNumber(detail.Net_price, 3)}}</td>
<td>
<span class="badge badge-warning" v-if="detail.product_type == 'is_service'">----</span>
<span class="badge badge-warning" v-else>{{detail.stock}} {{detail.unitSale}}</span>
</td>
<td>
<div class="quantity">
<b-input-group>
<b-input-group-prepend>
<span
class="btn btn-primary btn-sm"
@click="decrement(detail ,detail.detail_id)"
>-</span>
</b-input-group-prepend>
<input
class="form-control"
@keyup="Verified_Qty(detail,detail.detail_id)"
:min="0.00"
:max="detail.stock"
v-model.number="detail.quantity"
>
<b-input-group-append>
<span
class="btn btn-primary btn-sm"
@click="increment(detail ,detail.detail_id)"
>+</span>
</b-input-group-append>
</b-input-group>
</div>
</td>
<td>{{currentUser.currency}} {{formatNumber(detail.DiscountNet * detail.quantity, 2)}}</td>
<td>{{currentUser.currency}} {{formatNumber(detail.taxe * detail.quantity, 2)}}</td>
<td>{{currentUser.currency}} {{detail.subtotal.toFixed(2)}}</td>
<td>
<i v-if="currentUserPermissions && currentUserPermissions.includes('edit_product_sale')"
@click="Modal_Updat_Detail(detail)" class="i-Edit text-25 text-success cursor-pointer"></i>
<i @click="delete_Product_Detail(detail.detail_id)" class="i-Close-Window text-25 text-danger cursor-pointer"></i>
</td>
</tr>
</tbody>
</table>
</div>
</b-col>
<div class="offset-md-9 col-md-3 mt-4">
<table class="table table-striped table-sm">
<tbody>
<tr>
<td class="bold">{{$t('OrderTax')}}</td>
<td>
<span>{{currentUser.currency}} {{sale.TaxNet.toFixed(2)}} ({{formatNumber(sale.tax_rate ,2)}} %)</span>
</td>
</tr>
<tr>
<td class="bold">{{$t('Discount')}}</td>
<td>{{currentUser.currency}} {{sale.discount.toFixed(2)}}</td>
</tr>
<tr>
<td class="bold">{{$t('Shipping')}}</td>
<td>{{currentUser.currency}} {{sale.shipping.toFixed(2)}}</td>
</tr>
<tr>
<td>
<span class="font-weight-bold">{{$t('Total')}}</span>
</td>
<td>
<span
class="font-weight-bold"
>{{currentUser.currency}} {{GrandTotal.toFixed(2)}}</span>
</td>
</tr>
</tbody>
</table>
</div>
<!-- Order Tax -->
<b-col lg="4" md="4" sm="12" class="mb-3" v-if="currentUserPermissions && currentUserPermissions.includes('edit_tax_discount_shipping_sale')">
<validation-provider
name="Order Tax"
:rules="{ regex: /^\d*\.?\d*$/}"
v-slot="validationContext"
>
<b-form-group :label="$t('OrderTax')">
<b-input-group append="%">
<b-form-input
:state="getValidationState(validationContext)"
aria-describedby="OrderTax-feedback"
label="Order Tax"
v-model.number="sale.tax_rate"
@keyup="keyup_OrderTax()"
></b-form-input>
</b-input-group>
<b-form-invalid-feedback
id="OrderTax-feedback"
>{{ validationContext.errors[0] }}</b-form-invalid-feedback>
</b-form-group>
</validation-provider>
</b-col>
<!-- Discount -->
<b-col lg="4" md="4" sm="12" class="mb-3" v-if="currentUserPermissions && currentUserPermissions.includes('edit_tax_discount_shipping_sale')">
<validation-provider
name="Discount"
:rules="{ regex: /^\d*\.?\d*$/}"
v-slot="validationContext"
>
<b-form-group :label="$t('Discount')">
<b-input-group :append="currentUser.currency">
<b-form-input
:state="getValidationState(validationContext)"
aria-describedby="Discount-feedback"
label="Discount"
v-model.number="sale.discount"
@keyup="keyup_Discount()"
></b-form-input>
</b-input-group>
<b-form-invalid-feedback
id="Discount-feedback"
>{{ validationContext.errors[0] }}</b-form-invalid-feedback>
</b-form-group>
</validation-provider>
</b-col>
<!-- Shipping -->
<b-col lg="4" md="4" sm="12" class="mb-3" v-if="currentUserPermissions && currentUserPermissions.includes('edit_tax_discount_shipping_sale')">
<validation-provider
name="Shipping"
:rules="{ regex: /^\d*\.?\d*$/}"
v-slot="validationContext"
>
<b-form-group :label="$t('Shipping')">
<b-input-group :append="currentUser.currency">
<b-form-input
:state="getValidationState(validationContext)"
aria-describedby="Shipping-feedback"
label="Shipping"
v-model.number="sale.shipping"
@keyup="keyup_Shipping()"
></b-form-input>
</b-input-group>
<b-form-invalid-feedback
id="Shipping-feedback"
>{{ validationContext.errors[0] }}</b-form-invalid-feedback>
</b-form-group>
</validation-provider>
</b-col>
<!-- Status -->
<b-col lg="4" md="4" sm="12" class="mb-3">
<validation-provider name="Status" :rules="{ required: true}">
<b-form-group slot-scope="{ valid, errors }" :label="$t('Status') + ' ' + '*'">
<v-select
@input="Selected_Status"
:class="{'is-invalid': !!errors.length}"
:state="errors[0] ? false : (valid ? true : null)"
v-model="sale.statut"
:reduce="label => label.value"
:placeholder="$t('Choose_Status')"
:options="
[
{label: 'completed', value: 'completed'},
{label: 'Pending', value: 'pending'},
{label: 'ordered', value: 'ordered'}
]"
></v-select>
<b-form-invalid-feedback>{{ errors[0] }}</b-form-invalid-feedback>
</b-form-group>
</validation-provider>
</b-col>
<!-- PaymentStatus -->
<b-col md="4" v-if="sale.statut == 'completed'">
<validation-provider name="PaymentStatus">
<b-form-group :label="$t('PaymentStatus')">
<v-select
@input="Selected_PaymentStatus"
:reduce="label => label.value"
v-model="payment.status"
:placeholder="$t('Choose_Status')"
:options="
[
{label: 'Paid', value: 'paid'},
{label: 'partial', value: 'partial'},
{label: 'Pending', value: 'pending'},
]"
></v-select>
</b-form-group>
</validation-provider>
</b-col>
<!-- Payment choice -->
<b-col md="4" v-if="payment.status != 'pending' && sale.statut == 'completed'">
<validation-provider name="Payment choice" :rules="{ required: true}">
<b-form-group slot-scope="{ valid, errors }" :label="$t('Paymentchoice') + ' ' + '*'">
<v-select
:class="{'is-invalid': !!errors.length}"
:state="errors[0] ? false : (valid ? true : null)"
:reduce="label => label.value"
v-model="payment.Reglement"
:placeholder="$t('PleaseSelect')"
:options="
[
{label: 'Cash', value: 'Cash'},
{label: 'cheque', value: 'cheque'},
{label: 'TPE', value: 'tpe'},
{label: 'Western Union', value: 'Western Union'},
{label: 'bank transfer', value: 'bank transfer'},
{label: 'credit card', value: 'credit card'},
{label: 'other', value: 'other'},
]"
></v-select>
<b-form-invalid-feedback>{{ errors[0] }}</b-form-invalid-feedback>
</b-form-group>
</validation-provider>
</b-col>
<!-- Received Amount -->
<b-col md="4" v-if="payment.status != 'pending' && sale.statut == 'completed'">
<validation-provider
name="Received Amount"
:rules="{ required: true , regex: /^\d*\.?\d*$/}"
v-slot="validationContext"
>
<b-form-group :label="$t('Received_Amount') + ' ' + '*'">
<b-form-input
@keyup="Verified_Received_Amount(payment.received_amount)"
label="Received_Amount"
:placeholder="$t('Received_Amount')"
v-model.number="payment.received_amount"
:state="getValidationState(validationContext)"
aria-describedby="Received_Amount-feedback"
></b-form-input>
<b-form-invalid-feedback
id="Received_Amount-feedback"
>{{ validationContext.errors[0] }}</b-form-invalid-feedback>
</b-form-group>
</validation-provider>
</b-col>
<!-- Amount -->
<b-col md="4" v-if="payment.status != 'pending' && sale.statut == 'completed'">
<validation-provider
name="Amount"
:rules="{ required: true , regex: /^\d*\.?\d*$/}"
v-slot="validationContext"
>
<b-form-group :label="$t('Paying_Amount') + ' ' + '*'">
<b-form-input
:disabled="payment.status == 'paid'"
label="Amount"
:placeholder="$t('Paying_Amount')"
v-model.number="payment.amount"
@keyup="Verified_paidAmount(payment.amount)"
:state="getValidationState(validationContext)"
aria-describedby="Amount-feedback"
></b-form-input>
<b-form-invalid-feedback
id="Amount-feedback"
>{{ validationContext.errors[0] }}</b-form-invalid-feedback>
</b-form-group>
</validation-provider>
</b-col>
<!-- change Amount -->
<b-col md="4" v-if="payment.status != 'pending' && sale.statut == 'completed'">
<label>{{$t('Change')}} :</label>
<p
class="change_amount"
>{{parseFloat(payment.received_amount - payment.amount).toFixed(2)}}</p>
</b-col>
<!-- Account -->
<b-col lg="4" md="4" sm="12" v-if="payment.status != 'pending' && sale.statut == 'completed'">
<validation-provider name="Account">
<b-form-group slot-scope="{ valid, errors }" :label="$t('Account')">
<v-select
:class="{'is-invalid': !!errors.length}"
:state="errors[0] ? false : (valid ? true : null)"
v-model="payment.account_id"
:reduce="label => label.value"
:placeholder="$t('Choose_Account')"
:options="accounts.map(accounts => ({label: accounts.account_name, value: accounts.id}))"
/>
<b-form-invalid-feedback>{{ errors[0] }}</b-form-invalid-feedback>
</b-form-group>
</validation-provider>
</b-col>
<b-col md="12">
<b-form-group :label="$t('Note')" class="mt-4">
<textarea
v-model="sale.notes"
rows="4"
class="form-control"
:placeholder="$t('Afewwords')"
></textarea>
</b-form-group>
</b-col>
<b-col md="12">
<b-form-group>
<b-button variant="primary" @click="Submit_Sale" :disabled="SubmitProcessing"><i class="i-Yes me-2 font-weight-bold"></i> {{$t('submit')}}</b-button>
<div v-once class="typo__p" v-if="SubmitProcessing">
<div class="spinner sm spinner-primary mt-3"></div>
</div>
</b-form-group>
</b-col>
</b-row>
</b-card>
</b-col>
</b-row>
</b-form>
</validation-observer>
<!-- Modal Update Detail Product -->
<validation-observer ref="Update_Detail_change_sale">
<b-modal hide-footer size="lg" id="form_Update_Detail" :title="detail.name">
<b-form @submit.prevent="submit_Update_Detail">
<b-row>
<!-- Unit Price -->
<b-col lg="6" md="6" sm="12">
<validation-provider
name="Product Price"
:rules="{ required: true , regex: /^\d*\.?\d*$/}"
v-slot="validationContext"
>
<b-form-group :label="$t('ProductPrice') + ' ' + '*'" id="Price-input">
<b-form-input
label="Product Price"
v-model.number="detail.Unit_price"
:state="getValidationState(validationContext)"
aria-describedby="Price-feedback"
></b-form-input>
<b-form-invalid-feedback id="Price-feedback">{{ validationContext.errors[0] }}</b-form-invalid-feedback>
</b-form-group>
</validation-provider>
</b-col>
<!-- Tax Method -->
<b-col lg="6" md="6" sm="12">
<validation-provider name="Tax Method" :rules="{ required: true}">
<b-form-group slot-scope="{ valid, errors }" :label="$t('TaxMethod') + ' ' + '*'">
<v-select
:class="{'is-invalid': !!errors.length}"
:state="errors[0] ? false : (valid ? true : null)"
v-model="detail.tax_method"
:reduce="label => label.value"
:placeholder="$t('Choose_Method')"
:options="
[
{label: 'Exclusive', value: '1'},
{label: 'Inclusive', value: '2'}
]"
></v-select>
<b-form-invalid-feedback>{{ errors[0] }}</b-form-invalid-feedback>
</b-form-group>
</validation-provider>
</b-col>
<!-- Tax Rate -->
<b-col lg="6" md="6" sm="12">
<validation-provider
name="Order Tax"
:rules="{ required: true , regex: /^\d*\.?\d*$/}"
v-slot="validationContext"
>
<b-form-group :label="$t('OrderTax') + ' ' + '*'">
<b-input-group append="%">
<b-form-input
label="Order Tax"
v-model.number="detail.tax_percent"
:state="getValidationState(validationContext)"
aria-describedby="OrderTax-feedback"
></b-form-input>
</b-input-group>
<b-form-invalid-feedback id="OrderTax-feedback">{{ validationContext.errors[0] }}</b-form-invalid-feedback>
</b-form-group>
</validation-provider>
</b-col>
<!-- Discount Method -->
<b-col lg="6" md="6" sm="12">
<validation-provider name="Discount Method" :rules="{ required: true}">
<b-form-group slot-scope="{ valid, errors }" :label="$t('Discount_Method') + ' ' + '*'">
<v-select
v-model="detail.discount_Method"
:reduce="label => label.value"
:placeholder="$t('Choose_Method')"
:class="{'is-invalid': !!errors.length}"
:state="errors[0] ? false : (valid ? true : null)"
:options="
[
{label: 'Percent %', value: '1'},
{label: 'Fixed', value: '2'}
]"
></v-select>
<b-form-invalid-feedback>{{ errors[0] }}</b-form-invalid-feedback>
</b-form-group>
</validation-provider>
</b-col>
<!-- Discount Rate -->
<b-col lg="6" md="6" sm="12">
<validation-provider
name="Discount Rate"
:rules="{ required: true , regex: /^\d*\.?\d*$/}"
v-slot="validationContext"
>
<b-form-group :label="$t('Discount') + ' ' + '*'">
<b-form-input
label="Discount"
v-model.number="detail.discount"
:state="getValidationState(validationContext)"
aria-describedby="Discount-feedback"
></b-form-input>
<b-form-invalid-feedback id="Discount-feedback">{{ validationContext.errors[0] }}</b-form-invalid-feedback>
</b-form-group>
</validation-provider>
</b-col>
<!-- Unit Sale -->
<b-col lg="6" md="6" sm="12" v-if="detail.product_type != 'is_service'">
<validation-provider name="Unit Sale" :rules="{ required: true}">
<b-form-group slot-scope="{ valid, errors }" :label="$t('UnitSale') + ' ' + '*'">
<v-select
:class="{'is-invalid': !!errors.length}"
:state="errors[0] ? false : (valid ? true : null)"
v-model="detail.sale_unit_id"
:placeholder="$t('Choose_Unit_Sale')"
:reduce="label => label.value"
:options="units.map(units => ({label: units.name, value: units.id}))"
/>
<b-form-invalid-feedback>{{ errors[0] }}</b-form-invalid-feedback>
</b-form-group>
</validation-provider>
</b-col>
<!-- Imei or serial numbers -->
<b-col lg="12" md="12" sm="12" v-show="detail.is_imei">
<b-form-group :label="$t('Add_product_IMEI_Serial_number')">
<b-form-input
label="Add_product_IMEI_Serial_number"
v-model="detail.imei_number"
:placeholder="$t('Add_product_IMEI_Serial_number')"
></b-form-input>
</b-form-group>
</b-col>
<b-col md="12">
<b-form-group>
<b-button variant="primary" type="submit" :disabled="Submit_Processing_detail"><i class="i-Yes me-2 font-weight-bold"></i> {{$t('submit')}}</b-button>
<div v-once class="typo__p" v-if="Submit_Processing_detail">
<div class="spinner sm spinner-primary mt-3"></div>
</div>
</b-form-group>
</b-col>
</b-row>
</b-form>
</b-modal>
</validation-observer>
</div>
</template>
<script>
import { mapActions, mapGetters } from "vuex";
import NProgress from "nprogress";
export default {
metaInfo: {
title: "Create Sale"
},
data() {
return {
focused: false,
timer:null,
search_input:'',
product_filter:[],
isLoading: true,
SubmitProcessing:false,
Submit_Processing_detail:false,
warehouses: [],
units: [],
clients: [],
products: [],
details: [],
detail: {},
sales: [],
payment: {
status: "pending",
Reglement: "Cash",
amount: "",
received_amount: "",
},
sale: {
id: "",
date: "",
statut: "completed",
notes: "",
client_id: "",
warehouse_id: "",
tax_rate: 0,
TaxNet: 0,
shipping: 0,
discount: 0
},
total: 0,
GrandTotal: 0,
product: {
id: "",
code: "",
product_type: "",
stock: "",
quantity: 1,
discount: "",
DiscountNet: "",
discount_Method: "",
sale_unit_id:"",
fix_stock:"",
fix_price:"",
name: "",
unitSale: "",
Net_price: "",
Unit_price: "",
Total_price: "",
subtotal: "",
product_id: "",
detail_id: "",
taxe: "",
tax_percent: "",
tax_method: "",
product_variant_id: "",
del: "",
etat: "",
is_imei: "",
imei_number:"",
}
};
},
computed: {
...mapGetters(["currentUserPermissions","currentUser"])
},
methods: {
handleFocus() {
this.focused = true
},
handleBlur() {
this.focused = false
},
showModal() {
this.$bvModal.show('open_scan');
},
onScan (decodedText, decodedResult) {
const code = decodedText;
this.search_input = code;
this.search();
this.$bvModal.hide('open_scan');
},
//--- Submit Validate Create Sale
Submit_Sale() {
this.$refs.create_sale.validate().then(success => {
if (!success) {
this.makeToast(
"danger",
this.$t("Please_fill_the_form_correctly"),
this.$t("Failed")
);
} else if (this.payment.amount > this.payment.received_amount) {
this.makeToast(
"warning",
this.$t("Paying_amount_is_greater_than_Received_amount"),
this.$t("Warning")
);
this.payment.received_amount = 0;
}
else if (this.payment.amount > this.GrandTotal) {
this.makeToast(
"warning",
this.$t("Paying_amount_is_greater_than_Grand_Total"),
this.$t("Warning")
);
this.payment.amount = 0;
}else{
this.Create_Sale();
}
});
},
//---Submit Validation Update Detail
submit_Update_Detail() {
this.$refs.Update_Detail_change_sale.validate().then(success => {
if (!success) {
return;
} else {
this.Update_Detail();
}
});
},
//---Validate State Fields
getValidationState({ dirty, validated, valid = null }) {
return dirty || validated ? valid : null;
},
//------ Toast
makeToast(variant, msg, title) {
this.$root.$bvToast.toast(msg, {
title: title,
variant: variant,
solid: true
});
},
//---------------------- get_units ------------------------------\\
get_units(value) {
axios
.get("get_units?id=" + value)
.then(({ data }) => (this.units = data));
},
//------ Show Modal Update Detail Product
Modal_Updat_Detail(detail) {
NProgress.start();
NProgress.set(0.1);
this.detail = {};
this.get_units(detail.product_id);
this.detail.detail_id = detail.detail_id;
this.detail.sale_unit_id = detail.sale_unit_id;
this.detail.name = detail.name;
this.detail.product_type = detail.product_type;
this.detail.Unit_price = detail.Unit_price;
this.detail.fix_price = detail.fix_price;
this.detail.fix_stock = detail.fix_stock;
this.detail.stock = detail.stock;
this.detail.tax_method = detail.tax_method;
this.detail.discount_Method = detail.discount_Method;
this.detail.discount = detail.discount;
this.detail.quantity = detail.quantity;
this.detail.tax_percent = detail.tax_percent;
this.detail.is_imei = detail.is_imei;
this.detail.imei_number = detail.imei_number;
setTimeout(() => {
NProgress.done();
this.$bvModal.show("form_Update_Detail");
}, 1000);
},
//------ Submit Update Detail Product
Update_Detail() {
NProgress.start();
NProgress.set(0.1);
this.Submit_Processing_detail = true;
for (var i = 0; i < this.details.length; i++) {
if (this.details[i].detail_id === this.detail.detail_id) {
// this.convert_unit();
for(var k=0; k<this.units.length; k++){
if (this.units[k].id == this.detail.sale_unit_id) {
if(this.units[k].operator == '/'){
this.details[i].stock = this.detail.fix_stock * this.units[k].operator_value;
this.details[i].unitSale = this.units[k].ShortName;
}else{
this.details[i].stock = this.detail.fix_stock / this.units[k].operator_value;
this.details[i].unitSale = this.units[k].ShortName;
}
}
}
if (this.details[i].stock < this.details[i].quantity) {
this.details[i].quantity = this.details[i].stock;
} else {
this.details[i].quantity =1;
}
this.details[i].Unit_price = this.detail.Unit_price;
this.details[i].tax_percent = this.detail.tax_percent;
this.details[i].tax_method = this.detail.tax_method;
this.details[i].discount_Method = this.detail.discount_Method;
this.details[i].discount = this.detail.discount;
this.details[i].sale_unit_id = this.detail.sale_unit_id;
this.details[i].imei_number = this.detail.imei_number;
this.details[i].product_type = this.detail.product_type;
if (this.details[i].discount_Method == "2") {
//Fixed
this.details[i].DiscountNet = this.details[i].discount;
} else {
//Percentage %
this.details[i].DiscountNet = parseFloat(
(this.details[i].Unit_price * this.details[i].discount) / 100
);
}
if (this.details[i].tax_method == "1") {
//Exclusive
this.details[i].Net_price = parseFloat(
this.details[i].Unit_price - this.details[i].DiscountNet
);
this.details[i].taxe = parseFloat(
(this.details[i].tax_percent *
(this.details[i].Unit_price - this.details[i].DiscountNet)) /
100
);
} else {
//Inclusive
this.details[i].taxe = parseFloat(
(this.details[i].Unit_price - this.details[i].DiscountNet) *
(this.details[i].tax_percent / 100)
);
this.details[i].Net_price = parseFloat(
this.details[i].Unit_price -
this.details[i].taxe -
this.details[i].DiscountNet
);
}
this.$forceUpdate();
}
}
this.Calcul_Total();
setTimeout(() => {
NProgress.done();
this.Submit_Processing_detail = false;
this.$bvModal.hide("form_Update_Detail");
}, 1000);
},
// Search Products
search(){
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
if (this.search_input.length < 2) {
return this.product_filter= [];
}
if (this.sale.warehouse_id != "" && this.sale.warehouse_id != null) {
this.timer = setTimeout(() => {
const product_filter = this.products.filter(product => product.code === this.search_input || product.barcode.includes(this.search_input));
if(product_filter.length === 1){
this.SearchProduct(product_filter[0])
}else{
this.product_filter= this.products.filter(product => {
return (
product.name.toLowerCase().includes(this.search_input.toLowerCase()) ||
product.code.toLowerCase().includes(this.search_input.toLowerCase()) ||
product.barcode.toLowerCase().includes(this.search_input.toLowerCase())
);
});
// Check if product_filter is empty and show alert
if (this.product_filter.length <= 0) {
this.makeToast(
"warning",
"Product Not Found",
"Warning"
);
}
}
}, 800);
} else {
this.makeToast(
"warning",
this.$t("SelectWarehouse"),
this.$t("Warning")
);
}
},
//---------------------- Event Select Status ------------------------------\\
Selected_Status(value){
if (value != "completed") {
this.payment.status = 'pending';
this.payment.amount = 0;
this.payment.received_amount = 0;
this.payment.account_id = NULL;
}
},
//---------------------- Event Select Payment Status ------------------------------\\
Selected_PaymentStatus(value){
if (value == "paid") {
var payment_amount = this.GrandTotal.toFixed(2);
this.payment.amount = this.formatNumber(payment_amount, 2);
this.payment.received_amount = this.formatNumber(payment_amount, 2);
}else{
this.payment.amount = 0;
this.payment.received_amount = 0;
}
},
//---------- keyup paid Amount
Verified_paidAmount() {
if (isNaN(this.payment.amount)) {
this.payment.amount = 0;
} else {
if (this.payment.amount > this.payment.received_amount) {
this.makeToast(
"warning",
this.$t("Paying_amount_is_greater_than_Received_amount"),
this.$t("Warning")
);
this.payment.amount = 0;
}
else if (this.payment.amount > this.GrandTotal) {
this.makeToast(
"warning",
this.$t("Paying_amount_is_greater_than_Grand_Total"),
this.$t("Warning")
);
this.payment.amount = 0;
}
}
},
//---------- keyup Received Amount
Verified_Received_Amount() {
if (isNaN(this.payment.received_amount)) {
this.payment.received_amount = 0;
}
},
//------------------------- get Result Value Search Product
getResultValue(result) {
return result.code + " " + "(" + result.name + ")";
},
//------------------------- Submit Search Product
SearchProduct(result) {
this.product = {};
if (
this.details.length > 0 &&
this.details.some(detail => detail.code === result.code)
) {
this.makeToast("warning", this.$t("AlreadyAdd"), this.$t("Warning"));
} else {
if( result.product_type =='is_service'){
this.product.quantity = 1;
this.product.code = result.code;
}else{
this.product.code = result.code;
this.product.stock = result.qte_sale;
this.product.fix_stock = result.qte;
if (result.qte_sale < 1) {
this.product.quantity = result.qte_sale;
} else {
this.product.quantity = 1;
}
}
this.product.product_variant_id = result.product_variant_id;
this.Get_Product_Details(result.id, result.product_variant_id);
}
this.search_input= '';
this.$refs.product_autocomplete.value = "";
this.product_filter = [];
},
//---------------------- Event Select Warehouse ------------------------------\\
Selected_Warehouse(value) {
this.search_input= '';
this.product_filter = [];
this.Get_Products_By_Warehouse(value);
},
//------------------------------------ Get Products By Warehouse -------------------------\\
Get_Products_By_Warehouse(id) {
// Start the progress bar.
NProgress.start();
NProgress.set(0.1);
axios
.get("get_Products_by_warehouse/" + id + "?stock=" + 1 + "&is_sale=" + 1 + "&product_service=" + 1 + "&product_combo=" + 1)
.then(response => {
this.products = response.data;
NProgress.done();
})
.catch(error => {
});
},
//----------------------------------------- Add Product -------------------------\\
add_product() {
if (this.details.length > 0) {
this.Last_Detail_id();
} else if (this.details.length === 0) {
this.product.detail_id = 1;
}
this.details.push(this.product);
if(this.product.is_imei){
this.Modal_Updat_Detail(this.product);
}
},
//-----------------------------------Verified QTY ------------------------------\\
Verified_Qty(detail, id) {
for (var i = 0; i < this.details.length; i++) {
if (this.details[i].detail_id === id) {
if (isNaN(detail.quantity)) {
this.details[i].quantity = detail.qte_copy;
}
if (detail.etat == "new" && detail.quantity > detail.stock) {
this.makeToast("warning", this.$t("LowStock"), this.$t("Warning"));
this.details[i].quantity = detail.stock;
} else if (
detail.etat == "current" &&
detail.quantity > detail.stock + detail.qte_copy
) {
this.makeToast("warning", this.$t("LowStock"), this.$t("Warning"));
this.details[i].quantity = detail.qte_copy;
} else {
this.details[i].quantity = detail.quantity;
}
}
}
this.$forceUpdate();
this.Calcul_Total();
},
//-----------------------------------increment QTY ------------------------------\\
increment(detail, id) {
for (var i = 0; i < this.details.length; i++) {
if (this.details[i].detail_id == id) {
if (detail.etat == "new" && detail.quantity + 1 > detail.stock) {
this.makeToast("warning", this.$t("LowStock"), this.$t("Warning"));
} else if (
detail.etat == "current" &&
detail.quantity + 1 > detail.stock + detail.qte_copy
) {
this.makeToast("warning", this.$t("LowStock"), this.$t("Warning"));
} else {
this.formatNumber(this.details[i].quantity++, 2);
}
}
}
this.$forceUpdate();
this.Calcul_Total();
},
//-----------------------------------decrement QTY ------------------------------\\
decrement(detail, id) {
for (var i = 0; i < this.details.length; i++) {
if (this.details[i].detail_id == id) {
if (detail.quantity - 1 > 0) {
if (detail.etat == "new" && detail.quantity - 1 > detail.stock) {
this.makeToast(
"warning",
this.$t("LowStock"),
this.$t("Warning")
);
} else if (
detail.etat == "current" &&
detail.quantity - 1 > detail.stock + detail.qte_copy
) {
this.makeToast(
"warning",
this.$t("LowStock"),
this.$t("Warning")
);
} else {
this.formatNumber(this.details[i].quantity--, 2);
}
}
}
}
this.$forceUpdate();
this.Calcul_Total();
},
//---------- keyup OrderTax
keyup_OrderTax() {
if (isNaN(this.sale.tax_rate)) {
this.sale.tax_rate = 0;
} else if(this.sale.tax_rate == ''){
this.sale.tax_rate = 0;
this.Calcul_Total();
}else {
this.Calcul_Total();
}
},
//---------- keyup Discount
keyup_Discount() {
if (isNaN(this.sale.discount)) {
this.sale.discount = 0;
} else if(this.sale.discount == ''){
this.sale.discount = 0;
this.Calcul_Total();
}else {
this.Calcul_Total();
}
},
//---------- keyup Shipping
keyup_Shipping() {
if (isNaN(this.sale.shipping)) {
this.sale.shipping = 0;
} else if(this.sale.shipping == ''){
this.sale.shipping = 0;
this.Calcul_Total();
}else {
this.Calcul_Total();
}
},
//------------------------------Formetted Numbers -------------------------\\
formatNumber(number, dec) {
const value = (typeof number === "string"
? number
: number.toString()
).split(".");
if (dec <= 0) return value[0];
let formated = value[1] || "";
if (formated.length > dec)
return `${value[0]}.${formated.substr(0, dec)}`;
while (formated.length < dec) formated += "0";
return `${value[0]}.${formated}`;
},
//-----------------------------------------Calcul Total ------------------------------\\
Calcul_Total() {
this.total = 0;
for (var i = 0; i < this.details.length; i++) {
var tax = this.details[i].taxe * this.details[i].quantity;
this.details[i].subtotal = parseFloat(
this.details[i].quantity * this.details[i].Net_price + tax
);
this.total = parseFloat(this.total + this.details[i].subtotal);
}
const total_without_discount = parseFloat(
this.total - this.sale.discount
);
this.sale.TaxNet = parseFloat(
(total_without_discount * this.sale.tax_rate) / 100
);
this.GrandTotal = parseFloat(
total_without_discount + this.sale.TaxNet + this.sale.shipping
);
var grand_total = this.GrandTotal.toFixed(2);
this.GrandTotal = parseFloat(grand_total);
if(this.payment.status == 'paid'){
this.payment.amount = this.formatNumber(this.GrandTotal, 2);
}
},
//-----------------------------------Delete Detail Product ------------------------------\\
delete_Product_Detail(id) {
for (var i = 0; i < this.details.length; i++) {
if (id === this.details[i].detail_id) {
this.details.splice(i, 1);
this.Calcul_Total();
}
}
},
//-----------------------------------verified Order List ------------------------------\\
verifiedForm() {
if (this.details.length <= 0) {
this.makeToast(
"warning",
this.$t("AddProductToList"),
this.$t("Warning")
);
return false;
} else {
var count = 0;
for (var i = 0; i < this.details.length; i++) {
if (
this.details[i].quantity == "" ||
this.details[i].quantity === 0 ||
this.details[i].quantity > this.details[i].stock
) {
count += 1;
if(this.details[i].quantity > this.details[i].stock){
this.makeToast("warning", this.$t("LowStock"), this.$t("Warning"));
return false;
}
}
}
if (count > 0) {
this.makeToast("warning", this.$t("AddQuantity"), this.$t("Warning"));
return false;
} else {
return true;
}
}
},
//--------------------------------- Create Sale -------------------------\\
Create_Sale() {
if (this.verifiedForm()) {
this.SubmitProcessing = true;
NProgress.start();
NProgress.set(0.1);
axios
.post("sales", {
date: this.sale.date,
client_id: this.sale.client_id,
warehouse_id: this.sale.warehouse_id,
statut: this.sale.statut,
notes: this.sale.notes,
tax_rate: this.sale.tax_rate?this.sale.tax_rate:0,
TaxNet: this.sale.TaxNet?this.sale.TaxNet:0,
discount: this.sale.discount?this.sale.discount:0,
shipping: this.sale.shipping?this.sale.shipping:0,
GrandTotal: this.GrandTotal,
details: this.details,
payment: this.payment,
change: parseFloat(this.payment.received_amount - this.payment.amount).toFixed(2),
})
.then(response => {
NProgress.done();
this.makeToast(
"success",
this.$t("Create.TitleSale"),
this.$t("Success")
);
this.SubmitProcessing = false;
this.$router.push({ name: "index_sales" });
})
.catch(error => {
NProgress.done();
this.makeToast("danger", this.$t("InvalidData"), this.$t("Failed"));
this.SubmitProcessing = false;
});
}
},
//-------------------------------- Get Last Detail Id -------------------------\\
Last_Detail_id() {
this.product.detail_id = 0;
var len = this.details.length;
this.product.detail_id = this.details[len - 1].detail_id + 1;
},
//---------------------------------get Product Details ------------------------\\
Get_Product_Details(product_id, variant_id) {
axios.get("/show_product_data/" + product_id +"/"+ variant_id).then(response => {
this.product.discount = 0;
this.product.DiscountNet = 0;
this.product.discount_Method = "2";
this.product.etat = "new";
this.product.del = 0;
this.product.product_id = response.data.id;
this.product.name = response.data.name;
this.product.product_type = response.data.product_type;
this.product.Net_price = response.data.Net_price;
this.product.Unit_price = response.data.Unit_price;
this.product.fix_price = response.data.fix_price;
this.product.taxe = response.data.tax_price;
this.product.tax_method = response.data.tax_method;
this.product.tax_percent = response.data.tax_percent;
this.product.unitSale = response.data.unitSale;
this.product.sale_unit_id = response.data.sale_unit_id;
this.product.is_imei = response.data.is_imei;
this.product.imei_number = '';
this.add_product();
this.Calcul_Total();
});
},
//---------------------------------------Get Elements ------------------------------\\
GetElements() {
let id = this.$route.params.id;
axios
.get(`convert_to_sale_data/${id}`)
.then(response => {
this.sale = response.data.sale;
this.details = response.data.details;
this.clients = response.data.clients;
this.warehouses = response.data.warehouses;
this.Get_Products_By_Warehouse(this.sale.warehouse_id);
this.Calcul_Total();
this.isLoading = false;
})
.catch(response => {
setTimeout(() => {
this.isLoading = false;
}, 500);
});
}
},
//----------------------------- Created function-------------------
created() {
this.GetElements();
}
};
</script>
<style>
.input-with-icon {
display: flex;
align-items: center;
}
.scan-icon {
width: 50px; /* Adjust size as needed */
height: 50px;
margin-right: 8px; /* Adjust spacing as needed */
cursor: pointer;
}
</style>