2
0
mirror of https://github.com/frappe/books.git synced 2024-11-15 01:44:04 +00:00
books/models/inventory/StockMovementItem.ts

256 lines
6.4 KiB
TypeScript
Raw Normal View History

2023-02-15 09:09:56 +00:00
import { t } from 'fyo';
import { DocValue } from 'fyo/core/types';
import {
FiltersMap,
FormulaMap,
HiddenMap,
ReadOnlyMap,
2022-11-21 07:15:57 +00:00
RequiredMap,
ValidationMap,
} from 'fyo/model/types';
import { ValidationError } from 'fyo/utils/errors';
import { ModelNameEnum } from 'models/types';
import { Money } from 'pesa';
2023-02-15 09:09:56 +00:00
import { safeParseFloat } from 'utils/index';
import { StockMovement } from './StockMovement';
import { TransferItem } from './TransferItem';
import { MovementTypeEnum } from './types';
export class StockMovementItem extends TransferItem {
name?: string;
item?: string;
fromLocation?: string;
toLocation?: string;
unit?: string;
transferUnit?: string;
quantity?: number;
transferQuantity?: number;
unitConversionFactor?: number;
rate?: Money;
amount?: Money;
2023-02-28 06:01:04 +00:00
batch?: string;
2023-05-04 10:45:12 +00:00
serialNumber?: string;
parentdoc?: StockMovement;
2022-11-21 07:15:57 +00:00
get isIssue() {
2023-05-04 10:45:12 +00:00
return this.parentdoc?.movementType === MovementTypeEnum.MaterialIssue;
2022-11-21 07:15:57 +00:00
}
get isReceipt() {
2023-05-04 10:45:12 +00:00
return this.parentdoc?.movementType === MovementTypeEnum.MaterialReceipt;
2022-11-21 07:15:57 +00:00
}
get isTransfer() {
2023-05-04 10:45:12 +00:00
return this.parentdoc?.movementType === MovementTypeEnum.MaterialTransfer;
2022-11-21 07:15:57 +00:00
}
get isManufacture() {
2023-05-04 10:45:12 +00:00
return this.parentdoc?.movementType === MovementTypeEnum.Manufacture;
}
static filters: FiltersMap = {
item: () => ({ trackItem: true }),
};
formulas: FormulaMap = {
rate: {
formula: async () => {
if (!this.item) {
return this.rate;
}
return await this.fyo.getValue(ModelNameEnum.Item, this.item, 'rate');
},
dependsOn: ['item'],
},
amount: {
formula: () => this.rate!.mul(this.quantity!),
dependsOn: ['item', 'rate', 'quantity'],
},
fromLocation: {
formula: () => {
if (this.isReceipt || this.isTransfer || this.isManufacture) {
return null;
}
2022-11-21 07:15:57 +00:00
const defaultLocation =
this.fyo.singles.InventorySettings?.defaultLocation;
if (defaultLocation && !this.fromLocation && this.isIssue) {
2022-11-21 07:15:57 +00:00
return defaultLocation;
}
return this.toLocation;
},
2022-11-21 07:15:57 +00:00
dependsOn: ['movementType'],
},
toLocation: {
formula: () => {
if (this.isIssue || this.isTransfer || this.isManufacture) {
return null;
}
2022-11-21 07:15:57 +00:00
const defaultLocation =
this.fyo.singles.InventorySettings?.defaultLocation;
if (defaultLocation && !this.toLocation && this.isReceipt) {
2022-11-21 07:15:57 +00:00
return defaultLocation;
}
return this.toLocation;
},
2022-11-21 07:15:57 +00:00
dependsOn: ['movementType'],
},
unit: {
formula: async () =>
(await this.fyo.getValue(
'Item',
this.item as string,
2023-02-15 09:09:56 +00:00
'unit'
)) as string,
dependsOn: ['item'],
},
transferUnit: {
formula: async (fieldname) => {
if (fieldname === 'quantity' || fieldname === 'unit') {
return this.unit;
}
return (await this.fyo.getValue(
'Item',
this.item as string,
'unit'
)) as string;
},
dependsOn: ['item', 'unit'],
2023-02-15 09:09:56 +00:00
},
transferQuantity: {
formula: (fieldname) => {
if (fieldname === 'quantity' || this.unit === this.transferUnit) {
return this.quantity;
}
return this.transferQuantity;
2023-02-15 09:09:56 +00:00
},
dependsOn: ['item', 'quantity'],
2023-02-15 09:09:56 +00:00
},
quantity: {
formula: async (fieldname) => {
2023-02-15 09:09:56 +00:00
if (!this.item) {
return this.quantity as number;
}
const itemDoc = await this.fyo.doc.getDoc(
ModelNameEnum.Item,
this.item
2023-02-15 09:09:56 +00:00
);
const unitDoc = itemDoc.getLink('uom');
let quantity: number = this.quantity ?? 1;
if (fieldname === 'transferQuantity') {
quantity = this.transferQuantity! * this.unitConversionFactor!;
}
2023-02-15 09:09:56 +00:00
if (unitDoc?.isWhole) {
return Math.round(quantity);
2023-02-15 09:09:56 +00:00
}
return safeParseFloat(quantity);
},
dependsOn: [
'quantity',
'transferQuantity',
'transferUnit',
'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);
2023-02-15 09:09:56 +00:00
},
dependsOn: ['transferUnit'],
2023-02-15 09:09:56 +00:00
},
};
validations: ValidationMap = {
fromLocation: (value) => {
if (!this.isManufacture) {
return;
}
if (value && this.toLocation) {
throw new ValidationError(
this.fyo.t`Only From or To can be set for Manufacture`
);
}
},
toLocation: (value) => {
if (!this.isManufacture) {
return;
}
if (value && this.fromLocation) {
throw new ValidationError(
this.fyo.t`Only From or To can be set for Manufacture`
);
}
},
transferUnit: async (value: DocValue) => {
if (!this.item) {
return;
}
const item = await this.fyo.db.getAll(ModelNameEnum.UOMConversionItem, {
2023-02-15 09:09:56 +00:00
fields: ['parent'],
filters: { uom: value as string, parent: this.item },
2023-02-15 09:09:56 +00:00
});
2023-02-15 09:09:56 +00:00
if (item.length < 1)
throw new ValidationError(
t`Transfer Unit ${value as string} is not applicable for Item ${
this.item
}`
2023-02-15 09:09:56 +00:00
);
},
};
required: RequiredMap = {
2022-11-21 07:15:57 +00:00
fromLocation: () => this.isIssue || this.isTransfer,
toLocation: () => this.isReceipt || this.isTransfer,
};
readOnly: ReadOnlyMap = {
2022-11-21 07:15:57 +00:00
fromLocation: () => this.isReceipt,
toLocation: () => this.isIssue,
};
override hidden: HiddenMap = {
2023-02-28 06:01:04 +00:00
batch: () => !this.fyo.singles.InventorySettings?.enableBatches,
2023-05-04 10:45:12 +00:00
serialNumber: () => !this.fyo.singles.InventorySettings?.enableSerialNumber,
transferUnit: () =>
!this.fyo.singles.InventorySettings?.enableUomConversions,
transferQuantity: () =>
!this.fyo.singles.InventorySettings?.enableUomConversions,
unitConversionFactor: () =>
!this.fyo.singles.InventorySettings?.enableUomConversions,
};
static createFilters: FiltersMap = {
item: () => ({ trackItem: true, itemType: 'Product' }),
};
}