2
0
mirror of https://github.com/frappe/books.git synced 2024-11-09 23:30:56 +00:00

incr: use Stock Manager in Stock Queue

This commit is contained in:
18alantom 2022-10-29 11:45:23 +05:30
parent daaf56da48
commit d9f47c01e3
4 changed files with 135 additions and 32 deletions

View File

@ -4,6 +4,7 @@ import { ModelNameEnum } from 'models/types';
import { Money } from 'pesa';
import { getStockQueue } from './helpers';
import { StockLedgerEntry } from './StockLedgerEntry';
import { StockQueue } from './StockQueue';
import { SMDetails } from './types';
export class StockManager {
@ -20,63 +21,96 @@ export class StockManager {
* 7. Insert Stock Ledger Entry
*/
date?: Date;
item?: string;
rate?: Money;
quantity?: number;
date: Date;
item: string;
rate: Money;
quantity: number;
referenceName: string;
referenceType: string;
fromLocation?: string;
toLocation?: string;
referenceName?: string;
referenceType?: string;
stockValue?: string;
stockValueDifference?: string;
stockQueues?: StockQueue[];
stockLedgerEntries?: StockLedgerEntry[];
fyo: Fyo;
constructor(fyo: Fyo) {
this.fyo = fyo;
}
moveStock(details: SMDetails) {
constructor(details: SMDetails, fyo: Fyo) {
this.date = details.date;
this.item = details.item;
this.rate = details.rate;
this.quantity = details.quantity;
this.fromLocation = details.fromLocation;
this.toLocation = details.toLocation;
this.referenceName = details.referenceName;
this.referenceType = details.referenceType;
this.#validate();
this.#moveStockForBothLocations();
this.fyo = fyo;
}
async #moveStockForBothLocations() {
async transferStock(isCancelled: boolean) {
this.#clear();
await this.#moveStockForBothLocations(isCancelled);
}
async sync() {
for (const sq of this.stockQueues ?? []) {
await sq.sync();
}
for (const sle of this.stockLedgerEntries ?? []) {
await sle.sync();
}
}
async #moveStockForBothLocations(isCancelled: boolean) {
if (this.fromLocation) {
await this.#moveStockForSingleLocation(this.fromLocation, true);
await this.#moveStockForSingleLocation(
this.fromLocation,
isCancelled ? false : true,
isCancelled
);
}
if (this.toLocation) {
await this.#moveStockForSingleLocation(this.toLocation, false);
await this.#moveStockForSingleLocation(
this.toLocation,
isCancelled ? true : false,
isCancelled
);
}
}
async #moveStockForSingleLocation(location: string, isOutward: boolean) {
async #moveStockForSingleLocation(
location: string,
isOutward: boolean,
isCancelled: boolean
) {
let quantity = this.quantity!;
if (quantity === 0) {
return;
}
if (isOutward) {
quantity = -quantity;
}
// Stock Queue Changes
const { stockQueue, stockValueBefore, stockValueAfter } =
await this.#makeStockQueueChange(location, isOutward);
const stockLedgerEntry = this.#getStockLedgerEntry(
location,
quantity,
stockValueBefore,
stockValueAfter
);
this.stockQueues?.push(stockQueue);
await stockQueue.sync();
await stockLedgerEntry.sync();
// Stock Ledger Entry
if (!isCancelled) {
const stockLedgerEntry = this.#getStockLedgerEntry(
location,
quantity,
stockValueBefore,
stockValueAfter
);
this.stockLedgerEntries?.push(stockLedgerEntry);
}
}
#getStockLedgerEntry(
@ -123,11 +157,29 @@ export class StockManager {
return { stockQueue, stockValueBefore, stockValueAfter };
}
#clear() {
this.stockQueues = [];
this.stockLedgerEntries = [];
}
#validate() {
this.#validateRate();
this.#validateQuantity();
this.#validateLocation();
}
#validateQuantity() {
if (!this.quantity) {
throw new ValidationError(t`Stock Manager: quantity needs to be set`);
}
if (this.quantity <= 0) {
throw new ValidationError(
t`Stock Manager: quantity (${this.quantity}) has to be greater than zero`
);
}
}
#validateRate() {
if (!this.rate) {
throw new ValidationError(t`Stock Manager: rate needs to be set`);

View File

@ -7,6 +7,7 @@ import {
} from 'fyo/model/types';
import { ModelNameEnum } from 'models/types';
import { Money } from 'pesa';
import { StockManager } from './StockManager';
import { StockMovementItem } from './StockMovementItem';
import { MovementType } from './types';
@ -41,4 +42,49 @@ export class StockMovement extends Doc {
static getListViewSettings(): ListViewSettings {
return { columns: ['name', 'date', 'movementType'] };
}
async afterSubmit(): Promise<void> {
await this._transferStock();
}
async afterCancel(): Promise<void> {
await this._transferStock();
}
async _transferStock() {
const stockManagers = this._getStockManagers();
for (const sm of stockManagers) {
sm.transferStock(this.isCancelled);
}
for (const sm of stockManagers) {
await sm.sync();
}
}
_getStockManagers(): StockManager[] {
const stockManagers: StockManager[] = [];
for (const row of this.items ?? []) {
const stockManager = this._getStockManager(row);
stockManagers.push(stockManager);
}
return stockManagers;
}
_getStockManager(row: StockMovementItem): StockManager {
return new StockManager(
{
date: this.date!,
item: row.item!,
rate: row.rate!,
quantity: row.quantity!,
referenceName: this.name!,
referenceType: this.schemaName,
fromLocation: row.fromLocation,
toLocation: row.toLocation,
},
this.fyo
);
}
}

View File

@ -1,7 +1,6 @@
import { Doc } from 'fyo/model/doc';
import { Money } from 'pesa';
type StockQueueItem = { rate: Money; quantity: number };
import { StockQueueItem } from './types';
export class StockQueue extends Doc {
item?: string;
@ -12,8 +11,12 @@ export class StockQueue extends Doc {
/**
* Stock Queue
*
* Used to keep track of inward rates for
* stock valuation purposes.
* Used to keep track of inward rates for stock
* valuation purposes.
*
* Stock Queue uses autoincrement as PK as opposed
* to (item, location, ...) to prevent NULL value
* primary keys.
*/
get quantity(): number {

View File

@ -14,4 +14,6 @@ export interface SMDetails {
referenceType: string;
fromLocation?: string;
toLocation?: string;
}
}
export type StockQueueItem = { rate: Money; quantity: number };