Be able to add default taxes to team.

This commit is contained in:
HenriT
2021-04-14 13:21:36 +03:00
parent 328e30e874
commit 8bfb088f30
7 changed files with 184 additions and 2 deletions

View File

@ -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,

View 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>

View 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
View 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(''),
};
}
}

View File

@ -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
View 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();
},
},
};

View File

@ -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();