feat: Tax included (#370)

* feat: Tax included

* Added a toggle switch in tax settings to enable the feature.
* Database migration adding tax_included field into estimates, invoices
  and recurring invoices table.
* Toggle switch to enable and store the tax_included by estimates,
  invoices and recurring invoices.
* In case of tax included enabled, total taxes will be recalculated and
  the invoices, estimates and recurring invoices total won't be sum with
  taxes.
* Apply tax included when discount_per_item/tax_per_item item is enabled.
* Custom component to show the net total when tax included is enabled.
* Update invoice and estimates pdfs with net total.

* chore: Tax included by default

A switch button inside the tax settings to enable the tax included by
default in invoices, estimates and recurring invoices.
This commit is contained in:
Fabio Ribeiro
2025-08-28 10:28:24 +02:00
committed by GitHub
parent 08e1bb2e22
commit d69a56e2d5
32 changed files with 582 additions and 83 deletions

View File

@@ -52,6 +52,21 @@
:title="$t('settings.tax_types.tax_per_item')"
:description="$t('settings.tax_types.tax_setting_description')"
/>
<BaseDivider class="mt-8 mb-2" />
<BaseSwitchSection
v-model="taxIncludedField"
:title="$t('settings.tax_types.tax_included')"
:description="$t('settings.tax_types.tax_included_description')"
/>
<BaseSwitchSection
v-if="taxIncludedField"
v-model="taxIncludedByDefaultField"
:title="$t('settings.tax_types.tax_included_by_default')"
:description="$t('settings.tax_types.tax_included_by_default_description')"
/>
</div>
</BaseSettingCard>
</template>
@@ -139,6 +154,61 @@ const taxPerItemField = computed({
},
})
const taxIncludedSettings = reactive({
tax_included: 'NO',
tax_included_by_default: 'NO',
})
utils.mergeSettings(taxIncludedSettings, {
...companyStore.selectedCompanySettings,
})
const taxIncludedField = computed({
get: () => {
return taxIncludedSettings.tax_included === 'YES'
},
set: async (newValue) => {
const value = newValue ? 'YES' : 'NO'
taxIncludedSettings.tax_included = value
if (!newValue) {
taxIncludedSettings.tax_included_by_default = 'NO'
}
let data = {
settings: {
...taxIncludedSettings,
},
}
await companyStore.updateCompanySettings({
data,
message: 'general.setting_updated',
})
},
})
const taxIncludedByDefaultField = computed({
get: () => {
return taxIncludedSettings.tax_included_by_default === 'YES'
},
set: async (newValue) => {
const value = newValue ? 'YES' : 'NO'
taxIncludedSettings.tax_included_by_default = value
let data = {
settings: {
tax_included_by_default: taxIncludedSettings.tax_included_by_default,
},
}
await companyStore.updateCompanySettings({
data,
message: 'general.setting_updated',
})
},
})
function hasAtleastOneAbility() {
return userStore.hasAbilities([
abilities.DELETE_TAX_TYPE,