mirror of
https://github.com/frappe/books.git
synced 2024-12-22 19:09:01 +00:00
fix: serial number validation
- add serial number creation for strictly incoming
This commit is contained in:
parent
0d80548c36
commit
4384e32706
@ -2,10 +2,16 @@ import { ListViewSettings } from 'fyo/model/types';
|
|||||||
import { getTransactionStatusColumn } from 'models/helpers';
|
import { getTransactionStatusColumn } from 'models/helpers';
|
||||||
import { PurchaseReceiptItem } from './PurchaseReceiptItem';
|
import { PurchaseReceiptItem } from './PurchaseReceiptItem';
|
||||||
import { StockTransfer } from './StockTransfer';
|
import { StockTransfer } from './StockTransfer';
|
||||||
|
import { createSerialNumbers } from './helpers';
|
||||||
|
|
||||||
export class PurchaseReceipt extends StockTransfer {
|
export class PurchaseReceipt extends StockTransfer {
|
||||||
items?: PurchaseReceiptItem[];
|
items?: PurchaseReceiptItem[];
|
||||||
|
|
||||||
|
override async afterSubmit(): Promise<void> {
|
||||||
|
await super.afterSubmit();
|
||||||
|
await createSerialNumbers(this);
|
||||||
|
}
|
||||||
|
|
||||||
static getListViewSettings(): ListViewSettings {
|
static getListViewSettings(): ListViewSettings {
|
||||||
return {
|
return {
|
||||||
columns: [
|
columns: [
|
||||||
|
@ -20,6 +20,7 @@ import { SerialNumber } from './SerialNumber';
|
|||||||
import { StockMovementItem } from './StockMovementItem';
|
import { StockMovementItem } from './StockMovementItem';
|
||||||
import { Transfer } from './Transfer';
|
import { Transfer } from './Transfer';
|
||||||
import {
|
import {
|
||||||
|
createSerialNumbers,
|
||||||
getSerialNumberFromDoc,
|
getSerialNumberFromDoc,
|
||||||
updateSerialNumbers,
|
updateSerialNumbers,
|
||||||
validateBatch,
|
validateBatch,
|
||||||
@ -65,6 +66,7 @@ export class StockMovement extends Transfer {
|
|||||||
|
|
||||||
async afterSubmit(): Promise<void> {
|
async afterSubmit(): Promise<void> {
|
||||||
await super.afterSubmit();
|
await super.afterSubmit();
|
||||||
|
await createSerialNumbers(this);
|
||||||
await updateSerialNumbers(this, false);
|
await updateSerialNumbers(this, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +165,7 @@ async function validateSerialNumberStatus(doc: StockMovement) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doc.movementType === 'MaterialIssue' && status !=='Active') {
|
if (doc.movementType === 'MaterialIssue' && status !== 'Active') {
|
||||||
validateMaterialIssueSerialNumber(serialNumber, status);
|
validateMaterialIssueSerialNumber(serialNumber, status);
|
||||||
throw new ValidationError(
|
throw new ValidationError(
|
||||||
t`Inactive Serial Number ${serialNumber} cannot be used for Material Issue`
|
t`Inactive Serial Number ${serialNumber} cannot be used for Material Issue`
|
||||||
|
@ -9,6 +9,7 @@ import type { StockMovementItem } from './StockMovementItem';
|
|||||||
import type { StockTransfer } from './StockTransfer';
|
import type { StockTransfer } from './StockTransfer';
|
||||||
import type { StockTransferItem } from './StockTransferItem';
|
import type { StockTransferItem } from './StockTransferItem';
|
||||||
import type { SerialNumberStatus } from './types';
|
import type { SerialNumberStatus } from './types';
|
||||||
|
import type { PurchaseReceipt } from './PurchaseReceipt';
|
||||||
|
|
||||||
export async function validateBatch(
|
export async function validateBatch(
|
||||||
doc: StockMovement | StockTransfer | Invoice
|
doc: StockMovement | StockTransfer | Invoice
|
||||||
@ -65,10 +66,6 @@ async function validateItemRowSerialNumber(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (row.parentdoc?.cancelled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasSerialNumber = await row.fyo.getValue(
|
const hasSerialNumber = await row.fyo.getValue(
|
||||||
ModelNameEnum.Item,
|
ModelNameEnum.Item,
|
||||||
item,
|
item,
|
||||||
@ -99,13 +96,6 @@ async function validateItemRowSerialNumber(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const serialNumbers = getSerialNumbers(serialNumber);
|
const serialNumbers = getSerialNumbers(serialNumber);
|
||||||
for (const serialNumber of serialNumbers) {
|
|
||||||
if (await row.fyo.db.exists(ModelNameEnum.SerialNumber, serialNumber)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new ValidationError(t`Serial Number ${serialNumber} does not exist.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const quantity = row.quantity ?? 0;
|
const quantity = row.quantity ?? 0;
|
||||||
if (serialNumbers.length !== quantity) {
|
if (serialNumbers.length !== quantity) {
|
||||||
@ -116,7 +106,25 @@ async function validateItemRowSerialNumber(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const nonExistingIncomingSerialNumbers: string[] = [];
|
||||||
for (const serialNumber of serialNumbers) {
|
for (const serialNumber of serialNumbers) {
|
||||||
|
if (await row.fyo.db.exists(ModelNameEnum.SerialNumber, serialNumber)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSerialNumberIncoming(row)) {
|
||||||
|
nonExistingIncomingSerialNumbers.push(serialNumber);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ValidationError(t`Serial Number ${serialNumber} does not exist.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const serialNumber of serialNumbers) {
|
||||||
|
if (nonExistingIncomingSerialNumbers.includes(serialNumber)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const snDoc = await row.fyo.doc.getDoc(
|
const snDoc = await row.fyo.doc.getDoc(
|
||||||
ModelNameEnum.SerialNumber,
|
ModelNameEnum.SerialNumber,
|
||||||
serialNumber
|
serialNumber
|
||||||
@ -168,6 +176,50 @@ export function getSerialNumberFromDoc(doc: StockTransfer | StockMovement) {
|
|||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function createSerialNumbers(
|
||||||
|
doc: PurchaseReceipt | StockMovement
|
||||||
|
) {
|
||||||
|
const items = doc.items ?? [];
|
||||||
|
const serialNumberCreateList = items
|
||||||
|
.map((item) => {
|
||||||
|
const serialNumbers = getSerialNumbers(item.serialNumber ?? '');
|
||||||
|
return serialNumbers.map((serialNumber) => ({
|
||||||
|
item: item.name ?? '',
|
||||||
|
serialNumber,
|
||||||
|
isIncoming: isSerialNumberIncoming(item),
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
.flat()
|
||||||
|
.filter(({ item, isIncoming }) => isIncoming && item);
|
||||||
|
|
||||||
|
for (const { item, serialNumber } of serialNumberCreateList) {
|
||||||
|
if (await doc.fyo.db.exists(ModelNameEnum.SerialNumber, serialNumber)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const snDoc = doc.fyo.doc.getNewDoc(ModelNameEnum.SerialNumber, {
|
||||||
|
name: serialNumber,
|
||||||
|
item,
|
||||||
|
});
|
||||||
|
|
||||||
|
const status: SerialNumberStatus = 'Active';
|
||||||
|
await snDoc.set('status', status);
|
||||||
|
await snDoc.sync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSerialNumberIncoming(item: StockTransferItem | StockMovementItem) {
|
||||||
|
if (item.parentdoc?.schemaName === ModelNameEnum.Shipment) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.parentdoc?.schemaName === ModelNameEnum.PurchaseReceipt) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!item.toLocation && !item.fromLocation;
|
||||||
|
}
|
||||||
|
|
||||||
export async function updateSerialNumbers(
|
export async function updateSerialNumbers(
|
||||||
doc: StockTransfer | StockMovement,
|
doc: StockTransfer | StockMovement,
|
||||||
isCancel: boolean
|
isCancel: boolean
|
||||||
@ -177,7 +229,7 @@ export async function updateSerialNumbers(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const status = getSerialNumberStatus(doc, isCancel, row.quantity ?? 0);
|
const status = getSerialNumberStatus(doc, row, isCancel);
|
||||||
await updateSerialNumberStatus(status, row.serialNumber, doc.fyo);
|
await updateSerialNumberStatus(status, row.serialNumber, doc.fyo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -197,8 +249,8 @@ async function updateSerialNumberStatus(
|
|||||||
|
|
||||||
function getSerialNumberStatus(
|
function getSerialNumberStatus(
|
||||||
doc: StockTransfer | StockMovement,
|
doc: StockTransfer | StockMovement,
|
||||||
isCancel: boolean,
|
item: StockTransferItem | StockMovementItem,
|
||||||
quantity: number
|
isCancel: boolean
|
||||||
): SerialNumberStatus {
|
): SerialNumberStatus {
|
||||||
if (doc.schemaName === ModelNameEnum.Shipment) {
|
if (doc.schemaName === ModelNameEnum.Shipment) {
|
||||||
return isCancel ? 'Active' : 'Delivered';
|
return isCancel ? 'Active' : 'Delivered';
|
||||||
@ -210,15 +262,15 @@ function getSerialNumberStatus(
|
|||||||
|
|
||||||
return getSerialNumberStatusForStockMovement(
|
return getSerialNumberStatusForStockMovement(
|
||||||
doc as StockMovement,
|
doc as StockMovement,
|
||||||
isCancel,
|
item,
|
||||||
quantity
|
isCancel
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSerialNumberStatusForStockMovement(
|
function getSerialNumberStatusForStockMovement(
|
||||||
doc: StockMovement,
|
doc: StockMovement,
|
||||||
isCancel: boolean,
|
item: StockTransferItem | StockMovementItem,
|
||||||
quantity: number
|
isCancel: boolean
|
||||||
): SerialNumberStatus {
|
): SerialNumberStatus {
|
||||||
if (doc.movementType === 'MaterialIssue') {
|
if (doc.movementType === 'MaterialIssue') {
|
||||||
return isCancel ? 'Active' : 'Inactive';
|
return isCancel ? 'Active' : 'Inactive';
|
||||||
@ -233,7 +285,7 @@ function getSerialNumberStatusForStockMovement(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MovementType is Manufacture
|
// MovementType is Manufacture
|
||||||
if (quantity < 0) {
|
if (item.fromLocation) {
|
||||||
return isCancel ? 'Active' : 'Inactive';
|
return isCancel ? 'Active' : 'Inactive';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user