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:
parent
eeb36d7f8b
commit
1a3248ad70
@ -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,
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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(
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user