Files
exchange/resources/assets/js/components/NewInvoice.vue
T
2020-09-02 16:18:34 +08:00

563 lines
17 KiB
Vue

/* eslint-disable camelcase */
<template>
<div class="invoice">
<h3 class="title">Purchase Order</h3>
<div class="invoice-container">
<div class="buyer-detail card">
<div class="card-body">
<div class="card-title">
<h5>
My Infomation
</h5>
</div>
<div class="form-group">
<label for="marking">Marking</label>
<input id="marking" v-model="$v.formData.marking.$model" type="text" class="form-control" disabled>
</div>
<div class="form-group">
<label for="buyer-company">Buyer's Company</label>
<input id="buyer-company"
v-model="$v.formData.buyer_company.$model"
:class="{
'is-invalid': $v.formData.buyer_company.$invalid && $v.formData.buyer_company.$dirty,
'is-valid': !$v.formData.buyer_company.$invalid && $v.formData.buyer_company.$dirty
}"
type="text"
class="form-control"
@blur="$v.formData.buyer_company.$touch()">
<div class="invalid-feedback">
Buyer Company Required
</div>
</div>
<!-- <div class="form-group">
<label for="gst-id">GST ID</label>
<input id="gst-id" type="text" class="form-control" disabled>
</div> -->
<div class="form-group">
<label for="contact-number">Contact Number</label>
<input id="contact-number"
v-model.trim="$v.formData.contact_no.$model"
:class="{
'is-invalid': $v.formData.contact_no.$invalid && $v.formData.contact_no.$dirty,
'is-valid': !$v.formData.contact_no.$invalid && $v.formData.contact_no.$dirty
}"
type="tel"
class="form-control"
@blur="$v.formData.contact_no.$touch()">
<div class="invalid-feedback">
Contact Number Required
</div>
</div>
<div class="form-group">
<label for="address">Address</label>
<textarea id="address"
v-model="$v.formData.address.$model"
:class="{
'is-invalid': $v.formData.address.$invalid && $v.formData.address.$dirty,
'is-valid': !$v.formData.address.$invalid && $v.formData.address.$dirty
}"
class="form-control"
cols="30"
rows="4"
@blur="$v.formData.address.$touch()"/>
<div class="invalid-feedback">
Address Required
</div>
</div>
</div>
</div>
<div class="conversion-rate">
<h5>
Conversion: {{ rate }}
</h5>
</div>
<div class="billing-detail-title">
<h5>Billing Detail</h5>
</div>
<div class="billing-detail-lines">
<table class="table">
<thead>
<tr>
<th class="align-middle">#</th>
<th class="align-middle">Stock Code</th>
<th class="align-middle">Description</th>
<th class="text-center align-middle">Qty</th>
<th class="text-center align-middle">Unit Price (RMB)</th>
<th class="text-center align-middle">Unit Price (RM)</th>
<th class="text-center align-middle">Total Amount (RM)</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody>
<tr>
<td>&nbsp;</td>
<td>
<div class="form-group">
<input v-model="$v.addLine.stock_code.$model"
:class="{
'is-invalid': $v.addLine.stock_code.$invalid && $v.addLine.stock_code.$dirty,
'is-valid': !$v.addLine.stock_code.$invalid && $v.addLine.stock_code.$dirty
}"
name="stockcode" type="text"
class="form-control"
@blur="$v.addLine.stock_code.$touch()">
<div class="invalid-feedback">
Stock Code Required
</div>
</div>
</td>
<td>
<div class="form-group">
<textarea id="description"
v-model="$v.addLine.description.$model"
:class="{
'is-invalid': $v.addLine.description.$invalid && $v.addLine.description.$dirty,
'is-valid': !$v.addLine.description.$invalid && $v.addLine.description.$dirty
}"
name="description" cols="20" rows="2"
@blur="$v.addLine.description.$touch()"/>
<div class="invalid-feedback">
Description Required
</div>
</div>
</td>
<td>
<div class="form-group">
<input id="quantity"
v-model="$v.addLine.quantity.$model"
:class="{
'is-invalid': $v.addLine.quantity.$invalid && $v.addLine.quantity.$dirty,
'is-valid': !$v.addLine.quantity.$invalid && $v.addLine.quantity.$dirty
}"
type="number"
min="1"
class="form-control"
name="quantity"
@change="onUnitPriceRM()"
@blur="$v.addLine.quantity.$touch()">
<div class="invalid-feedback">
Quantity Required
</div>
</div>
</td>
<td>
<div class="form-group">
<input id="rmb-unit-price"
v-model="$v.addLine.unit_price_rmb.$model"
:class="{
'is-invalid': $v.addLine.unit_price_rmb.$invalid && $v.addLine.unit_price_rmb.$dirty,
'is-valid': !$v.addLine.unit_price_rmb.$invalid && $v.addLine.unit_price_rmb.$dirty
}"
type="number"
min="0"
name="rmb-unit-price"
class="form-control"
@change="onUnitPriceRMB()"
@blur="$v.addLine.unit_price_rmb.$touch()">
<div class="invalid-feedback">
Unit Price Required
</div>
</div>
</td>
<td>
<div class="form-group">
<input id="rm-unit-price"
v-model="$v.addLine.unit_price_rm.$model"
:class="{
'is-invalid': $v.addLine.unit_price_rm.$invalid && $v.addLine.unit_price_rm.$dirty,
'is-valid': !$v.addLine.unit_price_rm.$invalid && $v.addLine.unit_price_rm.$dirty
}"
type="number"
min="0"
name="rm-unit-price"
class="form-control"
@change="onUnitPriceRM()"
@blur="$v.addLine.unit_price_rm.$touch()">
<div class="invalid-feedback">
Unit Price Required
</div>
</div>
</td>
<td>
<div class="form-group">
<input id="total"
v-model="$v.addLine.total.$model"
type="number"
min="0"
name="subtotal"
class="form-control"
disabled>
</div>
</td>
<td>
<button class="btn btn-success" type="button" @click="onAddLine()">
Add
</button>
</td>
</tr>
<tr v-for="(line, index) in formData.lines" :key="index">
<td class="line-number text-center align-middle">
{{ index + 1 }}
</td>
<td class="stock-code text-center align-middle">
{{ line.stock_code }}
</td>
<td class="description align-middle">
{{ line.description }}
</td>
<td class="quantity text-center align-middle">
{{ line.quantity }}
</td>
<td class="unit-price-rmb text-center align-middle">
{{ line.unit_price_rmb }}
</td>
<td class="unit-price-rm text-center align-middle">
{{ line.unit_price_rm }}
</td>
<td class="line-subtotal text-center align-middle">
{{ line.total }}
</td>
<td>
<button class="btn btn-danger" @click="onRemoveLine(index)">
Remove
</button>
</td>
</tr>
</tbody>
<tfoot>
<tr class="subtotal-line">
<td colspan="5"/>
<td class="subtotal-title text-center">
Subtotal
</td>
<td class="subtotal text-center">
{{ subtotal }}
</td>
<td>
&nbsp;
</td>
</tr>
<tr v-if="tax > 0" class="gst-line">
<td colspan="5"/>
<td class="gst-title text-center">
GST
</td>
<td class="gst-total text-center">
{{ tax }}
</td>
<td>
&nbsp;
</td>
</tr>
<tr class="total-line">
<td colspan="5"/>
<td class="total-title text-center">
Total
</td>
<td class="total text-center">
{{ total }}
</td>
<td>
&nbsp;
</td>
</tr>
<tr>
<td colspan="5">&nbsp;</td>
<td colspan="2">
<button class="btn btn-success btn-block">
Create PO
</button>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</template>
<style>
.container {
margin-left: 10% !important;
margin-right: 10% !important;
}
.el-main {
padding-left: 0 !important;
padding-right: 0 !important;
}
.title {
margin-top: 1em;
padding-left: 1.7em;
padding-bottom: 0 !important;
}
.buyer-detail {
grid-area: buyer-detail;
width: 100%;
}
.card-body {
display: flex !important;
flex-direction: row !important;
flex-wrap: wrap !important;
justify-content: space-around !important;
}
.buyer-detail .form-group {
width: 45%;
}
.card-title {
width: 100%;
}
.conversion-rate {
grid-area: conversion-rate;
}
.conversion-rate h5 {
float: right;
background-color: lightblue;
padding-left: 1em;
padding-right: 1em;
}
.billing-detail-title {
width: 100%;
grid-area: billing-detail-title;
}
.billing-detail-lines {
width: 100%;
grid-area: billing-detail-lines;
}
.invoice-container {
padding: 2em 3em;
display: grid;
grid-template-areas:
'buyer-detail buyer-detail'
'billing-detail-title conversion-rate'
'billing-detail-lines billing-detail-lines';
}
</style>
<script>
import Vue from 'vue'
import Vuelidate from 'vuelidate'
import { required, numeric, or, decimal } from 'vuelidate/lib/validators'
Vue.use(Vuelidate)
export default {
name: 'NewComponent',
props: {
trackerConfig: {
type: Object,
default: function () {
return {
status: 5,
term: null
}
}
},
booking_id: {
type: String,
default: null
},
booking_details: {
type: Object,
default: function () {
return {
id: null,
amount: null,
bia: null,
user_bankslip_path: null,
china_bankslip_path: null,
marking: null
}
}
}
},
data: function () {
return {
formData: {
buyer_company: '',
address: '',
contact_no: '',
marking: this.booking_details.marking,
gst_id: '',
lines: []
},
addLine: {
order: null,
description: null,
quantity: null,
unit_price_rmb: null,
unit_price_rm: null,
stock_code: null,
total: null
},
rate: 0,
service_charge: 0,
amount: 0,
invoice_total: 0,
tax: 0,
subtotal: 0,
total: 0
}
},
computed: {
},
validations: {
formData: {
buyer_company: {
required
},
address: {
required
},
contact_no: {
required
},
marking: {
required
},
gst_id: {
},
lines: [
{
stock_code: {
required
},
description: {
required
},
quantity: {
required,
numeric
},
unit_price_rmb: {
required,
mycustomval: or(numeric, decimal)
},
unit_price_rm: {
required,
mycustomval: or(numeric, decimal)
},
total: {
required,
mycustomval: or(numeric, decimal)
}
}
]
},
addLine: {
stock_code: {
required
},
description: {
required
},
quantity: {
required,
numeric
},
unit_price_rmb: {
required,
mycustomval: or(numeric, decimal)
},
unit_price_rm: {
required,
mycustomval: or(numeric, decimal)
},
total: {
required,
mycustomval: or(numeric, decimal)
}
}
},
watch: {
booking_details: function () {
const {
buyer_company,
reg_no,
address,
contact_no,
marking,
tax,
service_charge,
amount,
rate
} = this.booking_details
this.formData.buyer_company = buyer_company
this.formData.reg_no = reg_no
this.formData.address = address
this.formData.contact_no = contact_no
this.formData.marking = marking
this.tax = tax
this.service_charge = service_charge
this.amount = amount
this.rate = rate
}
},
created: {
},
methods: {
onAddLine: function () {
if (this.$v.addLine.$invalid) {
console.log('invalid', this.$v.addLine.$invalid)
this.$v.addLine.$touch()
return
}
const {
order,
description,
quantity,
stock_code,
unit_price_rmb,
unit_price_rm,
total
} = this.addLine
const data = {
order: order,
description,
quantity,
stock_code,
unit_price_rmb,
unit_price_rm,
total
}
this.formData.lines.push(data)
this.setTotal()
this.clearAddLine()
},
onUnitPriceRMB: function () {
console.log(this.addLine.unit_price_rmb)
this.addLine.unit_price_rm = (+this.addLine.unit_price_rmb * +this.rate).toFixed(2)
this.addLine.total = (+this.addLine.unit_price_rm * +this.addLine.quantity).toFixed(2)
},
onUnitPriceRM: function () {
this.addLine.unit_price_rmb = (this.addLine.unit_price_rm / this.rate).toFixed(2)
this.addLine.total = (+this.addLine.unit_price_rm * +this.addLine.quantity).toFixed(2)
},
onRemoveLine: function (line) {
this.formData.lines.splice(line)
this.setTotal()
},
setTotal: function () {
console.log(this.formData.lines)
console.log(this.formData.lines.map(line => line.total))
console.log(this.formData.lines.map(line => line.total).reduce((a, b) => +a + +b))
this.subtotal = parseFloat(this.formData.lines.map(line => line.total).reduce((a, b) => parseFloat(a) + parseFloat(b))).toFixed(2)
this.total = parseFloat(+this.subtotal + (+this.subtotal * (+this.tax || 0) / 100)).toFixed(2)
},
clearAddLine: function () {
this.addLine.order = null
this.addLine.description = null
this.addLine.quantity = null
this.addLine.unit_price_rmb = null
this.addLine.unit_price_rm = null
this.addLine.stock_code = null
this.addLine.total = null
this.$v.addLine.$reset()
}
}
}
</script>