import { t } from 'fyo'; import { DocValue } from 'fyo/core/types'; import { Doc } from 'fyo/model/doc'; 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; unit?: string; transferUnit?: string; quantity?: number; transferQuantity?: number; unitConversionFactor?: number; rate?: Money; amount?: Money; description?: string; hsnCode?: number; formulas: FormulaMap = { description: { formula: async () => (await this.fyo.getValue( 'Item', this.item as string, 'description' )) as string, dependsOn: ['item'], }, unit: { formula: async () => (await this.fyo.getValue( 'Item', this.item as string, 'unit' )) as string, dependsOn: ['item'], }, transferUnit: { formula: async () => (await this.fyo.getValue( 'Item', this.item as string, 'unit' )) as string, dependsOn: ['item'], }, transferQuantity: { formula: async () => { if (this.unit === this.transferUnit) { return this.quantity; } return this.transferQuantity; }, dependsOn: ['item'], }, 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.transferQuantity! * this.unitConversionFactor! ); } return safeParseFloat( this.transferQuantity! * this.unitConversionFactor! ); }, dependsOn: ['quantity', 'transferQuantity', 'unitConversionFactor'], }, unitConversionFactor: { formula: async () => { if (this.unit === this.transferUnit) { return 1; } const conversionFactor = await this.fyo.db.getAll( ModelNameEnum.UOMConversionItem, { fields: ['conversionFactor'], filters: { parent: this.item! }, } ); return safeParseFloat(conversionFactor[0]?.conversionFactor ?? 1); }, dependsOn: ['transferUnit'], }, hsnCode: { formula: async () => (await this.fyo.getValue( 'Item', this.item as string, 'hsnCode' )) as string, dependsOn: ['item'], }, amount: { formula: () => { return this.rate?.mul(this.quantity ?? 0) ?? this.fyo.pesa(0); }, dependsOn: ['rate', 'quantity'], }, rate: { formula: async (fieldname) => { const rate = (await this.fyo.getValue( 'Item', this.item as string, 'rate' )) as undefined | Money; if (!rate?.float && this.rate?.float) { return this.rate; } return rate ?? this.fyo.pesa(0); }, dependsOn: ['item'], }, account: { formula: () => { let accountType = 'expenseAccount'; if (this.isSales) { accountType = 'incomeAccount'; } return this.fyo.getValue('Item', this.item as string, accountType); }, dependsOn: ['item'], }, location: { formula: () => { if (this.location) { return; } const defaultLocation = this.fyo.singles.InventorySettings ?.defaultLocation as string | undefined; if (defaultLocation && !this.location) { return defaultLocation; } }, }, }; validations: ValidationMap = { transferUnit: async (value: DocValue) => { if (!this.item) { return; } const item = await this.fyo.db.getAll(ModelNameEnum.UOMConversionItem, { fields: ['parent'], filters: { uom: value as string, parent: this.item! }, }); if (item.length < 1) throw new ValidationError( t`Transfer Unit ${value as string} is not applicable for Item ${this .item!}` ); }, }; static filters: FiltersMap = { item: (doc: Doc) => { let itemNotFor = 'Sales'; if (doc.isSales) { itemNotFor = 'Purchases'; } return { for: ['not in', [itemNotFor]], trackItem: true }; }, }; }