2
0
mirror of https://github.com/frappe/books.git synced 2024-09-20 03:29:00 +00:00

fix: batch-wise stock validations

This commit is contained in:
akshayitzme 2023-01-18 17:37:31 +05:30
parent 20279c5a12
commit a8d5d9d7ef
3 changed files with 90 additions and 39 deletions

View File

@ -82,12 +82,13 @@ export class StockManager {
#getSMIDetails(transferDetails: SMTransferDetails): SMIDetails {
return Object.assign({}, this.details, transferDetails);
}
// flag
async #validate(details: SMIDetails) {
this.#validateRate(details);
this.#validateQuantity(details);
this.#validateLocation(details);
await this.#validateStockAvailability(details);
await this.#validateBatchWiseStockAvailability(details);
}
#validateQuantity(details: SMIDetails) {
@ -125,7 +126,59 @@ export class StockManager {
throw new ValidationError(t`Both From and To Location cannot be undefined`);
}
// flag
async #validateBatchWiseStockAvailability(details: SMIDetails) {
/*
* Checks if hasBatchNumber is enabled in the item
* If user has not entered batchNumber raises a ValidationError
* If entered quantity is greater than the available quantity in the batch, raises a ValidationError
*/
if (!details.fromLocation) {
return;
}
const ifItemHasBatchNumber = await this.fyo.getValue(
'Item',
details.item,
'hasBatchNumber'
);
const date = details.date.toISOString();
const formattedDate = this.fyo.format(details.date, 'Datetime');
if (ifItemHasBatchNumber) {
if (!details.batchNumber) {
throw new ValidationError(
t`Please enter Batch Number for ${details.item}`
);
}
const itemsInBatch =
(await this.fyo.db.getStockQuantity(
details.item,
details.fromLocation,
undefined,
date,
details.batchNumber
)) ?? 0;
if (details.quantity > itemsInBatch) {
throw new ValidationError(
[
t`Insufficient Quantity in Batch ${details.batchNumber}`,
t`Additional quantity (${
details.quantity - itemsInBatch
}) is required in batch ${
details.batchNumber
} to make the outward transfer of item ${details.item} from ${
details.fromLocation
} on ${formattedDate}`,
].join('\n')
);
}
}
}
async #validateStockAvailability(details: SMIDetails) {
if (!details.fromLocation) {
return;
@ -141,44 +194,21 @@ export class StockManager {
undefined
)) ?? 0;
const formattedDate = this.fyo.format(details.date, 'Datetime');
if (this.isCancelled) {
quantityBefore += details.quantity;
}
// batch-wise stock validation
let itemsInBatch =
(await this.fyo.db.getStockQuantity(
details.item,
details.fromLocation,
undefined,
date,
details.batchNumber
)) ?? 0;
let ifItemHasBatchNumber= await this.fyo.getValue('Item', details.item, 'hasBatchNumber');
if ((ifItemHasBatchNumber && details.batchNumber) && details.quantity > itemsInBatch) {
throw new ValidationError(
[
t`Insufficient Quantity in Batch ${details.batchNumber}`,
t`Additional quantity (${details.quantity - itemsInBatch
}) is required in batch ${details.batchNumber} to make the outward transfer of item ${details.item} from ${details.fromLocation
} on ${formattedDate}`,
].join('\n')
);
}
if (quantityBefore < details.quantity) {
throw new ValidationError(
[
t`Insufficient Quantity.`,
t`Additional quantity (${details.quantity - quantityBefore
}) required to make outward transfer of item ${details.item} from ${details.fromLocation
} on ${formattedDate}`,
t`Additional quantity (${
details.quantity - quantityBefore
}) required to make outward transfer of item ${details.item} from ${
details.fromLocation
} on ${formattedDate}`,
].join('\n')
);
}
@ -201,17 +231,17 @@ export class StockManager {
[
t`Insufficient Quantity.`,
t`Transfer will cause future entries to have negative stock.`,
t`Additional quantity (${quantityAfter - quantityRemaining
}) required to make outward transfer of item ${details.item} from ${details.fromLocation
} on ${formattedDate}`,
t`Additional quantity (${
quantityAfter - quantityRemaining
}) required to make outward transfer of item ${details.item} from ${
details.fromLocation
} on ${formattedDate}`,
].join('\n')
);
}
}
}
//
class StockManagerItem {
/**
* The Stock Manager Item is used to move stock to and from a location. It

View File

@ -260,6 +260,11 @@ export class StockLedger extends Report {
label: 'Location',
fieldtype: 'Link',
},
{
fieldname: 'batchNumber',
label: 'Batch No.',
fieldtype: 'Link',
},
{
fieldname: 'quantity',
label: 'Quantity',

View File

@ -17,7 +17,7 @@ export async function getRawStockLedgerEntries(fyo: Fyo) {
'name',
'date',
'item',
"batchNumber",
'batchNumber',
'rate',
'quantity',
'location',
@ -43,7 +43,14 @@ export function getStockLedgerEntries(
const name = safeParseInt(sle.name);
const date = new Date(sle.date);
const rate = safeParseFloat(sle.rate);
const { item, location, batchNumber, quantity, referenceName, referenceType } = sle;
const {
item,
location,
batchNumber,
quantity,
referenceName,
referenceType,
} = sle;
if (quantity === 0) {
continue;
@ -126,7 +133,11 @@ export function getStockBalanceEntries(
}
sbeMap[sle.item] ??= {};
sbeMap[sle.item][sle.location] ??= getSBE(sle.item, sle.location);
sbeMap[sle.item][sle.location] ??= getSBE(
sle.item,
sle.location,
sle.batchNumber
);
const date = sle.date.valueOf();
if (fromDate && date < fromDate) {
@ -148,13 +159,18 @@ export function getStockBalanceEntries(
.flat();
}
function getSBE(item: string, location: string): StockBalanceEntry {
function getSBE(
item: string,
location: string,
batchNumber: string
): StockBalanceEntry {
return {
name: 0,
item,
location,
batchNumber,
balanceQuantity: 0,
balanceValue: 0,