diff --git a/models/inventory/PurchaseReceipt.ts b/models/inventory/PurchaseReceipt.ts index f835d2e9..6da16e02 100644 --- a/models/inventory/PurchaseReceipt.ts +++ b/models/inventory/PurchaseReceipt.ts @@ -2,16 +2,10 @@ import { ListViewSettings } from 'fyo/model/types'; import { getTransactionStatusColumn } from 'models/helpers'; import { PurchaseReceiptItem } from './PurchaseReceiptItem'; import { StockTransfer } from './StockTransfer'; -import { createSerialNumbers } from './helpers'; export class PurchaseReceipt extends StockTransfer { items?: PurchaseReceiptItem[]; - override async afterSubmit(): Promise { - await super.afterSubmit(); - await createSerialNumbers(this); - } - static getListViewSettings(): ListViewSettings { return { columns: [ diff --git a/models/inventory/StockMovement.ts b/models/inventory/StockMovement.ts index 33a3a585..778fb478 100644 --- a/models/inventory/StockMovement.ts +++ b/models/inventory/StockMovement.ts @@ -1,5 +1,4 @@ import { Fyo, t } from 'fyo'; -import type { Doc } from 'fyo/model/doc'; import { Action, DefaultMap, @@ -20,13 +19,13 @@ import { SerialNumber } from './SerialNumber'; import { StockMovementItem } from './StockMovementItem'; import { Transfer } from './Transfer'; import { - createSerialNumbers, + canValidateSerialNumber, getSerialNumberFromDoc, updateSerialNumbers, validateBatch, - validateSerialNumber, + validateSerialNumber } from './helpers'; -import { MovementType, MovementTypeEnum, SerialNumberStatus } from './types'; +import { MovementType, MovementTypeEnum } from './types'; export class StockMovement extends Transfer { name?: string; @@ -66,7 +65,6 @@ export class StockMovement extends Transfer { async afterSubmit(): Promise { await super.afterSubmit(); - await createSerialNumbers(this); await updateSerialNumbers(this, false); } @@ -147,7 +145,12 @@ export class StockMovement extends Transfer { } async function validateSerialNumberStatus(doc: StockMovement) { - for (const serialNumber of getSerialNumberFromDoc(doc)) { + for (const { serialNumber, item } of getSerialNumberFromDoc(doc)) { + const cannotValidate = !(await canValidateSerialNumber(item, serialNumber)); + if (cannotValidate) { + continue; + } + const snDoc = await doc.fyo.doc.getDoc( ModelNameEnum.SerialNumber, serialNumber @@ -161,35 +164,26 @@ async function validateSerialNumberStatus(doc: StockMovement) { if (doc.movementType === 'MaterialReceipt' && status !== 'Inactive') { throw new ValidationError( - t`Active Serial Number ${serialNumber} cannot be used for Material Issue` + t`Non Inactive Serial Number ${serialNumber} cannot be used for Material Receipt` ); } if (doc.movementType === 'MaterialIssue' && status !== 'Active') { - validateMaterialIssueSerialNumber(serialNumber, status); throw new ValidationError( - t`Inactive Serial Number ${serialNumber} cannot be used for Material Issue` + t`Non Active Serial Number ${serialNumber} cannot be used for Material Issue` + ); + } + + if (doc.movementType === 'MaterialTransfer' && status !== 'Active') { + throw new ValidationError( + t`Non Active Serial Number ${serialNumber} cannot be used for Material Transfer` + ); + } + + if (item.fromLocation && status !== 'Active') { + throw new ValidationError( + t`Non Active Serial Number ${serialNumber} cannot be used as Manufacture raw material` ); } } } - -async function validateMaterialReceiptSerialNumber( - serialNumber: string, - status: string -) { - if (status === 'Inactive') { - return; - } -} - -async function validateMaterialIssueSerialNumber( - serialNumber: string, - status: SerialNumberStatus -) { - if (status === 'Active') { - return; - } - - throw new ValidationError(t`Serial Number ${serialNumber} is not Active.`); -} diff --git a/models/inventory/StockMovementItem.ts b/models/inventory/StockMovementItem.ts index 7e8561a7..41f61c68 100644 --- a/models/inventory/StockMovementItem.ts +++ b/models/inventory/StockMovementItem.ts @@ -15,8 +15,9 @@ import { Money } from 'pesa'; import { safeParseFloat } from 'utils/index'; import { StockMovement } from './StockMovement'; import { MovementTypeEnum } from './types'; +import { TransferItem } from './TransferItem'; -export class StockMovementItem extends Doc { +export class StockMovementItem extends TransferItem { name?: string; item?: string; fromLocation?: string; @@ -30,10 +31,12 @@ export class StockMovementItem extends Doc { rate?: Money; amount?: Money; - parentdoc?: StockMovement; + batch?: string; serialNumber?: string; + parentdoc?: StockMovement; + get isIssue() { return this.parentdoc?.movementType === MovementTypeEnum.MaterialIssue; } diff --git a/models/inventory/StockTransfer.ts b/models/inventory/StockTransfer.ts index bb8107bf..5ac81aa1 100644 --- a/models/inventory/StockTransfer.ts +++ b/models/inventory/StockTransfer.ts @@ -17,15 +17,16 @@ import { addItem, getLedgerLinkAction, getNumberSeries } from 'models/helpers'; import { ModelNameEnum } from 'models/types'; import { Money } from 'pesa'; import { TargetField } from 'schemas/types'; +import { SerialNumber } from './SerialNumber'; import { StockTransferItem } from './StockTransferItem'; import { Transfer } from './Transfer'; import { + canValidateSerialNumber, getSerialNumberFromDoc, updateSerialNumbers, validateBatch, validateSerialNumber, } from './helpers'; -import { SerialNumber } from './SerialNumber'; export abstract class StockTransfer extends Transfer { name?: string; @@ -311,7 +312,12 @@ export abstract class StockTransfer extends Transfer { } async function validateSerialNumberStatus(doc: StockTransfer) { - for (const serialNumber of getSerialNumberFromDoc(doc)) { + for (const { serialNumber, item } of getSerialNumberFromDoc(doc)) { + const cannotValidate = !(await canValidateSerialNumber(item, serialNumber)); + if (cannotValidate) { + continue; + } + const snDoc = await doc.fyo.doc.getDoc( ModelNameEnum.SerialNumber, serialNumber diff --git a/models/inventory/StockTransferItem.ts b/models/inventory/StockTransferItem.ts index f5524c62..c02c60cb 100644 --- a/models/inventory/StockTransferItem.ts +++ b/models/inventory/StockTransferItem.ts @@ -12,8 +12,9 @@ import { ModelNameEnum } from 'models/types'; import { Money } from 'pesa'; import { safeParseFloat } from 'utils/index'; import { StockTransfer } from './StockTransfer'; +import { TransferItem } from './TransferItem'; -export class StockTransferItem extends Doc { +export class StockTransferItem extends TransferItem { item?: string; location?: string; @@ -25,8 +26,10 @@ export class StockTransferItem extends Doc { rate?: Money; amount?: Money; + description?: string; hsnCode?: number; + batch?: string; serialNumber?: string; diff --git a/models/inventory/Transfer.ts b/models/inventory/Transfer.ts index 375ab40a..567dfd45 100644 --- a/models/inventory/Transfer.ts +++ b/models/inventory/Transfer.ts @@ -1,9 +1,12 @@ import { Transactional } from 'models/Transactional/Transactional'; import { StockManager } from './StockManager'; -import { SMTransferDetails } from './types'; +import type { SMTransferDetails } from './types'; +import type { TransferItem } from './TransferItem'; +import { createSerialNumbers } from './helpers'; export abstract class Transfer extends Transactional { date?: Date; + items?: TransferItem[]; async beforeSubmit(): Promise { await super.beforeSubmit(); @@ -13,6 +16,7 @@ export abstract class Transfer extends Transactional { async afterSubmit(): Promise { await super.afterSubmit(); + await createSerialNumbers(this); const transferDetails = this._getTransferDetails(); await this._getStockManager().createTransfers(transferDetails); } diff --git a/models/inventory/TransferItem.ts b/models/inventory/TransferItem.ts new file mode 100644 index 00000000..c5ac5cd2 --- /dev/null +++ b/models/inventory/TransferItem.ts @@ -0,0 +1,21 @@ +import { Doc } from 'fyo/model/doc'; +import type { Transfer } from './Transfer'; +import type { Money } from 'pesa'; + +export class TransferItem extends Doc { + item?: string; + + unit?: string; + transferUnit?: string; + quantity?: number; + transferQuantity?: number; + unitConversionFactor?: number; + + rate?: Money; + amount?: Money; + + batch?: string; + serialNumber?: string; + + parentdoc?: Transfer; +} diff --git a/models/inventory/helpers.ts b/models/inventory/helpers.ts index 4403de09..6c6334a3 100644 --- a/models/inventory/helpers.ts +++ b/models/inventory/helpers.ts @@ -8,8 +8,9 @@ import type { StockMovement } from './StockMovement'; import type { StockMovementItem } from './StockMovementItem'; import type { StockTransfer } from './StockTransfer'; import type { StockTransferItem } from './StockTransferItem'; +import { Transfer } from './Transfer'; +import { TransferItem } from './TransferItem'; import type { SerialNumberStatus } from './types'; -import type { PurchaseReceipt } from './PurchaseReceipt'; export async function validateBatch( doc: StockMovement | StockTransfer | Invoice @@ -171,14 +172,17 @@ export function getSerialNumberFromDoc(doc: StockTransfer | StockMovement) { } return doc.items - .map((item) => getSerialNumbers(item.serialNumber ?? '')) + .map((item) => + getSerialNumbers(item.serialNumber ?? '').map((serialNumber) => ({ + serialNumber, + item, + })) + ) .flat() .filter(Boolean); } -export async function createSerialNumbers( - doc: PurchaseReceipt | StockMovement -) { +export async function createSerialNumbers(doc: Transfer) { const items = doc.items ?? []; const serialNumberCreateList = items .map((item) => { @@ -208,7 +212,7 @@ export async function createSerialNumbers( } } -function isSerialNumberIncoming(item: StockTransferItem | StockMovementItem) { +function isSerialNumberIncoming(item: TransferItem) { if (item.parentdoc?.schemaName === ModelNameEnum.Shipment) { return false; } @@ -220,6 +224,17 @@ function isSerialNumberIncoming(item: StockTransferItem | StockMovementItem) { return !!item.toLocation && !item.fromLocation; } +export async function canValidateSerialNumber( + item: StockTransferItem | StockMovementItem, + serialNumber: string +) { + if (!isSerialNumberIncoming(item)) { + return true; + } + + return await item.fyo.db.exists(ModelNameEnum.SerialNumber, serialNumber); +} + export async function updateSerialNumbers( doc: StockTransfer | StockMovement, isCancel: boolean diff --git a/schemas/app/inventory/SerialNumber.json b/schemas/app/inventory/SerialNumber.json index 4516673e..cf8ecf09 100644 --- a/schemas/app/inventory/SerialNumber.json +++ b/schemas/app/inventory/SerialNumber.json @@ -29,6 +29,7 @@ "label": "Status", "fieldtype": "Select", "default": "Inactive", + "readOnly": true, "options": [ { "value": "Inactive",