mirror of
https://github.com/mokuappio/serverless-invoices.git
synced 2026-02-07 16:41:42 -05:00
Separated client form into tabs. Fixed deleting client. Implemented custom fields for client and invoice client fields. Removed "hardcoded" client_reg_no and client_vat_no fields from client and invoice model - can be replaced with custom fields. Abstracted invoice-rows management to separate store namespace. Invoice client fields are prefilled from selected client.
This commit is contained in:
31
src/store/client-fields.js
Normal file
31
src/store/client-fields.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import ClientField from '@/store/models/client-field';
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {},
|
||||
mutations: {},
|
||||
actions: {
|
||||
init() {},
|
||||
terminate() {},
|
||||
async clientFieldProps(store, payload) {
|
||||
return ClientField.update({
|
||||
where: payload.fieldId,
|
||||
data: payload.props,
|
||||
});
|
||||
},
|
||||
async updateClientField({ dispatch }, payload) {
|
||||
await dispatch('clientFieldProps', payload);
|
||||
return dispatch('clients/updateClient', null, { root: true }); // TODO: pass clientId to make generic
|
||||
},
|
||||
async addNewField(store, clientId) {
|
||||
const field = await ClientField.createNew();
|
||||
field.$update({
|
||||
client_id: clientId,
|
||||
});
|
||||
},
|
||||
async deleteClientField({ dispatch }, fieldId) {
|
||||
await ClientField.delete(fieldId);
|
||||
return dispatch('clients/updateClient', null, { root: true }); // TODO: pass clientId to make generic
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -47,11 +47,15 @@ export default {
|
||||
});
|
||||
},
|
||||
async updateClient({ getters, dispatch }, props) {
|
||||
await dispatch('clientProps', props);
|
||||
if (props) {
|
||||
await dispatch('clientProps', props);
|
||||
}
|
||||
return ClientService.updateClient(getters.client);
|
||||
},
|
||||
async updateClientById(store, payload) {
|
||||
const client = Client.find(payload.clientId);
|
||||
const client = Client.query()
|
||||
.with('fields')
|
||||
.find(payload.clientId);
|
||||
client.$update(payload.props);
|
||||
return ClientService.updateClient(client);
|
||||
},
|
||||
@@ -60,24 +64,22 @@ export default {
|
||||
commit('clientId', client.id);
|
||||
commit('isModalOpen', true);
|
||||
},
|
||||
async deleteClient(clientId) {
|
||||
async deleteClient(store, clientId) {
|
||||
const res = await ClientService.deleteClient(clientId);
|
||||
if ('client_id' in res) {
|
||||
Client.delete(res.client_id);
|
||||
}
|
||||
await Client.delete(clientId);
|
||||
return res;
|
||||
},
|
||||
},
|
||||
getters: {
|
||||
client(state) {
|
||||
return Client.query()
|
||||
.with(['bank_account'])
|
||||
.with(['bank_account', 'fields'])
|
||||
.find(state.clientId);
|
||||
},
|
||||
all() {
|
||||
return Client.query()
|
||||
.where('$isNew', false)
|
||||
.with(['bank_account'])
|
||||
.with(['bank_account', 'fields'])
|
||||
.get();
|
||||
},
|
||||
},
|
||||
|
||||
34
src/store/invoice-client-fields.js
Normal file
34
src/store/invoice-client-fields.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import InvoiceClientField from '@/store/models/invoice-client-field';
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {},
|
||||
mutations: {},
|
||||
actions: {
|
||||
init() {},
|
||||
terminate() {},
|
||||
invoiceClientFieldProps(store, payload) {
|
||||
return InvoiceClientField.update({
|
||||
where: payload.fieldId,
|
||||
data: payload.props,
|
||||
});
|
||||
},
|
||||
async updateInvoiceClientField({ dispatch }, payload) {
|
||||
await dispatch('invoiceClientFieldProps', payload);
|
||||
return dispatch('invoices/updateInvoice', null, { root: true });
|
||||
},
|
||||
async removeInvoiceClientFields(store, invoiceId) {
|
||||
return InvoiceClientField.delete(field => field.invoice_id === invoiceId);
|
||||
},
|
||||
async addInvoiceClientField(store, payload) {
|
||||
const field = await InvoiceClientField.createNew();
|
||||
await field.$update({
|
||||
...payload.props,
|
||||
invoice_id: payload.invoiceId,
|
||||
});
|
||||
},
|
||||
async removeInvoiceClientField(store, fieldId) {
|
||||
await InvoiceClientField.delete(fieldId);
|
||||
},
|
||||
},
|
||||
};
|
||||
34
src/store/invoice-rows.js
Normal file
34
src/store/invoice-rows.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import InvoiceRow from '@/store/models/invoice-row';
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {
|
||||
},
|
||||
mutations: {
|
||||
},
|
||||
actions: {
|
||||
init() {},
|
||||
terminate() {},
|
||||
invoiceRowProps(store, payload) {
|
||||
return InvoiceRow.update({
|
||||
where: payload.id,
|
||||
data: payload.props,
|
||||
});
|
||||
},
|
||||
async updateInvoiceRow({ dispatch }, payload) {
|
||||
await dispatch('invoiceRowProps', payload);
|
||||
return dispatch('invoices/updateInvoice', null, { root: true });
|
||||
},
|
||||
async addRow(store, invoiceId) {
|
||||
const row = await InvoiceRow.createNew();
|
||||
const rowCount = InvoiceRow.query().where('invoice_id', invoiceId).count();
|
||||
row.$update({
|
||||
invoice_id: invoiceId,
|
||||
order: rowCount,
|
||||
});
|
||||
},
|
||||
async removeRow(store, rowId) {
|
||||
await InvoiceRow.delete(rowId);
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,6 +1,5 @@
|
||||
import InvoiceService from '@/services/invoice.service';
|
||||
import Invoice from '@/store/models/invoice';
|
||||
import InvoiceRow from '@/store/models/invoice-row';
|
||||
import { pick } from '@/utils/helpers';
|
||||
import dayjs from 'dayjs';
|
||||
import Errors from '@/utils/errors';
|
||||
@@ -55,16 +54,7 @@ export default {
|
||||
data: props,
|
||||
});
|
||||
},
|
||||
invoiceRowProps(store, payload) {
|
||||
return InvoiceRow.update({
|
||||
where: payload.id,
|
||||
data: payload.props,
|
||||
});
|
||||
},
|
||||
async updateInvoice({ getters, dispatch, commit }, props) {
|
||||
await dispatch('invoiceProps', props);
|
||||
|
||||
// Update client
|
||||
async updateClient({ getters, dispatch }, props) {
|
||||
const clientProps = pick(props, {
|
||||
bank_account_id: 'bank_account_id',
|
||||
client_name: 'company_name',
|
||||
@@ -73,8 +63,6 @@ export default {
|
||||
client_country: 'company_country',
|
||||
client_county: 'company_county',
|
||||
client_city: 'company_city',
|
||||
client_reg_no: 'company_reg_no',
|
||||
client_vat_no: 'company_vat_no',
|
||||
client_email: 'invoice_email',
|
||||
currency: 'currency',
|
||||
});
|
||||
@@ -88,7 +76,8 @@ export default {
|
||||
clientId: getters.invoice.client_id,
|
||||
}, { root: true });
|
||||
}
|
||||
|
||||
},
|
||||
async updateTeam({ getters, dispatch }, props) {
|
||||
const teamProps = pick(props, {
|
||||
late_fee: 'invoice_late_fee',
|
||||
from_name: 'company_name',
|
||||
@@ -119,37 +108,23 @@ export default {
|
||||
if (Object.keys(teamProps).length > 0) {
|
||||
dispatch('teams/updateTeam', teamProps, { root: true });
|
||||
}
|
||||
|
||||
commit('clearErrors');
|
||||
|
||||
return InvoiceService.updateInvoice(getters.invoice)
|
||||
.catch(err => commit('setErrors', err.errors));
|
||||
},
|
||||
async updateInvoiceRow({ getters, dispatch, commit }, payload) {
|
||||
await dispatch('invoiceRowProps', payload);
|
||||
async updateInvoice({ dispatch, commit, getters }, props) {
|
||||
if (props) {
|
||||
await dispatch('invoiceProps', props);
|
||||
await dispatch('updateClient', props);
|
||||
await dispatch('updateTeam', props);
|
||||
}
|
||||
|
||||
commit('clearErrors');
|
||||
|
||||
return InvoiceService.updateInvoice(getters.invoice)
|
||||
.catch(err => commit('setErrors', err.errors));
|
||||
},
|
||||
async deleteInvoice(store, invoice) {
|
||||
const res = await InvoiceService.deleteInvoice(invoice.id);
|
||||
if ('invoice_id' in res) {
|
||||
Invoice.delete(res.invoice_id);
|
||||
}
|
||||
await Invoice.delete(invoice.id);
|
||||
return res;
|
||||
},
|
||||
async addRow({ state, getters }) {
|
||||
const row = await InvoiceRow.createNew();
|
||||
row.$update({
|
||||
invoice_id: state.invoiceId,
|
||||
order: getters.invoice.rows.length,
|
||||
});
|
||||
},
|
||||
async removeRow(store, row) {
|
||||
await InvoiceRow.delete(row.id);
|
||||
},
|
||||
async bookInvoice({ getters, commit, dispatch }) {
|
||||
commit('clearErrors');
|
||||
|
||||
@@ -164,7 +139,7 @@ export default {
|
||||
getters: {
|
||||
invoice(state) {
|
||||
return Invoice.query()
|
||||
.with(['client'])
|
||||
.with(['client', 'client_fields'])
|
||||
.with('rows', query => query.orderBy('order', 'asc'))
|
||||
.find(state.invoiceId);
|
||||
},
|
||||
|
||||
16
src/store/models/client-field.js
Normal file
16
src/store/models/client-field.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Model } from '@vuex-orm/core';
|
||||
import { uuidv4 } from '@/utils/helpers';
|
||||
|
||||
export default class ClientField extends Model {
|
||||
// This is the name used as module name of the Vuex Store.
|
||||
static entity = 'client_fields';
|
||||
|
||||
static fields() {
|
||||
return {
|
||||
id: this.attr(() => uuidv4()),
|
||||
client_id: this.attr(null),
|
||||
label: this.attr(''),
|
||||
value: this.attr(''),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Model } from '@vuex-orm/core';
|
||||
import { uuidv4 } from '@/utils/helpers';
|
||||
import BankAccount from '@/store/models/bank-account';
|
||||
import ClientField from '@/store/models/client-field';
|
||||
|
||||
export default class Client extends Model {
|
||||
// This is the name used as module name of the Vuex Store.
|
||||
@@ -15,14 +16,13 @@ export default class Client extends Model {
|
||||
company_country: this.attr(''),
|
||||
company_county: this.attr(''),
|
||||
company_city: this.attr(''),
|
||||
company_reg_no: this.attr(''),
|
||||
company_vat_no: this.attr(''),
|
||||
has_vat: this.attr(null),
|
||||
currency: this.attr(null),
|
||||
rate: this.attr(null),
|
||||
invoice_email: this.attr(''),
|
||||
bank_account_id: this.attr(null),
|
||||
bank_account: this.belongsTo(BankAccount, 'bank_account_id', 'id'),
|
||||
bank_account: this.belongsTo(BankAccount, 'bank_account_id'),
|
||||
fields: this.hasMany(ClientField, 'client_id'),
|
||||
updated_at: this.attr(''),
|
||||
created_at: this.attr(''),
|
||||
};
|
||||
|
||||
17
src/store/models/invoice-client-field.js
Normal file
17
src/store/models/invoice-client-field.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Model } from '@vuex-orm/core';
|
||||
import { uuidv4 } from '@/utils/helpers';
|
||||
|
||||
export default class InvoiceClientField extends Model {
|
||||
// This is the name used as module name of the Vuex Store.
|
||||
static entity = 'invoice_client_fields';
|
||||
|
||||
static fields() {
|
||||
return {
|
||||
id: this.attr(() => uuidv4()),
|
||||
invoice_id: this.attr(null),
|
||||
client_field_id: this.attr(null),
|
||||
label: this.attr(''),
|
||||
value: this.attr(''),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { Model } from '@vuex-orm/core';
|
||||
import { uuidv4 } from '@/utils/helpers';
|
||||
import Client from '@/store/models/client';
|
||||
import InvoiceRow from '@/store/models/invoice-row';
|
||||
import InvoiceClientField from '@/store/models/invoice-client-field';
|
||||
|
||||
export default class Invoice extends Model {
|
||||
// This is the name used as module name of the Vuex Store.
|
||||
@@ -36,8 +37,6 @@ export default class Invoice extends Model {
|
||||
client_country: this.attr(''),
|
||||
client_county: this.attr(''),
|
||||
client_city: this.attr(''),
|
||||
client_reg_no: this.attr(''),
|
||||
client_vat_no: this.attr(''),
|
||||
client_email: this.attr(''),
|
||||
client_id: this.attr(null),
|
||||
client: this.belongsTo(Client, 'client_id'),
|
||||
@@ -46,6 +45,7 @@ export default class Invoice extends Model {
|
||||
updated_at: this.attr(''),
|
||||
created_at: this.attr(''),
|
||||
total: this.attr(null), // Only used in lists.
|
||||
client_fields: this.hasMany(InvoiceClientField, 'invoice_id'),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
16
src/store/models/team-field.js
Normal file
16
src/store/models/team-field.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Model } from '@vuex-orm/core';
|
||||
import { uuidv4 } from '@/utils/helpers';
|
||||
|
||||
export default class TeamField extends Model {
|
||||
// This is the name used as module name of the Vuex Store.
|
||||
static entity = 'team_fields';
|
||||
|
||||
static fields() {
|
||||
return {
|
||||
id: this.attr(() => uuidv4()),
|
||||
team_id: this.attr(null),
|
||||
label: this.attr(''),
|
||||
value: this.attr(''),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Model } from '@vuex-orm/core';
|
||||
import { uuidv4 } from '@/utils/helpers';
|
||||
import TeamField from '@/store/models/team-field';
|
||||
|
||||
export default class Team extends Model {
|
||||
// This is the name used as module name of the Vuex Store.
|
||||
@@ -22,6 +23,7 @@ export default class Team extends Model {
|
||||
vat_rate: this.attr(null),
|
||||
invoice_late_fee: this.attr(null),
|
||||
invoice_due_days: this.attr(null),
|
||||
fields: this.hasMany(TeamField, 'team_id'),
|
||||
updated_at: this.attr(''),
|
||||
created_at: this.attr(''),
|
||||
logo_url: this.attr(''),
|
||||
|
||||
@@ -9,10 +9,16 @@ import InvoiceRow from '@/store/models/invoice-row';
|
||||
import Team from '@/store/models/team';
|
||||
import bankAccounts from '@/store/bank-accounts';
|
||||
import clients from '@/store/clients';
|
||||
import clientFields from '@/store/client-fields';
|
||||
import invoices from '@/store/invoices';
|
||||
import invoiceRows from '@/store/invoice-rows';
|
||||
import invoiceClientFields from '@/store/invoice-client-fields';
|
||||
import teams from '@/store/teams';
|
||||
import themes from '@/store/themes';
|
||||
import data from '@/store/data';
|
||||
import ClientField from '@/store/models/client-field';
|
||||
import TeamField from '@/store/models/team-field';
|
||||
import InvoiceClientField from '@/store/models/invoice-client-field';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
@@ -20,8 +26,11 @@ VuexORM.use(VuexORMisDirtyPlugin);
|
||||
const database = new VuexORM.Database();
|
||||
|
||||
database.register(Team);
|
||||
database.register(TeamField);
|
||||
database.register(Client);
|
||||
database.register(ClientField);
|
||||
database.register(Invoice);
|
||||
database.register(InvoiceClientField);
|
||||
database.register(InvoiceRow);
|
||||
database.register(BankAccount);
|
||||
|
||||
@@ -30,7 +39,10 @@ export default new Vuex.Store({
|
||||
modules: {
|
||||
bankAccounts,
|
||||
clients,
|
||||
clientFields,
|
||||
invoices,
|
||||
invoiceRows,
|
||||
invoiceClientFields,
|
||||
teams,
|
||||
themes,
|
||||
data,
|
||||
|
||||
Reference in New Issue
Block a user