Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <template>
- <div>
- <ValidationObserver ref="form" v-slot="{ handleSubmit }">
- <form @submit.prevent="handleSubmit(onSubmit)">
- <div class="row mb-3">
- <div class="col-12 mb-4">
- <div class="d-flex justify-content-between align-items-center">
- <div class="page-inner-header">
- <h5><i class="bi bi-file-ruled mr-2"></i>
- New invoice</h5>
- <p class="text-muted mb-0 small">Create invoice</p>
- </div>
- <div class="row">
- <div class="col text-center">
- <img src="/assets/img/crm/invoice.svg" width="120px" alt="invoice">
- </div>
- </div>
- </div>
- </div>
- </div>
- <div class="row">
- <div class="col-md-6">
- <div><label for="invoice_date" class="form-control-label">Search</label></div>
- <div class="row">
- <div class="col-md-3">
- <b-button v-b-modal.newCustomer class="btn-sm mb-3 mb-md-3">Add new Customer</b-button>
- </div>
- <div class="col-md-9">
- <ValidationProvider vid="crm_customer_id" name="Customer" rules="required" v-slot="{ errors }">
- <typehead-component :url="customersApi" :initialize="customer"
- @input="onCustomer" :error="errors[0]"/>
- </ValidationProvider>
- </div>
- </div>
- <div v-if="customer.id">
- <div class="card p-4">
- <label for="invoice_date" class="form-control-label">Customer details:</label>
- <hr class="m-0">
- <div class="mt-3"><i class="bi bi-person mr-2"></i>{{ customer.name }}</div>
- <div v-if="customer.email"><i class="bi bi-inbox mr-2"></i> {{ customer.email }}</div>
- <div v-if="customer.address"><i class="bi bi-geo mr-2"></i>{{ customer.address }}</div>
- <div v-if="customer.phone_number"><i class="bi bi-phone mr-2"></i>{{ customer.phone_number }}</div>
- </div>
- </div>
- </div>
- <div class="col-md-6">
- <div class="row">
- <div class="col-md-6">
- <ValidationProvider vid="invoice_date" name="Invoice Date" rules="required" v-slot="{ errors }">
- <label for="invoice_date" class="form-control-label">Invoice Date</label>
- <input type="date" v-model="invoice_date" id="invoice_date"
- class="form-control form-control-sm" :class="{'is-invalid': errors[0] }">
- <span v-if="errors[0]" class="invalid-feedback">{{ errors[0] }}</span>
- </ValidationProvider>
- </div>
- <div class="col-md-6">
- <ValidationProvider vid="due_date" name="Due Date" rules="required" v-slot="{ errors }">
- <label for="due_date" class="form-control-label">Due Date</label>
- <input type="date" v-model="due_date" id="due_date"
- class="form-control form-control-sm" :class="{'is-invalid': errors[0] }">
- <span v-if="errors[0]" class="invalid-feedback">{{ errors[0] }}</span>
- </ValidationProvider>
- </div>
- </div>
- </div>
- </div>
- <hr>
- <div class="row">
- <div class="col-12">
- <div class="invoice-scroll">
- <table class="table">
- <thead>
- <tr>
- <th class="col-1">No</th>
- <th class="col-4">Item</th>
- <th class="col-2">Price/unit</th>
- <th class="col-2">Quantity</th>
- <th class="col-2 text-right">Total</th>
- <th class="col-1"></th>
- </tr>
- </thead>
- <tr v-for="(item, index) in items">
- <td data-label="No" class="p-4">{{ index + 1 }}</td>
- <td data-label="Item">
- <ValidationProvider name="description" rules="required|max:250|is_not:Item name"
- v-slot="{ errors }">
- <input type="text" v-model="item.description" class="form-control form-control-sm"
- :class="{'is-invalid': errors[0] }">
- <span v-if="errors[0]" class="invalid-feedback">{{ errors[0] }}</span>
- </ValidationProvider>
- </td>
- <td data-label="Price/unite">
- <ValidationProvider name="Price" rules="required|min_value:0.01" v-slot="{ errors }">
- <input type="number" min="0" step="0.01" v-model="item.price"
- class="form-control form-control-sm" :class="{'is-invalid': errors[0] }">
- <span v-if="errors[0]" class="invalid-feedback">{{ errors[0] }}</span>
- </ValidationProvider>
- </td>
- <td data-label="Quantity">
- <ValidationProvider name="Quantity" rules="required|min_value:1" v-slot="{ errors }">
- <input type="number" min="0" v-model="item.quantity" class="form-control form-control-sm"
- :class="{'is-invalid': errors[0] }">
- <span v-if="errors[0]" class="invalid-feedback">{{ errors[0] }}</span>
- </ValidationProvider>
- </td>
- <td data-label="Total" class="text-right p-4"><strong>{{
- decimalDigits(item.price * item.quantity)
- }}</strong></td>
- <td class="text-right">
- <button class="btn btn-danger btn-sm"
- @click.prevent="deleteItem(index)"><i class="bi bi-x"></i>
- </button>
- </td>
- </tr>
- </table>
- </div>
- </div>
- </div>
- <div class="row">
- <div class="col-12">
- <button @click.prevent="addNewItem" class="btn btn-success btn-sm">Add item</button>
- </div>
- </div>
- <hr>
- <div class="row">
- <div class="col-12 col-md-6 order-12 order-md-1">
- <div class="row">
- <div class="col-12">
- <p class="mb-n1"><label class="form-control-label">Notes:</label></p>
- <ValidationProvider vid="note" name="Notes" rules="max:1000" v-slot="{ errors }">
- <textarea class="form-control form-control-sm" :class="{'is-invalid': errors[0] }" rows="4"
- v-model="note"></textarea>
- <span v-if="errors[0]" class="invalid-feedback">{{ errors[0] }}</span>
- </ValidationProvider>
- </div>
- </div>
- <div class="row">
- <div class="col-12">
- <p class="mb-n1 mt-3"><label class="form-control-label">Terms:</label></p>
- <ValidationProvider vid="terms" name="Terms" rules="max:1000" v-slot="{ errors }">
- <textarea class="form-control form-control-sm" :class="{'is-invalid': errors[0] }" rows="4"
- v-model="terms"></textarea>
- <span v-if="errors[0]" class="invalid-feedback">{{ errors[0] }}</span>
- </ValidationProvider>
- </div>
- </div>
- </div>
- <div class="col-12 col-md-6 order-1 order-md-12">
- <div class="row">
- <div class="col-4"><label class="form-control-label">Subtotal:</label></div>
- <div class="col-4"></div>
- <div class="col-4 text-right">{{ decimalDigits(subTotal) }}</div>
- </div>
- <div class="row mt-2">
- <div class="col-12 col-md-4"><label class="form-control-label">Discount:</label></div>
- <div class="col-8 col-md-4">
- <div class="input-group input-group-sm">
- <input type="number" min="0" max="100" v-model="discountRate"
- class="form-control form-control-sm"/>
- <div class="input-group-append">
- <span class="input-group-text">%</span>
- </div>
- </div>
- </div>
- <div class="col-4 text-right">{{ decimalDigits(discountTotal) }}</div>
- </div>
- <div class="row mt-2">
- <div class="col-12 col-md-4"><label class="form-control-label">Tax:</label></div>
- <div class="col-8 col-md-4">
- <div class="input-group input-group-sm">
- <input type="number" min="0" max="100" step="1" v-model="taxRate"
- class="form-control form-control-sm"/>
- <div class="input-group-append">
- <span class="input-group-text">%</span>
- </div>
- </div>
- </div>
- <div class="col-4 text-right">{{ decimalDigits(taxTotal) }}</div>
- </div>
- <div class="row mt-2">
- <div class="col-8"><label class="form-control-label">Total:</label></div>
- <div class="col-4 text-right">{{ decimalDigits(grandTotal) }}</div>
- </div>
- </div>
- </div>
- <div class="row">
- <div class="col-12 mt-5">
- <input type="submit" value="Create invoice" class="btn btn-primary btn-sm w-100" :disabled="loadingBtn">
- </div>
- </div>
- </form>
- <new-customer-component @customer="addNewCustomer"></new-customer-component>
- </ValidationObserver>
- </div>
- </template>
- <script>
- import TypeheadComponent from "../../../helpers/Typehead.vue";
- import NewCustomerComponent from "./NewCustomerComponent";
- export default {
- components: {
- TypeheadComponent,
- NewCustomerComponent
- },
- data() {
- return {
- loadingBtn: false,
- invoiceDate: '',
- items: [{
- description: 'Item name',
- quantity: 1,
- price: 0
- }],
- customers: [],
- customer: {
- id: '',
- name: '',
- email: '',
- address: '',
- phone_number: ''
- },
- invoiceCurrency: '£',
- discountRate: 0,
- taxRate: 20,
- due_date: '',
- invoice_date: '',
- terms: '',
- note: '',
- customersApi: '/crm/api/customer',
- crm_customer_id: ''
- }
- },
- computed: {
- subTotal() {
- return this.items.reduce(function (accumulator, item) {
- return accumulator + (item.price * item.quantity);
- }, 0);
- },
- discountTotal() {
- return this.subTotal * (this.discountRate / 100);
- },
- taxTotal() {
- return (this.subTotal - this.discountTotal) * (this.taxRate / 100);
- },
- grandTotal() {
- return (this.subTotal - this.discountTotal) + this.taxTotal;
- }
- },
- methods: {
- addNewCustomer(value) {
- this.customers.push(value);
- },
- resetFields() {
- let initialData = initialState();
- for (let prop in initialData) {
- this[prop] = initialData[prop];
- }
- },
- onCustomer(e) {
- const customer = e.target.value;
- this.customer.id = customer.id;
- this.customer.name = customer.name;
- this.customer.email = customer.email;
- this.customer.address = customer.address;
- },
- onSubmit() {
- alert('hit');
- this.loadingBtn = true;
- axios.post('/crm/invoice', {
- due_date: this.due_date,
- invoice_date: this.invoice_date,
- crm_customer_id: this.customer.id,
- tax: this.taxRate,
- sub_total: this.subTotal,
- discount: this.discountTotal,
- discount_rate: this.discountRate,
- grand_total: this.grandTotal,
- terms: this.terms,
- note: this.note,
- items: this.items
- })
- .then((response) => {
- this.$notify({
- type: 'success',
- group: 'crm',
- title: 'Success',
- text: 'Your Invoice has been created'
- });
- setTimeout(() => {
- window.location.href = '/crm/invoice';
- }, 500)
- })
- .catch((error) => {
- this.loadingBtn = false;
- if (error.response.status === 422) {
- this.$notify({
- type: 'error',
- group: 'crm',
- title: 'Validation errors',
- text: error.response.data.message
- });
- this.$refs.form.setErrors(error.response.data.errors)
- } else {
- this.$notify({
- type: 'warn',
- group: 'crm',
- title: 'Unexpected error',
- text: 'Unexpected error, please try later.'
- });
- }
- });
- },
- addNewItem() {
- this.items.push({
- description: 'Item name',
- quantity: 0,
- price: 0
- })
- },
- deleteItem(index) {
- this.items.splice(index, 1)
- },
- decimalDigits(value) {
- return this.invoiceCurrency + ' ' + value.toFixed(2);
- },
- }
- };
- </script>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement