mirror of
https://github.com/mokuappio/serverless-invoices.git
synced 2025-10-27 07:51:08 -04:00
Be able to add default taxes to team.
This commit is contained in:
@ -34,9 +34,11 @@
|
||||
<div class="row">
|
||||
<AppInput :value="team.vat_rate" @change="updateProp({ vat_rate: $event })" type="number"
|
||||
label="VAT rate" field="vat_rate" :errors="errors" class="col-sm-4"/>
|
||||
<AppInput :value="team.invoice_late_fee" @change="updateProp({ invoice_late_fee: $event })" type="number"
|
||||
<AppInput :value="team.invoice_late_fee" @change="updateProp({ invoice_late_fee: $event })"
|
||||
type="number"
|
||||
label="Late fee (%)" field="invoice_late_fee" :errors="errors" class="col-sm-4"/>
|
||||
<AppInput :value="team.invoice_due_days" @change="updateProp({ invoice_due_days: $event })" type="number"
|
||||
<AppInput :value="team.invoice_due_days" @change="updateProp({ invoice_due_days: $event })"
|
||||
type="number"
|
||||
label="Payment terms, days" field="invoice_due_days" :errors="errors" class="col-sm-4"/>
|
||||
<AppInput :value="team.currency" @change="updateProp({ currency: $event })"
|
||||
label="Default currency" field="currency" :errors="errors" class="col-sm-4"/>
|
||||
@ -61,6 +63,10 @@
|
||||
</div>
|
||||
</b-tab>
|
||||
|
||||
<b-tab title="Taxes" class="col-12">
|
||||
<TeamTaxes class="row"/>
|
||||
</b-tab>
|
||||
|
||||
</b-tabs>
|
||||
|
||||
<div v-if="!team">Loading</div>
|
||||
@ -76,11 +82,13 @@ import AppInput from '@/components/form/AppInput';
|
||||
import Errors from '@/utils/errors';
|
||||
import TeamFields from '@/components/team/TeamFields';
|
||||
import TeamLogo from '@/components/team/TeamLogo';
|
||||
import TeamTaxes from '@/components/team/TeamTaxes';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TeamLogo,
|
||||
TeamFields,
|
||||
TeamTaxes,
|
||||
AppInput,
|
||||
BTab,
|
||||
BTabs,
|
||||
|
||||
64
src/components/team/TeamTaxes.vue
Normal file
64
src/components/team/TeamTaxes.vue
Normal file
@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-for="tax in taxes" :key="tax.id" class="col-sm-6">
|
||||
<AppEditable :value="tax.label"
|
||||
placeholder="Label"
|
||||
@change="updateTaxProp({ label: $event }, tax)"/>
|
||||
<i class="material-icons md-18 float-right pointer" @click="removeTax(tax)">close</i>
|
||||
<AppInput :value="tax.value" @change="updateTaxProp({ value: $event }, tax)"
|
||||
:placeholder="tax.label"/>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<button class="btn btn-sm btn-secondary " @click="addNewTax">
|
||||
<i class="material-icons md-18">add</i>
|
||||
Tax
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import NotificationService from '@/services/notification.service';
|
||||
import AppInput from '@/components/form/AppInput';
|
||||
import AppEditable from '@/components/form/AppEditable';
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AppEditable,
|
||||
AppInput,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
taxes: 'taxes/all',
|
||||
}),
|
||||
},
|
||||
methods: {
|
||||
addNewTax() {
|
||||
this.$store.dispatch('taxes/addNewTax');
|
||||
},
|
||||
async removeTax(field) {
|
||||
const confirmed = await this.$bvModal.msgBoxConfirm(`Delete tax ${field.label}?`, {
|
||||
okTitle: 'Delete',
|
||||
okVariant: 'danger',
|
||||
cancelTitle: 'Dismiss',
|
||||
cancelVariant: 'btn-link',
|
||||
contentClass: 'bg-base dp--24',
|
||||
});
|
||||
if (confirmed) {
|
||||
await this.$store.dispatch('taxes/deleteTax', field.id);
|
||||
try {
|
||||
NotificationService.success('Deleted');
|
||||
} catch (err) {
|
||||
NotificationService.error(err.message);
|
||||
}
|
||||
}
|
||||
},
|
||||
updateTaxProp(props, tax) {
|
||||
this.$store.dispatch('taxes/updateTax', {
|
||||
props,
|
||||
taxId: tax.id,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
45
src/services/tax.service.js
Normal file
45
src/services/tax.service.js
Normal file
@ -0,0 +1,45 @@
|
||||
import storage from 'localforage';
|
||||
import { removeVuexORMFlags } from '@/utils/helpers';
|
||||
|
||||
class TaxService {
|
||||
async getTaxes() {
|
||||
const taxes = await storage.getItem('taxes');
|
||||
|
||||
return taxes || [];
|
||||
}
|
||||
|
||||
async getTax(taxId) {
|
||||
const taxes = await this.getTaxes();
|
||||
return taxes.find(tax => tax.id === taxId);
|
||||
}
|
||||
|
||||
async createTax(tax) {
|
||||
return this.saveTax(tax);
|
||||
}
|
||||
|
||||
async updateTax(tax) {
|
||||
return this.saveTax(tax);
|
||||
}
|
||||
|
||||
async deleteTax(taxId) {
|
||||
const taxes = await this.getTaxes();
|
||||
const index = taxes.findIndex(item => item.id === taxId);
|
||||
taxes.splice(index, 1);
|
||||
return storage.setItem('taxes', taxes);
|
||||
}
|
||||
|
||||
async saveTax(tax) {
|
||||
const taxes = await this.getTaxes();
|
||||
const index = taxes.findIndex(item => item.id === tax.id);
|
||||
removeVuexORMFlags(tax);
|
||||
if (index === -1) {
|
||||
taxes.push(tax);
|
||||
} else {
|
||||
taxes[index] = tax;
|
||||
}
|
||||
await storage.setItem('taxes', taxes);
|
||||
return tax;
|
||||
}
|
||||
}
|
||||
|
||||
export default new TaxService();
|
||||
15
src/store/models/tax.js
Normal file
15
src/store/models/tax.js
Normal file
@ -0,0 +1,15 @@
|
||||
import { Model } from '@vuex-orm/core';
|
||||
import { uuidv4 } from '@/utils/helpers';
|
||||
|
||||
export default class Tax extends Model {
|
||||
// This is the name used as module name of the Vuex Store.
|
||||
static entity = 'taxes';
|
||||
|
||||
static fields() {
|
||||
return {
|
||||
id: this.attr(() => uuidv4()),
|
||||
label: this.attr(''),
|
||||
value: this.attr(''),
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -17,17 +17,20 @@ import invoiceTeamFields from '@/store/invoice-team-fields';
|
||||
import teams from '@/store/teams';
|
||||
import teamFields from '@/store/team-fields';
|
||||
import themes from '@/store/themes';
|
||||
import taxes from '@/store/taxes';
|
||||
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';
|
||||
import InvoiceTeamField from '@/store/models/invoice-team-field';
|
||||
import Tax from '@/store/models/tax';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
VuexORM.use(VuexORMisDirtyPlugin);
|
||||
const database = new VuexORM.Database();
|
||||
|
||||
database.register(Tax);
|
||||
database.register(Team);
|
||||
database.register(TeamField);
|
||||
database.register(Client);
|
||||
@ -51,6 +54,7 @@ export default new Vuex.Store({
|
||||
teams,
|
||||
teamFields,
|
||||
themes,
|
||||
taxes,
|
||||
data,
|
||||
},
|
||||
state: {},
|
||||
|
||||
44
src/store/taxes.js
Normal file
44
src/store/taxes.js
Normal file
@ -0,0 +1,44 @@
|
||||
import Tax from '@/store/models/tax';
|
||||
import TaxService from '@/services/tax.service';
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: {},
|
||||
mutations: {},
|
||||
actions: {
|
||||
init({ dispatch }) {
|
||||
return dispatch('getTaxes');
|
||||
},
|
||||
terminate() {
|
||||
return Tax.deleteAll();
|
||||
},
|
||||
async getTaxes() {
|
||||
const taxes = await TaxService.getTaxes();
|
||||
await Tax.create({ data: taxes });
|
||||
return taxes;
|
||||
},
|
||||
async taxProps(store, payload) {
|
||||
return Tax.update({
|
||||
where: payload.taxId,
|
||||
data: payload.props,
|
||||
});
|
||||
},
|
||||
async updateTax({ dispatch }, payload) {
|
||||
const tax = await dispatch('taxProps', payload);
|
||||
return TaxService.updateTax(tax);
|
||||
},
|
||||
async addNewTax() {
|
||||
const tax = await Tax.createNew();
|
||||
return TaxService.createTax(tax);
|
||||
},
|
||||
async deleteTax(store, taxId) {
|
||||
await Tax.delete(taxId);
|
||||
return TaxService.deleteTax(taxId);
|
||||
},
|
||||
},
|
||||
getters: {
|
||||
all() {
|
||||
return Tax.all();
|
||||
},
|
||||
},
|
||||
};
|
||||
@ -17,6 +17,7 @@ export default {
|
||||
dispatch('clients/terminate', null, { root: true }),
|
||||
dispatch('bankAccounts/terminate', null, { root: true }),
|
||||
dispatch('invoices/terminate', null, { root: true }),
|
||||
dispatch('taxes/terminate', null, { root: true }),
|
||||
]);
|
||||
|
||||
await dispatch('getTeam');
|
||||
@ -24,6 +25,7 @@ export default {
|
||||
dispatch('clients/init', null, { root: true });
|
||||
dispatch('bankAccounts/init', null, { root: true });
|
||||
dispatch('invoices/init', null, { root: true });
|
||||
dispatch('taxes/init', null, { root: true });
|
||||
},
|
||||
async terminate() {
|
||||
return Team.deleteAll();
|
||||
|
||||
Reference in New Issue
Block a user