mirror of
https://github.com/mokuappio/serverless-invoices.git
synced 2025-10-28 00:11:08 -04:00
Improve naming conventions. Fail route first, then happy route. Abstract invoice no generation. Fix nested items validation.
This commit is contained in:
@ -1,4 +1,5 @@
|
|||||||
import storage from 'localforage';
|
import storage from 'localforage';
|
||||||
|
import TeamService from '@/services/team.service';
|
||||||
import { validate, generateInvoiceNumber } from '@/utils/helpers';
|
import { validate, generateInvoiceNumber } from '@/utils/helpers';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
@ -14,7 +15,7 @@ class InvoiceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async createInvoice(invoice) {
|
async createInvoice(invoice) {
|
||||||
const team = storage.getItem('team');
|
const team = await TeamService.getTeam();
|
||||||
|
|
||||||
const invoices = await this.getInvoices();
|
const invoices = await this.getInvoices();
|
||||||
|
|
||||||
@ -23,8 +24,7 @@ class InvoiceService {
|
|||||||
invoice.due_at = dayjs()
|
invoice.due_at = dayjs()
|
||||||
.add(14, 'days')
|
.add(14, 'days')
|
||||||
.format('YYYY-MM-DD');
|
.format('YYYY-MM-DD');
|
||||||
invoice.number = generateInvoiceNumber(dayjs()
|
invoice.number = generateInvoiceNumber(invoices);
|
||||||
.format('YYYY'), invoices.length + 1);
|
|
||||||
invoice.late_fee = 0.5;
|
invoice.late_fee = 0.5;
|
||||||
invoice.from_name = team.company_name;
|
invoice.from_name = team.company_name;
|
||||||
invoice.from_address = team.company_address;
|
invoice.from_address = team.company_address;
|
||||||
@ -49,7 +49,7 @@ class InvoiceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async updateInvoice(invoice) {
|
async updateInvoice(invoice) {
|
||||||
const necessaryFields = {
|
const requiredFields = {
|
||||||
currency: 'Currency',
|
currency: 'Currency',
|
||||||
vat_rate: 'Vat Rate',
|
vat_rate: 'Vat Rate',
|
||||||
late_fee: 'Late Fee',
|
late_fee: 'Late Fee',
|
||||||
@ -58,15 +58,14 @@ class InvoiceService {
|
|||||||
number: 'Number',
|
number: 'Number',
|
||||||
};
|
};
|
||||||
|
|
||||||
const validation = validate(necessaryFields, invoice);
|
const errors = validate(requiredFields, invoice);
|
||||||
|
if (Object.keys(errors).length > 0) {
|
||||||
if (validation.length === 0) {
|
return Promise.reject(errors);
|
||||||
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);
|
const invoices = await this.getInvoices();
|
||||||
|
const index = invoices.findIndex(item => item.id === invoice.id);
|
||||||
|
invoices[index] = invoice;
|
||||||
|
return storage.setItem('invoices', invoices);
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteInvoice(invoiceId) {
|
async deleteInvoice(invoiceId) {
|
||||||
@ -77,7 +76,7 @@ class InvoiceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async bookInvoice(invoice) {
|
async bookInvoice(invoice) {
|
||||||
const necessaryFields = {
|
const requiredFields = {
|
||||||
currency: 'Currency',
|
currency: 'Currency',
|
||||||
vat_rate: 'Vat rate',
|
vat_rate: 'Vat rate',
|
||||||
late_fee: 'Late fee',
|
late_fee: 'Late fee',
|
||||||
@ -110,13 +109,13 @@ class InvoiceService {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const validation = await validate(necessaryFields, invoice);
|
const errors = await validate(requiredFields, invoice);
|
||||||
|
if (Object.keys(errors).length > 0) {
|
||||||
if (validation.length === 0) {
|
return Promise.reject(errors);
|
||||||
invoice.status = 'booked';
|
|
||||||
return this.updateInvoice(invoice);
|
|
||||||
}
|
}
|
||||||
return Promise.reject(validation);
|
|
||||||
|
invoice.status = 'booked';
|
||||||
|
return this.updateInvoice(invoice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -131,7 +131,7 @@ export default {
|
|||||||
commit('clearErrors');
|
commit('clearErrors');
|
||||||
|
|
||||||
return InvoiceService.updateInvoice(getters.invoice)
|
return InvoiceService.updateInvoice(getters.invoice)
|
||||||
.catch(err => commit('setErrors', err.response.data.errors));
|
.catch(err => commit('setErrors', err.errors));
|
||||||
},
|
},
|
||||||
async deleteInvoice(invoice) {
|
async deleteInvoice(invoice) {
|
||||||
const res = await InvoiceService.deleteInvoice(invoice.id);
|
const res = await InvoiceService.deleteInvoice(invoice.id);
|
||||||
@ -161,11 +161,9 @@ export default {
|
|||||||
commit('clearErrors');
|
commit('clearErrors');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('tryBookInvoice');
|
|
||||||
const res = await InvoiceService.bookInvoice(getters.invoice);
|
const res = await InvoiceService.bookInvoice(getters.invoice);
|
||||||
return dispatch('getInvoice', res.invoice_id);
|
return dispatch('getInvoice', res.invoice_id);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
|
||||||
commit('setErrors', err.errors);
|
commit('setErrors', err.errors);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
import dayjs from '../services/invoice.service';
|
||||||
|
|
||||||
export function uuidv4() {
|
export function uuidv4() {
|
||||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||||
var r = Math.random() * 16 | 0,
|
var r = Math.random() * 16 | 0,
|
||||||
@ -32,25 +34,42 @@ export function pick(obj, map) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function validate(neededFields, fieldsToValidate) {
|
export function validate(requiredFields, input) {
|
||||||
const validationErrors = {};
|
const errors = {};
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(neededFields)) {
|
for (let [key, value] of Object.entries(requiredFields)) {
|
||||||
if (Array.isArray(fieldsToValidate[key])) {
|
if (Array.isArray(input[key])) {
|
||||||
fieldsToValidate[key].forEach((item) => {
|
input[key].forEach((subInput, index) => {
|
||||||
|
for (let [subKey, subValue] of Object.entries(value)) {
|
||||||
|
const error = validateField(subInput, subKey, subValue);
|
||||||
|
if (error) {
|
||||||
|
errors[`${key}.${index}.${subKey}`] = error;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
if (!fieldsToValidate.hasOwnProperty(key) || !fieldsToValidate[key] || fieldsToValidate[key].length === 0) {
|
const error = validateField(input, key, value);
|
||||||
validationErrors[key] = [`Field ${value} is required`];
|
if (error) {
|
||||||
|
errors[key] = error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('errors', validationErrors);
|
return { errors };
|
||||||
return { errors: validationErrors };
|
}
|
||||||
|
|
||||||
|
export function validateField(input, field, label) {
|
||||||
|
if (!input.hasOwnProperty(field) || !input[field] || input[field].length === 0) {
|
||||||
|
return [`${label} is required`];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function generateInvoiceNumber(date, number) {
|
export function generateInvoiceNumber(invoices) {
|
||||||
|
const date = dayjs()
|
||||||
|
.format('YYYY');
|
||||||
|
const number = invoices.length + 1;
|
||||||
return `${date}-${number}`;
|
return `${date}-${number}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user