fix: added erp item visibility

This commit is contained in:
Gadha2311
2026-01-31 18:49:23 +05:30
parent 8cefa35b9b
commit 08cbb4569c
17 changed files with 178 additions and 24 deletions
+33 -2
View File
@@ -920,6 +920,35 @@ export class Doc extends Observable<DocValue | Doc[]> {
return this;
}
async _hasERPSyncableItems(): Promise<boolean> {
const isSalesInvoice = this.schemaName === ModelNameEnum.SalesInvoice;
if (!isSalesInvoice) {
return true;
}
const items = (this.get('items') as Doc[]) ?? [];
for (const item of items) {
const itemName = item.get('item') as string;
if (!itemName) {
continue;
}
try {
const itemDoc = await this.fyo.doc.getDoc('Item', itemName);
const isInventoryItem = !!itemDoc.get('trackItem');
const isFromERP = !!itemDoc.get('datafromErp');
if (!isInventoryItem && isFromERP) {
return true;
}
} catch (err) {
continue;
}
}
return false;
}
async sync(): Promise<Doc> {
this._syncing = true;
@@ -936,10 +965,12 @@ export class Doc extends Observable<DocValue | Doc[]> {
if (this._addDocToSyncQueue && !!this.shouldDocSyncToERPNext) {
const isSalesInvoice = this.schemaName === ModelNameEnum.SalesInvoice;
const hasERPSyncableItems = await this._hasERPSyncableItems();
if (
!(isSalesInvoice && this.isSyncedWithErp) ||
(isSalesInvoice && !!this.isReturn)
hasERPSyncableItems &&
(!(isSalesInvoice && this.isSyncedWithErp) ||
(isSalesInvoice && !!this.isReturn))
) {
if (isSalesInvoice && !this.isReturn) {
await this.setAndSync('isSyncedWithErp', true);
@@ -40,6 +40,9 @@ export class ERPNextSyncSettings extends Doc {
batchSyncType: () => {
return !this.fyo.singles.InventorySettings?.enableBatches;
},
// syncDataFromServer: () => {
// return !this.deviceID;
// },
};
async change(ch: ChangeArg) {
+23 -3
View File
@@ -19,8 +19,13 @@ import { Item } from '../Item/Item';
import { StockTransfer } from 'models/inventory/StockTransfer';
import { isPesa } from 'fyo/utils';
import { PricingRule } from '../PricingRule/PricingRule';
import { getItemRateFromPriceList, getPricingRule } from 'models/helpers';
import {
getItemRateFromPriceList,
getPricingRule,
getItemVisibility,
} from 'models/helpers';
import { SalesInvoice } from '../SalesInvoice/SalesInvoice';
import { QueryFilter } from 'utils/db/types';
export abstract class InvoiceItem extends Doc {
item?: string;
@@ -646,13 +651,28 @@ export abstract class InvoiceItem extends Doc {
};
static filters: FiltersMap = {
item: (doc: Doc) => {
item: async (doc: Doc): Promise<QueryFilter> => {
let itemNotFor = 'Sales';
if (doc.isSales) {
itemNotFor = 'Purchases';
}
return { for: ['not in', [itemNotFor]] };
const filters: QueryFilter = {
for: ['not in', [itemNotFor]],
};
const enableERPNextSync =
doc.fyo.singles.AccountingSettings?.enableERPNextSync;
if (enableERPNextSync) {
const itemVisibility = await getItemVisibility(doc.fyo);
if (itemVisibility === 'ERP Sync Items') {
filters.datafromErp = true;
}
}
return filters;
},
batch: async (doc: Doc) => {
const batches = await doc.fyo.db.getAll(ModelNameEnum.Batch, {
+2
View File
@@ -30,6 +30,7 @@ export class Item extends Doc {
hsnCode?: number;
hasSerialNumber?: boolean;
serialNumberSeries?: string;
datafromErp?: boolean;
uomConversions: UOMConversionItem[] = [];
formulas: FormulaMap = {
@@ -237,5 +238,6 @@ export class Item extends Doc {
trackItem: () => this.inserted,
hasBatch: () => this.inserted,
hasSerialNumber: () => this.inserted,
datafromErp: () => true,
};
}
+6
View File
@@ -116,6 +116,12 @@ export async function getItemQtyMap(doc: SalesInvoice): Promise<ItemQtyMap> {
export async function getItemVisibility(fyo: Fyo): Promise<ItemVisibility> {
const posProfileName = fyo.singles.POSSettings?.posProfile as string;
const enableERPNextSync = fyo.singles.AccountingSettings?.enableERPNextSync;
if (enableERPNextSync) {
// When ERP sync is enabled, use itemVisibilityERP from POSSettings
return fyo.singles.POSSettings?.itemVisibilityERP as ItemVisibility;
}
if (posProfileName) {
const posProfile = await fyo.doc.getDoc(
@@ -16,6 +16,7 @@ export class POSSettings extends Doc {
itemWeightDigits?: number;
defaultAccount?: string;
itemVisibility?: string;
itemVisibilityERP?: 'ERP Sync Items';
posUI?: 'Classic' | 'Modern';
canChangeRate?: boolean;
canEditDiscount?: boolean;
@@ -46,6 +47,8 @@ export class POSSettings extends Doc {
!this.fyo.singles.InventorySettings?.enableBarcodes ||
!this.weightEnabledBarcode,
itemVisibility: () =>
!this.fyo.singles.AccountingSettings?.enablePointOfSaleWithOutInventory,
!!this.fyo.singles.AccountingSettings?.enableERPNextSync,
itemVisibilityERP: () =>
!this.fyo.singles.AccountingSettings?.enableERPNextSync,
};
}
+7
View File
@@ -172,6 +172,13 @@
"fieldtype": "Table",
"target": "UOMConversionItem",
"section": "Inventory"
},
{
"fieldname": "datafromErp",
"fieldtype": "Check",
"hidden": false,
"default": false,
"section": "Default"
}
],
"quickEditFields": [
@@ -121,6 +121,28 @@
"required": true,
"section": "Default"
},
{
"fieldname": "itemVisibilityERP",
"label": "Item Visibility",
"fieldtype": "Select",
"options": [
{
"value": "ERP Sync Items",
"label": "ERP Sync Items"
},
{
"value": "Inventory Items",
"label": "Inventory Items"
},
{
"value": "Non-Inventory Items",
"label": "Non-Inventory Items"
}
],
"default": "ERP Sync Items",
"required": true,
"section": "Default"
},
{
"fieldname": "canChangeRate",
"label": "Can Change Rate",
+5
View File
@@ -63,6 +63,7 @@
</p>
</div>
<p
v-if="!isErpSync"
class="
absolute
top-1
@@ -111,6 +112,10 @@ export default defineComponent({
itemQtyMap: {
type: Object,
},
isErpSync: {
type: Boolean,
default: false,
},
},
methods: {
getExtractedWords(item: string) {
+20 -8
View File
@@ -81,13 +81,20 @@ export default defineComponent({
props: {
items: Array,
itemQtyMap: Object,
isErpSync: {
type: Boolean,
default: false,
},
},
computed: {
ratio() {
if (this.isErpSync) {
return [1, 1.5, 0.8];
}
return [1, 1, 1, 0.7];
},
tableFields() {
return [
const fields = [
{
fieldname: 'name',
fieldtype: 'Data',
@@ -102,13 +109,6 @@ export default defineComponent({
fieldtype: 'Currency',
readOnly: true,
},
{
fieldname: 'availableQty',
label: 'Qty',
placeholder: 'Available Qty',
fieldtype: 'Float',
readOnly: true,
},
{
fieldname: 'unit',
label: 'Unit',
@@ -118,6 +118,18 @@ export default defineComponent({
readOnly: true,
},
] as Field[];
if (!this.isErpSync) {
fields.splice(2, 0, {
fieldname: 'availableQty',
label: 'Qty',
placeholder: 'Available Qty',
fieldtype: 'Float',
readOnly: true,
});
}
return fields;
},
},
methods: {
@@ -66,6 +66,7 @@
</p>
</div>
<p
v-if="!isErpSync"
class="
w-6
h-6
@@ -114,6 +115,10 @@ export default defineComponent({
itemQtyMap: {
type: Object,
},
isErpSync: {
type: Boolean,
default: false,
},
},
methods: {
getExtractedWords(item: string) {
@@ -137,13 +137,20 @@ export default defineComponent({
props: {
items: Array,
itemQtyMap: Object,
isErpSync: {
type: Boolean,
default: false,
},
},
computed: {
ratio() {
return [1, 1, 0.6, 0.7];
if (this.isErpSync) {
return [1, 1.5, 0.8];
}
return [1, 1, 1, 0.7];
},
tableFields() {
return [
const fields = [
{
fieldname: 'name',
fieldtype: 'Data',
@@ -158,13 +165,6 @@ export default defineComponent({
fieldtype: 'Currency',
readOnly: true,
},
{
fieldname: 'availableQty',
label: t`Qty`,
placeholder: 'Available Qty',
fieldtype: 'Float',
readOnly: true,
},
{
fieldname: 'unit',
label: t`Unit`,
@@ -174,6 +174,18 @@ export default defineComponent({
readOnly: true,
},
] as Field[];
if (!this.isErpSync) {
fields.splice(2, 0, {
fieldname: 'availableQty',
label: t`Qty`,
placeholder: 'Available Qty',
fieldtype: 'Float',
readOnly: true,
});
}
return fields;
},
firstColumnItems() {
return this.items?.slice(0, Math.ceil(this.items.length / 2));
+1 -1
View File
@@ -10,7 +10,7 @@ export type ItemGroupMap = Record<string, string>;
export type DiscountType = 'percent' | 'amount';
export type ItemVisibility = 'Inventory Items' | 'Non-Inventory Items'
export type ItemVisibility = 'Inventory Items' | 'Non-Inventory Items' | 'ERP Sync Items'
export const modalNames = [
'Keyboard',
+6
View File
@@ -134,6 +134,7 @@
v-if="tableView"
:items="items"
:item-qty-map="itemQuantityMap as ItemQtyMap"
:is-erp-sync="isErpSync"
@add-item="(item) => emitEvent('addItem', item)"
/>
@@ -141,6 +142,7 @@
v-else
:items="items"
:item-qty-map="itemQuantityMap as ItemQtyMap"
:is-erp-sync="isErpSync"
@add-item="(item) => emitEvent('addItem', item)"
/>
@@ -483,6 +485,10 @@ export default defineComponent({
type: Array as PropType<POSItem[] | undefined>,
default: () => [],
},
isErpSync: {
type: Boolean,
default: false,
},
profile: {
type: Object as PropType<POSProfile>,
required: false,
+6
View File
@@ -345,6 +345,7 @@
v-if="tableView"
:items="items"
:item-qty-map="itemQuantityMap as ItemQtyMap"
:is-erp-sync="isErpSync"
@add-item="(item:string) => emitEvent('addItem', item)"
/>
@@ -352,6 +353,7 @@
v-else
:items="items"
:item-qty-map="itemQuantityMap as ItemQtyMap"
:is-erp-sync="isErpSync"
@add-item="(item:string) => emitEvent('addItem', item)"
/>
@@ -489,6 +491,10 @@ export default defineComponent({
type: Array as PropType<POSItem[] | undefined>,
default: () => [],
},
isErpSync: {
type: Boolean,
default: false,
},
profile: {
type: Object as PropType<POSProfile>,
required: false,
+10
View File
@@ -27,6 +27,7 @@
:selected-item-group="selectedItemGroup"
:is-pos-shift-open="isPosShiftOpen"
:items="(items as [] as POSItem[])"
:is-erp-sync="isErpSync"
:sinv-doc="(sinvDoc as SalesInvoice)"
:disable-pay-button="disablePayButton"
:open-payment-modal="openPaymentModal"
@@ -83,6 +84,7 @@
:selected-item-group="selectedItemGroup"
:is-pos-shift-open="isPosShiftOpen"
:items="(items as [] as POSItem[])"
:is-erp-sync="isErpSync"
:sinv-doc="(sinvDoc as SalesInvoice)"
:disable-pay-button="disablePayButton"
:open-payment-modal="openPaymentModal"
@@ -262,6 +264,7 @@ export default defineComponent({
quickQtyKeyUpHandler: null as ((e: KeyboardEvent) => void) | null,
selectedItemForBatch: '' as string,
pendingBatchItem: null as { item: POSItem; quantity: number } | null,
isErpSyncValue: false,
};
},
computed: {
@@ -271,6 +274,9 @@ export default defineComponent({
return !!fyo.singles.AccountingSettings?.enableDiscounting;
},
isPosShiftOpen: () => !!fyo.singles.POSSettings?.isShiftOpen,
isErpSync() {
return this.isErpSyncValue;
},
disablePayButton(): boolean {
if (!this.sinvDoc.items?.length || !this.sinvDoc.party) {
return true;
@@ -295,6 +301,7 @@ export default defineComponent({
async mounted() {
await this.setItems();
await this.loadPOSProfile();
this.isErpSyncValue = !!fyo.singles.AccountingSettings?.enableERPNextSync;
},
async activated() {
toggleSidebar(false);
@@ -694,8 +701,11 @@ export default defineComponent({
if (itemVisibility === 'Inventory Items') {
filters.trackItem = true;
} else if (itemVisibility === 'ERP Sync Items') {
filters.datafromErp = true;
} else {
filters.trackItem = false;
filters.datafromErp = false;
}
if (this.selectedItemGroup) {
+4
View File
@@ -150,6 +150,10 @@ export async function syncDocumentsFromERPNext(fyo: Fyo) {
continue;
}
if (getDocTypeName(doc) === ModelNameEnum.Item) {
doc.datafromErp = true;
}
try {
if ((doc.fbooksDocName as string) || (doc.name as string)) {
const isDocExists = await fyo.db.exists(