mirror of
				https://github.com/crater-invoice/crater.git
				synced 2025-10-28 04:01:10 -04:00 
			
		
		
		
	Compare commits
	
		
			9 Commits
		
	
	
		
			TimVoschfe
			...
			tax-calcul
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 9608ab6207 | |||
| c14eb1b414 | |||
| 6d0edb4b5a | |||
| 0dc8941975 | |||
| f11437ce63 | |||
| dbd75bbe68 | |||
| 4fc67c74e4 | |||
| 27660c6bce | |||
| 05d5ce26fd | 
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -16,4 +16,5 @@ Homestead.yaml | |||||||
| .gitkeep | .gitkeep | ||||||
| /public/docs | /public/docs | ||||||
| /.scribe | /.scribe | ||||||
| !storage/fonts/.gitkeep | !storage/fonts/.gitkeep | ||||||
|  | .DS_Store | ||||||
|  | |||||||
| @ -45,15 +45,21 @@ class EstimatesRequest extends FormRequest | |||||||
|                 'nullable' |                 'nullable' | ||||||
|             ], |             ], | ||||||
|             'discount' => [ |             'discount' => [ | ||||||
|  |                 'numeric', | ||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|             'discount_val' => [ |             'discount_val' => [ | ||||||
|  |                 'integer', | ||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|             'sub_total' => [ |             'sub_total' => [ | ||||||
|  |                 'integer', | ||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|             'total' => [ |             'total' => [ | ||||||
|  |                 'integer', | ||||||
|  |                 'numeric', | ||||||
|  |                 'max:99999999', | ||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|             'tax' => [ |             'tax' => [ | ||||||
| @ -77,9 +83,11 @@ class EstimatesRequest extends FormRequest | |||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|             'items.*.quantity' => [ |             'items.*.quantity' => [ | ||||||
|  |                 'integer', | ||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|             'items.*.price' => [ |             'items.*.price' => [ | ||||||
|  |                 'integer', | ||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|         ]; |         ]; | ||||||
|  | |||||||
| @ -45,15 +45,21 @@ class InvoicesRequest extends FormRequest | |||||||
|                 'nullable' |                 'nullable' | ||||||
|             ], |             ], | ||||||
|             'discount' => [ |             'discount' => [ | ||||||
|  |                 'numeric', | ||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|             'discount_val' => [ |             'discount_val' => [ | ||||||
|  |                 'integer', | ||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|             'sub_total' => [ |             'sub_total' => [ | ||||||
|  |                 'integer', | ||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|             'total' => [ |             'total' => [ | ||||||
|  |                 'integer', | ||||||
|  |                 'numeric', | ||||||
|  |                 'max:99999999', | ||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|             'tax' => [ |             'tax' => [ | ||||||
| @ -77,9 +83,11 @@ class InvoicesRequest extends FormRequest | |||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|             'items.*.quantity' => [ |             'items.*.quantity' => [ | ||||||
|  |                 'integer', | ||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|             'items.*.price' => [ |             'items.*.price' => [ | ||||||
|  |                 'integer', | ||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|         ]; |         ]; | ||||||
|  | |||||||
| @ -43,15 +43,21 @@ class RecurringInvoiceRequest extends FormRequest | |||||||
|                 'nullable' |                 'nullable' | ||||||
|             ], |             ], | ||||||
|             'discount' => [ |             'discount' => [ | ||||||
|  |                 'numeric', | ||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|             'discount_val' => [ |             'discount_val' => [ | ||||||
|  |                 'integer', | ||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|             'sub_total' => [ |             'sub_total' => [ | ||||||
|  |                 'integer', | ||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|             'total' => [ |             'total' => [ | ||||||
|  |                 'integer', | ||||||
|  |                 'numeric', | ||||||
|  |                 'max:99999999', | ||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|             'tax' => [ |             'tax' => [ | ||||||
|  | |||||||
| @ -27,6 +27,7 @@ return [ | |||||||
|             'tokenizer', |             'tokenizer', | ||||||
|             'JSON', |             'JSON', | ||||||
|             'cURL', |             'cURL', | ||||||
|  |             'zip', | ||||||
|         ], |         ], | ||||||
|         'apache' => [ |         'apache' => [ | ||||||
|             'mod_rewrite', |             'mod_rewrite', | ||||||
|  | |||||||
| @ -271,23 +271,19 @@ const price = computed({ | |||||||
|     } else { |     } else { | ||||||
|       updateItemAttribute('price', newValue) |       updateItemAttribute('price', newValue) | ||||||
|     } |     } | ||||||
|  |     setDiscount() | ||||||
|   }, |   }, | ||||||
| }) | }) | ||||||
|  |  | ||||||
| const subtotal = computed(() => props.itemData.price * props.itemData.quantity) | const subtotal = computed(() => Math.round(props.itemData.price * props.itemData.quantity)) | ||||||
|  |  | ||||||
| const discount = computed({ | const discount = computed({ | ||||||
|   get: () => { |   get: () => { | ||||||
|     return props.itemData.discount |     return props.itemData.discount | ||||||
|   }, |   }, | ||||||
|   set: (newValue) => { |   set: (newValue) => { | ||||||
|     if (props.itemData.discount_type === 'percentage') { |  | ||||||
|       updateItemAttribute('discount_val', (subtotal.value * newValue) / 100) |  | ||||||
|     } else { |  | ||||||
|       updateItemAttribute('discount_val', Math.round(newValue * 100)) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     updateItemAttribute('discount', newValue) |     updateItemAttribute('discount', newValue) | ||||||
|  |     setDiscount() | ||||||
|   }, |   }, | ||||||
| }) | }) | ||||||
|  |  | ||||||
| @ -313,7 +309,7 @@ const showRemoveButton = computed(() => { | |||||||
| const totalSimpleTax = computed(() => { | const totalSimpleTax = computed(() => { | ||||||
|   return Math.round( |   return Math.round( | ||||||
|     sumBy(props.itemData.taxes, function (tax) { |     sumBy(props.itemData.taxes, function (tax) { | ||||||
|       if (!tax.compound_tax) { |       if (tax.amount) { | ||||||
|         return tax.amount |         return tax.amount | ||||||
|       } |       } | ||||||
|       return 0 |       return 0 | ||||||
| @ -321,18 +317,7 @@ const totalSimpleTax = computed(() => { | |||||||
|   ) |   ) | ||||||
| }) | }) | ||||||
|  |  | ||||||
| const totalCompoundTax = computed(() => { | const totalTax = computed(() => totalSimpleTax.value) | ||||||
|   return Math.round( |  | ||||||
|     sumBy(props.itemData.taxes, function (tax) { |  | ||||||
|       if (tax.compound_tax) { |  | ||||||
|         return tax.amount |  | ||||||
|       } |  | ||||||
|       return 0 |  | ||||||
|     }) |  | ||||||
|   ) |  | ||||||
| }) |  | ||||||
|  |  | ||||||
| const totalTax = computed(() => totalSimpleTax.value + totalCompoundTax.value) |  | ||||||
|  |  | ||||||
| const rules = { | const rules = { | ||||||
|   name: { |   name: { | ||||||
| @ -399,7 +384,7 @@ const v$ = useVuelidate( | |||||||
|  |  | ||||||
| function updateTax(data) { | function updateTax(data) { | ||||||
|   props.store.$patch((state) => { |   props.store.$patch((state) => { | ||||||
|     state[props.storeProp].items[props.index]['taxes'][data.index] = data.item |      state[props.storeProp].items[props.index]['taxes'][data.index] = data.item | ||||||
|   }) |   }) | ||||||
|  |  | ||||||
|   let lastTax = props.itemData.taxes[props.itemData.taxes.length - 1] |   let lastTax = props.itemData.taxes[props.itemData.taxes.length - 1] | ||||||
| @ -416,6 +401,16 @@ function updateTax(data) { | |||||||
|   syncItemToStore() |   syncItemToStore() | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function setDiscount() { | ||||||
|  |   const newValue = props.store[props.storeProp].items[props.index].discount | ||||||
|  |  | ||||||
|  |   if (props.itemData.discount_type === 'percentage'){ | ||||||
|  |     updateItemAttribute('discount_val', Math.round((subtotal.value * newValue) / 100)) | ||||||
|  |   }else{ | ||||||
|  |     updateItemAttribute('discount_val', Math.round(newValue * 100)) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| function searchVal(val) { | function searchVal(val) { | ||||||
|   updateItemAttribute('name', val) |   updateItemAttribute('name', val) | ||||||
| } | } | ||||||
| @ -485,10 +480,12 @@ function syncItemToStore() { | |||||||
|     total: total.value, |     total: total.value, | ||||||
|     sub_total: subtotal.value, |     sub_total: subtotal.value, | ||||||
|     totalSimpleTax: totalSimpleTax.value, |     totalSimpleTax: totalSimpleTax.value, | ||||||
|     totalCompoundTax: totalCompoundTax.value, |  | ||||||
|     totalTax: totalTax.value, |     totalTax: totalTax.value, | ||||||
|     tax: totalTax.value, |     tax: totalTax.value, | ||||||
|     taxes: [...itemTaxes], |     taxes: [...itemTaxes], | ||||||
|  |     tax_type_ids: itemTaxes.flatMap(_t => | ||||||
|  |       _t.tax_type_id ? _t.tax_type_id : [], | ||||||
|  |     ), | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   props.store.updateItem(data) |   props.store.updateItem(data) | ||||||
|  | |||||||
| @ -146,14 +146,14 @@ const filteredTypes = computed(() => { | |||||||
| }) | }) | ||||||
|  |  | ||||||
| const taxAmount = computed(() => { | const taxAmount = computed(() => { | ||||||
|   if (localTax.compound_tax && props.discountedTotal) { |  | ||||||
|     return ((props.discountedTotal + props.totalTax) * localTax.percent) / 100 |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (props.discountedTotal && localTax.percent) { |   if (props.discountedTotal && localTax.percent) { | ||||||
|  |     const taxPerItemEnabled = props.store[props.storeProp].tax_per_item === 'YES' | ||||||
|  |     const discountPerItemEnabled = props.store[props.storeProp].discount_per_item === 'YES' | ||||||
|  |     if (taxPerItemEnabled && !discountPerItemEnabled){ | ||||||
|  |       return getTaxAmount() | ||||||
|  |     } | ||||||
|     return (props.discountedTotal * localTax.percent) / 100 |     return (props.discountedTotal * localTax.percent) / 100 | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   return 0 |   return 0 | ||||||
| }) | }) | ||||||
|  |  | ||||||
| @ -171,6 +171,13 @@ watch( | |||||||
|   } |   } | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | watch( | ||||||
|  |   () => taxAmount.value, | ||||||
|  |   () => { | ||||||
|  |     updateRowTax() | ||||||
|  |   }, | ||||||
|  | ) | ||||||
|  |  | ||||||
| // Set SelectedTax | // Set SelectedTax | ||||||
| if (props.taxData.tax_type_id > 0) { | if (props.taxData.tax_type_id > 0) { | ||||||
|   selectedTax.value = taxTypeStore.taxTypes.find( |   selectedTax.value = taxTypeStore.taxTypes.find( | ||||||
| @ -183,7 +190,6 @@ updateRowTax() | |||||||
| function onSelectTax(val) { | function onSelectTax(val) { | ||||||
|   localTax.percent = val.percent |   localTax.percent = val.percent | ||||||
|   localTax.tax_type_id = val.id |   localTax.tax_type_id = val.id | ||||||
|   localTax.compound_tax = val.compound_tax |  | ||||||
|   localTax.name = val.name |   localTax.name = val.name | ||||||
|  |  | ||||||
|   updateRowTax() |   updateRowTax() | ||||||
| @ -220,6 +226,27 @@ function openTaxModal() { | |||||||
| function removeTax(index) { | function removeTax(index) { | ||||||
|   props.store.$patch((state) => { |   props.store.$patch((state) => { | ||||||
|     state[props.storeProp].items[props.itemIndex].taxes.splice(index, 1) |     state[props.storeProp].items[props.itemIndex].taxes.splice(index, 1) | ||||||
|  |     state[props.storeProp].items[props.itemIndex].tax = 0 | ||||||
|  |     state[props.storeProp].items[props.itemIndex].totalTax = 0 | ||||||
|   }) |   }) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function getTaxAmount() { | ||||||
|  |   let total = 0 | ||||||
|  |   let discount = 0 | ||||||
|  |   const itemTotal = props.discountedTotal | ||||||
|  |   const modelDiscount = props.store[props.storeProp].discount ? props.store[props.storeProp].discount : 0 | ||||||
|  |   const type = props.store[props.storeProp].discount_type | ||||||
|  |   if (modelDiscount > 0) { | ||||||
|  |     props.store[props.storeProp].items.forEach((_i) => { | ||||||
|  |       total += _i.total | ||||||
|  |     }) | ||||||
|  |     const proportion = (itemTotal / total).toFixed(2) | ||||||
|  |     discount = type === 'fixed' ? modelDiscount * 100 : (total * modelDiscount) / 100 | ||||||
|  |     const itemDiscount = Math.round(discount * proportion) | ||||||
|  |     const discounted = itemTotal - itemDiscount | ||||||
|  |     return Math.round((discounted * localTax.percent) / 100) | ||||||
|  |   } | ||||||
|  |   return Math.round((props.discountedTotal * localTax.percent) / 100) | ||||||
|  | } | ||||||
| </script> | </script> | ||||||
|  | |||||||
| @ -191,7 +191,7 @@ | |||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script setup> | <script setup> | ||||||
| import { computed, inject, ref } from 'vue' | import { computed, inject, ref, watch } from 'vue' | ||||||
| import Guid from 'guid' | import Guid from 'guid' | ||||||
| import Tax from './CreateTotalTaxes.vue' | import Tax from './CreateTotalTaxes.vue' | ||||||
| import TaxStub from '@/scripts/admin/stub/abilities' | import TaxStub from '@/scripts/admin/stub/abilities' | ||||||
| @ -227,19 +227,20 @@ const utils = inject('$utils') | |||||||
|  |  | ||||||
| const companyStore = useCompanyStore() | const companyStore = useCompanyStore() | ||||||
|  |  | ||||||
|  | watch( | ||||||
|  |   () => props.store[props.storeProp].items, | ||||||
|  |   (val) => { | ||||||
|  |     setDiscount() | ||||||
|  |   }, { deep: true }, | ||||||
|  | ) | ||||||
|  |  | ||||||
| const totalDiscount = computed({ | const totalDiscount = computed({ | ||||||
|   get: () => { |   get: () => { | ||||||
|     return props.store[props.storeProp].discount |     return props.store[props.storeProp].discount | ||||||
|   }, |   }, | ||||||
|   set: (newValue) => { |   set: (newValue) => { | ||||||
|     if (props.store[props.storeProp].discount_type === 'percentage') { |  | ||||||
|       props.store[props.storeProp].discount_val = Math.round( |  | ||||||
|         (props.store.getSubTotal * newValue) / 100 |  | ||||||
|       ) |  | ||||||
|     } else { |  | ||||||
|       props.store[props.storeProp].discount_val = Math.round(newValue * 100) |  | ||||||
|     } |  | ||||||
|     props.store[props.storeProp].discount = newValue |     props.store[props.storeProp].discount = newValue | ||||||
|  |     setDiscount() | ||||||
|   }, |   }, | ||||||
| }) | }) | ||||||
|  |  | ||||||
| @ -265,7 +266,7 @@ const itemWiseTaxes = computed(() => { | |||||||
|         } else if (tax.tax_type_id) { |         } else if (tax.tax_type_id) { | ||||||
|           taxes.push({ |           taxes.push({ | ||||||
|             tax_type_id: tax.tax_type_id, |             tax_type_id: tax.tax_type_id, | ||||||
|             amount: tax.amount, |             amount: Math.round(tax.amount), | ||||||
|             percent: tax.percent, |             percent: tax.percent, | ||||||
|             name: tax.name, |             name: tax.name, | ||||||
|           }) |           }) | ||||||
| @ -284,6 +285,19 @@ const defaultCurrency = computed(() => { | |||||||
|   } |   } | ||||||
| }) | }) | ||||||
|  |  | ||||||
|  | function setDiscount() { | ||||||
|  |   const newValue = props.store[props.storeProp].discount | ||||||
|  |  | ||||||
|  |   if (props.store[props.storeProp].discount_type === 'percentage') { | ||||||
|  |     props.store[props.storeProp].discount_val | ||||||
|  |       = Math.round((props.store.getSubTotal * newValue) / 100) | ||||||
|  |  | ||||||
|  |     return | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   props.store[props.storeProp].discount_val = Math.round(newValue * 100) | ||||||
|  | } | ||||||
|  |  | ||||||
| function selectFixed() { | function selectFixed() { | ||||||
|   if (props.store[props.storeProp].discount_type === 'fixed') { |   if (props.store[props.storeProp].discount_type === 'fixed') { | ||||||
|     return |     return | ||||||
| @ -295,24 +309,21 @@ function selectFixed() { | |||||||
| } | } | ||||||
|  |  | ||||||
| function selectPercentage() { | function selectPercentage() { | ||||||
|   if (props.store[props.storeProp].discount_type === 'percentage') { |   if (props.store[props.storeProp].discount_type === 'percentage'){ | ||||||
|     return |     return | ||||||
|   } |   } | ||||||
|   props.store[props.storeProp].discount_val = |  | ||||||
|     (props.store.getSubTotal * props.store[props.storeProp].discount) / 100 |   const val = Math.round(props.store[props.storeProp].discount * 100) / 100 | ||||||
|  |  | ||||||
|  |   props.store[props.storeProp].discount_val | ||||||
|  |     = Math.round((props.store.getSubTotal * val) / 100) | ||||||
|  |  | ||||||
|   props.store[props.storeProp].discount_type = 'percentage' |   props.store[props.storeProp].discount_type = 'percentage' | ||||||
| } | } | ||||||
|  |  | ||||||
| function onSelectTax(selectedTax) { | function onSelectTax(selectedTax) { | ||||||
|   let amount = 0 |   let amount = 0 | ||||||
|  |   if (props.store.getSubtotalWithDiscount && selectedTax.percent) { | ||||||
|   if (selectedTax.compound_tax && props.store.getSubtotalWithDiscount) { |  | ||||||
|     amount = Math.round( |  | ||||||
|       ((props.store.getSubtotalWithDiscount + props.store.getTotalSimpleTax) * |  | ||||||
|         selectedTax.percent) / |  | ||||||
|         100 |  | ||||||
|     ) |  | ||||||
|   } else if (props.store.getSubtotalWithDiscount && selectedTax.percent) { |  | ||||||
|     amount = Math.round( |     amount = Math.round( | ||||||
|       (props.store.getSubtotalWithDiscount * selectedTax.percent) / 100 |       (props.store.getSubtotalWithDiscount * selectedTax.percent) / 100 | ||||||
|     ) |     ) | ||||||
| @ -323,7 +334,6 @@ function onSelectTax(selectedTax) { | |||||||
|     id: Guid.raw(), |     id: Guid.raw(), | ||||||
|     name: selectedTax.name, |     name: selectedTax.name, | ||||||
|     percent: selectedTax.percent, |     percent: selectedTax.percent, | ||||||
|     compound_tax: selectedTax.compound_tax, |  | ||||||
|     tax_type_id: selectedTax.id, |     tax_type_id: selectedTax.id, | ||||||
|     amount, |     amount, | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -77,17 +77,6 @@ | |||||||
|               @input="v$.currentTaxType.description.$touch()" |               @input="v$.currentTaxType.description.$touch()" | ||||||
|             /> |             /> | ||||||
|           </BaseInputGroup> |           </BaseInputGroup> | ||||||
|  |  | ||||||
|           <BaseInputGroup |  | ||||||
|             :label="$t('tax_types.compound_tax')" |  | ||||||
|             variant="horizontal" |  | ||||||
|             class="flex flex-row-reverse" |  | ||||||
|           > |  | ||||||
|             <BaseSwitch |  | ||||||
|               v-model="taxTypeStore.currentTaxType.compound_tax" |  | ||||||
|               class="flex items-center" |  | ||||||
|             /> |  | ||||||
|           </BaseInputGroup> |  | ||||||
|         </BaseInputGrid> |         </BaseInputGrid> | ||||||
|       </div> |       </div> | ||||||
|       <div |       <div | ||||||
| @ -209,14 +198,7 @@ async function submitTaxTypeData() { | |||||||
|  |  | ||||||
| function SelectTax(taxData) { | function SelectTax(taxData) { | ||||||
|   let amount = 0 |   let amount = 0 | ||||||
|   if (taxData.compound_tax && estimateStore.getSubtotalWithDiscount) { |  if (estimateStore.getSubtotalWithDiscount && taxData.percent) { | ||||||
|     amount = Math.round( |  | ||||||
|       ((estimateStore.getSubtotalWithDiscount + |  | ||||||
|         estimateStore.getTotalSimpleTax) * |  | ||||||
|         taxData.percent) / |  | ||||||
|         100 |  | ||||||
|     ) |  | ||||||
|   } else if (estimateStore.getSubtotalWithDiscount && taxData.percent) { |  | ||||||
|     amount = Math.round( |     amount = Math.round( | ||||||
|       (estimateStore.getSubtotalWithDiscount * taxData.percent) / 100 |       (estimateStore.getSubtotalWithDiscount * taxData.percent) / 100 | ||||||
|     ) |     ) | ||||||
| @ -226,7 +208,6 @@ function SelectTax(taxData) { | |||||||
|     id: Guid.raw(), |     id: Guid.raw(), | ||||||
|     name: taxData.name, |     name: taxData.name, | ||||||
|     percent: taxData.percent, |     percent: taxData.percent, | ||||||
|     compound_tax: taxData.compound_tax, |  | ||||||
|     tax_type_id: taxData.id, |     tax_type_id: taxData.id, | ||||||
|     amount, |     amount, | ||||||
|   } |   } | ||||||
| @ -242,7 +223,6 @@ function selectItemTax(taxData) { | |||||||
|       id: Guid.raw(), |       id: Guid.raw(), | ||||||
|       name: taxData.name, |       name: taxData.name, | ||||||
|       percent: taxData.percent, |       percent: taxData.percent, | ||||||
|       compound_tax: taxData.compound_tax, |  | ||||||
|       tax_type_id: taxData.id, |       tax_type_id: taxData.id, | ||||||
|     } |     } | ||||||
|     modalStore.refreshData(data) |     modalStore.refreshData(data) | ||||||
|  | |||||||
| @ -143,7 +143,8 @@ export const useEstimateStore = (useWindow = false) => { | |||||||
|           axios |           axios | ||||||
|             .get(`/api/v1/estimates/${id}`) |             .get(`/api/v1/estimates/${id}`) | ||||||
|             .then((response) => { |             .then((response) => { | ||||||
|               Object.assign(this.newEstimate, response.data.data) |               this.setEstimateData(response.data.data) | ||||||
|  |               this.setCustomerAddresses(this.newEstimate.customer) | ||||||
|               resolve(response) |               resolve(response) | ||||||
|             }) |             }) | ||||||
|             .catch((err) => { |             .catch((err) => { | ||||||
| @ -154,6 +155,41 @@ export const useEstimateStore = (useWindow = false) => { | |||||||
|         }) |         }) | ||||||
|       }, |       }, | ||||||
|  |  | ||||||
|  |       setEstimateData(estimate) { | ||||||
|  |         Object.assign(this.newEstimate, estimate) | ||||||
|  |         if (this.newEstimate.tax_per_item === 'YES') { | ||||||
|  |           this.newEstimate.items.forEach((_i) => { | ||||||
|  |             if (_i.taxes && !_i.taxes.length){ | ||||||
|  |               _i.taxes.push({ ...taxStub, id: Guid.raw() }) | ||||||
|  |             } | ||||||
|  |           }) | ||||||
|  |         } | ||||||
|  |         if (this.newEstimate.discount_per_item === 'YES') { | ||||||
|  |           this.newEstimate.items.forEach((_i, index) => { | ||||||
|  |             if (_i.discount_type === 'fixed'){ | ||||||
|  |               this.newEstimate.items[index].discount = _i.discount / 100 | ||||||
|  |             } | ||||||
|  |           }) | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |           if (this.newEstimate.discount_type === 'fixed'){ | ||||||
|  |             this.newEstimate.discount = this.newEstimate.discount / 100 | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       setCustomerAddresses(customer) { | ||||||
|  |         const customer_business = customer.customer_business | ||||||
|  |  | ||||||
|  |         if (customer_business?.billing_address){ | ||||||
|  |           this.newEstimate.customer.billing_address = customer_business.billing_address | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (customer_business?.shipping_address){ | ||||||
|  |           this.newEstimate.customer.shipping_address = customer_business.shipping_address | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |  | ||||||
|       addSalesTaxUs() { |       addSalesTaxUs() { | ||||||
|         const taxTypeStore = useTaxTypeStore() |         const taxTypeStore = useTaxTypeStore() | ||||||
|         let salesTax = { ...taxStub } |         let salesTax = { ...taxStub } | ||||||
|  | |||||||
| @ -133,8 +133,8 @@ export const useInvoiceStore = (useWindow = false) => { | |||||||
|           axios |           axios | ||||||
|             .get(`/api/v1/invoices/${id}`) |             .get(`/api/v1/invoices/${id}`) | ||||||
|             .then((response) => { |             .then((response) => { | ||||||
|               Object.assign(this.newInvoice, response.data.data) |               this.setInvoiceData(response.data.data) | ||||||
|               this.newInvoice.customer = response.data.data.customer |               this.setCustomerAddresses(this.newInvoice.customer) | ||||||
|               resolve(response) |               resolve(response) | ||||||
|             }) |             }) | ||||||
|             .catch((err) => { |             .catch((err) => { | ||||||
| @ -144,6 +144,38 @@ export const useInvoiceStore = (useWindow = false) => { | |||||||
|         }) |         }) | ||||||
|       }, |       }, | ||||||
|  |  | ||||||
|  |       setInvoiceData(invoice) { | ||||||
|  |         Object.assign(this.newInvoice, invoice) | ||||||
|  |  | ||||||
|  |         if (this.newInvoice.tax_per_item === 'YES') { | ||||||
|  |           this.newInvoice.items.forEach((_i) => { | ||||||
|  |             if (_i.taxes && !_i.taxes.length) | ||||||
|  |               _i.taxes.push({ ...taxStub, id: Guid.raw() }) | ||||||
|  |           }) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (this.newInvoice.discount_per_item === 'YES') { | ||||||
|  |           this.newInvoice.items.forEach((_i, index) => { | ||||||
|  |             if (_i.discount_type === 'fixed') | ||||||
|  |               this.newInvoice.items[index].discount = _i.discount / 100 | ||||||
|  |           }) | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |           if (this.newInvoice.discount_type === 'fixed') | ||||||
|  |             this.newInvoice.discount = this.newInvoice.discount / 100 | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       setCustomerAddresses(customer) { | ||||||
|  |         const customer_business = customer.customer_business | ||||||
|  |  | ||||||
|  |         if (customer_business?.billing_address) | ||||||
|  |           this.newInvoice.customer.billing_address = customer_business.billing_address | ||||||
|  |  | ||||||
|  |         if (customer_business?.shipping_address) | ||||||
|  |           this.newInvoice.customer.shipping_address = customer_business.shipping_address | ||||||
|  |       }, | ||||||
|  |  | ||||||
|       addSalesTaxUs() { |       addSalesTaxUs() { | ||||||
|         const taxTypeStore = useTaxTypeStore() |         const taxTypeStore = useTaxTypeStore() | ||||||
|         let salesTax = { ...taxStub } |         let salesTax = { ...taxStub } | ||||||
|  | |||||||
| @ -138,6 +138,7 @@ | |||||||
|  |  | ||||||
| <script setup> | <script setup> | ||||||
| import { computed, ref, watch, onMounted } from 'vue' | import { computed, ref, watch, onMounted } from 'vue' | ||||||
|  | import { cloneDeep } from 'lodash' | ||||||
| import { useRoute, useRouter } from 'vue-router' | import { useRoute, useRouter } from 'vue-router' | ||||||
| import { useI18n } from 'vue-i18n' | import { useI18n } from 'vue-i18n' | ||||||
| import { | import { | ||||||
| @ -257,11 +258,30 @@ async function submitForm() { | |||||||
|  |  | ||||||
|   isSaving.value = true |   isSaving.value = true | ||||||
|  |  | ||||||
|   let data = { |   let data = cloneDeep({ | ||||||
|     ...estimateStore.newEstimate, |     ...estimateStore.newEstimate, | ||||||
|     sub_total: estimateStore.getSubTotal, |     sub_total: estimateStore.getSubTotal, | ||||||
|     total: estimateStore.getTotal, |     total: estimateStore.getTotal, | ||||||
|     tax: estimateStore.getTotalTax, |     tax: estimateStore.getTotalTax, | ||||||
|  |   }) | ||||||
|  |   if (data.discount_per_item === 'YES') { | ||||||
|  |     data.items.forEach((item, index) => { | ||||||
|  |       if (item.discount_type === 'fixed'){ | ||||||
|  |         data.items[index].discount = Math.round(item.discount * 100) | ||||||
|  |       } | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  |   else { | ||||||
|  |     if (data.discount_type === 'fixed'){ | ||||||
|  |       data.discount = Math.round(data.discount * 100) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if ( | ||||||
|  |     !estimateStore.newEstimate.tax_per_item === 'YES' | ||||||
|  |     && data.taxes.length | ||||||
|  |   ){ | ||||||
|  |     data.tax_type_ids = data.taxes.map(_t => _t.tax_type_id) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   const action = isEdit.value |   const action = isEdit.value | ||||||
|  | |||||||
| @ -147,6 +147,7 @@ import { | |||||||
|   decimal, |   decimal, | ||||||
| } from '@vuelidate/validators' | } from '@vuelidate/validators' | ||||||
| import useVuelidate from '@vuelidate/core' | import useVuelidate from '@vuelidate/core' | ||||||
|  | import { cloneDeep } from 'lodash' | ||||||
|  |  | ||||||
| import { useInvoiceStore } from '@/scripts/admin/stores/invoice' | import { useInvoiceStore } from '@/scripts/admin/stores/invoice' | ||||||
| import { useModuleStore } from '@/scripts/admin/stores/module' | import { useModuleStore } from '@/scripts/admin/stores/module' | ||||||
| @ -258,11 +259,29 @@ async function submitForm() { | |||||||
|  |  | ||||||
|   isSaving.value = true |   isSaving.value = true | ||||||
|  |  | ||||||
|   let data = { |   let data = cloneDeep({ | ||||||
|     ...invoiceStore.newInvoice, |     ...invoiceStore.newInvoice, | ||||||
|     sub_total: invoiceStore.getSubTotal, |     sub_total: invoiceStore.getSubTotal, | ||||||
|     total: invoiceStore.getTotal, |     total: invoiceStore.getTotal, | ||||||
|     tax: invoiceStore.getTotalTax, |     tax: invoiceStore.getTotalTax, | ||||||
|  |   }) | ||||||
|  |   if (data.discount_per_item === 'YES') { | ||||||
|  |     data.items.forEach((item, index) => { | ||||||
|  |       if (item.discount_type === 'fixed'){ | ||||||
|  |         data.items[index].discount = item.discount * 100 | ||||||
|  |       } | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  |   else { | ||||||
|  |     if (data.discount_type === 'fixed'){ | ||||||
|  |       data.discount = data.discount * 100 | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |     if ( | ||||||
|  |     !invoiceStore.newInvoice.tax_per_item === 'YES' | ||||||
|  |     && data.taxes.length | ||||||
|  |   ){ | ||||||
|  |     data.tax_type_ids = data.taxes.map(_t => _t.tax_type_id) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   try { |   try { | ||||||
|  | |||||||
| @ -20,21 +20,6 @@ | |||||||
|       :data="fetchData" |       :data="fetchData" | ||||||
|       :columns="taxTypeColumns" |       :columns="taxTypeColumns" | ||||||
|     > |     > | ||||||
|       <template #cell-compound_tax="{ row }"> |  | ||||||
|         <BaseBadge |  | ||||||
|           :bg-color=" |  | ||||||
|             utils.getBadgeStatusColor(row.data.compound_tax ? 'YES' : 'NO') |  | ||||||
|               .bgColor |  | ||||||
|           " |  | ||||||
|           :color=" |  | ||||||
|             utils.getBadgeStatusColor(row.data.compound_tax ? 'YES' : 'NO') |  | ||||||
|               .color |  | ||||||
|           " |  | ||||||
|         > |  | ||||||
|           {{ row.data.compound_tax ? 'Yes' : 'No'.replace('_', ' ') }} |  | ||||||
|         </BaseBadge> |  | ||||||
|       </template> |  | ||||||
|  |  | ||||||
|       <template #cell-percent="{ row }"> {{ row.data.percent }} % </template> |       <template #cell-percent="{ row }"> {{ row.data.percent }} % </template> | ||||||
|  |  | ||||||
|       <template v-if="hasAtleastOneAbility()" #cell-actions="{ row }"> |       <template v-if="hasAtleastOneAbility()" #cell-actions="{ row }"> | ||||||
| @ -91,11 +76,6 @@ const taxTypeColumns = computed(() => { | |||||||
|       thClass: 'extra', |       thClass: 'extra', | ||||||
|       tdClass: 'font-medium text-gray-900', |       tdClass: 'font-medium text-gray-900', | ||||||
|     }, |     }, | ||||||
|     { |  | ||||||
|       key: 'compound_tax', |  | ||||||
|       label: t('settings.tax_types.compound_tax'), |  | ||||||
|       tdClass: 'font-medium text-gray-900', |  | ||||||
|     }, |  | ||||||
|     { |     { | ||||||
|       key: 'percent', |       key: 'percent', | ||||||
|       label: t('settings.tax_types.percent'), |       label: t('settings.tax_types.percent'), | ||||||
|  | |||||||
| @ -309,6 +309,8 @@ function changeSorting(column) { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (!usesLocalData.value) { |   if (!usesLocalData.value) { | ||||||
|  |     if (pagination.value) | ||||||
|  |       pagination.value.currentPage = 1 | ||||||
|     mapDataToRows() |     mapDataToRows() | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @ -326,7 +328,10 @@ async function pageChange(page) { | |||||||
|   await mapDataToRows() |   await mapDataToRows() | ||||||
| } | } | ||||||
|  |  | ||||||
| async function refresh() { | async function refresh(isPreservePage = false) { | ||||||
|  |   if (pagination.value && !isPreservePage) | ||||||
|  |     pagination.value.currentPage = 1 | ||||||
|  |  | ||||||
|   await mapDataToRows() |   await mapDataToRows() | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	