mirror of
https://github.com/frappe/books.git
synced 2026-08-24 02:24:17 -05:00
Merge pull request #1245 from frappe/feat-item-group
feat: item group functionality
This commit is contained in:
@@ -71,6 +71,9 @@ export class AccountingSettings extends Doc {
|
||||
enablePointOfSaleWithOutInventory: () => {
|
||||
return !!this.enablePointOfSaleWithOutInventory;
|
||||
},
|
||||
enableitemGroup: () => {
|
||||
return !!this.enableitemGroup;
|
||||
},
|
||||
};
|
||||
|
||||
override hidden: HiddenMap = {
|
||||
|
||||
@@ -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'],
|
||||
},
|
||||
|
||||
@@ -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<void> {
|
||||
@@ -156,6 +171,7 @@ export class Item extends Doc {
|
||||
),
|
||||
uomConversions: () =>
|
||||
!this.fyo.singles.InventorySettings?.enableUomConversions,
|
||||
itemGroup: () => !this.fyo.singles.AccountingSettings?.enableitemGroup,
|
||||
};
|
||||
|
||||
readOnly: ReadOnlyMap = {
|
||||
|
||||
@@ -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'],
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"]
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -6,6 +6,8 @@ export type ItemQtyMap = {
|
||||
|
||||
export type ItemSerialNumbers = { [item: string]: string };
|
||||
|
||||
export type ItemGroupMap = Record<string, string>;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -103,6 +103,18 @@
|
||||
"
|
||||
@change="(item: string) => emitEvent('handleItemSearch', item)"
|
||||
/>
|
||||
|
||||
<Link
|
||||
:df="{
|
||||
label: t`Filter by Group`,
|
||||
fieldtype: 'Link',
|
||||
fieldname: 'itemGroup',
|
||||
target: 'ItemGroup',
|
||||
}"
|
||||
:border="true"
|
||||
:value="selectedItemGroup"
|
||||
@change="(group: string) => emitEvent('setItemGroup',group)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<ItemsTable
|
||||
@@ -348,6 +360,7 @@ import { Item } from 'models/baseModels/Item/Item';
|
||||
import CouponCodeModal from './CouponCodeModal.vue';
|
||||
import POSQuickActions from './POSQuickActions.vue';
|
||||
import { PosEmits } from 'src/components/POS/types';
|
||||
import Link from 'src/components/Controls/Link.vue';
|
||||
import SavedInvoiceModal from './SavedInvoiceModal.vue';
|
||||
import OpenPOSShiftModal from './OpenPOSShiftModal.vue';
|
||||
import ClosePOSShiftModal from './ClosePOSShiftModal.vue';
|
||||
@@ -366,6 +379,7 @@ import { AppliedCouponCodes } from 'models/baseModels/AppliedCouponCodes/Applied
|
||||
export default defineComponent({
|
||||
name: 'ClassicPOS',
|
||||
components: {
|
||||
Link,
|
||||
Button,
|
||||
ItemsGrid,
|
||||
AlertModal,
|
||||
@@ -411,6 +425,10 @@ export default defineComponent({
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
selectedItemGroup: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
loyaltyProgram: {
|
||||
type: String,
|
||||
default: '',
|
||||
@@ -442,6 +460,7 @@ export default defineComponent({
|
||||
'toggleModal',
|
||||
'setCustomer',
|
||||
'clearValues',
|
||||
'setItemGroup',
|
||||
'setPaidAmount',
|
||||
'setCouponsCount',
|
||||
'routeToSinvList',
|
||||
@@ -460,6 +479,7 @@ export default defineComponent({
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
itemGroupFilter: '',
|
||||
additionalDiscounts: fyo.pesa(0),
|
||||
};
|
||||
},
|
||||
|
||||
+12
-1
@@ -19,6 +19,7 @@
|
||||
:open-alert-modal="openAlertModal"
|
||||
:default-customer="defaultCustomer"
|
||||
:item-search-term="itemSearchTerm"
|
||||
:selected-item-group="selectedItemGroup"
|
||||
:is-pos-shift-open="isPosShiftOpen"
|
||||
:items="(items as [] as POSItem[])"
|
||||
:sinv-doc="(sinvDoc as SalesInvoice)"
|
||||
@@ -40,6 +41,7 @@
|
||||
@clear-values="clearValues"
|
||||
@set-customer="setCustomer"
|
||||
@toggle-modal="toggleModal"
|
||||
@set-item-group="setItemGroup"
|
||||
@handle-item-search="handleItemSearch"
|
||||
@set-paid-amount="setPaidAmount"
|
||||
@set-payment-method="setPaymentMethod"
|
||||
@@ -214,6 +216,7 @@ export default defineComponent({
|
||||
appliedCoupons: [] as AppliedCouponCodes[],
|
||||
|
||||
itemSearchTerm: '',
|
||||
selectedItemGroup: '',
|
||||
paymentMethod: undefined as string | undefined,
|
||||
transferRefNo: undefined as string | undefined,
|
||||
defaultCustomer: undefined as string | undefined,
|
||||
@@ -458,6 +461,10 @@ export default defineComponent({
|
||||
|
||||
await this.afterSync();
|
||||
},
|
||||
async setItemGroup(itemGroupName: string) {
|
||||
this.selectedItemGroup = itemGroupName;
|
||||
await this.setItems();
|
||||
},
|
||||
async setItems() {
|
||||
const filters: Record<string, boolean> = {};
|
||||
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[];
|
||||
|
||||
Reference in New Issue
Block a user