diff --git a/models/baseModels/AccountingSettings/AccountingSettings.ts b/models/baseModels/AccountingSettings/AccountingSettings.ts index 899f5a76..ba2dd6b9 100644 --- a/models/baseModels/AccountingSettings/AccountingSettings.ts +++ b/models/baseModels/AccountingSettings/AccountingSettings.ts @@ -71,6 +71,9 @@ export class AccountingSettings extends Doc { enablePointOfSaleWithOutInventory: () => { return !!this.enablePointOfSaleWithOutInventory; }, + enableitemGroup: () => { + return !!this.enableitemGroup; + }, }; override hidden: HiddenMap = { diff --git a/models/baseModels/InvoiceItem/InvoiceItem.ts b/models/baseModels/InvoiceItem/InvoiceItem.ts index 4e12e445..9eea9d76 100644 --- a/models/baseModels/InvoiceItem/InvoiceItem.ts +++ b/models/baseModels/InvoiceItem/InvoiceItem.ts @@ -299,11 +299,29 @@ export abstract class InvoiceItem extends Doc { }, tax: { formula: async () => { - return (await this.fyo.getValue( + const itemTax = (await this.fyo.getValue( 'Item', this.item as string, 'tax' )) as string; + + if (itemTax) { + return itemTax; + } + + const itemGroup = (await this.fyo.getValue( + 'Item', + this.item as string, + 'itemGroup' + )) as string; + + if (!itemGroup) { + return ''; + } + + const itemGroupDoc = await this.fyo.doc.getDoc('ItemGroup', itemGroup); + + return itemGroupDoc?.tax as string; }, dependsOn: ['item'], }, diff --git a/models/baseModels/Item/Item.ts b/models/baseModels/Item/Item.ts index fb057f02..9400439e 100644 --- a/models/baseModels/Item/Item.ts +++ b/models/baseModels/Item/Item.ts @@ -26,6 +26,7 @@ export class Item extends Doc { itemType?: 'Product' | 'Service'; for?: 'Purchases' | 'Sales' | 'Both'; hasBatch?: boolean; + itemGroup?: string; hasSerialNumber?: boolean; uomConversions: UOMConversionItem[] = []; @@ -63,6 +64,20 @@ export class Item extends Doc { }, dependsOn: ['itemType', 'trackItem'], }, + hsnCode: { + formula: async () => { + if (!this.itemGroup) { + return ''; + } + + const itemGroupDoc = await this.fyo.doc.getDoc( + 'ItemGroup', + this.itemGroup + ); + return itemGroupDoc?.hsnCode as string; + }, + dependsOn: ['itemGroup'], + }, }; async beforeSync(): Promise { @@ -156,6 +171,7 @@ export class Item extends Doc { ), uomConversions: () => !this.fyo.singles.InventorySettings?.enableUomConversions, + itemGroup: () => !this.fyo.singles.AccountingSettings?.enableitemGroup, }; readOnly: ReadOnlyMap = { diff --git a/models/baseModels/ItemGroup/ItemGroup.ts b/models/baseModels/ItemGroup/ItemGroup.ts new file mode 100644 index 00000000..4ec1fdbc --- /dev/null +++ b/models/baseModels/ItemGroup/ItemGroup.ts @@ -0,0 +1,10 @@ +import { Doc } from 'fyo/model/doc'; +import { ListViewSettings } from 'fyo/model/types'; + +export class ItemGroup extends Doc { + static getListViewSettings(): ListViewSettings { + return { + columns: ['name', 'tax', 'hsnCode'], + }; + } +} diff --git a/models/index.ts b/models/index.ts index c4638732..2fc1aa26 100644 --- a/models/index.ts +++ b/models/index.ts @@ -31,6 +31,7 @@ import { SalesInvoiceItem } from './baseModels/SalesInvoiceItem/SalesInvoiceItem import { SalesQuote } from './baseModels/SalesQuote/SalesQuote'; import { SalesQuoteItem } from './baseModels/SalesQuoteItem/SalesQuoteItem'; import { SetupWizard } from './baseModels/SetupWizard/SetupWizard'; +import { ItemGroup } from './baseModels/ItemGroup/ItemGroup'; import { Tax } from './baseModels/Tax/Tax'; import { TaxSummary } from './baseModels/TaxSummary/TaxSummary'; import { Batch } from './inventory/Batch'; @@ -64,6 +65,7 @@ export const models = { Batch, Defaults, Item, + ItemGroup, JournalEntry, JournalEntryAccount, Misc, diff --git a/schemas/app/AccountingSettings.json b/schemas/app/AccountingSettings.json index aa443f49..3e541c2c 100644 --- a/schemas/app/AccountingSettings.json +++ b/schemas/app/AccountingSettings.json @@ -135,6 +135,13 @@ "default": false, "section": "Features" }, + { + "fieldname": "enableitemGroup", + "label": "Enable Item Group", + "fieldtype": "Check", + "default": false, + "section": "Features" + }, { "fieldname": "enablePointOfSaleWithOutInventory", "label": "Enable POS Without Inventory", diff --git a/schemas/app/Item.json b/schemas/app/Item.json index d04c6b19..79545a94 100644 --- a/schemas/app/Item.json +++ b/schemas/app/Item.json @@ -25,6 +25,14 @@ "placeholder": "Item Code", "section": "Default" }, + { + "fieldname": "itemGroup", + "label": "Item Group", + "fieldtype": "Link", + "target": "ItemGroup", + "create": true, + "placeholder": "Item Group" + }, { "fieldname": "for", "label": "Purpose", diff --git a/schemas/app/ItemGroup.json b/schemas/app/ItemGroup.json new file mode 100644 index 00000000..6b019932 --- /dev/null +++ b/schemas/app/ItemGroup.json @@ -0,0 +1,31 @@ +{ + "name": "ItemGroup", + "label": "item Group", + "naming": "manual", + "fields": [ + { + "fieldname": "name", + "label": "Name", + "fieldtype": "Data", + "placeholder": "Name", + "section": "Default", + "required": true + }, + { + "fieldname": "tax", + "label": "Tax", + "fieldtype": "Link", + "target": "Tax", + "create": true, + "placeholder": "Tax" + }, + { + "fieldname": "hsnCode", + "label": "HSN/SAC", + "fieldtype": "Data", + "placeholder": "HSN/SAC Code" + } + ], + "quickEditFields": ["tax", "hsnCode"], + "keywordFields": ["name"] +} diff --git a/schemas/schemas.ts b/schemas/schemas.ts index 99a766bc..71f26fb8 100644 --- a/schemas/schemas.ts +++ b/schemas/schemas.ts @@ -78,6 +78,7 @@ import ERPNextSyncSettings from './app/ERPNextSyncSettings.json'; import ERPNextSyncQueue from './app/ERPNextSyncQueue.json'; import FetchFromERPNextQueue from './app/FetchFromERPNextQueue.json'; import IntegrationErrorLog from './app/IntegrationErrorLog.json'; +import ItemGroup from './app/ItemGroup.json'; import { Schema, SchemaStub } from './types'; export const coreSchemas: Schema[] = [ @@ -113,6 +114,7 @@ export const appSchemas: Schema[] | SchemaStub[] = [ Party as Schema, Lead as Schema, Address as Schema, + ItemGroup as Schema, Item as Schema, UOM as Schema, UOMConversionItem as Schema, diff --git a/src/components/POS/types.ts b/src/components/POS/types.ts index 3825c798..5970c103 100644 --- a/src/components/POS/types.ts +++ b/src/components/POS/types.ts @@ -6,6 +6,8 @@ export type ItemQtyMap = { export type ItemSerialNumbers = { [item: string]: string }; +export type ItemGroupMap = Record; + export type DiscountType = 'percent' | 'amount'; export const modalNames = [ @@ -26,6 +28,7 @@ export type PosEmits = | 'addItem' | 'toggleView' | 'toggleModal' + | 'setItemGroup' | 'setPaidAmount' | 'setPaymentMethod' | 'setCouponsCount' @@ -50,4 +53,5 @@ export interface POSItem { unit: string; hasBatch: boolean; hasSerialNumber: boolean; + itemGroup?: string; } diff --git a/src/pages/POS/ClassicPOS.vue b/src/pages/POS/ClassicPOS.vue index 313d31e7..1deca7c6 100644 --- a/src/pages/POS/ClassicPOS.vue +++ b/src/pages/POS/ClassicPOS.vue @@ -103,6 +103,18 @@ " @change="(item: string) => emitEvent('handleItemSearch', item)" /> + + = {}; const itemVisibility = this.fyo.singles.POSSettings?.itemVisibility; @@ -470,9 +477,13 @@ export default defineComponent({ filters.trackItem = false; } + const itemGroupfilter = this.selectedItemGroup + ? { itemGroup: this.selectedItemGroup } + : undefined; + const items = (await fyo.db.getAll(ModelNameEnum.Item, { fields: [], - filters, + filters: itemGroupfilter, })) as Item[]; this.items = [] as POSItem[];