mirror of
https://github.com/frappe/books.git
synced 2024-11-13 00:46:28 +00:00
incr: use Stock Manager in Stock Queue
This commit is contained in:
parent
daaf56da48
commit
d9f47c01e3
@ -4,6 +4,7 @@ import { ModelNameEnum } from 'models/types';
|
|||||||
import { Money } from 'pesa';
|
import { Money } from 'pesa';
|
||||||
import { getStockQueue } from './helpers';
|
import { getStockQueue } from './helpers';
|
||||||
import { StockLedgerEntry } from './StockLedgerEntry';
|
import { StockLedgerEntry } from './StockLedgerEntry';
|
||||||
|
import { StockQueue } from './StockQueue';
|
||||||
import { SMDetails } from './types';
|
import { SMDetails } from './types';
|
||||||
|
|
||||||
export class StockManager {
|
export class StockManager {
|
||||||
@ -20,63 +21,96 @@ export class StockManager {
|
|||||||
* 7. Insert Stock Ledger Entry
|
* 7. Insert Stock Ledger Entry
|
||||||
*/
|
*/
|
||||||
|
|
||||||
date?: Date;
|
date: Date;
|
||||||
item?: string;
|
item: string;
|
||||||
rate?: Money;
|
rate: Money;
|
||||||
quantity?: number;
|
quantity: number;
|
||||||
|
referenceName: string;
|
||||||
|
referenceType: string;
|
||||||
fromLocation?: string;
|
fromLocation?: string;
|
||||||
toLocation?: string;
|
toLocation?: string;
|
||||||
referenceName?: string;
|
|
||||||
referenceType?: string;
|
stockQueues?: StockQueue[];
|
||||||
stockValue?: string;
|
stockLedgerEntries?: StockLedgerEntry[];
|
||||||
stockValueDifference?: string;
|
|
||||||
|
|
||||||
fyo: Fyo;
|
fyo: Fyo;
|
||||||
|
|
||||||
constructor(fyo: Fyo) {
|
constructor(details: SMDetails, fyo: Fyo) {
|
||||||
this.fyo = fyo;
|
|
||||||
}
|
|
||||||
|
|
||||||
moveStock(details: SMDetails) {
|
|
||||||
this.date = details.date;
|
this.date = details.date;
|
||||||
this.item = details.item;
|
this.item = details.item;
|
||||||
|
this.rate = details.rate;
|
||||||
this.quantity = details.quantity;
|
this.quantity = details.quantity;
|
||||||
this.fromLocation = details.fromLocation;
|
this.fromLocation = details.fromLocation;
|
||||||
this.toLocation = details.toLocation;
|
this.toLocation = details.toLocation;
|
||||||
this.referenceName = details.referenceName;
|
this.referenceName = details.referenceName;
|
||||||
this.referenceType = details.referenceType;
|
this.referenceType = details.referenceType;
|
||||||
|
|
||||||
this.#validate();
|
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) {
|
if (this.fromLocation) {
|
||||||
await this.#moveStockForSingleLocation(this.fromLocation, true);
|
await this.#moveStockForSingleLocation(
|
||||||
|
this.fromLocation,
|
||||||
|
isCancelled ? false : true,
|
||||||
|
isCancelled
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.toLocation) {
|
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!;
|
let quantity = this.quantity!;
|
||||||
|
if (quantity === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isOutward) {
|
if (isOutward) {
|
||||||
quantity = -quantity;
|
quantity = -quantity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stock Queue Changes
|
||||||
const { stockQueue, stockValueBefore, stockValueAfter } =
|
const { stockQueue, stockValueBefore, stockValueAfter } =
|
||||||
await this.#makeStockQueueChange(location, isOutward);
|
await this.#makeStockQueueChange(location, isOutward);
|
||||||
const stockLedgerEntry = this.#getStockLedgerEntry(
|
this.stockQueues?.push(stockQueue);
|
||||||
location,
|
|
||||||
quantity,
|
|
||||||
stockValueBefore,
|
|
||||||
stockValueAfter
|
|
||||||
);
|
|
||||||
|
|
||||||
await stockQueue.sync();
|
// Stock Ledger Entry
|
||||||
await stockLedgerEntry.sync();
|
if (!isCancelled) {
|
||||||
|
const stockLedgerEntry = this.#getStockLedgerEntry(
|
||||||
|
location,
|
||||||
|
quantity,
|
||||||
|
stockValueBefore,
|
||||||
|
stockValueAfter
|
||||||
|
);
|
||||||
|
this.stockLedgerEntries?.push(stockLedgerEntry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#getStockLedgerEntry(
|
#getStockLedgerEntry(
|
||||||
@ -123,11 +157,29 @@ export class StockManager {
|
|||||||
return { stockQueue, stockValueBefore, stockValueAfter };
|
return { stockQueue, stockValueBefore, stockValueAfter };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#clear() {
|
||||||
|
this.stockQueues = [];
|
||||||
|
this.stockLedgerEntries = [];
|
||||||
|
}
|
||||||
|
|
||||||
#validate() {
|
#validate() {
|
||||||
this.#validateRate();
|
this.#validateRate();
|
||||||
|
this.#validateQuantity();
|
||||||
this.#validateLocation();
|
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() {
|
#validateRate() {
|
||||||
if (!this.rate) {
|
if (!this.rate) {
|
||||||
throw new ValidationError(t`Stock Manager: rate needs to be set`);
|
throw new ValidationError(t`Stock Manager: rate needs to be set`);
|
||||||
|
@ -7,6 +7,7 @@ import {
|
|||||||
} from 'fyo/model/types';
|
} from 'fyo/model/types';
|
||||||
import { ModelNameEnum } from 'models/types';
|
import { ModelNameEnum } from 'models/types';
|
||||||
import { Money } from 'pesa';
|
import { Money } from 'pesa';
|
||||||
|
import { StockManager } from './StockManager';
|
||||||
import { StockMovementItem } from './StockMovementItem';
|
import { StockMovementItem } from './StockMovementItem';
|
||||||
import { MovementType } from './types';
|
import { MovementType } from './types';
|
||||||
|
|
||||||
@ -41,4 +42,49 @@ export class StockMovement extends Doc {
|
|||||||
static getListViewSettings(): ListViewSettings {
|
static getListViewSettings(): ListViewSettings {
|
||||||
return { columns: ['name', 'date', 'movementType'] };
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { Doc } from 'fyo/model/doc';
|
import { Doc } from 'fyo/model/doc';
|
||||||
import { Money } from 'pesa';
|
import { Money } from 'pesa';
|
||||||
|
import { StockQueueItem } from './types';
|
||||||
type StockQueueItem = { rate: Money; quantity: number };
|
|
||||||
|
|
||||||
export class StockQueue extends Doc {
|
export class StockQueue extends Doc {
|
||||||
item?: string;
|
item?: string;
|
||||||
@ -12,8 +11,12 @@ export class StockQueue extends Doc {
|
|||||||
/**
|
/**
|
||||||
* Stock Queue
|
* Stock Queue
|
||||||
*
|
*
|
||||||
* Used to keep track of inward rates for
|
* Used to keep track of inward rates for stock
|
||||||
* stock valuation purposes.
|
* valuation purposes.
|
||||||
|
*
|
||||||
|
* Stock Queue uses autoincrement as PK as opposed
|
||||||
|
* to (item, location, ...) to prevent NULL value
|
||||||
|
* primary keys.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
get quantity(): number {
|
get quantity(): number {
|
||||||
|
@ -14,4 +14,6 @@ export interface SMDetails {
|
|||||||
referenceType: string;
|
referenceType: string;
|
||||||
fromLocation?: string;
|
fromLocation?: string;
|
||||||
toLocation?: string;
|
toLocation?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type StockQueueItem = { rate: Money; quantity: number };
|
Loading…
Reference in New Issue
Block a user