diff --git a/src/components/Controls/AutoComplete.vue b/src/components/Controls/AutoComplete.vue index 948bf38e..361b746e 100644 --- a/src/components/Controls/AutoComplete.vue +++ b/src/components/Controls/AutoComplete.vue @@ -300,6 +300,7 @@ export default { return; } + this.triggerChange(e.target.value); this.toggleDropdown(true); this.updateSuggestions(e.target.value); }, diff --git a/src/components/Controls/MultiLabelLink.vue b/src/components/Controls/MultiLabelLink.vue index 0d702542..cfb4a524 100644 --- a/src/components/Controls/MultiLabelLink.vue +++ b/src/components/Controls/MultiLabelLink.vue @@ -22,6 +22,11 @@ export default { }, }, props: { + thirdLink: String, + showSecondaryLink: { + type: Boolean, + default: false, + }, secondaryLink: String, }, mounted() { @@ -80,9 +85,10 @@ export default { return (this.results = results .map((r) => { const option = { - label: r[this.secondaryLink] - ? `${r[schema.titleField]} ` + ` ${r[this.secondaryLink]}` - : r[schema.titleField], + label: + r[this.secondaryLink] && this.showSecondaryLink + ? `${r[schema.titleField]} ` + ` ${r[this.secondaryLink]}` + : r[schema.titleField], value: r.name, value2: r[this.secondaryLink], }; diff --git a/src/components/POS/types.ts b/src/components/POS/types.ts index 0e5321ae..3825c798 100644 --- a/src/components/POS/types.ts +++ b/src/components/POS/types.ts @@ -30,6 +30,7 @@ export type PosEmits = | 'setPaymentMethod' | 'setCouponsCount' | 'routeToSinvList' + | 'handleItemSearch' | 'applyPricingRule' | 'setTransferRefNo' | 'setLoyaltyPoints' diff --git a/src/pages/POS/ClassicPOS.vue b/src/pages/POS/ClassicPOS.vue index c85c94fd..313d31e7 100644 --- a/src/pages/POS/ClassicPOS.vue +++ b/src/pages/POS/ClassicPOS.vue @@ -85,47 +85,23 @@
- - - - - + emitEvent('handleItemSearch', item.target.value as string, true) " + @change="(item: string) => emitEvent('handleItemSearch', item)" />
@@ -369,14 +345,12 @@ import Button from 'src/components/Button.vue'; import { defineComponent, PropType } from 'vue'; import PriceListModal from './PriceListModal.vue'; import { Item } from 'models/baseModels/Item/Item'; -import Link from 'src/components/Controls/Link.vue'; import CouponCodeModal from './CouponCodeModal.vue'; import POSQuickActions from './POSQuickActions.vue'; import { PosEmits } from 'src/components/POS/types'; import SavedInvoiceModal from './SavedInvoiceModal.vue'; import OpenPOSShiftModal from './OpenPOSShiftModal.vue'; import ClosePOSShiftModal from './ClosePOSShiftModal.vue'; -import Barcode from 'src/components/Controls/Barcode.vue'; import LoyaltyProgramModal from './LoyaltyProgramModal.vue'; import { POSItem, ItemQtyMap } from 'src/components/POS/types'; import ItemsGrid from 'src/components/POS/Classic/ItemsGrid.vue'; @@ -385,7 +359,6 @@ import ReturnSalesInvoiceModal from './ReturnSalesInvoiceModal.vue'; import MultiLabelLink from 'src/components/Controls/MultiLabelLink.vue'; import { SalesInvoice } from 'models/baseModels/SalesInvoice/SalesInvoice'; import SelectedItemTable from 'src/components/POS/Classic/SelectedItemTable.vue'; -import WeightEnabledBarcode from 'src/components/Controls/WeightEnabledBarcode.vue'; import FloatingLabelFloatInput from 'src/components/POS/FloatingLabelFloatInput.vue'; import FloatingLabelCurrencyInput from 'src/components/POS/FloatingLabelCurrencyInput.vue'; import { AppliedCouponCodes } from 'models/baseModels/AppliedCouponCodes/AppliedCouponCodes'; @@ -393,9 +366,7 @@ import { AppliedCouponCodes } from 'models/baseModels/AppliedCouponCodes/Applied export default defineComponent({ name: 'ClassicPOS', components: { - Link, Button, - Barcode, ItemsGrid, AlertModal, ItemsTable, @@ -409,7 +380,6 @@ export default defineComponent({ SavedInvoiceModal, ClosePOSShiftModal, LoyaltyProgramModal, - WeightEnabledBarcode, FloatingLabelFloatInput, ReturnSalesInvoiceModal, FloatingLabelCurrencyInput, @@ -437,6 +407,10 @@ export default defineComponent({ type: Number, default: 0, }, + itemSearchTerm: { + type: String, + default: '', + }, loyaltyProgram: { type: String, default: '', @@ -471,6 +445,7 @@ export default defineComponent({ 'setPaidAmount', 'setCouponsCount', 'routeToSinvList', + 'handleItemSearch', 'setPaymentMethod', 'setTransferRefNo', 'setLoyaltyPoints', @@ -486,7 +461,6 @@ export default defineComponent({ data() { return { additionalDiscounts: fyo.pesa(0), - itemSearchTerm: '', }; }, computed: { diff --git a/src/pages/POS/POS.vue b/src/pages/POS/POS.vue index a3978995..e8da11e8 100644 --- a/src/pages/POS/POS.vue +++ b/src/pages/POS/POS.vue @@ -18,6 +18,7 @@ :loyalty-points="loyaltyPoints" :open-alert-modal="openAlertModal" :default-customer="defaultCustomer" + :item-search-term="itemSearchTerm" :is-pos-shift-open="isPosShiftOpen" :items="(items as [] as POSItem[])" :sinv-doc="(sinvDoc as SalesInvoice)" @@ -39,6 +40,7 @@ @clear-values="clearValues" @set-customer="setCustomer" @toggle-modal="toggleModal" + @handle-item-search="handleItemSearch" @set-paid-amount="setPaidAmount" @set-payment-method="setPaymentMethod" @set-coupons-count="setCouponsCount" @@ -287,6 +289,87 @@ export default defineComponent({ this.loyaltyProgram = party[0]?.loyaltyProgram as string; this.loyaltyPoints = party[0]?.loyaltyPoints as number; }, + + async handleItemSearch(searchTerm: string, addItem?: boolean) { + this.itemSearchTerm = searchTerm; + if (!addItem) return; + + let quantity = 1; + const posSettings = fyo.singles.POSSettings; + const isWeightEnabledBarcode = posSettings?.weightEnabledBarcode; + + const checkDigits = posSettings?.checkDigits || ''; + const itemCodeDigits = posSettings?.itemCodeDigits || 0; + const weightDigits = posSettings?.itemWeightDigits || 0; + + const expectedWeightBarcodeLength = + String(checkDigits).length + + Number(itemCodeDigits) + + Number(weightDigits); + + let isWeightBarcode = false; + let itemCode = searchTerm; + let weightPart = ''; + + if ( + isWeightEnabledBarcode && + searchTerm.length === expectedWeightBarcodeLength + ) { + const extractedItemCode = searchTerm.slice( + checkDigits.toString().length, + checkDigits.toString().length + itemCodeDigits + ); + const weightData = searchTerm.slice( + checkDigits.toString().length + itemCodeDigits + ); + + if (!isNaN(Number(weightData))) { + isWeightBarcode = true; + itemCode = extractedItemCode; + weightPart = weightData; + } + } + + const allItems = await this.fyo.db.getAll(ModelNameEnum.Item, { + fields: ['name', 'barcode', 'itemCode', 'unit'], + }); + + let matchedItem = null; + + if (isWeightBarcode) { + matchedItem = allItems.find( + (item) => item.itemCode === itemCode || item.barcode === itemCode + ); + } else if (searchTerm.length === 12) { + matchedItem = allItems.find((item) => item.barcode === searchTerm); + } + + if (!matchedItem) { + matchedItem = allItems.find((item) => item.name === searchTerm); + } + + if (!matchedItem) return; + + if (isWeightBarcode && weightPart) { + const weightValue = parseInt(weightPart, 10); + if ((matchedItem.unit as string)?.toLowerCase() === 'kg') { + quantity = weightValue / 1000; + } else { + quantity = weightValue; + } + } + + const itemDoc = this.getItem(matchedItem.name as string); + if (itemDoc && addItem) { + await this.addItem(itemDoc as POSItem, quantity); + this.itemSearchTerm = ''; + } + }, + + getItem(name: string) { + return this.items.find((item) => item.name === name); + }, + isModalOpen() { for (const modal of modalNames) { if (modal && this[`open${modal}Modal`]) { diff --git a/src/pages/POS/POSQuickActions.vue b/src/pages/POS/POSQuickActions.vue index a265d259..9d50dfbf 100644 --- a/src/pages/POS/POSQuickActions.vue +++ b/src/pages/POS/POSQuickActions.vue @@ -337,7 +337,6 @@ export default defineComponent({ paymentDoc: {} as Payment, itemSerialNumbers: {} as ItemSerialNumbers, - itemSearchTerm: '', transferRefNo: undefined as string | undefined, transferClearanceDate: undefined as Date | undefined, };