-
-
-
-
-
General
-
-
-
-
-
-
-
Invoice Settings
- Address
-
-
-
-
-
-
-
-
-
-
-
VAT
-
-
-
-
-
-
Banking details
-
-
-
-
Loading
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Loading
diff --git a/src/components/invoices/InvoiceClientFields.vue b/src/components/invoices/InvoiceClientFields.vue
new file mode 100644
index 0000000..8d517b8
--- /dev/null
+++ b/src/components/invoices/InvoiceClientFields.vue
@@ -0,0 +1,29 @@
+
+
+
+
diff --git a/src/components/invoices/InvoiceForm.vue b/src/components/invoices/InvoiceForm.vue
index 1a516a0..8cf4e42 100644
--- a/src/components/invoices/InvoiceForm.vue
+++ b/src/components/invoices/InvoiceForm.vue
@@ -137,7 +137,7 @@ export default {
this.$store.dispatch('invoices/updateInvoice', props);
},
addRow() {
- this.$store.dispatch('invoices/addRow');
+ this.$store.dispatch('invoiceRows/addRow', this.invoice.id);
},
updateTeam(props) {
this.$store.dispatch('teams/updateTeam', props);
diff --git a/src/components/invoices/InvoiceRow.vue b/src/components/invoices/InvoiceRow.vue
index aaf6fa8..4a8a5be 100644
--- a/src/components/invoices/InvoiceRow.vue
+++ b/src/components/invoices/InvoiceRow.vue
@@ -52,13 +52,13 @@ export default {
},
methods: {
updateProp(props) {
- this.$store.dispatch('invoices/updateInvoiceRow', {
+ this.$store.dispatch('invoiceRows/updateInvoiceRow', {
props,
id: this.row.id,
});
},
async removeRow(row) {
- await this.$store.dispatch('invoices/removeRow', row);
+ await this.$store.dispatch('invoiceRows/removeRow', row.id);
this.updateProp();
},
},
diff --git a/src/store/client-fields.js b/src/store/client-fields.js
new file mode 100644
index 0000000..390f7fd
--- /dev/null
+++ b/src/store/client-fields.js
@@ -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
+ },
+ },
+};
diff --git a/src/store/clients.js b/src/store/clients.js
index efda1b8..b506e40 100644
--- a/src/store/clients.js
+++ b/src/store/clients.js
@@ -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();
},
},
diff --git a/src/store/invoice-client-fields.js b/src/store/invoice-client-fields.js
new file mode 100644
index 0000000..35826ff
--- /dev/null
+++ b/src/store/invoice-client-fields.js
@@ -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);
+ },
+ },
+};
diff --git a/src/store/invoice-rows.js b/src/store/invoice-rows.js
new file mode 100644
index 0000000..196eb25
--- /dev/null
+++ b/src/store/invoice-rows.js
@@ -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);
+ },
+ },
+};
diff --git a/src/store/invoices.js b/src/store/invoices.js
index ce91e75..c69b6be 100644
--- a/src/store/invoices.js
+++ b/src/store/invoices.js
@@ -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);
},
diff --git a/src/store/models/client-field.js b/src/store/models/client-field.js
new file mode 100644
index 0000000..799f3d3
--- /dev/null
+++ b/src/store/models/client-field.js
@@ -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(''),
+ };
+ }
+}
diff --git a/src/store/models/client.js b/src/store/models/client.js
index 1c13f16..f5cdc36 100644
--- a/src/store/models/client.js
+++ b/src/store/models/client.js
@@ -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(''),
};
diff --git a/src/store/models/invoice-client-field.js b/src/store/models/invoice-client-field.js
new file mode 100644
index 0000000..ed575cd
--- /dev/null
+++ b/src/store/models/invoice-client-field.js
@@ -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(''),
+ };
+ }
+}
diff --git a/src/store/models/invoice.js b/src/store/models/invoice.js
index 5a5e252..14bb2f2 100644
--- a/src/store/models/invoice.js
+++ b/src/store/models/invoice.js
@@ -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'),
};
}
diff --git a/src/store/models/team-field.js b/src/store/models/team-field.js
new file mode 100644
index 0000000..85e01de
--- /dev/null
+++ b/src/store/models/team-field.js
@@ -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(''),
+ };
+ }
+}
diff --git a/src/store/models/team.js b/src/store/models/team.js
index cdfb62e..6d60f44 100644
--- a/src/store/models/team.js
+++ b/src/store/models/team.js
@@ -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(''),
diff --git a/src/store/store.js b/src/store/store.js
index 22298b3..6fff037 100644
--- a/src/store/store.js
+++ b/src/store/store.js
@@ -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,