mirror of
				https://github.com/crater-invoice/crater.git
				synced 2025-10-29 20:51:09 -04:00 
			
		
		
		
	Compare commits
	
		
			2 Commits
		
	
	
		
			tax-calcul
			...
			fix-logout
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| bdf8fa8b5a | |||
| ba298cdb0a | 
| @ -45,21 +45,15 @@ 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' => [ | ||||||
| @ -83,11 +77,9 @@ class EstimatesRequest extends FormRequest | |||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|             'items.*.quantity' => [ |             'items.*.quantity' => [ | ||||||
|                 'integer', |  | ||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|             'items.*.price' => [ |             'items.*.price' => [ | ||||||
|                 'integer', |  | ||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|         ]; |         ]; | ||||||
|  | |||||||
| @ -45,21 +45,15 @@ 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' => [ | ||||||
| @ -83,11 +77,9 @@ class InvoicesRequest extends FormRequest | |||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|             'items.*.quantity' => [ |             'items.*.quantity' => [ | ||||||
|                 'integer', |  | ||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|             'items.*.price' => [ |             'items.*.price' => [ | ||||||
|                 'integer', |  | ||||||
|                 'required', |                 'required', | ||||||
|             ], |             ], | ||||||
|         ]; |         ]; | ||||||
|  | |||||||
| @ -43,21 +43,15 @@ 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' => [ | ||||||
|  | |||||||
| @ -271,19 +271,23 @@ const price = computed({ | |||||||
|     } else { |     } else { | ||||||
|       updateItemAttribute('price', newValue) |       updateItemAttribute('price', newValue) | ||||||
|     } |     } | ||||||
|     setDiscount() |  | ||||||
|   }, |   }, | ||||||
| }) | }) | ||||||
|  |  | ||||||
| const subtotal = computed(() => Math.round(props.itemData.price * props.itemData.quantity)) | const subtotal = computed(() => 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() |  | ||||||
|   }, |   }, | ||||||
| }) | }) | ||||||
|  |  | ||||||
| @ -309,7 +313,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.amount) { |       if (!tax.compound_tax) { | ||||||
|         return tax.amount |         return tax.amount | ||||||
|       } |       } | ||||||
|       return 0 |       return 0 | ||||||
| @ -317,7 +321,18 @@ const totalSimpleTax = computed(() => { | |||||||
|   ) |   ) | ||||||
| }) | }) | ||||||
|  |  | ||||||
| const totalTax = computed(() => totalSimpleTax.value) | const totalCompoundTax = computed(() => { | ||||||
|  |   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: { | ||||||
| @ -401,16 +416,6 @@ 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) | ||||||
| } | } | ||||||
| @ -480,12 +485,10 @@ 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 (props.discountedTotal && localTax.percent) { |   if (localTax.compound_tax && props.discountedTotal) { | ||||||
|     const taxPerItemEnabled = props.store[props.storeProp].tax_per_item === 'YES' |     return ((props.discountedTotal + props.totalTax) * localTax.percent) / 100 | ||||||
|     const discountPerItemEnabled = props.store[props.storeProp].discount_per_item === 'YES' |  | ||||||
|     if (taxPerItemEnabled && !discountPerItemEnabled){ |  | ||||||
|       return getTaxAmount() |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   if (props.discountedTotal && localTax.percent) { | ||||||
|     return (props.discountedTotal * localTax.percent) / 100 |     return (props.discountedTotal * localTax.percent) / 100 | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   return 0 |   return 0 | ||||||
| }) | }) | ||||||
|  |  | ||||||
| @ -171,13 +171,6 @@ 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( | ||||||
| @ -190,6 +183,7 @@ 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() | ||||||
| @ -226,27 +220,6 @@ 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, watch } from 'vue' | import { computed, inject, ref } 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,20 +227,19 @@ 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() |  | ||||||
|   }, |   }, | ||||||
| }) | }) | ||||||
|  |  | ||||||
| @ -266,7 +265,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: Math.round(tax.amount), |             amount: tax.amount, | ||||||
|             percent: tax.percent, |             percent: tax.percent, | ||||||
|             name: tax.name, |             name: tax.name, | ||||||
|           }) |           }) | ||||||
| @ -285,19 +284,6 @@ 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 | ||||||
| @ -312,18 +298,21 @@ 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 = | ||||||
|   const val = Math.round(props.store[props.storeProp].discount * 100) / 100 |     (props.store.getSubTotal * props.store[props.storeProp].discount) / 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 | ||||||
|     ) |     ) | ||||||
| @ -334,6 +323,7 @@ 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,6 +77,17 @@ | |||||||
|               @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 | ||||||
| @ -198,7 +209,14 @@ async function submitTaxTypeData() { | |||||||
|  |  | ||||||
| function SelectTax(taxData) { | function SelectTax(taxData) { | ||||||
|   let amount = 0 |   let amount = 0 | ||||||
|  if (estimateStore.getSubtotalWithDiscount && taxData.percent) { |   if (taxData.compound_tax && estimateStore.getSubtotalWithDiscount) { | ||||||
|  |     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 | ||||||
|     ) |     ) | ||||||
| @ -208,6 +226,7 @@ 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, | ||||||
|   } |   } | ||||||
| @ -223,6 +242,7 @@ 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,8 +143,7 @@ export const useEstimateStore = (useWindow = false) => { | |||||||
|           axios |           axios | ||||||
|             .get(`/api/v1/estimates/${id}`) |             .get(`/api/v1/estimates/${id}`) | ||||||
|             .then((response) => { |             .then((response) => { | ||||||
|               this.setEstimateData(response.data.data) |               Object.assign(this.newEstimate, response.data.data) | ||||||
|               this.setCustomerAddresses(this.newEstimate.customer) |  | ||||||
|               resolve(response) |               resolve(response) | ||||||
|             }) |             }) | ||||||
|             .catch((err) => { |             .catch((err) => { | ||||||
| @ -155,41 +154,6 @@ 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) => { | ||||||
|               this.setInvoiceData(response.data.data) |               Object.assign(this.newInvoice, response.data.data) | ||||||
|               this.setCustomerAddresses(this.newInvoice.customer) |               this.newInvoice.customer = response.data.data.customer | ||||||
|               resolve(response) |               resolve(response) | ||||||
|             }) |             }) | ||||||
|             .catch((err) => { |             .catch((err) => { | ||||||
| @ -144,38 +144,6 @@ 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 } | ||||||
|  | |||||||
| @ -35,16 +35,7 @@ | |||||||
|       </div> |       </div> | ||||||
|  |  | ||||||
|       <div |       <div | ||||||
|         class=" |         class="grid col-span-12 mt-6 text-center xl:mt-0 sm:grid-cols-4 xl:text-right xl:col-span-3 xl:grid-cols-1 xxl:col-span-2" | ||||||
|           grid |  | ||||||
|           col-span-12 |  | ||||||
|           mt-6 |  | ||||||
|           text-center |  | ||||||
|           xl:mt-0 |  | ||||||
|           sm:grid-cols-4 |  | ||||||
|           xl:text-right xl:col-span-3 xl:grid-cols-1 |  | ||||||
|           xxl:col-span-2 |  | ||||||
|         " |  | ||||||
|       > |       > | ||||||
|         <div class="px-6 py-2"> |         <div class="px-6 py-2"> | ||||||
|           <span class="text-xs leading-5 lg:text-sm"> |           <span class="text-xs leading-5 lg:text-sm"> | ||||||
| @ -177,10 +168,12 @@ const getChartInvoices = computed(() => { | |||||||
|   return [] |   return [] | ||||||
| }) | }) | ||||||
|  |  | ||||||
|  | const customerId = computed(() => route.params.id) | ||||||
|  |  | ||||||
| watch( | watch( | ||||||
|   route, |   () => customerId.value, | ||||||
|   () => { |   (id) => { | ||||||
|     if (route.params.id) { |     if (id && route.name === 'customers.view') { | ||||||
|       loadCustomer() |       loadCustomer() | ||||||
|     } |     } | ||||||
|     selectedYear.value = 'This year' |     selectedYear.value = 'This year' | ||||||
|  | |||||||
| @ -37,32 +37,10 @@ | |||||||
|  |  | ||||||
|     <!-- Sidebar --> |     <!-- Sidebar --> | ||||||
|     <div |     <div | ||||||
|       class=" |       class="fixed top-0 left-0 hidden h-full pt-16 pb-[6.4rem] ml-56 bg-white xl:ml-64 w-88 xl:block" | ||||||
|         fixed |  | ||||||
|         top-0 |  | ||||||
|         left-0 |  | ||||||
|         hidden |  | ||||||
|         h-full |  | ||||||
|         pt-16 |  | ||||||
|         pb-[6.4rem] |  | ||||||
|         ml-56 |  | ||||||
|         bg-white |  | ||||||
|         xl:ml-64 |  | ||||||
|         w-88 |  | ||||||
|         xl:block |  | ||||||
|       " |  | ||||||
|     > |     > | ||||||
|       <div |       <div | ||||||
|         class=" |         class="flex items-center justify-between px-4 pt-8 pb-2 border border-gray-200 border-solid height-full" | ||||||
|           flex |  | ||||||
|           items-center |  | ||||||
|           justify-between |  | ||||||
|           px-4 |  | ||||||
|           pt-8 |  | ||||||
|           pb-2 |  | ||||||
|           border border-gray-200 border-solid |  | ||||||
|           height-full |  | ||||||
|         " |  | ||||||
|       > |       > | ||||||
|         <div class="mb-6"> |         <div class="mb-6"> | ||||||
|           <BaseInput |           <BaseInput | ||||||
| @ -92,14 +70,7 @@ | |||||||
|             </template> |             </template> | ||||||
|  |  | ||||||
|             <div |             <div | ||||||
|               class=" |               class="px-4 py-1 pb-2 mb-1 mb-2 text-sm border-b border-gray-200 border-solid" | ||||||
|                 px-4 |  | ||||||
|                 py-1 |  | ||||||
|                 pb-2 |  | ||||||
|                 mb-1 mb-2 |  | ||||||
|                 text-sm |  | ||||||
|                 border-b border-gray-200 border-solid |  | ||||||
|               " |  | ||||||
|             > |             > | ||||||
|               {{ $t('general.sort_by') }} |               {{ $t('general.sort_by') }} | ||||||
|             </div> |             </div> | ||||||
| @ -156,12 +127,7 @@ | |||||||
|  |  | ||||||
|       <div |       <div | ||||||
|         ref="estimateListSection" |         ref="estimateListSection" | ||||||
|         class=" |         class="h-full overflow-y-scroll border-l border-gray-200 border-solid base-scroll" | ||||||
|           h-full |  | ||||||
|           overflow-y-scroll |  | ||||||
|           border-l border-gray-200 border-solid |  | ||||||
|           base-scroll |  | ||||||
|         " |  | ||||||
|       > |       > | ||||||
|         <div v-for="(estimate, index) in estimateList" :key="index"> |         <div v-for="(estimate, index) in estimateList" :key="index"> | ||||||
|           <router-link |           <router-link | ||||||
| @ -181,29 +147,11 @@ | |||||||
|               <BaseText |               <BaseText | ||||||
|                 :text="estimate.customer.name" |                 :text="estimate.customer.name" | ||||||
|                 :length="30" |                 :length="30" | ||||||
|                 class=" |                 class="pr-2 mb-2 text-sm not-italic font-normal leading-5 text-black capitalize truncate" | ||||||
|                   pr-2 |  | ||||||
|                   mb-2 |  | ||||||
|                   text-sm |  | ||||||
|                   not-italic |  | ||||||
|                   font-normal |  | ||||||
|                   leading-5 |  | ||||||
|                   text-black |  | ||||||
|                   capitalize |  | ||||||
|                   truncate |  | ||||||
|                 " |  | ||||||
|               /> |               /> | ||||||
|  |  | ||||||
|               <div |               <div | ||||||
|                 class=" |                 class="mt-1 mb-2 text-xs not-italic font-medium leading-5 text-gray-600" | ||||||
|                   mt-1 |  | ||||||
|                   mb-2 |  | ||||||
|                   text-xs |  | ||||||
|                   not-italic |  | ||||||
|                   font-medium |  | ||||||
|                   leading-5 |  | ||||||
|                   text-gray-600 |  | ||||||
|                 " |  | ||||||
|               > |               > | ||||||
|                 {{ estimate.estimate_number }} |                 {{ estimate.estimate_number }} | ||||||
|               </div> |               </div> | ||||||
| @ -220,26 +168,11 @@ | |||||||
|               <BaseFormatMoney |               <BaseFormatMoney | ||||||
|                 :amount="estimate.total" |                 :amount="estimate.total" | ||||||
|                 :currency="estimate.customer.currency" |                 :currency="estimate.customer.currency" | ||||||
|                 class=" |                 class="block mb-2 text-xl not-italic font-semibold leading-8 text-right text-gray-900" | ||||||
|                   block |  | ||||||
|                   mb-2 |  | ||||||
|                   text-xl |  | ||||||
|                   not-italic |  | ||||||
|                   font-semibold |  | ||||||
|                   leading-8 |  | ||||||
|                   text-right text-gray-900 |  | ||||||
|                 " |  | ||||||
|               /> |               /> | ||||||
|  |  | ||||||
|               <div |               <div | ||||||
|                 class=" |                 class="text-sm not-italic font-normal leading-5 text-right text-gray-600 est-date" | ||||||
|                   text-sm |  | ||||||
|                   not-italic |  | ||||||
|                   font-normal |  | ||||||
|                   leading-5 |  | ||||||
|                   text-right text-gray-600 |  | ||||||
|                   est-date |  | ||||||
|                 " |  | ||||||
|               > |               > | ||||||
|                 {{ estimate.formatted_estimate_date }} |                 {{ estimate.formatted_estimate_date }} | ||||||
|               </div> |               </div> | ||||||
| @ -264,13 +197,7 @@ | |||||||
|     > |     > | ||||||
|       <iframe |       <iframe | ||||||
|         :src="`${shareableLink}`" |         :src="`${shareableLink}`" | ||||||
|         class=" |         class="flex-1 border border-gray-400 border-solid rounded-md bg-white frame-style" | ||||||
|           flex-1 |  | ||||||
|           border border-gray-400 border-solid |  | ||||||
|           rounded-md |  | ||||||
|           bg-white |  | ||||||
|           frame-style |  | ||||||
|         " |  | ||||||
|       /> |       /> | ||||||
|     </div> |     </div> | ||||||
|   </BasePage> |   </BasePage> | ||||||
| @ -345,11 +272,14 @@ const getCurrentEstimateId = computed(() => { | |||||||
|   return null |   return null | ||||||
| }) | }) | ||||||
|  |  | ||||||
| watch(route, (to, from) => { | const estimateId = computed(() => route.params.id) | ||||||
|   if (to.name === 'estimates.view') { |  | ||||||
|     loadEstimate() | watch( | ||||||
|  |   () => estimateId.value, | ||||||
|  |   (id) => { | ||||||
|  |     if (id && route.name === 'estimates.view') loadEstimate() | ||||||
|   } |   } | ||||||
| }) | ) | ||||||
|  |  | ||||||
| loadEstimates() | loadEstimates() | ||||||
| loadEstimate() | loadEstimate() | ||||||
|  | |||||||
| @ -138,7 +138,6 @@ | |||||||
|  |  | ||||||
| <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 { | ||||||
| @ -258,30 +257,11 @@ async function submitForm() { | |||||||
|  |  | ||||||
|   isSaving.value = true |   isSaving.value = true | ||||||
|  |  | ||||||
|   let data = cloneDeep({ |   let data = { | ||||||
|     ...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 | ||||||
|  | |||||||
| @ -65,11 +65,14 @@ const getCurrentInvoiceId = computed(() => { | |||||||
|   return null |   return null | ||||||
| }) | }) | ||||||
|  |  | ||||||
| watch(route, (to, from) => { | const invoiceId = computed(() => route.params.id) | ||||||
|   if (to.name === 'invoices.view') { |  | ||||||
|     loadInvoice() | watch( | ||||||
|  |   () => invoiceId.value, | ||||||
|  |   (id) => { | ||||||
|  |     if (id && route.name === 'invoices.view') loadInvoice() | ||||||
|   } |   } | ||||||
| }) | ) | ||||||
|  |  | ||||||
| async function onMarkAsSent() { | async function onMarkAsSent() { | ||||||
|   dialogStore |   dialogStore | ||||||
| @ -286,32 +289,10 @@ onSearched = debounce(onSearched, 500) | |||||||
|  |  | ||||||
|     <!-- sidebar --> |     <!-- sidebar --> | ||||||
|     <div |     <div | ||||||
|       class=" |       class="fixed top-0 left-0 hidden h-full pt-16 pb-[6.4rem] ml-56 bg-white xl:ml-64 w-88 xl:block" | ||||||
|         fixed |  | ||||||
|         top-0 |  | ||||||
|         left-0 |  | ||||||
|         hidden |  | ||||||
|         h-full |  | ||||||
|         pt-16 |  | ||||||
|         pb-[6.4rem] |  | ||||||
|         ml-56 |  | ||||||
|         bg-white |  | ||||||
|         xl:ml-64 |  | ||||||
|         w-88 |  | ||||||
|         xl:block |  | ||||||
|       " |  | ||||||
|     > |     > | ||||||
|       <div |       <div | ||||||
|         class=" |         class="flex items-center justify-between px-4 pt-8 pb-2 border border-gray-200 border-solid height-full" | ||||||
|           flex |  | ||||||
|           items-center |  | ||||||
|           justify-between |  | ||||||
|           px-4 |  | ||||||
|           pt-8 |  | ||||||
|           pb-2 |  | ||||||
|           border border-gray-200 border-solid |  | ||||||
|           height-full |  | ||||||
|         " |  | ||||||
|       > |       > | ||||||
|         <div class="mb-6"> |         <div class="mb-6"> | ||||||
|           <BaseInput |           <BaseInput | ||||||
| @ -335,14 +316,7 @@ onSearched = debounce(onSearched, 500) | |||||||
|               </BaseButton> |               </BaseButton> | ||||||
|             </template> |             </template> | ||||||
|             <div |             <div | ||||||
|               class=" |               class="px-2 py-1 pb-2 mb-1 mb-2 text-sm border-b border-gray-200 border-solid" | ||||||
|                 px-2 |  | ||||||
|                 py-1 |  | ||||||
|                 pb-2 |  | ||||||
|                 mb-1 mb-2 |  | ||||||
|                 text-sm |  | ||||||
|                 border-b border-gray-200 border-solid |  | ||||||
|               " |  | ||||||
|             > |             > | ||||||
|               {{ $t('general.sort_by') }} |               {{ $t('general.sort_by') }} | ||||||
|             </div> |             </div> | ||||||
| @ -399,12 +373,7 @@ onSearched = debounce(onSearched, 500) | |||||||
|  |  | ||||||
|       <div |       <div | ||||||
|         ref="invoiceListSection" |         ref="invoiceListSection" | ||||||
|         class=" |         class="h-full overflow-y-scroll border-l border-gray-200 border-solid base-scroll" | ||||||
|           h-full |  | ||||||
|           overflow-y-scroll |  | ||||||
|           border-l border-gray-200 border-solid |  | ||||||
|           base-scroll |  | ||||||
|         " |  | ||||||
|       > |       > | ||||||
|         <div v-for="(invoice, index) in invoiceList" :key="index"> |         <div v-for="(invoice, index) in invoiceList" :key="index"> | ||||||
|           <router-link |           <router-link | ||||||
| @ -424,29 +393,11 @@ onSearched = debounce(onSearched, 500) | |||||||
|               <BaseText |               <BaseText | ||||||
|                 :text="invoice.customer.name" |                 :text="invoice.customer.name" | ||||||
|                 :length="30" |                 :length="30" | ||||||
|                 class=" |                 class="pr-2 mb-2 text-sm not-italic font-normal leading-5 text-black capitalize truncate" | ||||||
|                   pr-2 |  | ||||||
|                   mb-2 |  | ||||||
|                   text-sm |  | ||||||
|                   not-italic |  | ||||||
|                   font-normal |  | ||||||
|                   leading-5 |  | ||||||
|                   text-black |  | ||||||
|                   capitalize |  | ||||||
|                   truncate |  | ||||||
|                 " |  | ||||||
|               /> |               /> | ||||||
|  |  | ||||||
|               <div |               <div | ||||||
|                 class=" |                 class="mt-1 mb-2 text-xs not-italic font-medium leading-5 text-gray-600" | ||||||
|                   mt-1 |  | ||||||
|                   mb-2 |  | ||||||
|                   text-xs |  | ||||||
|                   not-italic |  | ||||||
|                   font-medium |  | ||||||
|                   leading-5 |  | ||||||
|                   text-gray-600 |  | ||||||
|                 " |  | ||||||
|               > |               > | ||||||
|                 {{ invoice.invoice_number }} |                 {{ invoice.invoice_number }} | ||||||
|               </div> |               </div> | ||||||
| @ -460,27 +411,12 @@ onSearched = debounce(onSearched, 500) | |||||||
|  |  | ||||||
|             <div class="flex-1 whitespace-nowrap right"> |             <div class="flex-1 whitespace-nowrap right"> | ||||||
|               <BaseFormatMoney |               <BaseFormatMoney | ||||||
|                 class=" |                 class="mb-2 text-xl not-italic font-semibold leading-8 text-right text-gray-900 block" | ||||||
|                   mb-2 |  | ||||||
|                   text-xl |  | ||||||
|                   not-italic |  | ||||||
|                   font-semibold |  | ||||||
|                   leading-8 |  | ||||||
|                   text-right text-gray-900 |  | ||||||
|                   block |  | ||||||
|                 " |  | ||||||
|                 :amount="invoice.total" |                 :amount="invoice.total" | ||||||
|                 :currency="invoice.customer.currency" |                 :currency="invoice.customer.currency" | ||||||
|               /> |               /> | ||||||
|               <div |               <div | ||||||
|                 class=" |                 class="text-sm not-italic font-normal leading-5 text-right text-gray-600 est-date" | ||||||
|                   text-sm |  | ||||||
|                   not-italic |  | ||||||
|                   font-normal |  | ||||||
|                   leading-5 |  | ||||||
|                   text-right text-gray-600 |  | ||||||
|                   est-date |  | ||||||
|                 " |  | ||||||
|               > |               > | ||||||
|                 {{ invoice.formatted_invoice_date }} |                 {{ invoice.formatted_invoice_date }} | ||||||
|               </div> |               </div> | ||||||
| @ -505,13 +441,7 @@ onSearched = debounce(onSearched, 500) | |||||||
|     > |     > | ||||||
|       <iframe |       <iframe | ||||||
|         :src="`${shareableLink}`" |         :src="`${shareableLink}`" | ||||||
|         class=" |         class="flex-1 border border-gray-400 border-solid bg-white rounded-md frame-style" | ||||||
|           flex-1 |  | ||||||
|           border border-gray-400 border-solid |  | ||||||
|           bg-white |  | ||||||
|           rounded-md |  | ||||||
|           frame-style |  | ||||||
|         " |  | ||||||
|       /> |       /> | ||||||
|     </div> |     </div> | ||||||
|   </BasePage> |   </BasePage> | ||||||
|  | |||||||
| @ -147,7 +147,6 @@ 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' | ||||||
| @ -259,29 +258,11 @@ async function submitForm() { | |||||||
|  |  | ||||||
|   isSaving.value = true |   isSaving.value = true | ||||||
|  |  | ||||||
|   let data = cloneDeep({ |   let data = { | ||||||
|     ...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 { | ||||||
|  | |||||||
| @ -22,31 +22,10 @@ | |||||||
|  |  | ||||||
|     <!-- Sidebar --> |     <!-- Sidebar --> | ||||||
|     <div |     <div | ||||||
|       class=" |       class="fixed top-0 left-0 hidden h-full pt-16 pb-[6rem] ml-56 bg-white xl:ml-64 w-88 xl:block" | ||||||
|         fixed |  | ||||||
|         top-0 |  | ||||||
|         left-0 |  | ||||||
|         hidden |  | ||||||
|         h-full |  | ||||||
|         pt-16 |  | ||||||
|         pb-[6rem] |  | ||||||
|         ml-56 |  | ||||||
|         bg-white |  | ||||||
|         xl:ml-64 |  | ||||||
|         w-88 |  | ||||||
|         xl:block |  | ||||||
|       " |  | ||||||
|     > |     > | ||||||
|       <div |       <div | ||||||
|         class=" |         class="flex items-center justify-between px-4 pt-8 pb-6 border border-gray-200 border-solid" | ||||||
|           flex |  | ||||||
|           items-center |  | ||||||
|           justify-between |  | ||||||
|           px-4 |  | ||||||
|           pt-8 |  | ||||||
|           pb-6 |  | ||||||
|           border border-gray-200 border-solid |  | ||||||
|         " |  | ||||||
|       > |       > | ||||||
|         <BaseInput |         <BaseInput | ||||||
|           v-model="searchData.searchText" |           v-model="searchData.searchText" | ||||||
| @ -70,14 +49,7 @@ | |||||||
|             </template> |             </template> | ||||||
|  |  | ||||||
|             <div |             <div | ||||||
|               class=" |               class="px-4 py-1 pb-2 mb-2 text-sm border-b border-gray-200 border-solid" | ||||||
|                 px-4 |  | ||||||
|                 py-1 |  | ||||||
|                 pb-2 |  | ||||||
|                 mb-2 |  | ||||||
|                 text-sm |  | ||||||
|                 border-b border-gray-200 border-solid |  | ||||||
|               " |  | ||||||
|             > |             > | ||||||
|               {{ $t('general.sort_by') }} |               {{ $t('general.sort_by') }} | ||||||
|             </div> |             </div> | ||||||
| @ -159,43 +131,17 @@ | |||||||
|               <BaseText |               <BaseText | ||||||
|                 :text="payment?.customer?.name" |                 :text="payment?.customer?.name" | ||||||
|                 :length="30" |                 :length="30" | ||||||
|                 class=" |                 class="pr-2 mb-2 text-sm not-italic font-normal leading-5 text-black capitalize truncate" | ||||||
|                   pr-2 |  | ||||||
|                   mb-2 |  | ||||||
|                   text-sm |  | ||||||
|                   not-italic |  | ||||||
|                   font-normal |  | ||||||
|                   leading-5 |  | ||||||
|                   text-black |  | ||||||
|                   capitalize |  | ||||||
|                   truncate |  | ||||||
|                 " |  | ||||||
|               /> |               /> | ||||||
|  |  | ||||||
|               <div |               <div | ||||||
|                 class=" |                 class="mb-1 text-xs not-italic font-medium leading-5 text-gray-500 capitalize" | ||||||
|                   mb-1 |  | ||||||
|                   text-xs |  | ||||||
|                   not-italic |  | ||||||
|                   font-medium |  | ||||||
|                   leading-5 |  | ||||||
|                   text-gray-500 |  | ||||||
|                   capitalize |  | ||||||
|                 " |  | ||||||
|               > |               > | ||||||
|                 {{ payment?.payment_number }} |                 {{ payment?.payment_number }} | ||||||
|               </div> |               </div> | ||||||
|  |  | ||||||
|               <div |               <div | ||||||
|                 class=" |                 class="mb-1 text-xs not-italic font-medium leading-5 text-gray-500 capitalize" | ||||||
|                   mb-1 |  | ||||||
|                   text-xs |  | ||||||
|                   not-italic |  | ||||||
|                   font-medium |  | ||||||
|                   leading-5 |  | ||||||
|                   text-gray-500 |  | ||||||
|                   capitalize |  | ||||||
|                 " |  | ||||||
|               > |               > | ||||||
|                 {{ payment?.invoice_number }} |                 {{ payment?.invoice_number }} | ||||||
|               </div> |               </div> | ||||||
| @ -203,15 +149,7 @@ | |||||||
|  |  | ||||||
|             <div class="flex-1 whitespace-nowrap right"> |             <div class="flex-1 whitespace-nowrap right"> | ||||||
|               <BaseFormatMoney |               <BaseFormatMoney | ||||||
|                 class=" |                 class="block mb-2 text-xl not-italic font-semibold leading-8 text-right text-gray-900" | ||||||
|                   block |  | ||||||
|                   mb-2 |  | ||||||
|                   text-xl |  | ||||||
|                   not-italic |  | ||||||
|                   font-semibold |  | ||||||
|                   leading-8 |  | ||||||
|                   text-right text-gray-900 |  | ||||||
|                 " |  | ||||||
|                 :amount="payment?.amount" |                 :amount="payment?.amount" | ||||||
|                 :currency="payment.customer?.currency" |                 :currency="payment.customer?.currency" | ||||||
|               /> |               /> | ||||||
| @ -313,9 +251,14 @@ const paymentDate = computed(() => { | |||||||
|   ) |   ) | ||||||
| }) | }) | ||||||
|  |  | ||||||
| watch(route, () => { | const paymentId = computed(() => route.params.id) | ||||||
|   loadPayment() |  | ||||||
| }) | watch( | ||||||
|  |   () => paymentId.value, | ||||||
|  |   (id) => { | ||||||
|  |     if (id && route.name === 'payments.view') loadPayment() | ||||||
|  |   } | ||||||
|  | ) | ||||||
|  |  | ||||||
| loadPayments() | loadPayments() | ||||||
| loadPayment() | loadPayment() | ||||||
|  | |||||||
| @ -78,10 +78,12 @@ let isLoading = computed(() => { | |||||||
|   return recurringInvoiceStore.isFetchingViewData |   return recurringInvoiceStore.isFetchingViewData | ||||||
| }) | }) | ||||||
|  |  | ||||||
|  | const invoiceId = computed(() => route.params.id) | ||||||
|  |  | ||||||
| watch( | watch( | ||||||
|   route, |   () => invoiceId.value, | ||||||
|   () => { |   (id) => { | ||||||
|     if (route.params.id && route.name === 'recurring-invoices.view') { |     if (id && route.name === 'recurring-invoices.view') { | ||||||
|       loadRecurringInvoice() |       loadRecurringInvoice() | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|  | |||||||
| @ -20,6 +20,21 @@ | |||||||
|       :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 }"> | ||||||
| @ -76,6 +91,11 @@ 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,8 +309,6 @@ function changeSorting(column) { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (!usesLocalData.value) { |   if (!usesLocalData.value) { | ||||||
|     if (pagination.value) |  | ||||||
|       pagination.value.currentPage = 1 |  | ||||||
|     mapDataToRows() |     mapDataToRows() | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @ -328,10 +326,7 @@ async function pageChange(page) { | |||||||
|   await mapDataToRows() |   await mapDataToRows() | ||||||
| } | } | ||||||
|  |  | ||||||
| async function refresh(isPreservePage = false) { | async function refresh() { | ||||||
|   if (pagination.value && !isPreservePage) |  | ||||||
|     pagination.value.currentPage = 1 |  | ||||||
|  |  | ||||||
|   await mapDataToRows() |   await mapDataToRows() | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	