From a132705545354d3d7b469d56c39092f2802d6138 Mon Sep 17 00:00:00 2001 From: akshayitzme Date: Wed, 15 Feb 2023 14:39:56 +0530 Subject: [PATCH] feat: uom conversion factor --- models/baseModels/InvoiceItem/InvoiceItem.ts | 50 ++++++++++++++-- models/inventory/StockMovementItem.ts | 60 ++++++++++++++++++++ models/inventory/StockTransferItem.ts | 56 ++++++++++++++++-- models/types.ts | 1 + schemas/schemas.ts | 4 +- 5 files changed, 158 insertions(+), 13 deletions(-) diff --git a/models/baseModels/InvoiceItem/InvoiceItem.ts b/models/baseModels/InvoiceItem/InvoiceItem.ts index 9675aa57..44d915ba 100644 --- a/models/baseModels/InvoiceItem/InvoiceItem.ts +++ b/models/baseModels/InvoiceItem/InvoiceItem.ts @@ -1,4 +1,4 @@ -import { Fyo } from 'fyo'; +import { Fyo, t } from 'fyo'; import { DocValue, DocValueMap } from 'fyo/core/types'; import { Doc } from 'fyo/model/doc'; import { @@ -13,6 +13,7 @@ import { ValidationError } from 'fyo/utils/errors'; import { ModelNameEnum } from 'models/types'; import { Money } from 'pesa'; import { FieldTypeEnum, Schema } from 'schemas/types'; +import { safeParseFloat } from 'utils/index'; import { Invoice } from '../Invoice/Invoice'; import { Item } from '../Item/Item'; @@ -23,6 +24,10 @@ export abstract class InvoiceItem extends Doc { parentdoc?: Invoice; rate?: Money; quantity?: number; + transferQty?: number; + stockUOM?: string; + uom?: string; + UOMConversionFactor?: number; tax?: string; stockNotTransferred?: number; @@ -146,15 +151,38 @@ export abstract class InvoiceItem extends Doc { ModelNameEnum.Item, this.item as string ); - - const unitDoc = itemDoc.getLink('unit'); + const unitDoc = itemDoc.getLink('uom'); if (unitDoc?.isWhole) { - return Math.round(this.quantity as number); + return Math.round(this.transferQty! * this.UOMConversionFactor!); } - return this.quantity as number; + return safeParseFloat(this.transferQty! * this.UOMConversionFactor!); }, - dependsOn: ['quantity'], + dependsOn: ['quantity', 'transferQty', 'UOMConversionFactor'], + }, + stockUOM: { + formula: async () => { + const { unit } = await this.fyo.db.get( + ModelNameEnum.Item, + this.item!, + 'unit' + ); + return unit; + }, + dependsOn: ['item'], + }, + UOMConversionFactor: { + formula: async () => { + const conversionFactor = await this.fyo.db.getAll( + ModelNameEnum.UOMConversionFactor, + { + fields: ['value'], + filters: { parent: this.item! }, + } + ); + return safeParseFloat(conversionFactor[0].value); + }, + dependsOn: ['uom'], }, account: { formula: () => { @@ -319,6 +347,16 @@ export abstract class InvoiceItem extends Doc { }) cannot be greater than 100.` ); }, + uom: async (value: DocValue) => { + const item = await this.fyo.db.getAll(ModelNameEnum.UOMConversionFactor, { + fields: ['parent'], + filters: { uom: value as string, parent: this.item! }, + }); + if (item.length < 1) + throw new ValidationError( + t`UOM ${value as string} is not applicable for item ${this.item!}` + ); + }, }; hidden: HiddenMap = { diff --git a/models/inventory/StockMovementItem.ts b/models/inventory/StockMovementItem.ts index 09c4ffba..ff87c769 100644 --- a/models/inventory/StockMovementItem.ts +++ b/models/inventory/StockMovementItem.ts @@ -1,3 +1,5 @@ +import { t } from 'fyo'; +import { DocValue } from 'fyo/core/types'; import { Doc } from 'fyo/model/doc'; import { FiltersMap, @@ -9,6 +11,7 @@ import { import { ValidationError } from 'fyo/utils/errors'; import { ModelNameEnum } from 'models/types'; import { Money } from 'pesa'; +import { safeParseFloat } from 'utils/index'; import { StockMovement } from './StockMovement'; import { MovementType } from './types'; @@ -18,6 +21,10 @@ export class StockMovementItem extends Doc { fromLocation?: string; toLocation?: string; quantity?: number; + transferQty?: number; + stockUOM?: string; + uom?: string; + UOMConversionFactor?: number; rate?: Money; amount?: Money; parentdoc?: StockMovement; @@ -89,6 +96,49 @@ export class StockMovementItem extends Doc { }, dependsOn: ['movementType'], }, + stockUOM: { + formula: async () => { + const { unit } = await this.fyo.db.get( + ModelNameEnum.Item, + this.item!, + 'unit' + ); + return unit; + }, + dependsOn: ['item'], + }, + UOMConversionFactor: { + formula: async () => { + const conversionFactor = await this.fyo.db.getAll( + ModelNameEnum.UOMConversionFactor, + { + fields: ['value'], + filters: { parent: this.item! }, + } + ); + return safeParseFloat(conversionFactor[0].value); + }, + dependsOn: ['uom'], + }, + quantity: { + formula: async () => { + if (!this.item) { + return this.quantity as number; + } + + const itemDoc = await this.fyo.doc.getDoc( + ModelNameEnum.Item, + this.item as string + ); + const unitDoc = itemDoc.getLink('uom'); + if (unitDoc?.isWhole) { + return Math.round(this.transferQty! * this.UOMConversionFactor!); + } + + return safeParseFloat(this.transferQty! * this.UOMConversionFactor!); + }, + dependsOn: ['quantity', 'transferQty', 'UOMConversionFactor'], + }, }; validations: ValidationMap = { @@ -114,6 +164,16 @@ export class StockMovementItem extends Doc { ); } }, + uom: async (value: DocValue) => { + const item = await this.fyo.db.getAll(ModelNameEnum.UOMConversionFactor, { + fields: ['parent'], + filters: { uom: value as string, parent: this.item! }, + }); + if (item.length < 1) + throw new ValidationError( + t`UOM ${value as string} is not applicable for item ${this.item!}` + ); + }, }; required: RequiredMap = { diff --git a/models/inventory/StockTransferItem.ts b/models/inventory/StockTransferItem.ts index 9b12d208..97b9e48c 100644 --- a/models/inventory/StockTransferItem.ts +++ b/models/inventory/StockTransferItem.ts @@ -1,12 +1,20 @@ +import { t } from 'fyo'; +import { DocValue } from 'fyo/core/types'; import { Doc } from 'fyo/model/doc'; -import { FiltersMap, FormulaMap } from 'fyo/model/types'; +import { FiltersMap, FormulaMap, ValidationMap } from 'fyo/model/types'; +import { ValidationError } from 'fyo/utils/errors'; import { ModelNameEnum } from 'models/types'; import { Money } from 'pesa'; +import { safeParseFloat } from 'utils/index'; export class StockTransferItem extends Doc { item?: string; location?: string; quantity?: number; + transferQty?: number; + stockUOM?: string; + uom?: string; + UOMConversionFactor?: number; rate?: Money; amount?: Money; unit?: string; @@ -63,6 +71,30 @@ export class StockTransferItem extends Doc { }, dependsOn: ['item'], }, + stockUOM: { + formula: async () => { + const { unit } = await this.fyo.db.get( + ModelNameEnum.Item, + this.item!, + 'unit' + ); + return unit; + }, + dependsOn: ['item'], + }, + UOMConversionFactor: { + formula: async () => { + const conversionFactor = await this.fyo.db.getAll( + ModelNameEnum.UOMConversionFactor, + { + fields: ['value'], + filters: { parent: this.item! }, + } + ); + return safeParseFloat(conversionFactor[0].value); + }, + dependsOn: ['uom'], + }, quantity: { formula: async () => { if (!this.item) { @@ -73,15 +105,14 @@ export class StockTransferItem extends Doc { ModelNameEnum.Item, this.item as string ); - - const unitDoc = itemDoc.getLink('unit'); + const unitDoc = itemDoc.getLink('uom'); if (unitDoc?.isWhole) { - return Math.round(this.quantity as number); + return Math.round(this.transferQty! * this.UOMConversionFactor!); } - return this.quantity as number; + return safeParseFloat(this.transferQty! * this.UOMConversionFactor!); }, - dependsOn: ['quantity'], + dependsOn: ['quantity', 'transferQty', 'UOMConversionFactor'], }, account: { formula: () => { @@ -109,6 +140,19 @@ export class StockTransferItem extends Doc { }, }; + validations: ValidationMap = { + uom: async (value: DocValue) => { + const item = await this.fyo.db.getAll(ModelNameEnum.UOMConversionFactor, { + fields: ['parent'], + filters: { uom: value as string, parent: this.item! }, + }); + if (item.length < 1) + throw new ValidationError( + t`UOM ${value as string} is not applicable for item ${this.item!}` + ); + }, + }; + static filters: FiltersMap = { item: (doc: Doc) => { let itemNotFor = 'Sales'; diff --git a/models/types.ts b/models/types.ts index 330c768f..584f602b 100644 --- a/models/types.ts +++ b/models/types.ts @@ -11,6 +11,7 @@ export enum ModelNameEnum { Defaults = 'Defaults', Item = 'Item', UOM = 'UOM', + UOMConversionFactor = 'UOMConversionFactor', JournalEntry = 'JournalEntry', JournalEntryAccount = 'JournalEntryAccount', Misc = 'Misc', diff --git a/schemas/schemas.ts b/schemas/schemas.ts index afde4c48..12fa2f24 100644 --- a/schemas/schemas.ts +++ b/schemas/schemas.ts @@ -37,6 +37,7 @@ import Tax from './app/Tax.json'; import TaxDetail from './app/TaxDetail.json'; import TaxSummary from './app/TaxSummary.json'; import UOM from './app/UOM.json'; +import UOMConversionFactor from './app/UOMConversionFactor.json' import PatchRun from './core/PatchRun.json'; import SingleValue from './core/SingleValue.json'; import SystemSettings from './core/SystemSettings.json'; @@ -81,7 +82,8 @@ export const appSchemas: Schema[] | SchemaStub[] = [ Address as Schema, Item as Schema, UOM as Schema, - + UOMConversionFactor as Schema, + Payment as Schema, PaymentFor as Schema,