Fix: Products could be added without skus rendering them useless

Feature: Change of product in purchase / issue / Purchase return allowed.
This commit is contained in:
Amritanshu Agrawal 2021-11-11 20:52:28 +05:30
parent eeb36d7f8b
commit 1a3248ad70
7 changed files with 52 additions and 52 deletions

View File

@ -3,7 +3,7 @@ from fastapi import HTTPException, status
from .voucher import Voucher
def check_journals_are_valid(voucher: Voucher):
def check_journals_are_valid(voucher: Voucher) -> None:
if len(voucher.journals) < 2:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
@ -27,7 +27,21 @@ def check_journals_are_valid(voucher: Voucher):
)
def check_inventories_are_valid(voucher: Voucher):
def check_duplicate_batches(voucher: Voucher) -> None:
if len(voucher.inventories) < 1:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail="Not enough inventories",
)
product_set = set(x.batch.id for x in voucher.inventories)
if len(voucher.inventories) != len(product_set):
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail="Duplicate inventories are not allowed",
)
def check_duplicate_skus(voucher: Voucher) -> None:
if len(voucher.inventories) < 1:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,

View File

@ -22,7 +22,7 @@ from ..models.inventory import Inventory
from ..models.journal import Journal
from ..models.product import Product
from ..models.stock_keeping_unit import StockKeepingUnit
from ..models.validations import check_inventories_are_valid, check_journals_are_valid
from ..models.validations import check_duplicate_batches, check_journals_are_valid
from ..models.voucher import Voucher
from ..models.voucher_type import VoucherType
from ..schemas.blank_voucher_info import BlankVoucherInfo
@ -54,7 +54,7 @@ def save_route(
with SessionFuture() as db:
item, batch_consumed = save(data, user, db)
amount = save_inventories(item, data.inventories, batch_consumed, db)
check_inventories_are_valid(item)
check_duplicate_batches(item)
save_journals(item, data.source, data.destination, amount, db)
check_journals_are_valid(item)
save_files(item.id, i, t, db)
@ -187,7 +187,7 @@ def update_route(
with SessionFuture() as db:
item, batch_consumed = update_voucher(id_, data, user, db)
amount = update_inventories(item, data.inventories, batch_consumed, db)
check_inventories_are_valid(item)
check_duplicate_batches(item)
update_journals(item, data.source, data.destination, amount)
check_journals_are_valid(item)
update_files(item.id, data.files, i, t, db)
@ -273,19 +273,14 @@ def update_inventories(
batch_consumed: Optional[bool],
db: Session,
):
old_set = set([(i.id, i.batch_id) for i in voucher.inventories])
new_set = set([(i.id_, i.batch.id_) for i in inventories if i.id_ is not None])
if len(new_set - old_set):
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail="Product / Batch cannot be changed",
)
amount: Decimal = Decimal(0)
for it in range(len(voucher.inventories), 0, -1):
item = voucher.inventories[it - 1]
batch: Batch = db.execute(select(Batch).where(Batch.id == item.batch_id)).scalar_one()
batch_quantity = get_batch_quantity(item.batch_id, voucher.id, db)
index = next((idx for (idx, d) in enumerate(inventories) if d.id_ == item.id), None)
index = next(
(idx for (idx, d) in enumerate(inventories) if d.id_ == item.id and d.batch.id_ == item.batch.id), None
)
if index is not None:
new_inventory = inventories.pop(index)
if batch_consumed and new_inventory.quantity > batch_quantity:

View File

@ -44,7 +44,11 @@ def save(
)
item.code = db.execute(select(func.coalesce(func.max(Product.code), 0) + 1)).scalar_one()
db.add(item)
if not len(data.skus):
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail="Not enough stock keeping units.",
)
for sku in data.skus:
db.add(
StockKeepingUnit(
@ -86,6 +90,11 @@ def update_route(
item.is_active = data.is_active
item.is_purchased = data.is_purchased
item.is_sold = data.is_sold
if not len(data.skus):
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail="Not enough stock keeping units.",
)
for i in range(len(item.skus), 0, -1):
sku = item.skus[i - 1]
index = next((idx for (idx, d) in enumerate(data.skus) if d.id_ == sku.id), None)

View File

@ -23,7 +23,7 @@ from ..models.product import Product
from ..models.rate_contract import RateContract
from ..models.rate_contract_item import RateContractItem
from ..models.stock_keeping_unit import StockKeepingUnit
from ..models.validations import check_inventories_are_valid, check_journals_are_valid
from ..models.validations import check_duplicate_skus, check_journals_are_valid
from ..models.voucher import Voucher
from ..models.voucher_type import VoucherType
from ..schemas.blank_voucher_info import BlankVoucherInfo
@ -55,7 +55,7 @@ def save_route(
with SessionFuture() as db:
item: Voucher = save(data, user, db)
save_inventories(item, data.vendor.id_, data.inventories, db)
check_inventories_are_valid(item)
check_duplicate_skus(item)
save_journals(item, data.vendor, db)
check_journals_are_valid(item)
save_files(item.id, i, t, db)
@ -186,7 +186,7 @@ def update_route(
with SessionFuture() as db:
item: Voucher = update_voucher(id_, data, user, db)
update_inventory(item, data.vendor.id_, data.inventories, db)
check_inventories_are_valid(item)
check_duplicate_skus(item)
update_journals(item, data.vendor, db)
check_journals_are_valid(item)
update_files(item.id, data.files, i, t, db)
@ -237,17 +237,13 @@ def update_voucher(id_: uuid.UUID, data: schema_in.PurchaseIn, user: UserToken,
def update_inventory(voucher: Voucher, vendor_id: uuid.UUID, inventories: List[InventorySchema], db: Session):
old_set = set([(i.id, i.batch.sku_id) for i in voucher.inventories])
new_set = set([(i.id_, i.batch.sku.id_) for i in inventories if i.id_ is not None])
if len(new_set - old_set):
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail="Product cannot be changed",
)
for it in range(len(voucher.inventories), 0, -1):
item = voucher.inventories[it - 1]
quantity_consumed = -1 * get_batch_quantity(item.batch_id, voucher.id, db)
index = next((idx for (idx, d) in enumerate(inventories) if d.id_ == item.id), None)
index = next(
(idx for (idx, d) in enumerate(inventories) if d.id_ == item.id and d.batch.sku.id_ == item.batch.sku_id),
None,
)
if index is not None:
new_inventory = inventories.pop(index)
sku: StockKeepingUnit = db.execute(

View File

@ -20,7 +20,7 @@ from ..models.inventory import Inventory
from ..models.journal import Journal
from ..models.product import Product
from ..models.stock_keeping_unit import StockKeepingUnit
from ..models.validations import check_inventories_are_valid, check_journals_are_valid
from ..models.validations import check_duplicate_batches, check_journals_are_valid
from ..models.voucher import Voucher
from ..models.voucher_type import VoucherType
from ..schemas.blank_voucher_info import BlankVoucherInfo
@ -51,7 +51,7 @@ def save_route(
with SessionFuture() as db:
item: Voucher = save(data, user, db)
save_inventories(item, data.inventories, db)
check_inventories_are_valid(item)
check_duplicate_batches(item)
save_journals(item, data.vendor, db)
check_journals_are_valid(item)
save_files(item.id, i, t, db)
@ -175,7 +175,7 @@ def update_route(
with SessionFuture() as db:
item: Voucher = update_voucher(id_, data, user, db)
update_inventory(item, data.inventories, db)
check_inventories_are_valid(item)
check_duplicate_batches(item)
update_journals(item, data.vendor, db)
check_journals_are_valid(item)
update_files(item.id, data.files, i, t, db)
@ -229,18 +229,13 @@ def update_voucher(id_: uuid.UUID, data: schema_in.PurchaseIn, user: UserToken,
def update_inventory(voucher: Voucher, new_inventories: List[InventorySchema], db: Session):
old_set = set([(i.id, i.batch.sku_id) for i in voucher.inventories])
new_set = set([(i.id_, i.batch.sku.id_) for i in new_inventories if i.id_ is not None])
if len(new_set - old_set):
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail="Product cannot be changed",
)
for it in range(len(voucher.inventories), 0, -1):
item = voucher.inventories[it - 1]
batch = db.execute(select(Batch).where(Batch.id == item.batch_id)).scalar_one()
batch_quantity = get_batch_quantity(item.batch_id, voucher.id, db)
index = next((idx for (idx, d) in enumerate(new_inventories) if d.id_ == item.id), None)
index = next(
(idx for (idx, d) in enumerate(new_inventories) if d.id_ == item.id and d.batch.id_ == item.batch.id), None
)
if index is not None:
new_inventory = new_inventories.pop(index)
if new_inventory.quantity > batch_quantity:

View File

@ -166,20 +166,13 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
if (this.batch === null || quantity <= 0) {
return;
}
const oldFiltered = this.voucher.inventories.filter(
(x) => x.batch.sku.id === (this.batch as Batch).sku.id,
);
const old = oldFiltered.length ? oldFiltered[0] : null;
if (oldFiltered.length) {
if (((old as Inventory).batch as Batch).id !== this.batch.id) {
this.toaster.show('Danger', 'Product with a different batch already added');
return;
}
if (isConsumption && (old as Inventory).quantity + quantity > this.batch.quantityRemaining) {
const old = this.voucher.inventories.find((x) => x.batch.id === (this.batch as Batch).id);
if (old !== undefined) {
if (isConsumption && old.quantity + quantity > this.batch.quantityRemaining) {
this.toaster.show('Danger', 'Quantity issued cannot be more than quantity available');
return;
}
(old as Inventory).quantity += quantity;
old.quantity += quantity;
} else {
if (isConsumption && quantity > this.batch.quantityRemaining) {
this.toaster.show('Danger', 'Quantity issued cannot be more than quantity available');
@ -238,7 +231,7 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
const j = result as Inventory;
if (
j.batch.sku.id !== row.batch.sku.id &&
this.voucher.inventories.filter((x) => x.batch.sku.id === j.batch.sku.id).length
this.voucher.inventories.filter((x) => x.batch.id === j.batch.id).length
) {
return;
}

View File

@ -179,10 +179,8 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy
if (this.batch === null || quantity <= 0 || this.batch.quantityRemaining < quantity) {
return;
}
const oldFiltered = this.voucher.inventories.filter(
(x) => x.batch.sku.id === (this.batch as Batch).sku.id,
);
if (oldFiltered.length) {
const old = this.voucher.inventories.find((x) => x.batch.id === (this.batch as Batch).id);
if (old !== undefined) {
this.toaster.show('Danger', 'Product already added');
return;
}