diff --git a/brewman/main.py b/brewman/main.py
index aa63214c..978ea176 100644
--- a/brewman/main.py
+++ b/brewman/main.py
@@ -7,13 +7,18 @@ from .routers import (
account_types,
attendance_types,
attendance,
+ batch,
employee_attendance,
attendance_report,
cost_centre,
employee,
fingerprint,
+ issue,
+ issue_grid,
+ payment,
product,
product_group,
+ receipt,
recipe,
login,
journal,
@@ -39,10 +44,6 @@ from .routers.reports import (
unposted,
)
-from .routers.voucher import (
- issue_grid,
- batch,
-)
from .db.base_class import Base
from .config import Settings
from .db.session import engine
@@ -105,10 +106,11 @@ app.include_router(unposted.router, prefix="/api/unposted", tags=["reports"])
app.include_router(issue_grid.router, prefix="/api/issue-grid", tags=["vouchers"])
app.include_router(batch.router, prefix="/api/batch", tags=["vouchers"])
app.include_router(journal.router, prefix="/api/journal", tags=["vouchers"])
-app.include_router(journal.router, prefix="/api/payment", tags=["vouchers"])
-app.include_router(journal.router, prefix="/api/receipt", tags=["vouchers"])
+app.include_router(payment.router, prefix="/api/payment", tags=["vouchers"])
+app.include_router(receipt.router, prefix="/api/receipt", tags=["vouchers"])
app.include_router(purchase.router, prefix="/api/purchase", tags=["vouchers"])
app.include_router(purchase_return.router, prefix="/api/purchase-return", tags=["vouchers"])
+app.include_router(issue.router, prefix="/api/issue", tags=["vouchers"])
def init():
diff --git a/brewman/models/voucher.py b/brewman/models/voucher.py
index a137d518..fd7b7020 100644
--- a/brewman/models/voucher.py
+++ b/brewman/models/voucher.py
@@ -22,13 +22,13 @@ from .meta import Base
class VoucherType:
- def __init__(self, id, name):
- self.id = id
+ def __init__(self, id_, name):
+ self.id = id_
self.name = name
@classmethod
def list(cls):
- list = [
+ list_ = [
VoucherType(1, "Journal"),
VoucherType(2, "Purchase"),
VoucherType(3, "Issue"),
@@ -43,20 +43,20 @@ class VoucherType:
VoucherType(12, "Employee Benefit"),
VoucherType(13, "Incentive"),
]
- return list
+ return list_
@classmethod
def by_name(cls, name):
- list = cls.list()
- for item in list:
+ list_ = cls.list()
+ for item in list_:
if item.name == name:
return item
@classmethod
- def by_id(cls, id):
- list = cls.list()
- for item in list:
- if item.id == id:
+ def by_id(cls, id_):
+ list_ = cls.list()
+ for item in list_:
+ if item.id == id_:
return item
diff --git a/brewman/routers/__init__.py b/brewman/routers/__init__.py
index 179b714f..ed365775 100644
--- a/brewman/routers/__init__.py
+++ b/brewman/routers/__init__.py
@@ -1,6 +1,6 @@
import re
import uuid
-from datetime import date, datetime, timedelta, time
+from datetime import date, timedelta
from decimal import Decimal
from io import BytesIO
from typing import Optional
diff --git a/brewman/routers/attendance.py b/brewman/routers/attendance.py
index 7a3efbfc..b6846926 100644
--- a/brewman/routers/attendance.py
+++ b/brewman/routers/attendance.py
@@ -1,5 +1,5 @@
import traceback
-from datetime import datetime, date, timedelta, time
+from datetime import datetime, date, timedelta
from fastapi import APIRouter, HTTPException, status, Depends, Security, Request
from sqlalchemy import or_
@@ -52,12 +52,7 @@ def attendance_date_report(date_: date, db: Session):
employees = (
db.query(Employee)
.filter(Employee.joining_date <= date_)
- .filter(
- or_(
- Employee.is_active,
- Employee.leaving_date >= date_,
- )
- )
+ .filter(or_(Employee.is_active, Employee.leaving_date >= date_,))
.order_by(Employee.cost_centre_id)
.order_by(Employee.designation)
.order_by(Employee.name)
diff --git a/brewman/routers/attendance_report.py b/brewman/routers/attendance_report.py
index f44c50c3..2e7db516 100644
--- a/brewman/routers/attendance_report.py
+++ b/brewman/routers/attendance_report.py
@@ -2,12 +2,10 @@ import csv
from datetime import datetime, date
import io
-from fastapi import APIRouter, HTTPException, status, Depends, Security, Request
+from fastapi import APIRouter, Depends
from fastapi.responses import StreamingResponse
from sqlalchemy import or_
from sqlalchemy.orm import Session
-from ..schemas.auth import UserToken
-from ..core.security import get_current_active_user as get_user
from ..models.master import AttendanceType, Employee
from ..models.voucher import Attendance
from .attendance import date_range
@@ -34,8 +32,15 @@ def get_report(
):
try:
output = io.StringIO()
- attendance_record(datetime.strptime(s, "%d-%b-%Y"), datetime.strptime(f, "%d-%b-%Y"), output, db)
- headers = {"Content-Disposition": "attachment; filename = 'attendance-record.csv'"}
+ attendance_record(
+ datetime.strptime(s, "%d-%b-%Y"),
+ datetime.strptime(f, "%d-%b-%Y"),
+ output,
+ db,
+ )
+ headers = {
+ "Content-Disposition": "attachment; filename = 'attendance-record.csv'"
+ }
output.seek(0)
return StreamingResponse(output, media_type="text/csv", headers=headers)
finally:
diff --git a/brewman/routers/voucher/batch.py b/brewman/routers/batch.py
similarity index 90%
rename from brewman/routers/voucher/batch.py
rename to brewman/routers/batch.py
index 8498cb43..2b87a5bb 100644
--- a/brewman/routers/voucher/batch.py
+++ b/brewman/routers/batch.py
@@ -3,9 +3,9 @@ import datetime
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
-from ...schemas.auth import UserToken
-from ...core.security import get_current_active_user as get_user
-from ...db.session import SessionLocal
+from ..schemas.auth import UserToken
+from ..core.security import get_current_active_user as get_user
+from ..db.session import SessionLocal
from brewman.models.voucher import Batch
router = APIRouter()
diff --git a/brewman/routers/cost_centre.py b/brewman/routers/cost_centre.py
index d9673940..090b1789 100644
--- a/brewman/routers/cost_centre.py
+++ b/brewman/routers/cost_centre.py
@@ -11,6 +11,7 @@ import brewman.schemas.master as schemas
from ..core.security import get_current_active_user as get_user
from ..db.session import SessionLocal
from ..models.master import CostCentre
+
router = APIRouter()
@@ -37,8 +38,7 @@ def save(
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
- detail=str(e),
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
)
except Exception:
db.rollback()
@@ -68,8 +68,7 @@ def update(
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
- detail=str(e),
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
)
except Exception:
db.rollback()
@@ -90,8 +89,7 @@ def delete(
if item is None:
raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND,
- detail="Cost Centre not found",
+ status_code=status.HTTP_404_NOT_FOUND, detail="Cost Centre not found",
)
elif item.is_fixture:
raise HTTPException(
diff --git a/brewman/routers/employee.py b/brewman/routers/employee.py
index d197a902..7cd24178 100644
--- a/brewman/routers/employee.py
+++ b/brewman/routers/employee.py
@@ -119,7 +119,8 @@ def delete(
@router.get("")
def show_blank(
- db: Session = Depends(get_db), user: UserToken = Security(get_user, scopes=["employees"])
+ db: Session = Depends(get_db),
+ user: UserToken = Security(get_user, scopes=["employees"]),
):
return employee_info(None, db)
diff --git a/brewman/routers/employee_attendance.py b/brewman/routers/employee_attendance.py
index b179d107..ac3e0993 100644
--- a/brewman/routers/employee_attendance.py
+++ b/brewman/routers/employee_attendance.py
@@ -30,8 +30,7 @@ def get_db() -> Session:
@router.get("", response_model=schemas.EmployeeAttendance)
def show_blank(
- request: Request,
- user: UserToken = Security(get_user, scopes=["attendance"]),
+ request: Request, user: UserToken = Security(get_user, scopes=["attendance"]),
):
return {
"startDate": get_start_date(request.session),
@@ -53,8 +52,7 @@ def employee_attendance_report(
employee: Employee = db.query(Employee).filter(Employee.id == id_).first()
if employee is None:
raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND,
- detail="Employee not found",
+ status_code=status.HTTP_404_NOT_FOUND, detail="Employee not found",
)
start_date = s if s is not None else get_start_date(request.session)
finish_date = f if f is not None else get_finish_date(request.session)
@@ -73,13 +71,13 @@ def employee_attendance_report(
if not employee.is_active and employee.leaving_date < finish_date
else finish_date
)
- info["body"] = employee_attendance(
- employee, start_date, finish_date, db
- )
+ info["body"] = employee_attendance(employee, start_date, finish_date, db)
return info
-def employee_attendance(employee: Employee, start_date: date, finish_date: date, db: Session):
+def employee_attendance(
+ employee: Employee, start_date: date, finish_date: date, db: Session
+):
list_ = []
for item in date_range(start_date, finish_date, inclusive=True):
att = (
@@ -97,7 +95,7 @@ def employee_attendance(employee: Employee, start_date: date, finish_date: date,
attendanceType={"id": att},
prints=prints,
hoursWorked=hours_worked,
- fullDay=full_day
+ fullDay=full_day,
)
)
return list_
diff --git a/brewman/routers/employee_benefit.py b/brewman/routers/employee_benefit.py
index e69de29b..9c502f2c 100644
--- a/brewman/routers/employee_benefit.py
+++ b/brewman/routers/employee_benefit.py
@@ -0,0 +1,103 @@
+import traceback
+import uuid
+from typing import List
+
+from fastapi import APIRouter, HTTPException, status, Depends, Security, UploadFile, File, Request
+from sqlalchemy.exc import SQLAlchemyError
+from sqlalchemy.orm import Session
+
+from .voucher import incentive_create_voucher, employee_benefit_create_voucher, voucher_info, check_voucher_lock_info, check_voucher_edit_allowed
+from ..core.session import set_date
+from ..schemas.auth import UserToken
+from ..core.security import get_current_active_user as get_user
+from ..db.session import SessionLocal
+from ..models.voucher import Voucher
+import brewman.schemas.voucher as schemas
+
+router = APIRouter()
+
+
+# Dependency
+def get_db() -> Session:
+ try:
+ db = SessionLocal()
+ yield db
+ finally:
+ db.close()
+
+
+@router.post("", response_model=schemas.Voucher)
+def save_route(
+ request: Request,
+ data: schemas.Voucher,
+ db: Session = Depends(get_db),
+ files: List[UploadFile] = File(...),
+ user: UserToken = Security(get_user, scopes=["journal"]),
+):
+ try:
+ item: Voucher = save(data, files, user, db)
+ db.commit()
+ set_date(request.session, data.date_)
+ # item: Voucher = db.query(Voucher).filter(Voucher.id == item.id).first()
+ return voucher_info(item, db)
+ except SQLAlchemyError as e:
+ db.rollback()
+ raise HTTPException(
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
+ detail=str(e),
+ )
+ except Exception:
+ db.rollback()
+ raise HTTPException(
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
+ detail=traceback.format_exc(),
+ )
+
+
+def save(data: schemas.Voucher, files: List[UploadFile], user: UserToken, db: Session) -> Voucher:
+ check_voucher_lock_info(None, data.date_, db)
+ if data.type_ in ["Employee Benefit"]:
+ voucher = employee_benefit_create_voucher(data, files, user, db)
+ elif data.type_ in ["Incentive"]:
+ voucher = incentive_create_voucher(data, files, user, db)
+ return voucher
+
+
+@router.get("/{id_}")
+def update_route(
+ id_: uuid.UUID,
+ request: Request,
+ data: schemas.Voucher,
+ db: Session = Depends(get_db),
+ files: List[UploadFile] = File(...),
+ user: UserToken = Security(get_user, scopes=["journal"]),
+):
+ try:
+ item: Voucher = update(id_, data, files, user, db)
+ db.commit()
+ set_date(request.session, data.date_)
+ # item: Voucher = db.query(Voucher).filter(Voucher.id == item.id).first()
+ return voucher_info(item, db)
+ except SQLAlchemyError as e:
+ db.rollback()
+ raise HTTPException(
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
+ detail=str(e),
+ )
+ except Exception:
+ db.rollback()
+ raise HTTPException(
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
+ detail=traceback.format_exc(),
+ )
+
+
+def update(id_: uuid.UUID, data: schemas.Voucher, files: List[UploadFile], user: UserToken, db: Session) -> Voucher:
+ item: Voucher = db.query(Voucher).filter(Voucher.id == id_).first()
+ check_voucher_lock_info(item.date, data.date_, db)
+ check_voucher_edit_allowed(item, user)
+ if data.type_ in ["Employee Benefit"]:
+ voucher = employee_benefit_update_voucher(item, data, files, user, db)
+ elif data.type_ in ["Incentive"]:
+ voucher = incentive_update_voucher(item, data, files, user, db)
+ return voucher
diff --git a/brewman/routers/fingerprint.py b/brewman/routers/fingerprint.py
index f9c4496d..c1b7c44e 100644
--- a/brewman/routers/fingerprint.py
+++ b/brewman/routers/fingerprint.py
@@ -5,7 +5,6 @@ from io import StringIO
from sqlalchemy import bindparam, select, exists, and_
from sqlalchemy.dialects.postgresql import insert as pg_insert
-# from zope.sqlalchemy import mark_changed
from sqlalchemy.orm import Session
from brewman.models.master import Employee
diff --git a/brewman/routers/issue.py b/brewman/routers/issue.py
index ad7c5efb..8407b5b6 100644
--- a/brewman/routers/issue.py
+++ b/brewman/routers/issue.py
@@ -1,19 +1,36 @@
import traceback
import uuid
-from typing import List
+from datetime import datetime
+from decimal import Decimal
+from typing import List, Optional
-from fastapi import APIRouter, HTTPException, status, Depends, Security, UploadFile, File, Request
+from fastapi import (
+ APIRouter,
+ HTTPException,
+ status,
+ Depends,
+ Security,
+ UploadFile,
+ File,
+ Request,
+)
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
-from .voucher import issue_create_voucher, incentive_create_voucher, \
- employee_benefit_create_voucher, voucher_info, check_voucher_lock_info, check_voucher_edit_allowed
-from ..core.session import set_date
+from .voucher import (
+ voucher_info,
+ check_voucher_lock_info,
+ check_voucher_edit_allowed,
+ blank_voucher,
+)
+from ..core.session import set_date, get_date
+from ..models import CostCentre, AccountBase
from ..schemas.auth import UserToken
from ..core.security import get_current_active_user as get_user
from ..db.session import SessionLocal
-from ..models.voucher import Voucher
-import brewman.schemas.voucher as schemas
+from ..models.voucher import Voucher, VoucherType, Batch, Inventory, Journal
+import brewman.schemas.voucher as output
+import brewman.schemas.input as schema_in
router = APIRouter()
@@ -27,25 +44,30 @@ def get_db() -> Session:
db.close()
-@router.post("", response_model=schemas.Voucher)
+@router.post("", response_model=output.Voucher)
def save_route(
request: Request,
- data: schemas.Voucher,
+ data: schema_in.IssueIn = Depends(schema_in.IssueIn.load_form),
db: Session = Depends(get_db),
- files: List[UploadFile] = File(...),
- user: UserToken = Security(get_user, scopes=["journal"]),
+ i: List[UploadFile] = File(None),
+ t: List[UploadFile] = File(None),
+ user: UserToken = Security(get_user, scopes=["issue"]),
):
try:
- item: Voucher = save(data, files, user, db)
+ i = i or []
+ t = t or []
+ item, batch_consumed = save(data, user, db)
+ amount = save_inventories(item, data.inventories, batch_consumed, db)
+ save_journals(item, data.source, data.destination, amount, db)
+ save_files(i + t, db)
db.commit()
- set_date(request.session, data.date_)
- # item: Voucher = db.query(Voucher).filter(Voucher.id == item.id).first()
- return voucher_info(item, db)
+ set_date(data.date_.strftime("%d-%b-%Y"), request.session)
+ info = voucher_info(item, db)
+ return info
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
- detail=str(e),
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
)
except Exception:
db.rollback()
@@ -55,37 +77,129 @@ def save_route(
)
-def save(data: schemas.Voucher, files: List[UploadFile], user: UserToken, db: Session) -> Voucher:
+def save(
+ data: schema_in.IssueIn, user: UserToken, db: Session
+) -> (Voucher, Optional[bool]):
check_voucher_lock_info(None, data.date_, db)
- if data.type_ in ["Issue"]:
- voucher = issue_create_voucher(data, files, user, db)
- elif data.type_ in ["Employee Benefit"]:
- voucher = employee_benefit_create_voucher(data, files, user, db)
- elif data.type_ in ["Incentive"]:
- voucher = incentive_create_voucher(data, files, user, db)
- return voucher
+ voucher = Voucher(
+ date=data.date_,
+ narration=data.narration,
+ is_starred=data.is_starred,
+ user_id=user.id_,
+ type_=VoucherType.by_name(data.type_),
+ )
+ db.add(voucher)
+ if data.source.id_ == data.destination.id_:
+ raise HTTPException(
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+ detail="Source cannot be the same as destination",
+ )
+ if data.source.id_ == CostCentre.cost_centre_purchase():
+ batch_consumed = True
+ elif data.destination.id_ == CostCentre.cost_centre_purchase():
+ batch_consumed = False
+ else:
+ batch_consumed = None
+ return voucher, batch_consumed
-@router.get("/{id_}")
+def save_inventories(
+ voucher: Voucher,
+ inventories: List[schema_in.Inventory],
+ batch_consumed: Optional[bool],
+ db: Session,
+) -> Decimal:
+ amount: Decimal = Decimal(0)
+ for item in inventories:
+ batch = db.query(Batch).filter(Batch.id == item.batch.id_).first()
+ if batch_consumed and item.quantity > batch.quantity_remaining:
+ raise HTTPException(
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+ detail=f"Quantity available is {batch.quantity_remaining} only",
+ )
+ if batch.name > voucher.date:
+ raise HTTPException(
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+ detail=f"Batch of {batch.product.name} was purchased after the issue date",
+ )
+ if batch_consumed is None:
+ pass
+ elif batch_consumed:
+ batch.quantity_remaining -= item.quantity
+ else:
+ batch.quantity_remaining += item.quantity
+
+ item = Inventory(
+ id_=item.id_,
+ product=batch.product,
+ quantity=item.quantity,
+ rate=batch.rate,
+ tax=batch.tax,
+ discount=batch.discount,
+ batch=batch,
+ )
+ voucher.inventories.append(item)
+ db.add(item)
+ amount += round(item.amount, 2)
+ return amount
+
+
+def save_journals(
+ voucher: Voucher,
+ source: schema_in.CostCentreLink,
+ destination: schema_in.CostCentreLink,
+ amount: Decimal,
+ db: Session,
+):
+ s = Journal(
+ debit=-1,
+ account_id=AccountBase.all_purchases(),
+ amount=amount,
+ cost_centre_id=source.id_,
+ )
+ d = Journal(
+ debit=1,
+ account_id=AccountBase.all_purchases(),
+ amount=amount,
+ cost_centre_id=destination.id_,
+ )
+ voucher.journals.append(s)
+ db.add(s)
+ voucher.journals.append(d)
+ db.add(d)
+
+
+def save_files(files: List[UploadFile], db: Session):
+ # for key, value in files.items():
+ # db.add(DbImage(voucher.id, "voucher", value["f"], value["t"]))
+ pass
+
+
+@router.put("/{id_}", response_model=output.Voucher)
def update_route(
id_: uuid.UUID,
request: Request,
- data: schemas.Voucher,
+ data: schema_in.IssueIn = Depends(schema_in.IssueIn.load_form),
db: Session = Depends(get_db),
- files: List[UploadFile] = File(...),
- user: UserToken = Security(get_user, scopes=["journal"]),
+ i: List[UploadFile] = File(None),
+ t: List[UploadFile] = File(None),
+ user: UserToken = Security(get_user, scopes=["issue"]),
):
try:
- item: Voucher = update(id_, data, files, user, db)
+ i = i or []
+ t = t or []
+ item, batch_consumed = update(id_, data, user, db)
+ amount = update_inventories(item, data.inventories, batch_consumed, db)
+ update_journals(item, data.source, data.destination, amount)
+ update_files(data, i + t, db)
db.commit()
- set_date(request.session, data.date_)
+ set_date(data.date_.strftime("%d-%b-%Y"), request.session)
# item: Voucher = db.query(Voucher).filter(Voucher.id == item.id).first()
return voucher_info(item, db)
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
- detail=str(e),
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
)
except Exception:
db.rollback()
@@ -95,14 +209,177 @@ def update_route(
)
-def update(id_: uuid.UUID, data: schemas.Voucher, files: List[UploadFile], user: UserToken, db: Session) -> Voucher:
- item: Voucher = db.query(Voucher).filter(Voucher.id == id_).first()
- check_voucher_lock_info(item.date, data.date_, db)
- check_voucher_edit_allowed(item, user)
- if data.type_ in ["Issue"]:
- voucher = issue_update_voucher(item, data, files, user, db)
- elif data.type_ in ["Employee Benefit"]:
- voucher = employee_benefit_update_voucher(item, data, files, user, db)
- elif data.type_ in ["Incentive"]:
- voucher = incentive_update_voucher(item, data, files, user, db)
- return voucher
+def update(
+ id_: uuid.UUID, data: schema_in.IssueIn, user: UserToken, db: Session
+) -> (Voucher, Optional[bool]):
+ voucher: Voucher = db.query(Voucher).filter(Voucher.id == id_).first()
+ check_voucher_lock_info(voucher.date, data.date_, db)
+ check_voucher_edit_allowed(voucher, user)
+ voucher.date = data.date_
+ voucher.is_starred = data.is_starred
+ voucher.narration = data.narration
+ voucher.user_id = user.id_
+ voucher.posted = False
+ voucher.last_edit_date = datetime.utcnow()
+
+ for item in voucher.journals:
+ if item.debit == 1:
+ destination = item.cost_centre_id
+ else:
+ source = item.cost_centre_id
+
+ if source == CostCentre.cost_centre_purchase():
+ old_batch_consumed = True
+ elif destination == CostCentre.cost_centre_purchase():
+ old_batch_consumed = False
+ else:
+ old_batch_consumed = None
+
+ if data.source.id_ == CostCentre.cost_centre_purchase():
+ new_batch_consumed = True
+ elif data.destination.id_ == CostCentre.cost_centre_purchase():
+ new_batch_consumed = False
+ else:
+ new_batch_consumed = None
+
+ if new_batch_consumed != old_batch_consumed:
+ raise HTTPException(
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+ detail="Purchase cost centre cannot be changed",
+ )
+ return voucher, new_batch_consumed
+
+
+def update_inventories(
+ voucher: Voucher,
+ inventories: List[schema_in.Inventory],
+ batch_consumed: Optional[bool],
+ db: Session,
+):
+ amount: Decimal = Decimal(0)
+ for it in range(len(voucher.inventories), 0, -1):
+ item = voucher.inventories[it - 1]
+ found = False
+ for j in range(len(inventories), 0, -1):
+ i = inventories[j - 1]
+ if item.id == i.id_:
+ batch = db.query(Batch).filter(Batch.id == i.batch.id_).first()
+ found = True
+ if item.batch_id != batch.id:
+ raise HTTPException(
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+ detail="Product / Batch cannot be changed",
+ )
+ if (
+ batch_consumed
+ and i.quantity - item.quantity > item.batch.quantity_remaining
+ ):
+ raise HTTPException(
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+ detail=f"Maximum quantity available for {item.product.full_name} is {item.quantity + item.batch.quantity_remaining}",
+ )
+ if item.batch.name > voucher.date:
+ raise HTTPException(
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+ detail=f"Batch of {item.product.name} was purchased after the issue date",
+ )
+
+ if batch_consumed is None:
+ pass
+ elif batch_consumed:
+ item.batch.quantity_remaining -= i.quantity - item.quantity
+ else:
+ item.batch.quantity_remaining += i.quantity - item.quantity
+
+ item.quantity = i.quantity
+ item.rate = batch.rate
+ item.tax = batch.tax
+ item.discount = batch.discount
+ amount += round(item.amount, 2)
+
+ inventories.remove(i)
+ break
+ if not found:
+ if batch_consumed is None:
+ pass
+ elif batch_consumed:
+ item.batch.quantity_remaining += item.quantity
+ else:
+ if item.batch.quantity_remaining < item.quantity:
+ raise HTTPException(
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+ detail=f"Product {item.product.name} cannot be removed, minimum quantity is {item.batch.quantity_remaining}",
+ )
+ item.batch.quantity_remaining -= item.quantity
+ db.delete(item)
+ voucher.inventories.remove(item)
+ amount += save_inventories(voucher, inventories, batch_consumed, db)
+ return amount
+
+
+def update_journals(
+ voucher: Voucher,
+ source: schema_in.CostCentreLink,
+ destination: schema_in.CostCentreLink,
+ amount: Decimal,
+):
+ for i in range(len(voucher.journals), 0, -1):
+ item = voucher.journals[i - 1]
+ if item.debit == -1:
+ item.cost_centre_id = source.id_
+ item.amount = amount
+ else:
+ item.cost_centre_id = destination.id_
+ item.amount = amount
+
+
+def update_files(data: schema_in.IssueIn, files: List[UploadFile], db: Session):
+ pass
+ # old_files = [
+ # uuid.UUID(f["id"]) for f in json["files"] if "id" in f and f["id"] is not None
+ # ]
+ # images = db.query(DbImage).filter(DbImage.resource_id == voucher.id).all()
+ # for image in [i for i in images if i.id not in old_files]:
+ # db.delete(image)
+ # for key, value in files.items():
+ # db.add(DbImage(voucher.id, "voucher", value["f"], value["t"]))
+
+
+@router.get("/{id_}", response_model=output.Voucher)
+def get_id(
+ id_: uuid.UUID,
+ db: Session = Depends(get_db),
+ user: UserToken = Security(get_user, scopes=["issue"]),
+):
+ try:
+ item: Voucher = db.query(Voucher).filter(Voucher.id == id_).first()
+ return voucher_info(item, db)
+ except SQLAlchemyError as e:
+ db.rollback()
+ raise HTTPException(
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
+ )
+ except Exception:
+ db.rollback()
+ raise HTTPException(
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
+ detail=traceback.format_exc(),
+ )
+
+
+@router.get("")
+def show_blank(
+ request: Request,
+ date: str = None,
+ source: str = None,
+ destination: str = None,
+ db: Session = Depends(get_db),
+ user: UserToken = Security(get_user, scopes=["issue"]),
+):
+ date_ = date or get_date(request.session)
+ additional_info = {"date": date_, "type": "Issue"}
+ if source:
+ additional_info["source"] = source
+ if destination:
+ additional_info["destination"] = destination
+ return blank_voucher(additional_info, db)
diff --git a/brewman/routers/voucher/issue_grid.py b/brewman/routers/issue_grid.py
similarity index 91%
rename from brewman/routers/voucher/issue_grid.py
rename to brewman/routers/issue_grid.py
index 4edd42db..26834bdc 100644
--- a/brewman/routers/voucher/issue_grid.py
+++ b/brewman/routers/issue_grid.py
@@ -5,9 +5,9 @@ from fastapi import APIRouter, Depends, Security, Request
from sqlalchemy.orm import Session
from sqlalchemy.orm.util import aliased
-from ...schemas.auth import UserToken
-from ...core.security import get_current_active_user as get_user
-from ...db.session import SessionLocal
+from ..schemas.auth import UserToken
+from ..core.security import get_current_active_user as get_user
+from ..db.session import SessionLocal
from brewman.models.voucher import Voucher, Journal, VoucherType
router = APIRouter()
diff --git a/brewman/routers/journal.py b/brewman/routers/journal.py
index a9cd8002..081cdbbc 100644
--- a/brewman/routers/journal.py
+++ b/brewman/routers/journal.py
@@ -2,11 +2,25 @@ import traceback
import uuid
from typing import List
from datetime import datetime
-from fastapi import APIRouter, HTTPException, status, Depends, Security, UploadFile, File, Request, Form
+from fastapi import (
+ APIRouter,
+ HTTPException,
+ status,
+ Depends,
+ Security,
+ UploadFile,
+ File,
+ Request,
+)
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
-from .voucher import voucher_info, check_voucher_lock_info, check_voucher_edit_allowed, blank_voucher
+from .voucher import (
+ voucher_info,
+ check_voucher_lock_info,
+ check_voucher_edit_allowed,
+ blank_voucher,
+)
from ..core.session import set_date, get_date
from ..models import AccountBase
from ..schemas.auth import UserToken
@@ -49,8 +63,7 @@ def save_route(
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
- detail=str(e),
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
)
except Exception:
db.rollback()
@@ -71,7 +84,9 @@ def save(data: schema_in.JournalIn, user: UserToken, db: Session) -> Voucher:
)
db.add(voucher)
for item in data.journals:
- account: AccountBase = db.query(AccountBase).filter(AccountBase.id == item.account.id_).first()
+ account: AccountBase = db.query(AccountBase).filter(
+ AccountBase.id == item.account.id_
+ ).first()
journal = Journal(
id=item.id_,
amount=item.amount,
@@ -111,8 +126,7 @@ def update_route(
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
- detail=str(e),
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
)
except Exception:
db.rollback()
@@ -122,7 +136,9 @@ def update_route(
)
-def update(id_: uuid.UUID, data: schema_in.JournalIn, user: UserToken, db: Session) -> Voucher:
+def update(
+ id_: uuid.UUID, data: schema_in.JournalIn, user: UserToken, db: Session
+) -> Voucher:
voucher: Voucher = db.query(Voucher).filter(Voucher.id == id_).first()
check_voucher_lock_info(voucher.date, data.date_, db)
check_voucher_edit_allowed(voucher, user)
@@ -139,7 +155,11 @@ def update(id_: uuid.UUID, data: schema_in.JournalIn, user: UserToken, db: Sessi
for j in range(len(data.journals), 0, -1):
new_item = data.journals[j - 1]
if new_item.id_ is not None and item.id == new_item.id_:
- account = db.query(AccountBase).filter(AccountBase.id == new_item.account.id_).first()
+ account = (
+ db.query(AccountBase)
+ .filter(AccountBase.id == new_item.account.id_)
+ .first()
+ )
found = True
item.debit = new_item.debit
item.amount = new_item.amount
@@ -150,7 +170,9 @@ def update(id_: uuid.UUID, data: schema_in.JournalIn, user: UserToken, db: Sessi
if not found:
voucher.journals.remove(item)
for new_item in data.journals:
- account = db.query(AccountBase).filter(AccountBase.id == new_item.account.id_).first()
+ account = (
+ db.query(AccountBase).filter(AccountBase.id == new_item.account.id_).first()
+ )
journal = Journal(
id=None,
amount=new_item.amount,
@@ -187,8 +209,7 @@ def get_id(
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
- detail=str(e),
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
)
except Exception:
db.rollback()
diff --git a/brewman/routers/payment.py b/brewman/routers/payment.py
index e69de29b..8d9707f3 100644
--- a/brewman/routers/payment.py
+++ b/brewman/routers/payment.py
@@ -0,0 +1,133 @@
+import traceback
+import uuid
+from typing import List
+from fastapi import (
+ APIRouter,
+ HTTPException,
+ status,
+ Depends,
+ Security,
+ UploadFile,
+ File,
+ Request,
+)
+from sqlalchemy.exc import SQLAlchemyError
+from sqlalchemy.orm import Session
+
+from .voucher import voucher_info, blank_voucher
+from ..core.session import set_date, get_date
+from ..schemas.auth import UserToken
+from ..core.security import get_current_active_user as get_user
+from ..db.session import SessionLocal
+from ..models.voucher import Voucher
+from brewman.routers.journal import save, save_files, update, update_files
+import brewman.schemas.voucher as output
+import brewman.schemas.input as schema_in
+
+router = APIRouter()
+
+
+# Dependency
+def get_db() -> Session:
+ try:
+ db = SessionLocal()
+ yield db
+ finally:
+ db.close()
+
+
+@router.post("", response_model=output.Voucher)
+def save_route(
+ request: Request,
+ data: schema_in.JournalIn = Depends(schema_in.JournalIn.load_form),
+ db: Session = Depends(get_db),
+ i: List[UploadFile] = File(None),
+ t: List[UploadFile] = File(None),
+ user: UserToken = Security(get_user, scopes=["payment"]),
+):
+ try:
+ i = i or []
+ t = t or []
+ item: Voucher = save(data, user, db)
+ save_files(i + t, db)
+ db.commit()
+ set_date(data.date_.strftime("%d-%b-%Y"), request.session)
+ info = voucher_info(item, db)
+ return info
+ except SQLAlchemyError as e:
+ db.rollback()
+ raise HTTPException(
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
+ )
+ except Exception:
+ db.rollback()
+ raise HTTPException(
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
+ detail=traceback.format_exc(),
+ )
+
+
+@router.put("/{id_}", response_model=output.Voucher)
+def update_route(
+ id_: uuid.UUID,
+ request: Request,
+ data: schema_in.JournalIn = Depends(schema_in.JournalIn.load_form),
+ db: Session = Depends(get_db),
+ i: List[UploadFile] = File(None),
+ t: List[UploadFile] = File(None),
+ user: UserToken = Security(get_user, scopes=["payment"]),
+):
+ try:
+ i = i or []
+ t = t or []
+ item: Voucher = update(id_, data, user, db)
+ update_files(data, i + t, db)
+ db.commit()
+ set_date(data.date_.strftime("%d-%b-%Y"), request.session)
+ return voucher_info(item, db)
+ except SQLAlchemyError as e:
+ db.rollback()
+ raise HTTPException(
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
+ )
+ except Exception:
+ db.rollback()
+ raise HTTPException(
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
+ detail=traceback.format_exc(),
+ )
+
+
+@router.get("/{id_}", response_model=output.Voucher)
+def get_id(
+ id_: uuid.UUID,
+ db: Session = Depends(get_db),
+ user: UserToken = Security(get_user, scopes=["payment"]),
+):
+ try:
+ item: Voucher = db.query(Voucher).filter(Voucher.id == id_).first()
+ return voucher_info(item, db)
+ except SQLAlchemyError as e:
+ db.rollback()
+ raise HTTPException(
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
+ )
+ except Exception:
+ db.rollback()
+ raise HTTPException(
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
+ detail=traceback.format_exc(),
+ )
+
+
+@router.get("")
+def show_blank(
+ request: Request,
+ a: str = None,
+ db: Session = Depends(get_db),
+ user: UserToken = Security(get_user, scopes=["payment"]),
+):
+ additional_info = {"date": get_date(request.session), "type": "Payment"}
+ if a:
+ additional_info["account"] = a
+ return blank_voucher(additional_info, db)
diff --git a/brewman/routers/product_group.py b/brewman/routers/product_group.py
index 6dc9b03b..fd1cbae0 100644
--- a/brewman/routers/product_group.py
+++ b/brewman/routers/product_group.py
@@ -11,6 +11,7 @@ from ..schemas.auth import UserToken
from ..core.security import get_current_active_user as get_user
from ..db.session import SessionLocal
from brewman.models.master import ProductGroup
+
router = APIRouter()
@@ -37,8 +38,7 @@ def save(
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
- detail=str(e),
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
)
except Exception:
db.rollback()
@@ -68,8 +68,7 @@ def update(
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
- detail=str(e),
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
)
except Exception:
db.rollback()
@@ -90,8 +89,7 @@ def delete(
if item is None:
raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND,
- detail="Product Group not found",
+ status_code=status.HTTP_404_NOT_FOUND, detail="Product Group not found",
)
elif item.is_fixture:
raise HTTPException(
@@ -121,7 +119,7 @@ def show_blank(
@router.get("/list", response_model=List[schemas.ProductGroup])
async def show_list(db: Session = Depends(get_db), user: UserToken = Depends(get_user)):
- return[
+ return [
{"id": item.id, "name": item.name, "isFixture": item.is_fixture}
for item in db.query(ProductGroup).order_by(ProductGroup.name).all()
]
diff --git a/brewman/routers/purchase.py b/brewman/routers/purchase.py
index 026a33ff..283adc09 100644
--- a/brewman/routers/purchase.py
+++ b/brewman/routers/purchase.py
@@ -3,12 +3,26 @@ import uuid
from decimal import Decimal
from typing import List
from datetime import datetime
-from fastapi import APIRouter, HTTPException, status, Depends, Security, UploadFile, File, Request
+from fastapi import (
+ APIRouter,
+ HTTPException,
+ status,
+ Depends,
+ Security,
+ UploadFile,
+ File,
+ Request,
+)
from sqlalchemy import func
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
-from .voucher import voucher_info, check_voucher_lock_info, check_voucher_edit_allowed, blank_voucher
+from .voucher import (
+ voucher_info,
+ check_voucher_lock_info,
+ check_voucher_edit_allowed,
+ blank_voucher,
+)
from ..core.session import set_date, get_date
from ..models import Product, AccountBase
from ..schemas.auth import UserToken
@@ -53,8 +67,7 @@ def save_route(
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
- detail=str(e),
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
)
except Exception:
db.rollback()
@@ -77,12 +90,31 @@ def save(data: schema_in.PurchaseIn, user: UserToken, db: Session) -> Voucher:
return voucher
-def save_inventories(voucher: Voucher, inventories: List[schema_in.Inventory], db: Session):
+def save_inventories(
+ voucher: Voucher, inventories: List[schema_in.Inventory], db: Session
+):
for item in inventories:
- product: Product = db.query(Product).filter(Product.id == item.product.id_).first()
- batch = Batch(name=voucher.date, product=product, quantity_remaining=item.quantity, rate=item.rate, tax=item.tax, discount=item.discount)
+ product: Product = db.query(Product).filter(
+ Product.id == item.product.id_
+ ).first()
+ batch = Batch(
+ name=voucher.date,
+ product=product,
+ quantity_remaining=item.quantity,
+ rate=item.rate,
+ tax=item.tax,
+ discount=item.discount,
+ )
db.add(batch)
- inventory = Inventory(id_=item.id_, product=product, batch=batch, quantity=item.quantity, rate=item.rate, tax=item.tax, discount=item.discount)
+ inventory = Inventory(
+ id_=item.id_,
+ product=product,
+ batch=batch,
+ quantity=item.quantity,
+ rate=item.rate,
+ tax=item.tax,
+ discount=item.discount,
+ )
product.price = item.rate
voucher.inventories.append(inventory)
db.add(inventory)
@@ -145,8 +177,7 @@ def update_route(
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
- detail=str(e),
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
)
except Exception:
db.rollback()
@@ -156,7 +187,9 @@ def update_route(
)
-def update(id_: uuid.UUID, data: schema_in.PurchaseIn, user: UserToken, db: Session) -> Voucher:
+def update(
+ id_: uuid.UUID, data: schema_in.PurchaseIn, user: UserToken, db: Session
+) -> Voucher:
voucher: Voucher = db.query(Voucher).filter(Voucher.id == id_).first()
check_voucher_lock_info(voucher.date, data.date_, db)
check_voucher_edit_allowed(voucher, user)
@@ -169,19 +202,26 @@ def update(id_: uuid.UUID, data: schema_in.PurchaseIn, user: UserToken, db: Sess
return voucher
-def update_inventory(voucher: Voucher, new_inventories: List[schema_in.Inventory], db: Session):
+def update_inventory(
+ voucher: Voucher, new_inventories: List[schema_in.Inventory], db: Session
+):
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):
new_inventory = new_inventories[j - 1]
if new_inventory.id_:
- product = db.query(Product).filter(Product.id == new_inventory.product.id_).first()
+ product = (
+ db.query(Product)
+ .filter(Product.id == new_inventory.product.id_)
+ .first()
+ )
found = True
if item.product_id != new_inventory.product.id_:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
- detail="Product cannot be changed")
+ detail="Product cannot be changed",
+ )
old_quantity = round(Decimal(item.quantity), 2)
quantity_remaining = round(Decimal(item.batch.quantity_remaining), 2)
if new_inventory.quantity < (old_quantity - quantity_remaining):
@@ -223,7 +263,9 @@ def update_inventory(voucher: Voucher, new_inventories: List[schema_in.Inventory
db.delete(item)
voucher.inventories.remove(item)
for new_inventory in new_inventories:
- product = db.query(Product).filter(Product.id == new_inventory.product.id_).first()
+ product = (
+ db.query(Product).filter(Product.id == new_inventory.product.id_).first()
+ )
batch = Batch(
name=voucher.date,
product_id=product.id,
@@ -312,8 +354,7 @@ def get_id(
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
- detail=str(e),
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
)
except Exception:
db.rollback()
diff --git a/brewman/routers/purchase_return.py b/brewman/routers/purchase_return.py
index 540a70fe..05268df0 100644
--- a/brewman/routers/purchase_return.py
+++ b/brewman/routers/purchase_return.py
@@ -3,14 +3,27 @@ import uuid
from decimal import Decimal
from typing import List
from datetime import datetime
-from fastapi import APIRouter, HTTPException, status, Depends, Security, UploadFile, File, Request
-from sqlalchemy import func
+from fastapi import (
+ APIRouter,
+ HTTPException,
+ status,
+ Depends,
+ Security,
+ UploadFile,
+ File,
+ Request,
+)
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
-from .voucher import voucher_info, check_voucher_lock_info, check_voucher_edit_allowed, blank_voucher
+from .voucher import (
+ voucher_info,
+ check_voucher_lock_info,
+ check_voucher_edit_allowed,
+ blank_voucher,
+)
from ..core.session import set_date, get_date
-from ..models import Product, AccountBase
+from ..models import AccountBase
from ..schemas.auth import UserToken
from ..core.security import get_current_active_user as get_user
from ..db.session import SessionLocal
@@ -53,8 +66,7 @@ def save_route(
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
- detail=str(e),
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
)
except Exception:
db.rollback()
@@ -77,14 +89,18 @@ def save(data: schema_in.PurchaseIn, user: UserToken, db: Session) -> Voucher:
return voucher
-def save_inventories(voucher: Voucher, inventories: List[schema_in.Inventory], db: Session):
+def save_inventories(
+ voucher: Voucher, inventories: List[schema_in.Inventory], db: Session
+):
for item in inventories:
batch = db.query(Batch).filter(Batch.id == item.batch.id_).first()
if item.quantity > batch.quantity_remaining:
raise ValueError(f"Maximum quantity is {batch.quantity_remaining}.")
if batch.name > voucher.date:
- raise ValueError(f"Return date cannot be before {batch.product.name.strftime('%d-%b-%Y')}")
+ raise ValueError(
+ f"Return date cannot be before {batch.product.name.strftime('%d-%b-%Y')}"
+ )
batch.quantity_remaining -= item.quantity
@@ -157,8 +173,7 @@ def update_route(
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
- detail=str(e),
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
)
except Exception:
db.rollback()
@@ -168,7 +183,9 @@ def update_route(
)
-def update(id_: uuid.UUID, data: schema_in.PurchaseIn, user: UserToken, db: Session) -> Voucher:
+def update(
+ id_: uuid.UUID, data: schema_in.PurchaseIn, user: UserToken, db: Session
+) -> Voucher:
voucher: Voucher = db.query(Voucher).filter(Voucher.id == id_).first()
check_voucher_lock_info(voucher.date, data.date_, db)
check_voucher_edit_allowed(voucher, user)
@@ -181,7 +198,9 @@ def update(id_: uuid.UUID, data: schema_in.PurchaseIn, user: UserToken, db: Sess
return voucher
-def update_inventory(voucher: Voucher, new_inventories: List[schema_in.Inventory], db: Session):
+def update_inventory(
+ voucher: Voucher, new_inventories: List[schema_in.Inventory], db: Session
+):
for it in range(len(voucher.inventories), 0, -1):
item = voucher.inventories[it - 1]
found = False
@@ -192,7 +211,8 @@ def update_inventory(voucher: Voucher, new_inventories: List[schema_in.Inventory
if item.product_id != new_inventory.product.id_:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
- detail="Product cannot be changed")
+ detail="Product cannot be changed",
+ )
old_quantity = round(Decimal(item.quantity), 2)
quantity_remaining = round(Decimal(item.batch.quantity_remaining), 2)
if new_inventory.quantity - old_quantity > quantity_remaining:
@@ -201,7 +221,9 @@ def update_inventory(voucher: Voucher, new_inventories: List[schema_in.Inventory
detail=f"{old_quantity + quantity_remaining} is the maximum for {item.product.full_name}.",
)
if item.batch.name > voucher.date:
- raise ValueError(f"Voucher cannot be before {item.product.name.strftime('%d-%b-%Y')}")
+ raise ValueError(
+ f"Voucher cannot be before {item.product.name.strftime('%d-%b-%Y')}"
+ )
item.batch.quantity_remaining -= new_inventory.quantity - old_quantity
item.quantity = new_inventory.quantity
new_inventories.remove(new_inventory)
@@ -275,8 +297,7 @@ def get_id(
except SQLAlchemyError as e:
db.rollback()
raise HTTPException(
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
- detail=str(e),
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
)
except Exception:
db.rollback()
diff --git a/brewman/routers/receipt.py b/brewman/routers/receipt.py
index e69de29b..30a3cf5b 100644
--- a/brewman/routers/receipt.py
+++ b/brewman/routers/receipt.py
@@ -0,0 +1,133 @@
+import traceback
+import uuid
+from typing import List
+from fastapi import (
+ APIRouter,
+ HTTPException,
+ status,
+ Depends,
+ Security,
+ UploadFile,
+ File,
+ Request,
+)
+from sqlalchemy.exc import SQLAlchemyError
+from sqlalchemy.orm import Session
+
+from .voucher import voucher_info, blank_voucher
+from ..core.session import set_date, get_date
+from ..schemas.auth import UserToken
+from ..core.security import get_current_active_user as get_user
+from ..db.session import SessionLocal
+from ..models.voucher import Voucher
+from brewman.routers.journal import save, save_files, update, update_files
+import brewman.schemas.voucher as output
+import brewman.schemas.input as schema_in
+
+router = APIRouter()
+
+
+# Dependency
+def get_db() -> Session:
+ try:
+ db = SessionLocal()
+ yield db
+ finally:
+ db.close()
+
+
+@router.post("", response_model=output.Voucher)
+def save_route(
+ request: Request,
+ data: schema_in.JournalIn = Depends(schema_in.JournalIn.load_form),
+ db: Session = Depends(get_db),
+ i: List[UploadFile] = File(None),
+ t: List[UploadFile] = File(None),
+ user: UserToken = Security(get_user, scopes=["receipt"]),
+):
+ try:
+ i = i or []
+ t = t or []
+ item: Voucher = save(data, user, db)
+ save_files(i + t, db)
+ db.commit()
+ set_date(data.date_.strftime("%d-%b-%Y"), request.session)
+ info = voucher_info(item, db)
+ return info
+ except SQLAlchemyError as e:
+ db.rollback()
+ raise HTTPException(
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
+ )
+ except Exception:
+ db.rollback()
+ raise HTTPException(
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
+ detail=traceback.format_exc(),
+ )
+
+
+@router.put("/{id_}", response_model=output.Voucher)
+def update_route(
+ id_: uuid.UUID,
+ request: Request,
+ data: schema_in.JournalIn = Depends(schema_in.JournalIn.load_form),
+ db: Session = Depends(get_db),
+ i: List[UploadFile] = File(None),
+ t: List[UploadFile] = File(None),
+ user: UserToken = Security(get_user, scopes=["receipt"]),
+):
+ try:
+ i = i or []
+ t = t or []
+ item: Voucher = update(id_, data, user, db)
+ update_files(data, i + t, db)
+ db.commit()
+ set_date(data.date_.strftime("%d-%b-%Y"), request.session)
+ return voucher_info(item, db)
+ except SQLAlchemyError as e:
+ db.rollback()
+ raise HTTPException(
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
+ )
+ except Exception:
+ db.rollback()
+ raise HTTPException(
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
+ detail=traceback.format_exc(),
+ )
+
+
+@router.get("/{id_}", response_model=output.Voucher)
+def get_id(
+ id_: uuid.UUID,
+ db: Session = Depends(get_db),
+ user: UserToken = Security(get_user, scopes=["receipt"]),
+):
+ try:
+ item: Voucher = db.query(Voucher).filter(Voucher.id == id_).first()
+ return voucher_info(item, db)
+ except SQLAlchemyError as e:
+ db.rollback()
+ raise HTTPException(
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
+ )
+ except Exception:
+ db.rollback()
+ raise HTTPException(
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
+ detail=traceback.format_exc(),
+ )
+
+
+@router.get("")
+def show_blank(
+ request: Request,
+ a: str = None,
+ db: Session = Depends(get_db),
+ user: UserToken = Security(get_user, scopes=["receipt"]),
+):
+ additional_info = {"date": get_date(request.session), "type": "Receipt"}
+ if a:
+ additional_info["account"] = a
+ return blank_voucher(additional_info, db)
diff --git a/brewman/routers/voucher/__init__.py b/brewman/routers/voucher/__init__.py
index d37c56bf..b136db68 100644
--- a/brewman/routers/voucher/__init__.py
+++ b/brewman/routers/voucher/__init__.py
@@ -22,7 +22,6 @@ from brewman.models.voucher import (
Journal,
)
from brewman.routers import get_lock_info
-from .issue import issue_create_voucher, issue_update_voucher
from .incentive import incentive_create_voucher, incentive_update_voucher
from .employee_benefit import employee_benefit_create_voucher, employee_benefit_update_voucher
from ...core.session import get_first_day
@@ -195,6 +194,11 @@ def voucher_info(voucher, db):
if voucher.type == 2: # "Purchase"
item = [j for j in voucher.journals if j.debit == -1][0]
json_voucher["vendor"] = {"id": item.account.id, "name": item.account.name}
+ elif voucher.type == 3: # "Issue"
+ item = [j for j in voucher.journals if j.debit == -1][0]
+ json_voucher["source"] = {"id": item.cost_centre_id, "name": ""}
+ item = [j for j in voucher.journals if j.debit == 1][0]
+ json_voucher["destination"] = {"id": item.cost_centre_id, "name": ""}
else:
for item in voucher.journals:
json_voucher["journals"].append(
@@ -340,52 +344,14 @@ def blank_voucher(info, db):
{"account": AccountBase.local_purchase(), "amount": 0, "debit": 1}
)
elif type_ == "Issue":
- if "dource" in info and "destination" in info:
- json_voucher["journals"].append(
- {
- "account": {"id": AccountBase.all_purchases()},
- "amount": 0,
- "debit": -1,
- "costCentre": {"id": info["source"]},
- }
- )
- json_voucher["journals"].append(
- {
- "account": {"id": AccountBase.all_purchases()},
- "amount": 0,
- "debit": 1,
- "costCentre": {"id": info["destination"]},
- }
- )
- elif "journals" not in info:
- json_voucher["journals"].append(
- {
- "account": {"id": AccountBase.all_purchases()},
- "amount": 0,
- "debit": -1,
- "costCentre": {"id": CostCentre.cost_centre_purchase()},
- }
- )
- json_voucher["journals"].append(
- {
- "account": {"id": AccountBase.all_purchases()},
- "amount": 0,
- "debit": 1,
- "costCentre": {"id": CostCentre.cost_centre_kitchen()},
- }
- )
+ if "source" in info:
+ json_voucher["source"] = {"id": info["source"]}
else:
- json_voucher["date"] = info["date"]
- for item in info["journals"]:
- json_voucher["journals"].append(
- {
- "account": {"id": item["account"]["id"]},
- "amount": 0,
- "debit": item["debit"],
- "costCentre": {"id": item["costCentre"]["id"]},
- }
- )
-
+ json_voucher["source"] = {"id": CostCentre.cost_centre_purchase()}
+ if "destination" in info:
+ json_voucher["destination"] = {"id": info["destination"]}
+ else:
+ json_voucher["destination"] = {"id": CostCentre.cost_centre_kitchen()}
elif type_ == "Employee Benefit":
json_voucher["employeeBenefits"] = []
elif type_ == "Incentive":
diff --git a/brewman/routers/voucher/emptyvoucher.py b/brewman/routers/voucher/emptyvoucher.py
index cbfe17cf..10fc2563 100644
--- a/brewman/routers/voucher/emptyvoucher.py
+++ b/brewman/routers/voucher/emptyvoucher.py
@@ -6,43 +6,10 @@ class EmptyVoucher(object):
def __init__(self, request):
self.request = request
- @router.get("/api/voucher", request_param="t=Payment") # "Payment"
- def payment(self):
- account = self.request.GET.get("a", None)
- return self.get_blank({"account": account})
-
- @router.get("/api/voucher", request_param="t=Receipt") # "Receipt"
- def receipt(self):
- account = self.request.GET.get("a", None)
- return self.get_blank({"account": account})
-
- @router.get("/api/voucher", request_param="t=Purchase Return") # "Purchase Return"
- def purchase_return(self):
- return self.get_blank()
-
@router.get("/api/voucher", request_param="t=Employee Benefit") # "Purchase Return"
def purchase_return(self):
return self.get_blank()
- @router.get("/api/voucher", request_param="t=Issue") # "Issue"
- def issue(self):
- voucher_type = self.request.GET.get("t", None)
- date = self.request.GET.get("date", None)
- source = self.request.GET.get("source", None)
- destination = self.request.GET.get("destination", None)
- if date is not None and source is not None and destination is not None:
- return blank_voucher(
- {
- "type": voucher_type,
- "date": date,
- "source": source,
- "destination": destination,
- },
- self.request.dbsession,
- )
- else:
- return self.get_blank()
-
@router.get("/api/voucher", request_param="t=Incentive") # "Incentive"
def incentive(self):
voucher_type = self.request.GET.get("t", None)
diff --git a/brewman/routers/voucher/issue.py b/brewman/routers/voucher/issue.py
deleted file mode 100644
index 46135abe..00000000
--- a/brewman/routers/voucher/issue.py
+++ /dev/null
@@ -1,246 +0,0 @@
-import datetime
-from decimal import Decimal
-import uuid
-
-from fastapi import HTTPException, status
-
-from brewman.models.master import CostCentre, AccountBase
-from brewman.models.voucher import Voucher, VoucherType, Batch, Inventory, Journal
-
-
-def issue_create_voucher(json, user, dbsession):
- dt = datetime.datetime.strptime(json["date"], "%d-%b-%Y")
- voucher = Voucher(
- date=dt,
- narration=json["narration"].strip(),
- user_id=user.id,
- type=VoucherType.by_name("Issue"),
- )
- dbsession.add(voucher)
-
- for item in json["journals"]:
- if int(item["debit"]) == 1:
- destination = uuid.UUID(item["costCentre"]["id"])
- else:
- source = uuid.UUID(item["costCentre"]["id"])
- if source == destination:
- raise HTTPException(
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
- detail="Source cannot be the same as destination",
- )
- if source == CostCentre.cost_centre_purchase():
- batch_consumed = True
- elif destination == CostCentre.cost_centre_purchase():
- batch_consumed = False
- else:
- batch_consumed = None
- for item in json["inventories"]:
- issue_create_inventory(voucher, item, batch_consumed, dbsession)
- for item in issue_create_journals(voucher.inventories, source, destination):
- voucher.journals.append(item)
- dbsession.add(item)
- journals_valid(voucher)
- inventory_valid(voucher)
- return voucher
-
-
-def issue_create_inventory(voucher, item, batch_consumed, dbsession):
- batch = (
- dbsession.query(Batch)
- .filter(Batch.id == uuid.UUID(item["batch"]["id"]))
- .first()
- )
- inventory_id = (
- uuid.UUID(item["id"]) if "id" in item and item["id"] is not None else None
- )
- quantity = round(Decimal(item["quantity"]), 2)
-
- if quantity <= 0:
- raise HTTPException(
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
- detail=f"Quantity of {item.product.name} cannot be zero",
- )
- if batch_consumed == True and quantity > batch.quantity_remaining:
- raise HTTPException(
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
- detail=f"Quantity available is {batch.quantity_remaining} only",
- )
- if batch.name > voucher.date:
- raise HTTPException(
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
- detail=f"Batch of {batch.product.name} was purchased after the issue date",
- )
- if batch_consumed is None:
- pass
- elif batch_consumed:
- batch.quantity_remaining -= quantity
- else:
- batch.quantity_remaining += quantity
-
- item = Inventory(
- id=inventory_id,
- product_id=batch.product.id,
- quantity=quantity,
- rate=batch.rate,
- tax=batch.tax,
- discount=batch.discount,
- batch=batch,
- )
- voucher.inventories.append(item)
- dbsession.add(item)
-
-
-def issue_create_journals(inventories, source, destination):
- amount = 0
- for item in inventories:
- amount += item.amount
- return [
- Journal(
- debit=-1,
- account_id=AccountBase.all_purchases(),
- amount=round(amount, 2),
- cost_centre_id=source,
- ),
- Journal(
- debit=1,
- account_id=AccountBase.all_purchases(),
- amount=round(amount, 2),
- cost_centre_id=destination,
- ),
- ]
-
-
-def issue_update_voucher(voucher, json, user, dbsession):
- voucher.date = datetime.datetime.strptime(json["date"], "%d-%b-%Y")
- voucher.narration = json["narration"].strip()
- voucher.user_id = user.id
- voucher.last_edit_date = datetime.datetime.utcnow()
-
- for item in voucher.journals:
- if item.debit == 1:
- destination = item.cost_centre_id
- else:
- source = item.cost_centre_id
- if source == CostCentre.cost_centre_purchase():
- old_batch_consumed = True
- elif destination == CostCentre.cost_centre_purchase():
- old_batch_consumed = False
- else:
- old_batch_consumed = None
-
- for item in json["journals"]:
- if int(item["debit"]) == 1:
- destination = uuid.UUID(item["costCentre"]["id"])
- else:
- source = uuid.UUID(item["costCentre"]["id"])
- if source == destination:
- raise HTTPException(
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
- detail="Source cannot be the same as destination",
- )
-
- if source == CostCentre.cost_centre_purchase():
- new_batch_consumed = True
- elif destination == CostCentre.cost_centre_purchase():
- new_batch_consumed = False
- else:
- new_batch_consumed = None
-
- if new_batch_consumed != old_batch_consumed:
- raise HTTPException(
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
- detail="Purchase cost centre cannot be changed",
- )
-
- issue_update_inventory(voucher, json["inventories"], old_batch_consumed, dbsession)
- issue_update_journals(voucher, source, destination)
- journals_valid(voucher)
- inventory_valid(voucher)
- return voucher
-
-
-def issue_update_inventory(voucher, new_inventories, batch_consumed, 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"]):
- batch = (
- dbsession.query(Batch)
- .filter(Batch.id == uuid.UUID(i["batch"]["id"]))
- .first()
- )
- found = True
- if item.batch_id != batch.id:
- raise HTTPException(
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
- detail="Product / Batch 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 (
- batch_consumed is True
- and new_quantity - old_quantity > quantity_remaining
- ):
- raise HTTPException(
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
- detail=f"Maximum quantity available for {item.product.full_name} is {old_quantity + quantity_remaining}",
- )
- if item.batch.name > voucher.date:
- raise HTTPException(
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
- detail=f"Batch of {item.product.name} was purchased after the issue date",
- )
-
- if batch_consumed is None:
- pass
- elif batch_consumed:
- item.batch.quantity_remaining -= new_quantity - old_quantity
- else:
- item.batch.quantity_remaining += new_quantity - old_quantity
-
- item.quantity = new_quantity
- item.rate = batch.rate
- item.tax = batch.tax
- item.discount = batch.discount
-
- new_inventories.remove(i)
- break
- if not found:
- if batch_consumed is None:
- pass
- elif batch_consumed:
- item.batch.quantity_remaining += item.quantity
- else:
- if item.batch.quantity_remaining < item.quantity:
- raise HTTPException(
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
- detail=f"Product {item.product.name} cannot be removed, minimum quantity is {item.batch.quantity_remaining}",
- )
- item.batch.quantity_remaining -= item.quantity
- dbsession.delete(item)
- voucher.inventories.remove(item)
- for i in new_inventories:
- issue_create_inventory(voucher, i, batch_consumed, dbsession)
-
-
-def issue_update_journals(voucher, source, destination):
- amount = 0
- for item in voucher.inventories:
- amount += item.amount
-
- for i in range(len(voucher.journals), 0, -1):
- item = voucher.journals[i - 1]
- if item.debit == -1:
- item.cost_centre_id = source
- item.amount = round(amount, 2)
- else:
- item.cost_centre_id = destination
- item.amount = round(amount, 2)
diff --git a/brewman/schemas/input.py b/brewman/schemas/input.py
index f2397309..fe064a2c 100644
--- a/brewman/schemas/input.py
+++ b/brewman/schemas/input.py
@@ -9,7 +9,7 @@ from pydantic import validator
from sqlalchemy.orm import Session
from brewman.schemas import to_camel
-from brewman.schemas.master import AccountLink, CostCentreLink, ProductLink
+from brewman.schemas.master import AccountLink, CostCentreLink
from brewman.schemas.voucher import VoucherIn, Journal, Inventory
@@ -84,12 +84,45 @@ class PurchaseIn(VoucherIn):
json_data = json.loads(data)
return cls.parse_obj(json_data)
- def validate_inventory(self, date_: date, old_inv: List[Inventory], db: Session):
- for it in range(len(old_inv), 0, -1):
- item = old_inv[it - 1]
- found = False
- for j in range(len(self.inventories), 0, -1):
- i = self.inventories[j - 1]
+class IssueIn(VoucherIn):
+ source: CostCentreLink
+ destination: CostCentreLink
+ inventories: List[Inventory]
- pass
\ No newline at end of file
+ class Config:
+ anystr_strip_whitespace = True
+ alias_generator = to_camel
+ json_encoders = {
+ date: lambda v: v.strftime("%d-%b-%Y"),
+ datetime: lambda v: v.strftime("%d-%b-%Y %H:%I")
+ }
+
+ @validator("date_", pre=True)
+ def parse_date(cls, value):
+ if isinstance(value, date):
+ return value
+ return datetime.strptime(value, "%d-%b-%Y").date()
+
+ @validator("inventories") # For Purchase, Issue and Return Vouchers
+ def validate_enough_inventories(cls, value: List[Inventory]):
+ if len(value) < 1:
+ raise ValueError("Not enough inventories")
+ return value
+
+ @validator("inventories") # For Purchase, Issue and Return Vouchers
+ def validate_inventories_unique(cls, value: List[Inventory]):
+ if len(set(x.product.id_ for x in value)) != len(value):
+ raise ValueError("Duplicate products")
+ return value
+
+ @validator("destination") # For Purchase, Issue and Return Vouchers
+ def source_destination_unique(cls, value: CostCentreLink, values):
+ if value.id_ == values['source'].id_:
+ raise ValueError("Source and destination cannot be the same")
+ return value
+
+ @classmethod
+ def load_form(cls, data: str = Form(...)):
+ json_data = json.loads(data)
+ return cls.parse_obj(json_data)
diff --git a/brewman/schemas/voucher.py b/brewman/schemas/voucher.py
index a009c983..e8557ca5 100644
--- a/brewman/schemas/voucher.py
+++ b/brewman/schemas/voucher.py
@@ -102,6 +102,8 @@ class Voucher(VoucherIn):
journals: List[Journal]
inventories: List[Inventory]
vendor: Optional[AccountLink]
+ source: Optional[CostCentreLink]
+ destination: Optional[CostCentreLink]
files: List[Any]
class Config:
diff --git a/overlord/src/app/core/voucher.ts b/overlord/src/app/core/voucher.ts
index 6f2d0180..e610345e 100644
--- a/overlord/src/app/core/voucher.ts
+++ b/overlord/src/app/core/voucher.ts
@@ -11,6 +11,8 @@ export class Voucher {
narration: string;
incentive?: number;
vendor?: Account;
+ source?: CostCentre;
+ destination?: CostCentre;
journals: Journal[];
inventories: Inventory[];
employeeBenefits: EmployeeBenefit[];
diff --git a/overlord/src/app/issue/issue.component.html b/overlord/src/app/issue/issue.component.html
index 4d01f7c7..1f09a2fc 100644
--- a/overlord/src/app/issue/issue.component.html
+++ b/overlord/src/app/issue/issue.component.html
@@ -13,14 +13,14 @@
-
+
{{ costCentre.name }}
-
+
{{ costCentre.name }}
diff --git a/overlord/src/app/issue/issue.component.ts b/overlord/src/app/issue/issue.component.ts
index 543d4ac9..e3b2c9ff 100644
--- a/overlord/src/app/issue/issue.component.ts
+++ b/overlord/src/app/issue/issue.component.ts
@@ -7,7 +7,7 @@ import {BehaviorSubject, Observable, of as observableOf} from 'rxjs';
import {debounceTime, distinctUntilChanged, map, startWith, switchMap} from 'rxjs/operators';
import {IssueDataSource} from './issue-datasource';
import {VoucherService} from '../core/voucher.service';
-import {Batch, Inventory, Journal, Voucher} from '../core/voucher';
+import {Batch, Inventory, Voucher} from '../core/voucher';
import * as moment from 'moment';
import {AuthService} from '../auth/auth.service';
import {ConfirmDialogComponent} from '../shared/confirm-dialog/confirm-dialog.component';
@@ -17,7 +17,7 @@ import {BatchService} from '../core/batch.service';
import {IssueGridService} from './issue-grid.service';
import {CostCentre} from '../core/cost-centre';
import {IssueGridDataSource} from './issue-grid-datasource';
-import {Hotkey, HotkeysService} from "angular2-hotkeys";
+import {Hotkey, HotkeysService} from 'angular2-hotkeys';
@Component({
selector: 'app-issue',
@@ -32,8 +32,6 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
dataSource: IssueDataSource;
gridDataSource: IssueGridDataSource;
form: FormGroup;
- sourceJournal: Journal;
- destinationJournal: Journal;
voucher: Voucher;
costCentres: CostCentre[];
batch: Batch;
@@ -74,8 +72,9 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
return false; // Prevent bubbling
}, ['INPUT', 'SELECT', 'TEXTAREA']));
this.hotkeys.add(new Hotkey('ctrl+s', (event: KeyboardEvent): boolean => {
- if (this.canSave())
+ if (this.canSave()) {
this.save();
+ }
return false; // Prevent bubbling
}, ['INPUT', 'SELECT', 'TEXTAREA']));
}
@@ -90,13 +89,11 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
loadVoucher(voucher: Voucher) {
this.voucher = voucher;
- this.sourceJournal = this.voucher.journals.filter(x => x.debit === -1)[0];
- this.destinationJournal = this.voucher.journals.filter(x => x.debit === 1)[0];
this.form.setValue({
date: moment(this.voucher.date, 'DD-MMM-YYYY').toDate(),
- sourceCostCentre: this.sourceJournal.costCentre.id,
- destinationCostCentre: this.destinationJournal.costCentre.id,
- amount: this.sourceJournal.amount,
+ source: this.voucher.source.id,
+ destination: this.voucher.destination.id,
+ amount: Math.abs(this.voucher.inventories.map((x) => x.amount).reduce((p, c) => p + c, 0)),
addRow: {
batch: '',
quantity: ''
@@ -116,10 +113,7 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
addRow() {
const formValue = this.form.get('addRow').value;
const quantity = +(formValue.quantity);
- const isConsumption = this.voucher.journals
- .filter(
- x => x.debit === -1
- )[0].costCentre.id === '7b845f95-dfef-fa4a-897c-f0baf15284a3';
+ const isConsumption = this.form.value.source === '7b845f95-dfef-fa4a-897c-f0baf15284a3';
if (this.batch === null || quantity <= 0) {
return;
}
@@ -169,8 +163,6 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
updateView() {
this.inventoryObservable.next(this.voucher.inventories);
const amount = Math.abs(this.voucher.inventories.map((x) => x.amount).reduce((p, c) => p + c, 0));
- this.sourceJournal.amount = amount;
- this.destinationJournal.amount = amount;
this.form.get('amount').setValue(amount);
}
@@ -201,8 +193,8 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
createForm() {
this.form = this.fb.group({
date: '',
- sourceCostCentre: '',
- destinationCostCentre: '',
+ source: '',
+ destination: '',
amount: {value: '', disabled: true},
addRow: this.fb.group({
batch: '',
@@ -243,8 +235,8 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
getVoucher(): Voucher {
const formModel = this.form.value;
this.voucher.date = moment(formModel.date).format('DD-MMM-YYYY');
- this.sourceJournal.costCentre.id = formModel.sourceCostCentre;
- this.destinationJournal.costCentre.id = formModel.destinationCostCentre;
+ this.voucher.source.id = formModel.source;
+ this.voucher.destination.id = formModel.destination;
this.voucher.narration = formModel.narration;
return this.voucher;
}