DbImage works!!
Credit Salary works!! Refresh router created, now need to use it in angular Errors should now show up in the frontend.
This commit is contained in:
parent
e3286c87ba
commit
10dbe6663d
brewman
overlord/src/app
account/account-detail
attendance
client/client-detail
core
cost-centre/cost-centre-detail
employee-attendance
employee-benefits
employee-functions
employee/employee-detail
incentive
issue
journal
payment
product-group/product-group-detail
product/product-detail
purchase-return
purchase
receipt
role/role-detail
settings
user/user-detail
@ -10,6 +10,8 @@ from .routers import (
|
|||||||
attendance,
|
attendance,
|
||||||
batch,
|
batch,
|
||||||
cost_centre,
|
cost_centre,
|
||||||
|
credit_salary,
|
||||||
|
db_image,
|
||||||
db_integrity,
|
db_integrity,
|
||||||
employee,
|
employee,
|
||||||
employee_attendance,
|
employee_attendance,
|
||||||
@ -61,7 +63,7 @@ app = FastAPI()
|
|||||||
|
|
||||||
|
|
||||||
app.add_middleware(SessionMiddleware, secret_key="c982367648")
|
app.add_middleware(SessionMiddleware, secret_key="c982367648")
|
||||||
# app.include_router(brewman.routers, prefix="/api/db-image", tags=["db-image"])
|
app.include_router(db_image.router, prefix="/db-image", tags=["db-image"])
|
||||||
app.include_router(login.router, tags=["login"])
|
app.include_router(login.router, tags=["login"])
|
||||||
app.include_router(account.router, prefix="/api/accounts", tags=["accounts"])
|
app.include_router(account.router, prefix="/api/accounts", tags=["accounts"])
|
||||||
app.include_router(account_types.router, prefix="/api/account-types", tags=["accounts"])
|
app.include_router(account_types.router, prefix="/api/account-types", tags=["accounts"])
|
||||||
@ -134,6 +136,7 @@ app.include_router(
|
|||||||
employee_benefit.router, prefix="/api/employee-benefit", tags=["vouchers"]
|
employee_benefit.router, prefix="/api/employee-benefit", tags=["vouchers"]
|
||||||
)
|
)
|
||||||
app.include_router(incentive.router, prefix="/api/incentive", tags=["vouchers"])
|
app.include_router(incentive.router, prefix="/api/incentive", tags=["vouchers"])
|
||||||
|
app.include_router(credit_salary.router, prefix="/api/credit-salary", tags=["vouchers"])
|
||||||
|
|
||||||
app.include_router(
|
app.include_router(
|
||||||
lock_information.router, prefix="/api/lock-information", tags=["settings"]
|
lock_information.router, prefix="/api/lock-information", tags=["settings"]
|
||||||
|
@ -366,6 +366,10 @@ class AccountBase(Base):
|
|||||||
def salary(cls):
|
def salary(cls):
|
||||||
return {"id": "5c2b54d0-c174-004d-a0d5-92cdaadcefa7", "name": "Staff Salary"}
|
return {"id": "5c2b54d0-c174-004d-a0d5-92cdaadcefa7", "name": "Staff Salary"}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def salary_id(cls):
|
||||||
|
return uuid.UUID("5c2b54d0-c174-004d-a0d5-92cdaadcefa7")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def incentive(cls):
|
def incentive(cls):
|
||||||
return {"id": "b7eff754-e8ba-e047-ab06-9132c15c7640", "name": "Incentives"}
|
return {"id": "b7eff754-e8ba-e047-ab06-9132c15c7640", "name": "Incentives"}
|
||||||
|
@ -14,7 +14,7 @@ from sqlalchemy import (
|
|||||||
)
|
)
|
||||||
from sqlalchemy.dialects.postgresql import BYTEA
|
from sqlalchemy.dialects.postgresql import BYTEA
|
||||||
from sqlalchemy.ext.hybrid import hybrid_property
|
from sqlalchemy.ext.hybrid import hybrid_property
|
||||||
from sqlalchemy.orm import relationship, synonym, backref
|
from sqlalchemy.orm import relationship, synonym, backref, Session
|
||||||
|
|
||||||
from brewman.models.guidtype import GUID
|
from brewman.models.guidtype import GUID
|
||||||
from brewman.models.master import Product
|
from brewman.models.master import Product
|
||||||
@ -176,14 +176,14 @@ class Journal(Base):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
id=None,
|
id_=None,
|
||||||
debit=None,
|
debit=None,
|
||||||
amount=None,
|
amount=None,
|
||||||
voucher_id=None,
|
voucher_id=None,
|
||||||
account_id=None,
|
account_id=None,
|
||||||
cost_centre_id=None,
|
cost_centre_id=None,
|
||||||
):
|
):
|
||||||
self.id = id
|
self.id = id_
|
||||||
self.debit = debit
|
self.debit = debit
|
||||||
self.amount = amount
|
self.amount = amount
|
||||||
self.voucher_id = voucher_id
|
self.voucher_id = voucher_id
|
||||||
@ -357,14 +357,14 @@ class Batch(Base):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def list(cls, name, include_nil, date, dbsession):
|
def list(cls, name, include_nil, date, db: Session):
|
||||||
query = dbsession.query(Batch).join(Batch.product)
|
query = db.query(Batch).join(Batch.product)
|
||||||
if not include_nil:
|
if not include_nil:
|
||||||
query = query.filter(cls.quantity_remaining > 0)
|
query = query.filter(cls.quantity_remaining > 0)
|
||||||
if date is not None:
|
if date is not None:
|
||||||
query = query.filter(cls.name <= date)
|
query = query.filter(cls.name <= date)
|
||||||
for item in name.split():
|
for item in name.split():
|
||||||
query = query.filter(Product.name.ilike("%" + item + "%"))
|
query = query.filter(Product.name.ilike(f"%{item}%"))
|
||||||
return query.order_by(Product.name).order_by(cls.name).all()
|
return query.order_by(Product.name).order_by(cls.name).all()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -388,7 +388,7 @@ class Attendance(Base):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
id=None,
|
id_=None,
|
||||||
employee_id=None,
|
employee_id=None,
|
||||||
date=None,
|
date=None,
|
||||||
attendance_type=None,
|
attendance_type=None,
|
||||||
@ -397,20 +397,18 @@ class Attendance(Base):
|
|||||||
user_id=None,
|
user_id=None,
|
||||||
is_valid=None,
|
is_valid=None,
|
||||||
):
|
):
|
||||||
self.id = id
|
self.id = id_
|
||||||
self.employee_id = employee_id
|
self.employee_id = employee_id
|
||||||
self.date = date
|
self.date = date
|
||||||
self.attendance_type = attendance_type
|
self.attendance_type = attendance_type
|
||||||
self.amount = amount if amount is not None else 0
|
self.amount = amount if amount is not None else 0
|
||||||
self.creation_date = (
|
self.creation_date = creation_date or datetime.utcnow()
|
||||||
datetime.utcnow() if creation_date is None else creation_date
|
|
||||||
)
|
|
||||||
self.user_id = user_id
|
self.user_id = user_id
|
||||||
self.is_valid = is_valid if is_valid is not None else True
|
self.is_valid = is_valid if is_valid is not None else True
|
||||||
|
|
||||||
def create(self, dbsession):
|
def create(self, db: Session):
|
||||||
old = (
|
old = (
|
||||||
dbsession.query(Attendance)
|
db.query(Attendance)
|
||||||
.filter(Attendance.date == self.date)
|
.filter(Attendance.date == self.date)
|
||||||
.filter(Attendance.employee_id == self.employee_id)
|
.filter(Attendance.employee_id == self.employee_id)
|
||||||
.filter(Attendance.is_valid == True)
|
.filter(Attendance.is_valid == True)
|
||||||
@ -453,13 +451,11 @@ class DbImage(Base):
|
|||||||
image=None,
|
image=None,
|
||||||
thumbnail=None,
|
thumbnail=None,
|
||||||
creation_date=None,
|
creation_date=None,
|
||||||
id=None,
|
id_=None,
|
||||||
):
|
):
|
||||||
self.resource_id = resource_id
|
self.resource_id = resource_id
|
||||||
self.resource_type = resource_type
|
self.resource_type = resource_type
|
||||||
self.image = image
|
self.image = image
|
||||||
self.thumbnail = thumbnail
|
self.thumbnail = thumbnail
|
||||||
self.creation_date = (
|
self.creation_date = creation_date or datetime.utcnow()
|
||||||
datetime.utcnow() if creation_date is None else creation_date
|
self.id = id_
|
||||||
)
|
|
||||||
self.id = id
|
|
||||||
|
@ -5,6 +5,8 @@ from decimal import Decimal
|
|||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from brewman.models.master import DbSetting
|
from brewman.models.master import DbSetting
|
||||||
from brewman.models.voucher import DbImage
|
from brewman.models.voucher import DbImage
|
||||||
|
|
||||||
@ -13,26 +15,10 @@ from fastapi import APIRouter
|
|||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{id}/{type}")
|
def get_lock_info(db: Session) -> (Optional[date], Optional[date]):
|
||||||
def db_image(request):
|
|
||||||
item = (
|
|
||||||
request.dbsession.query(DbImage)
|
|
||||||
.filter(DbImage.id == uuid.UUID(request.matchdict["id"]))
|
|
||||||
.first()
|
|
||||||
)
|
|
||||||
if request.matchdict["type"] == "thumbnail":
|
|
||||||
item = BytesIO(item.thumbnail)
|
|
||||||
else:
|
|
||||||
item = BytesIO(item.image)
|
|
||||||
response = Response(content_type="image/jpeg")
|
|
||||||
response.app_iter = item
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
def get_lock_info(dbsession) -> (Optional[date], Optional[date]):
|
|
||||||
start: Optional[date]
|
start: Optional[date]
|
||||||
finish: Optional[date]
|
finish: Optional[date]
|
||||||
data = dbsession.query(DbSetting).filter(DbSetting.name == "Lock Info").first()
|
data = db.query(DbSetting).filter(DbSetting.name == "Lock Info").first()
|
||||||
if data is None:
|
if data is None:
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
|
101
brewman/routers/credit_salary.py
Normal file
101
brewman/routers/credit_salary.py
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
from calendar import monthrange
|
||||||
|
from datetime import datetime, date
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Depends, Security, Body, HTTPException, status
|
||||||
|
from sqlalchemy import or_
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
from ..core.session import get_first_day, get_last_day
|
||||||
|
from ..schemas.auth import UserToken
|
||||||
|
from ..core.security import get_current_active_user as get_user
|
||||||
|
from ..db.session import SessionLocal
|
||||||
|
from ..models.master import Account, Employee, AttendanceType
|
||||||
|
from ..models.voucher import Voucher, Journal, VoucherType, Attendance
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
# Dependency
|
||||||
|
def get_db() -> Session:
|
||||||
|
try:
|
||||||
|
db = SessionLocal()
|
||||||
|
yield db
|
||||||
|
finally:
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("")
|
||||||
|
def credit_salary(
|
||||||
|
month: str = Body(..., embed=True),
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
user: UserToken = Security(get_user, scopes=["attendance"]),
|
||||||
|
):
|
||||||
|
month = datetime.strptime(month, "%d-%b-%Y").date()
|
||||||
|
|
||||||
|
start_date = get_first_day(month)
|
||||||
|
finish_date = get_last_day(month)
|
||||||
|
voucher = Voucher(
|
||||||
|
date=finish_date,
|
||||||
|
narration="Auto Generated Salary Entry",
|
||||||
|
user_id=user.id_,
|
||||||
|
type_=VoucherType.by_name("Journal"),
|
||||||
|
posted=True,
|
||||||
|
poster_id=user.id_,
|
||||||
|
)
|
||||||
|
db.add(voucher)
|
||||||
|
for item in salary_journals(start_date, finish_date, db):
|
||||||
|
voucher.journals.append(item)
|
||||||
|
db.add(item)
|
||||||
|
db.commit()
|
||||||
|
return {"message": "Salary Entry created"}
|
||||||
|
|
||||||
|
|
||||||
|
def salary_journals(start_date: date, finish_date: date, db: Session):
|
||||||
|
days = monthrange(start_date.year, start_date.month)[1]
|
||||||
|
amount = 0
|
||||||
|
journals = []
|
||||||
|
employees = (
|
||||||
|
db.query(Employee)
|
||||||
|
.filter(Employee.joining_date <= finish_date)
|
||||||
|
.filter(or_(Employee.is_active, Employee.leaving_date >= start_date))
|
||||||
|
.order_by(Employee.cost_centre_id)
|
||||||
|
.order_by(Employee.designation)
|
||||||
|
.order_by(Employee.name)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
for employee in employees:
|
||||||
|
att = (
|
||||||
|
db.query(Attendance)
|
||||||
|
.filter(Attendance.employee_id == employee.id)
|
||||||
|
.filter(Attendance.date >= start_date)
|
||||||
|
.filter(Attendance.date <= finish_date)
|
||||||
|
.filter(Attendance.is_valid == True)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
att = sum(map(lambda x: AttendanceType.by_id(x.attendance_type).value, att))
|
||||||
|
att = round(att * employee.salary / days)
|
||||||
|
if att != 0:
|
||||||
|
amount += att
|
||||||
|
journals.append(
|
||||||
|
Journal(
|
||||||
|
amount=att,
|
||||||
|
debit=-1,
|
||||||
|
account_id=employee.id,
|
||||||
|
cost_centre_id=employee.cost_centre_id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
salary = db.query(Account).filter(Account.id == Account.salary_id()).first()
|
||||||
|
if amount == 0:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail="No salaries to credit",
|
||||||
|
)
|
||||||
|
journals.append(
|
||||||
|
Journal(
|
||||||
|
amount=amount,
|
||||||
|
debit=1,
|
||||||
|
account_id=salary.id,
|
||||||
|
cost_centre_id=salary.cost_centre_id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return journals
|
36
brewman/routers/db_image.py
Normal file
36
brewman/routers/db_image.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import uuid
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Depends, Security
|
||||||
|
from fastapi.responses import StreamingResponse
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
from ..core.security import get_user
|
||||||
|
from ..models.voucher import DbImage
|
||||||
|
from ..db.session import SessionLocal
|
||||||
|
from ..schemas.auth import UserToken
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
# Dependency
|
||||||
|
def get_db() -> Session:
|
||||||
|
try:
|
||||||
|
db = SessionLocal()
|
||||||
|
yield db
|
||||||
|
finally:
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/{id_}/{type_}")
|
||||||
|
def db_image(
|
||||||
|
id_: uuid.UUID,
|
||||||
|
type_: str,
|
||||||
|
db: Session = Depends(get_db)
|
||||||
|
):
|
||||||
|
item = db.query(DbImage).filter(DbImage.id == id_).first()
|
||||||
|
if type_ == "thumbnail":
|
||||||
|
item = BytesIO(item.thumbnail)
|
||||||
|
else:
|
||||||
|
item = BytesIO(item.image)
|
||||||
|
return StreamingResponse(item, media_type="image/jpeg")
|
@ -26,7 +26,7 @@ from ..models import AccountBase
|
|||||||
from ..schemas.auth import UserToken
|
from ..schemas.auth import UserToken
|
||||||
from ..core.security import get_current_active_user as get_user
|
from ..core.security import get_current_active_user as get_user
|
||||||
from ..db.session import SessionLocal
|
from ..db.session import SessionLocal
|
||||||
from ..models.voucher import Voucher, VoucherType, Journal
|
from ..models.voucher import Voucher, VoucherType, Journal, DbImage
|
||||||
import brewman.schemas.voucher as output
|
import brewman.schemas.voucher as output
|
||||||
import brewman.schemas.input as schema_in
|
import brewman.schemas.input as schema_in
|
||||||
|
|
||||||
@ -47,15 +47,14 @@ def save_route(
|
|||||||
request: Request,
|
request: Request,
|
||||||
data: schema_in.JournalIn = Depends(schema_in.JournalIn.load_form),
|
data: schema_in.JournalIn = Depends(schema_in.JournalIn.load_form),
|
||||||
db: Session = Depends(get_db),
|
db: Session = Depends(get_db),
|
||||||
i: List[UploadFile] = File(None),
|
i: List[bytes] = File(None),
|
||||||
t: List[UploadFile] = File(None),
|
t: List[bytes] = File(None),
|
||||||
user: UserToken = Security(get_user, scopes=["journal"]),
|
user: UserToken = Security(get_user, scopes=["journal"]),
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
i = i or []
|
|
||||||
t = t or []
|
|
||||||
item: Voucher = save(data, user, db)
|
item: Voucher = save(data, user, db)
|
||||||
save_files(i + t, db)
|
db.flush()
|
||||||
|
save_files(item.id, i, t, db)
|
||||||
db.commit()
|
db.commit()
|
||||||
set_date(data.date_.strftime("%d-%b-%Y"), request.session)
|
set_date(data.date_.strftime("%d-%b-%Y"), request.session)
|
||||||
info = voucher_info(item, db)
|
info = voucher_info(item, db)
|
||||||
@ -66,11 +65,7 @@ def save_route(
|
|||||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e),
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
db.rollback()
|
raise
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
||||||
detail=traceback.format_exc(),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def save(data: schema_in.JournalIn, user: UserToken, db: Session) -> Voucher:
|
def save(data: schema_in.JournalIn, user: UserToken, db: Session) -> Voucher:
|
||||||
@ -88,7 +83,6 @@ def save(data: schema_in.JournalIn, user: UserToken, db: Session) -> Voucher:
|
|||||||
AccountBase.id == item.account.id_
|
AccountBase.id == item.account.id_
|
||||||
).first()
|
).first()
|
||||||
journal = Journal(
|
journal = Journal(
|
||||||
id=item.id_,
|
|
||||||
amount=item.amount,
|
amount=item.amount,
|
||||||
debit=item.debit,
|
debit=item.debit,
|
||||||
account_id=account.id,
|
account_id=account.id,
|
||||||
@ -99,10 +93,9 @@ def save(data: schema_in.JournalIn, user: UserToken, db: Session) -> Voucher:
|
|||||||
return voucher
|
return voucher
|
||||||
|
|
||||||
|
|
||||||
def save_files(files: List[UploadFile], db: Session):
|
def save_files(voucher_id: uuid.UUID, i: List[bytes], t: List[bytes], db: Session):
|
||||||
# for key, value in files.items():
|
for index, value in enumerate(i):
|
||||||
# db.add(DbImage(voucher.id, "voucher", value["f"], value["t"]))
|
db.add(DbImage(voucher_id, "voucher", i[index], t[index]))
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@router.put("/{id_}", response_model=output.Voucher)
|
@router.put("/{id_}", response_model=output.Voucher)
|
||||||
@ -111,15 +104,13 @@ def update_route(
|
|||||||
request: Request,
|
request: Request,
|
||||||
data: schema_in.JournalIn = Depends(schema_in.JournalIn.load_form),
|
data: schema_in.JournalIn = Depends(schema_in.JournalIn.load_form),
|
||||||
db: Session = Depends(get_db),
|
db: Session = Depends(get_db),
|
||||||
i: List[UploadFile] = File(None),
|
i: List[bytes] = File(None),
|
||||||
t: List[UploadFile] = File(None),
|
t: List[bytes] = File(None),
|
||||||
user: UserToken = Security(get_user, scopes=["journal"]),
|
user: UserToken = Security(get_user, scopes=["journal"]),
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
i = i or []
|
|
||||||
t = t or []
|
|
||||||
item: Voucher = update(id_, data, user, db)
|
item: Voucher = update(id_, data, user, db)
|
||||||
update_files(data, i + t, db)
|
update_files(item.id, data.files, i, t, db)
|
||||||
db.commit()
|
db.commit()
|
||||||
set_date(data.date_.strftime("%d-%b-%Y"), request.session)
|
set_date(data.date_.strftime("%d-%b-%Y"), request.session)
|
||||||
return voucher_info(item, db)
|
return voucher_info(item, db)
|
||||||
@ -174,7 +165,6 @@ def update(
|
|||||||
db.query(AccountBase).filter(AccountBase.id == new_item.account.id_).first()
|
db.query(AccountBase).filter(AccountBase.id == new_item.account.id_).first()
|
||||||
)
|
)
|
||||||
journal = Journal(
|
journal = Journal(
|
||||||
id=None,
|
|
||||||
amount=new_item.amount,
|
amount=new_item.amount,
|
||||||
debit=new_item.debit,
|
debit=new_item.debit,
|
||||||
account_id=account.id,
|
account_id=account.id,
|
||||||
@ -185,16 +175,13 @@ def update(
|
|||||||
return voucher
|
return voucher
|
||||||
|
|
||||||
|
|
||||||
def update_files(data: schema_in.VoucherIn, files: List[UploadFile], db: Session):
|
def update_files(voucher_id: uuid.UUID, data: List[output.ImageUpload], i: List[bytes], t: List[bytes], db: Session):
|
||||||
pass
|
old = [f.id_ for f in data if f.id_]
|
||||||
# old_files = [
|
images = db.query(DbImage).filter(DbImage.resource_id == voucher_id).all()
|
||||||
# uuid.UUID(f["id"]) for f in json["files"] if "id" in f and f["id"] is not None
|
for image in [i for i in images if i.id not in old]:
|
||||||
# ]
|
db.delete(image)
|
||||||
# images = db.query(DbImage).filter(DbImage.resource_id == voucher.id).all()
|
for index, value in enumerate(i):
|
||||||
# for image in [i for i in images if i.id not in old_files]:
|
db.add(DbImage(voucher_id, "voucher", i[index], t[index]))
|
||||||
# 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)
|
@router.get("/{id_}", response_model=output.Voucher)
|
||||||
|
@ -7,9 +7,10 @@ from ..core.security import (
|
|||||||
Token,
|
Token,
|
||||||
authenticate_user,
|
authenticate_user,
|
||||||
ACCESS_TOKEN_EXPIRE_MINUTES,
|
ACCESS_TOKEN_EXPIRE_MINUTES,
|
||||||
create_access_token,
|
create_access_token, get_user,
|
||||||
)
|
)
|
||||||
from ..db.session import SessionLocal
|
from ..db.session import SessionLocal
|
||||||
|
from ..schemas.auth import UserToken
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
@ -54,3 +55,21 @@ async def login_for_access_token(
|
|||||||
expires_delta=access_token_expires,
|
expires_delta=access_token_expires,
|
||||||
)
|
)
|
||||||
return {"access_token": access_token, "token_type": "bearer"}
|
return {"access_token": access_token, "token_type": "bearer"}
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/refresh", response_model=Token)
|
||||||
|
async def refresh_token(
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
user: UserToken = Depends(get_user)
|
||||||
|
):
|
||||||
|
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||||
|
access_token = create_access_token(
|
||||||
|
data={
|
||||||
|
"sub": user.name,
|
||||||
|
"scopes": user.permissions,
|
||||||
|
"userId": str(user.id_),
|
||||||
|
"lockedOut": user.locked_out,
|
||||||
|
},
|
||||||
|
expires_delta=access_token_expires,
|
||||||
|
)
|
||||||
|
return {"access_token": access_token, "token_type": "bearer"}
|
||||||
|
@ -283,7 +283,7 @@ def voucher_info(voucher, db):
|
|||||||
)
|
)
|
||||||
images = db.query(DbImage).filter(DbImage.resource_id == voucher.id).all()
|
images = db.query(DbImage).filter(DbImage.resource_id == voucher.id).all()
|
||||||
for image in images:
|
for image in images:
|
||||||
json_voucher["files"].append({"id": image.id, "resized": "", "thumbnail": ""})
|
json_voucher["files"].append({"id": image.id, "resized": f"/db-image/{image.id}/resized", "thumbnail": f"/db-image/{image.id}/thumbnail"})
|
||||||
return json_voucher
|
return json_voucher
|
||||||
|
|
||||||
|
|
||||||
@ -301,6 +301,7 @@ def blank_voucher(info, db):
|
|||||||
"narration": "",
|
"narration": "",
|
||||||
"journals": [],
|
"journals": [],
|
||||||
"inventories": [],
|
"inventories": [],
|
||||||
|
"employeeBenefits": [],
|
||||||
}
|
}
|
||||||
if type_ == "Journal":
|
if type_ == "Journal":
|
||||||
pass
|
pass
|
||||||
|
@ -1,87 +0,0 @@
|
|||||||
import calendar
|
|
||||||
import datetime
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
from sqlalchemy import or_
|
|
||||||
from ....models.auth import User
|
|
||||||
from ....models.master import Employee, AttendanceType, Account
|
|
||||||
from ....models.voucher import Voucher, VoucherType, Attendance, Journal
|
|
||||||
from ..session import get_first_day, get_last_day
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/api/credit-salary") # "Attendance"
|
|
||||||
def credit_salary(request):
|
|
||||||
user = (
|
|
||||||
request.dbsession.query(User)
|
|
||||||
.filter(User.id == uuid.UUID(request.authenticated_userid))
|
|
||||||
.one()
|
|
||||||
)
|
|
||||||
month = datetime.datetime.strptime(request.json_body["month"], "%d-%b-%Y")
|
|
||||||
|
|
||||||
start_date = get_first_day(month)
|
|
||||||
finish_date = get_last_day(month)
|
|
||||||
voucher = Voucher(
|
|
||||||
date=finish_date,
|
|
||||||
narration="Auto Generated Salary Entry",
|
|
||||||
user_id=user.id,
|
|
||||||
type=VoucherType.by_name("Journal"),
|
|
||||||
posted=True,
|
|
||||||
poster_id=user.id,
|
|
||||||
)
|
|
||||||
request.dbsession.add(voucher)
|
|
||||||
for item in salary_journals(start_date, finish_date, request.dbsession):
|
|
||||||
voucher.journals.append(item)
|
|
||||||
request.dbsession.add(item)
|
|
||||||
transaction.commit()
|
|
||||||
return {"message": "Salary Entry created"}
|
|
||||||
|
|
||||||
|
|
||||||
def salary_journals(start_date, finish_date, dbsession):
|
|
||||||
days = calendar.monthrange(start_date.year, start_date.month)[1]
|
|
||||||
finish_date = finish_date + datetime.timedelta(1)
|
|
||||||
amount = 0
|
|
||||||
journals = []
|
|
||||||
employees = (
|
|
||||||
dbsession.query(Employee)
|
|
||||||
.filter(Employee.joining_date <= finish_date)
|
|
||||||
.filter(or_(Employee.is_active, Employee.leaving_date >= start_date))
|
|
||||||
.order_by(Employee.cost_centre_id)
|
|
||||||
.order_by(Employee.designation)
|
|
||||||
.order_by(Employee.name)
|
|
||||||
.all()
|
|
||||||
)
|
|
||||||
for employee in employees:
|
|
||||||
att = (
|
|
||||||
dbsession.query(Attendance)
|
|
||||||
.filter(Attendance.employee_id == employee.id)
|
|
||||||
.filter(Attendance.date >= start_date)
|
|
||||||
.filter(Attendance.date < finish_date)
|
|
||||||
.filter(Attendance.is_valid == True)
|
|
||||||
.all()
|
|
||||||
)
|
|
||||||
att = sum(map(lambda x: AttendanceType.by_id(x.attendance_type).value, att))
|
|
||||||
att = round(att * employee.salary / days)
|
|
||||||
if att != 0:
|
|
||||||
amount += att
|
|
||||||
journals.append(
|
|
||||||
Journal(
|
|
||||||
amount=att,
|
|
||||||
debit=-1,
|
|
||||||
account_id=employee.id,
|
|
||||||
cost_centre_id=employee.cost_centre_id,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
salary = (
|
|
||||||
dbsession.query(Account)
|
|
||||||
.filter(Account.id == uuid.UUID(Account.salary()["id"]))
|
|
||||||
.first()
|
|
||||||
)
|
|
||||||
journals.append(
|
|
||||||
Journal(
|
|
||||||
amount=amount,
|
|
||||||
debit=1,
|
|
||||||
account_id=salary.id,
|
|
||||||
cost_centre_id=salary.cost_centre_id,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return journals
|
|
@ -1,27 +0,0 @@
|
|||||||
from ....core.session import get_date
|
|
||||||
from brewman.routers.services.voucher import blank_voucher
|
|
||||||
|
|
||||||
|
|
||||||
class EmptyVoucher(object):
|
|
||||||
def __init__(self, request):
|
|
||||||
self.request = request
|
|
||||||
|
|
||||||
@router.get("/api/voucher", request_param="t=Incentive") # "Incentive"
|
|
||||||
def incentive(self):
|
|
||||||
voucher_type = self.request.GET.get("t", None)
|
|
||||||
date = self.request.GET.get("d", None)
|
|
||||||
if date is not None:
|
|
||||||
return blank_voucher(
|
|
||||||
{"type": voucher_type, "date": date}, self.request.dbsession
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return self.get_blank()
|
|
||||||
|
|
||||||
def get_blank(self, additional_info=None):
|
|
||||||
voucher_type = self.request.GET.get("t", None)
|
|
||||||
if additional_info is None:
|
|
||||||
additional_info = {}
|
|
||||||
additional_info["date"] = get_date(self.request)
|
|
||||||
additional_info["type"] = voucher_type
|
|
||||||
|
|
||||||
return blank_voucher(additional_info, self.request.dbsession)
|
|
@ -16,6 +16,15 @@ from brewman.schemas.master import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ImageUpload(BaseModel):
|
||||||
|
id_: Optional[uuid.UUID]
|
||||||
|
resized: Optional[str]
|
||||||
|
thumbnail: Optional[str]
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
alias_generator = to_camel
|
||||||
|
|
||||||
|
|
||||||
class UserLink(BaseModel):
|
class UserLink(BaseModel):
|
||||||
id_: uuid.UUID
|
id_: uuid.UUID
|
||||||
name: str
|
name: str
|
||||||
@ -94,6 +103,7 @@ class VoucherIn(BaseModel):
|
|||||||
narration: str
|
narration: str
|
||||||
is_starred: bool
|
is_starred: bool
|
||||||
type_: str
|
type_: str
|
||||||
|
files: List[ImageUpload]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load_form(cls, data: str = Form(...)):
|
def load_form(cls, data: str = Form(...)):
|
||||||
@ -118,7 +128,7 @@ class Voucher(VoucherIn):
|
|||||||
incentives: Optional[List[Incentive]]
|
incentives: Optional[List[Incentive]]
|
||||||
incentive: Optional[Decimal]
|
incentive: Optional[Decimal]
|
||||||
employee_benefits: List[EmployeeBenefit]
|
employee_benefits: List[EmployeeBenefit]
|
||||||
files: List[Any]
|
files: List[ImageUpload]
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
anystr_strip_whitespace = True
|
anystr_strip_whitespace = True
|
||||||
|
@ -78,7 +78,7 @@ export class AccountDetailComponent implements OnInit, AfterViewInit {
|
|||||||
this.router.navigateByUrl('/accounts');
|
this.router.navigateByUrl('/accounts');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -91,7 +91,7 @@ export class AccountDetailComponent implements OnInit, AfterViewInit {
|
|||||||
this.router.navigateByUrl('/accounts');
|
this.router.navigateByUrl('/accounts');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ export class AttendanceComponent implements OnInit {
|
|||||||
this.toaster.show('Success', '');
|
this.toaster.show('Success', '');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ export class ClientDetailComponent implements OnInit, AfterViewInit {
|
|||||||
this.router.navigateByUrl('/clients');
|
this.router.navigateByUrl('/clients');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ export class ClientDetailComponent implements OnInit, AfterViewInit {
|
|||||||
this.router.navigateByUrl('/clients');
|
this.router.navigateByUrl('/clients');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ export class ErrorLoggerService {
|
|||||||
console.error(error); // log to console instead
|
console.error(error); // log to console instead
|
||||||
|
|
||||||
// TODO: better job of transforming error for user consumption
|
// TODO: better job of transforming error for user consumption
|
||||||
this.log(serviceName, `${operation} failed: ${error.message}`);
|
this.log(serviceName, `${operation} failed: ${error}`);
|
||||||
|
|
||||||
// // Let the app keep running by returning an empty result.
|
// // Let the app keep running by returning an empty result.
|
||||||
// return of(result as T);
|
// return of(result as T);
|
||||||
|
@ -60,7 +60,7 @@ export class CostCentreDetailComponent implements OnInit, AfterViewInit {
|
|||||||
this.router.navigateByUrl('/cost-centres');
|
this.router.navigateByUrl('/cost-centres');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,7 @@ export class EmployeeAttendanceComponent implements OnInit, AfterViewInit {
|
|||||||
this.toaster.show('Success', '');
|
this.toaster.show('Success', '');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -185,7 +185,7 @@ export class EmployeeBenefitsComponent implements OnInit, AfterViewInit {
|
|||||||
this.toaster.show('Success', 'Voucher Posted');
|
this.toaster.show('Success', 'Voucher Posted');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -198,7 +198,7 @@ export class EmployeeBenefitsComponent implements OnInit, AfterViewInit {
|
|||||||
this.router.navigate(['/employee-benefits', result.id]);
|
this.router.navigate(['/employee-benefits', result.id]);
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -217,7 +217,7 @@ export class EmployeeBenefitsComponent implements OnInit, AfterViewInit {
|
|||||||
this.router.navigate(['/employee-benefits'], {replaceUrl: true});
|
this.router.navigate(['/employee-benefits'], {replaceUrl: true});
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,8 @@ export class EmployeeFunctionsComponent implements OnInit {
|
|||||||
this.toaster.show('Success', 'Salaries Credited');
|
this.toaster.show('Success', 'Salaries Credited');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
console.log('Error:', error);
|
||||||
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -109,7 +110,7 @@ export class EmployeeFunctionsComponent implements OnInit {
|
|||||||
this.toaster.show('Success', 'Fingerprints uploaded');
|
this.toaster.show('Success', 'Fingerprints uploaded');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,7 @@ export class EmployeeDetailComponent implements OnInit, AfterViewInit {
|
|||||||
this.router.navigateByUrl('/employees');
|
this.router.navigateByUrl('/employees');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -103,7 +103,7 @@ export class EmployeeDetailComponent implements OnInit, AfterViewInit {
|
|||||||
this.router.navigateByUrl('/employees');
|
this.router.navigateByUrl('/employees');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,7 @@ export class IncentiveComponent implements OnInit {
|
|||||||
this.toaster.show('Success', 'Voucher Posted');
|
this.toaster.show('Success', 'Voucher Posted');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -153,7 +153,7 @@ export class IncentiveComponent implements OnInit {
|
|||||||
this.router.navigate(['/incentive', result.id]);
|
this.router.navigate(['/incentive', result.id]);
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -176,7 +176,7 @@ export class IncentiveComponent implements OnInit {
|
|||||||
this.router.navigate(['/incentive'], {replaceUrl: true});
|
this.router.navigate(['/incentive'], {replaceUrl: true});
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -223,7 +223,7 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.router.navigate(['/issue', result.id]);
|
this.router.navigate(['/issue', result.id]);
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -249,7 +249,7 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.router.navigate(['/issue'], {replaceUrl: true});
|
this.router.navigate(['/issue'], {replaceUrl: true});
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -218,7 +218,7 @@ export class JournalComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.toaster.show('Success', 'Voucher Posted');
|
this.toaster.show('Success', 'Voucher Posted');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -232,7 +232,7 @@ export class JournalComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.router.navigate(['/journal', result.id]);
|
this.router.navigate(['/journal', result.id]);
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -252,7 +252,7 @@ export class JournalComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.router.navigate(['/journal'], {replaceUrl: true});
|
this.router.navigate(['/journal'], {replaceUrl: true});
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -222,7 +222,7 @@ export class PaymentComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.toaster.show('Success', 'Voucher Posted');
|
this.toaster.show('Success', 'Voucher Posted');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -236,7 +236,7 @@ export class PaymentComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.router.navigate(['/payment', result.id]);
|
this.router.navigate(['/payment', result.id]);
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -257,7 +257,7 @@ export class PaymentComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.router.navigate(['/payment'], {replaceUrl: true});
|
this.router.navigate(['/payment'], {replaceUrl: true});
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ export class ProductGroupDetailComponent implements OnInit, AfterViewInit {
|
|||||||
this.router.navigateByUrl('/product-groups');
|
this.router.navigateByUrl('/product-groups');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
|||||||
this.router.navigateByUrl('/products');
|
this.router.navigateByUrl('/products');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -100,7 +100,7 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
|
|||||||
this.router.navigateByUrl('/products');
|
this.router.navigateByUrl('/products');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -209,7 +209,7 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy
|
|||||||
this.toaster.show('Success', 'Voucher Posted');
|
this.toaster.show('Success', 'Voucher Posted');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -223,7 +223,7 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy
|
|||||||
this.router.navigate(['/purchase-return', result.id]);
|
this.router.navigate(['/purchase-return', result.id]);
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -244,7 +244,7 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy
|
|||||||
this.router.navigate(['/purchase-return'], {replaceUrl: true});
|
this.router.navigate(['/purchase-return'], {replaceUrl: true});
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -222,7 +222,7 @@ export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.toaster.show('Success', 'Voucher Posted');
|
this.toaster.show('Success', 'Voucher Posted');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -236,7 +236,7 @@ export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.router.navigate(['/purchase', result.id]);
|
this.router.navigate(['/purchase', result.id]);
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -257,7 +257,7 @@ export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.router.navigate(['/purchase'], {replaceUrl: true});
|
this.router.navigate(['/purchase'], {replaceUrl: true});
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -221,7 +221,7 @@ export class ReceiptComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.toaster.show('Success', 'Voucher Posted');
|
this.toaster.show('Success', 'Voucher Posted');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -235,7 +235,7 @@ export class ReceiptComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.router.navigate(['/receipt', result.id]);
|
this.router.navigate(['/receipt', result.id]);
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -256,7 +256,7 @@ export class ReceiptComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.router.navigate(['/receipt'], {replaceUrl: true});
|
this.router.navigate(['/receipt'], {replaceUrl: true});
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ export class RoleDetailComponent implements OnInit, AfterViewInit {
|
|||||||
this.router.navigateByUrl('/roles');
|
this.router.navigateByUrl('/roles');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -78,7 +78,7 @@ export class RoleDetailComponent implements OnInit, AfterViewInit {
|
|||||||
this.router.navigateByUrl('/roles');
|
this.router.navigateByUrl('/roles');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,7 @@ export class SettingsComponent implements OnInit {
|
|||||||
this.toaster.show('Success', 'Lock information Updated');
|
this.toaster.show('Success', 'Lock information Updated');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -162,7 +162,7 @@ export class SettingsComponent implements OnInit {
|
|||||||
this.toaster.show('Success', 'Data has been rebased!');
|
this.toaster.show('Success', 'Data has been rebased!');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -213,7 +213,7 @@ export class SettingsComponent implements OnInit {
|
|||||||
this.toaster.show('Success', 'Stock has been reset!');
|
this.toaster.show('Success', 'Stock has been reset!');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -227,7 +227,7 @@ export class SettingsComponent implements OnInit {
|
|||||||
this.toaster.show('Success', 'Database checked, it is fine!');
|
this.toaster.show('Success', 'Database checked, it is fine!');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ export class UserDetailComponent implements OnInit, AfterViewInit {
|
|||||||
this.router.navigateByUrl('/users');
|
this.router.navigateByUrl('/users');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -89,7 +89,7 @@ export class UserDetailComponent implements OnInit, AfterViewInit {
|
|||||||
this.router.navigateByUrl('/users');
|
this.router.navigateByUrl('/users');
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
this.toaster.show('Danger', error.error);
|
this.toaster.show('Danger', error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,8 @@ fastapi
|
|||||||
environs
|
environs
|
||||||
python-jose[cryptography]
|
python-jose[cryptography]
|
||||||
passlib[bcrypt]
|
passlib[bcrypt]
|
||||||
psycopg2
|
psycopg2-binary
|
||||||
|
sqlalchemy
|
||||||
python-multipart
|
python-multipart
|
||||||
pyjwt
|
pyjwt
|
||||||
alembic
|
alembic
|
||||||
|
Loading…
x
Reference in New Issue
Block a user