Journal Done!! But there is issue of validation in purchase due to lack of proper journals when getting data from the frontend. The proposed solution is to create different schemas for various vouchers and then reexport and import them in a master schema for persisting Also, change "Supplier" to vendor in Purchase, etc. Also, convert all date field to date from datetime Rename "Salary Deduction" to "Employee Benefits" across the board
193 lines
7.1 KiB
Python
193 lines
7.1 KiB
Python
import datetime
|
|
import uuid
|
|
from decimal import Decimal
|
|
|
|
from fastapi import HTTPException, status
|
|
from sqlalchemy import func
|
|
|
|
from brewman.models.master import Product, AccountBase
|
|
from brewman.models.operations import inventory_valid
|
|
from brewman.models.voucher import (
|
|
Voucher,
|
|
VoucherType,
|
|
Batch,
|
|
Inventory,
|
|
Journal,
|
|
DbImage,
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def purchase_update_voucher(voucher, json, files, user, dbsession):
|
|
voucher.date = datetime.datetime.strptime(json["date"], "%d-%b-%Y")
|
|
voucher.is_starred = json["isStarred"]
|
|
voucher.narration = json["narration"].strip()
|
|
voucher.user_id = user.id
|
|
voucher.posted = False
|
|
voucher.last_edit_date = datetime.datetime.utcnow()
|
|
|
|
purchase_update_inventory(voucher, json["inventories"], dbsession)
|
|
purchase_update_journals(voucher, json["journals"], dbsession)
|
|
journals_valid(voucher)
|
|
inventory_valid(voucher)
|
|
|
|
old_files = [
|
|
uuid.UUID(f["id"]) for f in json["files"] if "id" in f and f["id"] is not None
|
|
]
|
|
images = dbsession.query(DbImage).filter(DbImage.resource_id == voucher.id).all()
|
|
for image in [i for i in images if i.id not in old_files]:
|
|
dbsession.delete(image)
|
|
for key, value in files.items():
|
|
dbsession.add(DbImage(voucher.id, "voucher", value["f"], value["t"]))
|
|
return voucher
|
|
|
|
|
|
def purchase_update_inventory(voucher, new_inventories, dbsession):
|
|
for it in range(len(voucher.inventories), 0, -1):
|
|
item = voucher.inventories[it - 1]
|
|
found = False
|
|
for j in range(len(new_inventories), 0, -1):
|
|
i = new_inventories[j - 1]
|
|
if "id" in i and i["id"] is not None and item.id == uuid.UUID(i["id"]):
|
|
product = (
|
|
dbsession.query(Product)
|
|
.filter(Product.id == uuid.UUID(i["product"]["id"]))
|
|
.first()
|
|
)
|
|
found = True
|
|
if item.product_id != product.id:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
detail="Product cannot be changed",
|
|
)
|
|
new_quantity = round(Decimal(i["quantity"]), 2)
|
|
old_quantity = round(Decimal(item.quantity), 2)
|
|
quantity_remaining = round(Decimal(item.batch.quantity_remaining), 2)
|
|
if new_quantity <= 0:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
detail=f"Quantity of {item.product.name} cannot be zero",
|
|
)
|
|
if old_quantity > new_quantity and quantity_remaining < (
|
|
old_quantity - new_quantity
|
|
):
|
|
raise HTTPException(
|
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
detail=f"{old_quantity - quantity_remaining} has been issued, minimum quantity is",
|
|
)
|
|
item.batch.quantity_remaining -= old_quantity - new_quantity
|
|
item.quantity = new_quantity
|
|
rate = round(Decimal(i["rate"]), 2)
|
|
discount = round(Decimal(i["discount"]), 5)
|
|
tax = round(Decimal(i["tax"]), 5)
|
|
if voucher.date != item.batch.name:
|
|
item.batch.name = voucher.date
|
|
if voucher.date < item.batch.name:
|
|
# TODO: check for issued products which might have been in a back date
|
|
pass
|
|
item.rate = rate
|
|
item.batch.rate = rate
|
|
item.discount = discount
|
|
item.batch.discount = discount
|
|
item.tax = tax
|
|
item.batch.tax = tax
|
|
product.price = rate
|
|
new_inventories.remove(i)
|
|
# TODO: Update all references of the batch with the new rates
|
|
break
|
|
if not found:
|
|
uses = (
|
|
dbsession.query(func.count(Inventory.id))
|
|
.filter(Inventory.batch_id == item.batch.id)
|
|
.filter(Inventory.id != item.id)
|
|
.scalar()
|
|
)
|
|
if uses > 0:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
detail=f"{item.product.name} has been issued, it cannot be deleted",
|
|
)
|
|
else:
|
|
dbsession.delete(item.batch)
|
|
dbsession.delete(item)
|
|
voucher.inventories.remove(item)
|
|
for i in new_inventories:
|
|
product = (
|
|
dbsession.query(Product)
|
|
.filter(Product.id == uuid.UUID(i["product"]["id"]))
|
|
.first()
|
|
)
|
|
new_quantity = round(Decimal(i["quantity"]), 2)
|
|
rate = round(Decimal(i["rate"]), 2)
|
|
tax = round(Decimal(i["tax"]), 5)
|
|
discount = round(Decimal(i["discount"]), 5)
|
|
batch = Batch(
|
|
name=voucher.date,
|
|
product_id=product.id,
|
|
quantity_remaining=new_quantity,
|
|
rate=rate,
|
|
tax=tax,
|
|
discount=discount,
|
|
)
|
|
inventory = Inventory(
|
|
id=None,
|
|
product_id=product.id,
|
|
batch=batch,
|
|
quantity=new_quantity,
|
|
rate=rate,
|
|
tax=tax,
|
|
discount=discount,
|
|
)
|
|
inventory.voucher_id = voucher.id
|
|
dbsession.add(batch)
|
|
inventory.batch_id = batch.id
|
|
product.price = rate
|
|
voucher.inventories.append(inventory)
|
|
dbsession.add(inventory)
|
|
|
|
|
|
def purchase_update_journals(voucher, journals, dbsession):
|
|
other_account = [ff for ff in journals if ff["debit"] == -1]
|
|
other_account = (
|
|
dbsession.query(AccountBase)
|
|
.filter(AccountBase.id == uuid.UUID(other_account[0]["account"]["id"]))
|
|
.first()
|
|
)
|
|
journals = dict()
|
|
amount = 0
|
|
for item in voucher.inventories:
|
|
product = dbsession.query(Product).filter(Product.id == item.product_id).first()
|
|
account = product.account
|
|
amount += item.amount
|
|
if account.id in journals:
|
|
journals[account.id].amount += item.amount
|
|
else:
|
|
journals[account.id] = Journal(
|
|
debit=1,
|
|
cost_centre_id=account.cost_centre_id,
|
|
account_id=account.id,
|
|
amount=item.amount,
|
|
)
|
|
journals[other_account.id] = Journal(
|
|
debit=-1,
|
|
cost_centre_id=other_account.cost_centre_id,
|
|
account_id=other_account.id,
|
|
amount=amount,
|
|
)
|
|
for i in range(len(voucher.journals), 0, -1):
|
|
item = voucher.journals[i - 1]
|
|
if item.account_id in journals:
|
|
item.debit = journals[item.account_id].debit
|
|
item.amount = round(journals[item.account_id].amount, 2)
|
|
item.cost_centre_id = journals[item.account_id].cost_centre_id
|
|
del journals[item.account_id]
|
|
else:
|
|
dbsession.delete(item)
|
|
voucher.journals.remove(item)
|
|
for item in journals.values():
|
|
item.amount = round(item.amount, 2)
|
|
voucher.journals.append(item)
|
|
dbsession.add(item)
|