From 9a3846b1e6cc1a536cf6ec89b13acbeac2df67c8 Mon Sep 17 00:00:00 2001 From: Karel Vendla Date: Tue, 16 Feb 2021 18:58:55 +0200 Subject: [PATCH] Add invoice validation & prefill invoice data. --- src/services/invoice.service.js | 95 +++++++++++++++++++++++++++++---- src/store/invoices.js | 6 ++- src/utils/helpers.js | 35 ++++++++++-- 3 files changed, 119 insertions(+), 17 deletions(-) diff --git a/src/services/invoice.service.js b/src/services/invoice.service.js index cfec055..983983d 100644 --- a/src/services/invoice.service.js +++ b/src/services/invoice.service.js @@ -1,4 +1,6 @@ import storage from 'localforage'; +import { validate, generateInvoiceNumber } from '@/utils/helpers'; +import dayjs from 'dayjs'; class InvoiceService { async getInvoices() { @@ -12,9 +14,32 @@ class InvoiceService { } async createInvoice(invoice) { - // TODO: add invoice no, issued_at, due_at, late_fee, prefill company info, bank_info, currency, vat_rate + const team = storage.getItem('team'); + const invoices = await this.getInvoices(); + invoice.issued_at = dayjs() + .format('YYYY-MM-DD'); + invoice.due_at = dayjs() + .add(14, 'days') + .format('YYYY-MM-DD'); + invoice.number = generateInvoiceNumber(dayjs() + .format('YYYY'), invoices.length + 1); + invoice.late_fee = 0.5; + invoice.from_name = team.company_name; + invoice.from_address = team.company_address; + invoice.from_postal_code = team.from_postal_code; + invoice.from_city = team.company_city; + invoice.from_country = team.company_country; + invoice.from_county = team.company_county; + invoice.from_reg_no = team.company_reg_no; + invoice.from_vat_no = team.company_vat_no; + invoice.from_website = team.website; + invoice.from_email = team.contact_email; + invoice.from_phone = team.contact_phone; + invoice.vat_rate = 0; + invoice.currency = 'USD'; + delete invoice.$id; delete invoice.$isNew; delete invoice.$isDirty; @@ -24,11 +49,24 @@ class InvoiceService { } async updateInvoice(invoice) { - // TODO: validation - const invoices = await this.getInvoices(); - const index = invoices.findIndex(item => item.id === invoice.id); - invoices[index] = invoice; - return storage.setItem('invoices', invoices); + const necessaryFields = { + currency: 'Currency', + vat_rate: 'Vat Rate', + late_fee: 'Late Fee', + issued_at: 'Issued At', + due_at: 'Due At', + number: 'Number', + }; + + const validation = validate(necessaryFields, invoice); + + if (validation.length === 0) { + const invoices = await this.getInvoices(); + const index = invoices.findIndex(item => item.id === invoice.id); + invoices[index] = invoice; + return storage.setItem('invoices', invoices); + } + return Promise.reject(validation); } async deleteInvoice(invoiceId) { @@ -38,10 +76,47 @@ class InvoiceService { return storage.setItem('invoices', invoices); } - bookInvoice(invoice) { - // TODO: validation - invoice.status = 'booked'; - return this.updateInvoice(invoice); + async bookInvoice(invoice) { + const necessaryFields = { + currency: 'Currency', + vat_rate: 'Vat rate', + late_fee: 'Late fee', + issued_at: 'Issued At', + due_at: 'Due At', + number: 'Number', + client_id: 'Client Id', + client_name: 'Client Name', + client_address: 'Client Address', + client_postal_code: 'Client Postal Code', + client_city: 'Client City', + client_email: 'Client Email', + client_country: 'Country', + from_name: 'Name', + from_address: 'Address', + from_postal_code: 'Postal Code', + from_country: 'Country/State', + from_city: 'City', + from_website: 'Website', + from_email: 'Your Email', + from_phone: 'From Phone', + bank_name: 'Bank Name', + bank_account_no: 'Bank Account No.', + project_id: 'Project Id', + rows: { + item: 'Item', + quantity: 'Quantity', + price: 'Price', + unit: 'Unit', + }, + }; + + const validation = await validate(necessaryFields, invoice); + + if (validation.length === 0) { + invoice.status = 'booked'; + return this.updateInvoice(invoice); + } + return Promise.reject(validation); } } diff --git a/src/store/invoices.js b/src/store/invoices.js index b650df8..20f0ffc 100644 --- a/src/store/invoices.js +++ b/src/store/invoices.js @@ -123,7 +123,7 @@ export default { commit('clearErrors'); return InvoiceService.updateInvoice(getters.invoice) - .catch(err => commit('setErrors', err.response.data.errors)); + .catch(err => commit('setErrors', err.errors)); }, async updateInvoiceRow({ getters, dispatch, commit }, payload) { await dispatch('invoiceRowProps', payload); @@ -161,10 +161,12 @@ export default { commit('clearErrors'); try { + console.log('tryBookInvoice'); const res = await InvoiceService.bookInvoice(getters.invoice); return dispatch('getInvoice', res.invoice_id); } catch (err) { - commit('setErrors', err.response.data.errors); + console.log(err); + commit('setErrors', err.errors); } }, }, diff --git a/src/utils/helpers.js b/src/utils/helpers.js index e5fe405..6687980 100644 --- a/src/utils/helpers.js +++ b/src/utils/helpers.js @@ -1,7 +1,8 @@ /* eslint-disable */ export function uuidv4() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { - var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); + var r = Math.random() * 16 | 0, + v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } @@ -30,18 +31,42 @@ export function pick(obj, map) { return objSubset; } + +export function validate(neededFields, fieldsToValidate) { + const validationErrors = {}; + + for (const [key, value] of Object.entries(neededFields)) { + if (Array.isArray(fieldsToValidate[key])) { + fieldsToValidate[key].forEach((item) => { + }); + } + if (!fieldsToValidate.hasOwnProperty(key) || !fieldsToValidate[key] || fieldsToValidate[key].length === 0) { + validationErrors[key] = [`Field ${value} is required`]; + } + } + + console.log('errors', validationErrors); + return { errors: validationErrors }; +} + + +export function generateInvoiceNumber(date, number) { + return `${date}-${number}`; +} + export function download(data, filename, type) { - var file = new Blob([data], {type: type}); + var file = new Blob([data], { type: type }); if (window.navigator.msSaveOrOpenBlob) // IE10+ + { window.navigator.msSaveOrOpenBlob(file, filename); - else { // Others - var a = document.createElement("a"), + } else { // Others + var a = document.createElement('a'), url = URL.createObjectURL(file); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); - setTimeout(function() { + setTimeout(function () { document.body.removeChild(a); window.URL.revokeObjectURL(url); }, 0);