Renamed "Salary Deduction" to "Employee Benefit"
Journal, Purchase and Purchase Return vouchers done!! Changed the column type of "date" columns from "datetime" to better fit the data.
This commit is contained in:
parent
a0f27fe364
commit
98edca5f60
alembic/versions
03ea3e9cb1e5_rename_further.py5498fc4bf58d_rename_service_charge_to_incentive.pyeed0b382c287_lowercase_fastapi.py
brewman
db
main.pymodels
routers
schemas
scripts
overlord/src/app
core
employee-benefits
incentive
issue
journal
payment
purchase-return
purchase
receipt
@ -1,54 +0,0 @@
|
||||
"""test
|
||||
|
||||
Revision ID: 03ea3e9cb1e5
|
||||
Revises: 5498fc4bf58d
|
||||
Create Date: 2020-05-14 21:25:08.945280
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '03ea3e9cb1e5'
|
||||
down_revision = '5498fc4bf58d'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table("attendances") as batch_op:
|
||||
batch_op.alter_column('date', type_=sa.Date(), nullable=False)
|
||||
with op.batch_alter_table("employees") as batch_op:
|
||||
batch_op.alter_column('Designation', new_column_name='designation', nullable=False)
|
||||
batch_op.alter_column('Salary', new_column_name='salary', nullable=False)
|
||||
batch_op.alter_column('ServicePoints', new_column_name='points', nullable=False)
|
||||
batch_op.alter_column('JoiningDate', new_column_name='joining_date', type_=sa.Date(), nullable=False)
|
||||
batch_op.alter_column('LeavingDate', new_column_name='leaving_date', type_=sa.Date(), nullable=True)
|
||||
with op.batch_alter_table("settings") as batch_op:
|
||||
batch_op.alter_column('SettingID', new_column_name='id')
|
||||
batch_op.alter_column('Name', new_column_name='name')
|
||||
batch_op.alter_column('Data', new_column_name='data')
|
||||
op.create_unique_constraint(op.f('uq_settings_name'), 'settings', ['name'])
|
||||
op.drop_constraint('uq_settings_Name', 'settings', type_='unique')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table("attendances") as batch_op:
|
||||
batch_op.alter_column('date', type_=sa.DateTime())
|
||||
with op.batch_alter_table("employees") as batch_op:
|
||||
batch_op.alter_column('designation', new_column_name='Designation', nullable=True)
|
||||
batch_op.alter_column('salary', new_column_name='Salary', nullable=True)
|
||||
batch_op.alter_column('points', new_column_name='ServicePoints', nullable=True)
|
||||
batch_op.alter_column('joining_date', new_column_name='JoiningDate', type_=sa.DateTime(), nullable=True)
|
||||
batch_op.alter_column('leaving_date', new_column_name='LeavingDate', type_=sa.DateTime(), nullable=True)
|
||||
with op.batch_alter_table("settings") as batch_op:
|
||||
batch_op.alter_column('id', new_column_name='SettingID')
|
||||
batch_op.alter_column('name', new_column_name='Name')
|
||||
batch_op.alter_column('data', new_column_name='Data')
|
||||
op.create_unique_constraint('uq_settings_Name', 'settings', ['name'])
|
||||
op.drop_constraint(op.f('uq_settings_name'), 'settings', type_='unique')
|
||||
# ### end Alembic commands ###
|
@ -1,46 +0,0 @@
|
||||
"""Rename Service Charge to Incentive
|
||||
|
||||
Revision ID: 5498fc4bf58d
|
||||
Revises: eed0b382c287
|
||||
Create Date: 2020-05-12 16:39:12.157447
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.sql import table, column
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '5498fc4bf58d'
|
||||
down_revision = 'eed0b382c287'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_constraint('service_charges_journal_id_fkey', 'service_charges', type_='foreignkey')
|
||||
op.drop_constraint('service_charges_voucher_id_fkey', 'service_charges', type_='foreignkey')
|
||||
op.rename_table('service_charges', 'incentives')
|
||||
op.create_foreign_key('fk_incentives_journal_id_journals', 'incentives', 'journals', ['journal_id'], ['id'])
|
||||
op.create_foreign_key('fk_incentives_voucher_id_vouchers', 'incentives', 'vouchers', ['voucher_id'], ['id'])
|
||||
|
||||
role = table('auth_roles', column('name', sa.String))
|
||||
op.execute(role.update().where(role.c.name == op.inline_literal('Service Charge')).values({'name': op.inline_literal('Incentive')}))
|
||||
account = table('accounts', column('name', sa.String))
|
||||
op.execute(account.update().where(account.c.name == op.inline_literal('Service Charges')).values({'name': op.inline_literal('Incentives')}))
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_constraint('fk_incentives_journal_id_journals', 'incentives', type_='foreignkey')
|
||||
op.drop_constraint('fk_incentives_voucher_id_vouchers', 'incentives', type_='foreignkey')
|
||||
op.rename_table('incentives', 'service_charges')
|
||||
op.create_foreign_key('service_charges_journal_id_fkey', 'service_charges', 'journals', ['journal_id'], ['journals.id'])
|
||||
op.create_foreign_key('service_charges_voucher_id_fkey', 'service_charges', 'vouchers', ['voucher_id'], ['vouchers.id'])
|
||||
|
||||
role = table('auth_roles', column('name', sa.String))
|
||||
op.execute(role.update().where(role.c.name == op.inline_literal('Incentive')).values({'name': op.inline_literal('Service Charge')}))
|
||||
account = table('accounts', column('name', sa.String))
|
||||
op.execute(account.update().where(account.c.name == op.inline_literal('Incentives')).values({'name': op.inline_literal('Service Charges')}))
|
||||
# ### end Alembic commands ###
|
@ -7,6 +7,7 @@ Create Date: 2020-05-10 19:52:58.163810
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import table, column
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
@ -51,7 +52,7 @@ def upgrade():
|
||||
batch_op.alter_column('UserID', new_column_name='user_id')
|
||||
batch_op.alter_column('AttendanceType', new_column_name='attendance_type')
|
||||
batch_op.alter_column('CreationDate', new_column_name='creation_date')
|
||||
batch_op.alter_column('Date', new_column_name='date')
|
||||
batch_op.alter_column('Date', new_column_name='date', type_=sa.Date(), nullable=False)
|
||||
batch_op.alter_column('EmployeeID', new_column_name='employee_id')
|
||||
batch_op.alter_column('AttendanceID', new_column_name='id')
|
||||
batch_op.alter_column('IsValid', new_column_name='is_valid')
|
||||
@ -65,7 +66,7 @@ def upgrade():
|
||||
with op.batch_alter_table("batches") as batch_op:
|
||||
batch_op.alter_column('BatchID', new_column_name='id')
|
||||
batch_op.alter_column('Discount', new_column_name='discount')
|
||||
batch_op.alter_column('Name', new_column_name='name')
|
||||
batch_op.alter_column('Name', new_column_name='name', type_=sa.Date(), nullable=False)
|
||||
batch_op.alter_column('ProductID', new_column_name='product_id')
|
||||
batch_op.alter_column('QuantityRemaining', new_column_name='quantity_remaining')
|
||||
batch_op.alter_column('Rate', new_column_name='rate')
|
||||
@ -118,7 +119,8 @@ def upgrade():
|
||||
with op.batch_alter_table("recipes") as batch_op:
|
||||
batch_op.alter_column('recipe_id', new_column_name='id')
|
||||
|
||||
with op.batch_alter_table("salary_deductions") as batch_op:
|
||||
op.rename_table('salary_deductions', 'employee_benefit')
|
||||
with op.batch_alter_table("employee_benefit") as batch_op:
|
||||
batch_op.alter_column('SalaryDeductionID', new_column_name='id')
|
||||
batch_op.alter_column('DaysWorked', new_column_name='days_worked')
|
||||
batch_op.alter_column('EsiEmployee', new_column_name='esi_employee')
|
||||
@ -131,6 +133,23 @@ def upgrade():
|
||||
|
||||
with op.batch_alter_table("vouchers") as batch_op:
|
||||
batch_op.alter_column('VoucherID', new_column_name='id')
|
||||
batch_op.alter_column('date', type_=sa.Date(), nullable=False)
|
||||
batch_op.alter_column('reconcile_date', type_=sa.Date(), nullable=False)
|
||||
|
||||
op.rename_table('service_charges', 'incentives')
|
||||
|
||||
with op.batch_alter_table("employees") as batch_op:
|
||||
batch_op.alter_column('Designation', new_column_name='designation', nullable=False)
|
||||
batch_op.alter_column('Salary', new_column_name='salary', nullable=False)
|
||||
batch_op.alter_column('ServicePoints', new_column_name='points', nullable=False)
|
||||
batch_op.alter_column('JoiningDate', new_column_name='joining_date', type_=sa.Date(), nullable=False)
|
||||
batch_op.alter_column('LeavingDate', new_column_name='leaving_date', type_=sa.Date(), nullable=True)
|
||||
|
||||
with op.batch_alter_table("settings") as batch_op:
|
||||
batch_op.alter_column('SettingID', new_column_name='id')
|
||||
batch_op.alter_column('Name', new_column_name='name')
|
||||
batch_op.alter_column('Data', new_column_name='data')
|
||||
|
||||
|
||||
op.create_unique_constraint(op.f('uq_accounts_name'), 'accounts', ['name'])
|
||||
op.drop_constraint('accounts_name_key', 'accounts', type_='unique')
|
||||
@ -162,9 +181,23 @@ def upgrade():
|
||||
op.drop_constraint('products_Name_Units_key', 'products', type_='unique')
|
||||
op.create_unique_constraint(op.f('uq_recipe_items_recipe_id'), 'recipe_items', ['recipe_id', 'product_id'])
|
||||
op.drop_constraint('recipe_items_recipe_id_product_id_key', 'recipe_items', type_='unique')
|
||||
op.create_unique_constraint(op.f('uq_settings_Name'), 'settings', ['Name'])
|
||||
op.create_unique_constraint(op.f('uq_settings_name'), 'settings', ['name'])
|
||||
op.drop_constraint('settings_Name_key', 'settings', type_='unique')
|
||||
op.create_index(op.f('ix_vouchers_date'), 'vouchers', ['date'], unique=False)
|
||||
op.create_foreign_key('fk_incentives_journal_id_journals', 'incentives', 'journals', ['journal_id'], ['id'])
|
||||
op.create_foreign_key('fk_incentives_voucher_id_vouchers', 'incentives', 'vouchers', ['voucher_id'], ['id'])
|
||||
op.drop_constraint('service_charges_journal_id_fkey', 'incentives', type_='foreignkey')
|
||||
op.drop_constraint('service_charges_voucher_id_fkey', 'incentives', type_='foreignkey')
|
||||
op.create_foreign_key('fk_employee_benefit_journal_id_journals', 'employee_benefit', 'journals', ['journal_id'], ['id'])
|
||||
op.create_foreign_key('fk_employee_benefit_voucher_id_vouchers', 'employee_benefit', 'vouchers', ['voucher_id'], ['id'])
|
||||
op.drop_constraint('entities_salarydeductions_JournalID_fkey', 'employee_benefit', type_='foreignkey')
|
||||
op.drop_constraint('salary_deductions_VoucherID_fkey', 'employee_benefit', type_='foreignkey')
|
||||
|
||||
role = table('auth_roles', column('name', sa.String))
|
||||
op.execute(role.update().where(role.c.name == op.inline_literal('Service Charge')).values({'name': op.inline_literal('Incentive')}))
|
||||
op.execute(role.update().where(role.c.name == op.inline_literal('Salary Deduction')).values({'name': op.inline_literal('Employee Benefit')}))
|
||||
account = table('accounts', column('name', sa.String))
|
||||
op.execute(account.update().where(account.c.name == op.inline_literal('Service Charges')).values({'name': op.inline_literal('Incentives')}))
|
||||
### end Alembic commands ###
|
||||
|
||||
|
||||
|
@ -25,7 +25,7 @@ from brewman.models import (
|
||||
Inventory,
|
||||
Journal,
|
||||
Product,
|
||||
SalaryDeduction,
|
||||
EmployeeBenefit,
|
||||
Voucher,
|
||||
VoucherType,
|
||||
) # noqa
|
||||
|
@ -16,7 +16,9 @@ from .routers import (
|
||||
product_group,
|
||||
recipe,
|
||||
login,
|
||||
journal
|
||||
journal,
|
||||
purchase,
|
||||
purchase_return
|
||||
)
|
||||
from .routers.auth import client, user, role
|
||||
from .routers.reports import (
|
||||
@ -105,6 +107,8 @@ 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(purchase.router, prefix="/api/purchase", tags=["vouchers"])
|
||||
app.include_router(purchase_return.router, prefix="/api/purchase-return", tags=["vouchers"])
|
||||
|
||||
|
||||
def init():
|
||||
|
@ -26,7 +26,7 @@ from .voucher import (
|
||||
Inventory,
|
||||
Journal,
|
||||
Product,
|
||||
SalaryDeduction,
|
||||
EmployeeBenefit,
|
||||
Voucher,
|
||||
VoucherType,
|
||||
)
|
||||
|
@ -126,29 +126,6 @@ def purchase_return_update(voucher):
|
||||
)
|
||||
|
||||
|
||||
def inventory_valid(voucher):
|
||||
if voucher.type in [2, 6, 3]:
|
||||
if not len(voucher.inventories):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="Not enough inventories",
|
||||
)
|
||||
is_distinct_inventory(voucher.inventories)
|
||||
|
||||
|
||||
def is_distinct_inventory(inventories):
|
||||
found = set()
|
||||
for item in inventories:
|
||||
item_hash = hash(item.product_id)
|
||||
if item_hash in found:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="Duplicate inventories",
|
||||
)
|
||||
else:
|
||||
found.add(item_hash)
|
||||
|
||||
|
||||
def batch_valid(voucher):
|
||||
pass
|
||||
|
||||
|
@ -9,7 +9,8 @@ from sqlalchemy import (
|
||||
DateTime,
|
||||
Numeric,
|
||||
ForeignKey,
|
||||
UniqueConstraint, Date,
|
||||
UniqueConstraint,
|
||||
Date,
|
||||
)
|
||||
from sqlalchemy.dialects.postgresql import BYTEA
|
||||
from sqlalchemy.ext.hybrid import hybrid_property
|
||||
@ -39,7 +40,7 @@ class VoucherType:
|
||||
VoucherType(9, "Verification"),
|
||||
VoucherType(10, "Opening Balance"),
|
||||
VoucherType(11, "Closing Balance"),
|
||||
VoucherType(12, "Salary Deduction"),
|
||||
VoucherType(12, "Employee Benefit"),
|
||||
VoucherType(13, "Incentive"),
|
||||
]
|
||||
return list
|
||||
@ -63,10 +64,10 @@ class Voucher(Base):
|
||||
__tablename__ = "vouchers"
|
||||
|
||||
id = Column("id", GUID(), primary_key=True, default=uuid.uuid4)
|
||||
date = Column("date", DateTime, nullable=False, index=True)
|
||||
date = Column("date", Date, nullable=False, index=True)
|
||||
narration = Column("narration", Unicode(1000), nullable=False)
|
||||
is_reconciled = Column("is_reconciled", Boolean, nullable=False)
|
||||
reconcile_date = Column("reconcile_date", DateTime, nullable=False)
|
||||
reconcile_date = Column("reconcile_date", Date, nullable=False)
|
||||
is_starred = Column("is_starred", Boolean, nullable=False)
|
||||
creation_date = Column("creation_date", DateTime(timezone=True), nullable=False)
|
||||
last_edit_date = Column("last_edit_date", DateTime(timezone=True), nullable=False)
|
||||
@ -86,14 +87,15 @@ class Voucher(Base):
|
||||
cascade="delete, delete-orphan",
|
||||
cascade_backrefs=False,
|
||||
)
|
||||
|
||||
inventories = relationship(
|
||||
"Inventory",
|
||||
back_populates="voucher",
|
||||
cascade="delete, delete-orphan",
|
||||
cascade_backrefs=False,
|
||||
)
|
||||
salary_deductions = relationship(
|
||||
"SalaryDeduction",
|
||||
employee_benefits = relationship(
|
||||
"EmployeeBenefit",
|
||||
backref="voucher",
|
||||
cascade="delete, delete-orphan",
|
||||
cascade_backrefs=False,
|
||||
@ -120,10 +122,6 @@ class Voucher(Base):
|
||||
type = property(_get_type, _set_type)
|
||||
type = synonym("_type", descriptor=type)
|
||||
|
||||
@property
|
||||
def __name__(self):
|
||||
return self.name
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
date=None,
|
||||
@ -134,25 +132,19 @@ class Voucher(Base):
|
||||
posted=False,
|
||||
creation_date=None,
|
||||
last_edit_date=None,
|
||||
type=None,
|
||||
type_=None,
|
||||
user_id=None,
|
||||
poster_id=None,
|
||||
):
|
||||
self.date = date
|
||||
self.is_reconciled = is_reconciled
|
||||
self.reconcile_date = (
|
||||
reconcile_date if reconcile_date and is_reconciled else date
|
||||
)
|
||||
self.reconcile_date = reconcile_date or date
|
||||
self.is_starred = is_starred if is_starred is not None else False
|
||||
self.narration = narration
|
||||
self.posted = posted
|
||||
self.creation_date = (
|
||||
datetime.utcnow() if creation_date is None else creation_date
|
||||
)
|
||||
self.last_edit_date = (
|
||||
datetime.utcnow() if last_edit_date is None else last_edit_date
|
||||
)
|
||||
self.type = type
|
||||
self.creation_date = creation_date or datetime.utcnow()
|
||||
self.last_edit_date = last_edit_date or datetime.utcnow()
|
||||
self.type = type_
|
||||
self.user_id = user_id
|
||||
self.poster_id = poster_id
|
||||
|
||||
@ -199,8 +191,8 @@ class Journal(Base):
|
||||
self.cost_centre_id = cost_centre_id
|
||||
|
||||
|
||||
class SalaryDeduction(Base):
|
||||
__tablename__ = "salary_deductions"
|
||||
class EmployeeBenefit(Base):
|
||||
__tablename__ = "employee_benefit"
|
||||
id = Column("id", GUID(), primary_key=True, default=uuid.uuid4)
|
||||
voucher_id = Column("voucher_id", GUID(), ForeignKey("vouchers.id"), nullable=False)
|
||||
journal_id = Column("journal_id", GUID(), ForeignKey("journals.id"), nullable=False)
|
||||
@ -213,14 +205,14 @@ class SalaryDeduction(Base):
|
||||
|
||||
journal = relationship(
|
||||
Journal,
|
||||
backref=backref("salary_deduction", uselist=False),
|
||||
backref=backref("employee_benefit", uselist=False),
|
||||
cascade=None,
|
||||
cascade_backrefs=False,
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
id=None,
|
||||
id_=None,
|
||||
voucher_id=None,
|
||||
journal_id=None,
|
||||
journal=None,
|
||||
@ -231,7 +223,7 @@ class SalaryDeduction(Base):
|
||||
esi_er=None,
|
||||
pf_er=None,
|
||||
):
|
||||
self.id = id
|
||||
self.id = id_
|
||||
self.voucher_id = voucher_id
|
||||
self.journal_id = journal_id
|
||||
self.gross_salary = gross_salary
|
||||
@ -304,17 +296,20 @@ class Inventory(Base):
|
||||
tax=None,
|
||||
discount=None,
|
||||
batch=None,
|
||||
product=None
|
||||
):
|
||||
self.id = id_
|
||||
self.voucher_id = voucher_id
|
||||
if product is None:
|
||||
self.product_id = product_id
|
||||
if batch is None:
|
||||
self.batch_id = batch_id
|
||||
self.quantity = quantity
|
||||
self.rate = rate
|
||||
self.tax = tax
|
||||
self.discount = discount
|
||||
if batch_id is None and batch is not None:
|
||||
self.batch = batch
|
||||
self.product = product
|
||||
|
||||
@hybrid_property
|
||||
def amount(self):
|
||||
@ -325,7 +320,7 @@ class Batch(Base):
|
||||
__tablename__ = "batches"
|
||||
|
||||
id = Column("id", GUID(), primary_key=True, default=uuid.uuid4)
|
||||
name = Column("name", DateTime)
|
||||
name = Column("name", Date, nullable=False)
|
||||
product_id = Column("product_id", GUID(), ForeignKey("products.id"), nullable=False)
|
||||
quantity_remaining = Column("quantity_remaining", Numeric)
|
||||
rate = Column("rate", Numeric)
|
||||
@ -344,6 +339,7 @@ class Batch(Base):
|
||||
rate=None,
|
||||
tax=None,
|
||||
discount=None,
|
||||
product=None
|
||||
):
|
||||
self.name = name
|
||||
self.product_id = product_id
|
||||
@ -351,6 +347,9 @@ class Batch(Base):
|
||||
self.rate = rate
|
||||
self.tax = tax
|
||||
self.discount = discount
|
||||
if product is None:
|
||||
self.product_id = product_id
|
||||
self.product = product
|
||||
|
||||
def amount(self):
|
||||
return (
|
||||
|
@ -251,8 +251,8 @@ def delete_with_data(employee, db):
|
||||
amount = (sus_jnl.debit * sus_jnl.amount) + (
|
||||
acc_jnl.debit * acc_jnl.amount
|
||||
)
|
||||
if acc_jnl.salary_deduction is not None:
|
||||
db.delete(acc_jnl.salary_deduction)
|
||||
if acc_jnl.employee_benefit is not None:
|
||||
db.delete(acc_jnl.employee_benefit)
|
||||
db.delete(acc_jnl)
|
||||
if amount == 0:
|
||||
db.delete(sus_jnl)
|
||||
|
@ -0,0 +1,108 @@
|
||||
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 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 ..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 ["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
|
||||
|
||||
|
||||
@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 ["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
|
@ -13,7 +13,8 @@ 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, VoucherType, Journal
|
||||
import brewman.schemas.voucher as schemas
|
||||
import brewman.schemas.voucher as output
|
||||
import brewman.schemas.input as schema_in
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@ -27,10 +28,10 @@ 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 = Depends(schemas.Voucher.load_form),
|
||||
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),
|
||||
@ -39,7 +40,8 @@ def save_route(
|
||||
try:
|
||||
i = i or []
|
||||
t = t or []
|
||||
item: Voucher = save(data, i + t, user, db)
|
||||
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)
|
||||
@ -58,14 +60,14 @@ def save_route(
|
||||
)
|
||||
|
||||
|
||||
def save(data: schemas.Voucher, files: List[UploadFile], user: UserToken, db: Session) -> Voucher:
|
||||
def save(data: schema_in.JournalIn, user: UserToken, db: Session) -> Voucher:
|
||||
check_voucher_lock_info(None, data.date_, db)
|
||||
voucher = Voucher(
|
||||
date=data.date_,
|
||||
narration=data.narration,
|
||||
is_starred=data.is_starred,
|
||||
user_id=user.id_,
|
||||
type=VoucherType.by_name(data.type_),
|
||||
type_=VoucherType.by_name(data.type_),
|
||||
)
|
||||
db.add(voucher)
|
||||
for item in data.journals:
|
||||
@ -79,16 +81,20 @@ def save(data: schemas.Voucher, files: List[UploadFile], user: UserToken, db: Se
|
||||
)
|
||||
voucher.journals.append(journal)
|
||||
db.add(journal)
|
||||
# for key, value in files.items():
|
||||
# db.add(DbImage(voucher.id, "voucher", value["f"], value["t"]))
|
||||
return voucher
|
||||
|
||||
|
||||
@router.put("/{id_}")
|
||||
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.JournalIn = Depends(schema_in.JournalIn.load_form),
|
||||
db: Session = Depends(get_db),
|
||||
i: List[UploadFile] = File(None),
|
||||
t: List[UploadFile] = File(None),
|
||||
@ -97,10 +103,10 @@ def update_route(
|
||||
try:
|
||||
i = i or []
|
||||
t = t or []
|
||||
item: Voucher = update(id_, data, i + t, user, db)
|
||||
item: Voucher = update(id_, data, user, db)
|
||||
update_files(data, i + t, db)
|
||||
db.commit()
|
||||
set_date(data.date_, request.session)
|
||||
# item: Voucher = db.query(Voucher).filter(Voucher.id == item.id).first()
|
||||
set_date(data.date_.strftime("%d-%b-%Y"), request.session)
|
||||
return voucher_info(item, db)
|
||||
except SQLAlchemyError as e:
|
||||
db.rollback()
|
||||
@ -116,30 +122,7 @@ def update_route(
|
||||
)
|
||||
|
||||
|
||||
@router.get("/{id_}")
|
||||
def get_id(
|
||||
id_: uuid.UUID,
|
||||
db: Session = Depends(get_db),
|
||||
user: UserToken = Security(get_user, scopes=["journal"]),
|
||||
):
|
||||
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(),
|
||||
)
|
||||
|
||||
|
||||
def update(id_: uuid.UUID, data: schemas.Voucher, files: List[UploadFile], 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)
|
||||
@ -177,15 +160,42 @@ def update(id_: uuid.UUID, data: schemas.Voucher, files: List[UploadFile], user:
|
||||
)
|
||||
db.add(journal)
|
||||
voucher.journals.append(journal)
|
||||
return voucher
|
||||
|
||||
|
||||
def update_files(data: schema_in.VoucherIn, 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 = dbsession.query(DbImage).filter(DbImage.resource_id == voucher.id).all()
|
||||
# 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]:
|
||||
# dbsession.delete(image)
|
||||
# db.delete(image)
|
||||
# for key, value in files.items():
|
||||
# dbsession.add(DbImage(voucher.id, "voucher", value["f"], value["t"])) return voucher
|
||||
# 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=["journal"]),
|
||||
):
|
||||
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("")
|
||||
|
@ -11,7 +11,7 @@ from brewman.models.voucher import (
|
||||
VoucherType,
|
||||
Batch,
|
||||
Inventory,
|
||||
SalaryDeduction,
|
||||
EmployeeBenefit,
|
||||
Fingerprint,
|
||||
Attendance,
|
||||
DbImage,
|
||||
@ -203,7 +203,7 @@ def delete_data(date, vouchers, dbsession):
|
||||
|
||||
dbsession.execute(Inventory.__table__.delete(Inventory.voucher_id.in_(sub_query)))
|
||||
dbsession.execute(
|
||||
SalaryDeduction.__table__.delete(SalaryDeduction.voucher_id.in_(sub_query))
|
||||
EmployeeBenefit.__table__.delete(EmployeeBenefit.voucher_id.in_(sub_query))
|
||||
)
|
||||
dbsession.execute(
|
||||
Incentive.__table__.delete(Incentive.voucher_id.in_(sub_query))
|
||||
|
@ -1,21 +1,22 @@
|
||||
import traceback
|
||||
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 sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from .voucher import journal_create_voucher, purchase_create_voucher, issue_create_voucher, incentive_create_voucher, \
|
||||
salary_deduction_create_voucher, voucher_info, check_voucher_lock_info, check_voucher_edit_allowed
|
||||
from .voucher.purchase_return import purchase_return_create_voucher
|
||||
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 Product, 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, VoucherType, Batch, Inventory, Journal
|
||||
import brewman.schemas.voucher as schemas
|
||||
import brewman.schemas.voucher as output
|
||||
import brewman.schemas.input as schema_in
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@ -29,10 +30,10 @@ 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 = Depends(schemas.Voucher.load_form),
|
||||
data: schema_in.PurchaseIn = Depends(schema_in.PurchaseIn.load_form),
|
||||
db: Session = Depends(get_db),
|
||||
i: List[UploadFile] = File(None),
|
||||
t: List[UploadFile] = File(None),
|
||||
@ -41,7 +42,10 @@ def save_route(
|
||||
try:
|
||||
i = i or []
|
||||
t = t or []
|
||||
item: Voucher = save(data, i + t, user, db)
|
||||
item: Voucher = save(data, user, db)
|
||||
save_inventories(item, data.inventories, db)
|
||||
save_journals(item, data.vendor, db)
|
||||
save_files(i + t, db)
|
||||
db.commit()
|
||||
set_date(data.date_.strftime("%d-%b-%Y"), request.session)
|
||||
info = voucher_info(item, db)
|
||||
@ -60,82 +64,83 @@ def save_route(
|
||||
)
|
||||
|
||||
|
||||
def save(data: schemas.Voucher, files: List[UploadFile], user: UserToken, db: Session) -> Voucher:
|
||||
def save(data: schema_in.PurchaseIn, user: UserToken, db: Session) -> Voucher:
|
||||
check_voucher_lock_info(None, data.date_, db)
|
||||
voucher = Voucher(
|
||||
date=data.date_,
|
||||
narration=data.narration,
|
||||
is_starred=data.is_starred,
|
||||
user_id=user.id_,
|
||||
type=VoucherType.by_name(data.type_),
|
||||
type_=VoucherType.by_name(data.type_),
|
||||
)
|
||||
db.add(voucher)
|
||||
journals = {}
|
||||
for item in data.inventories:
|
||||
product: Product = db.query(Product).filter(Product.id == item.product.id_).first()
|
||||
batch = Batch(name=data.date_, product_id=product.id, quantity_remaining=item.quantity, rate=item.rate, tax=item.tax,discount=item.discount)
|
||||
db.add(batch)
|
||||
inventory = Inventory(id=item.id_, product_id=product.id, 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)
|
||||
if product.account_id not in journals:
|
||||
journals[product.account_id] = {"account_id":product.account_id, "cost_centre_id": product.account.cost_centre_id, "debit": 1, "amount": inventory.amount}
|
||||
else:
|
||||
journals[product.account_id]["amount"] += inventory.amount
|
||||
supplier = db.query(AccountBase).filter(AccountBase.id == data.journals[0].account.id_).first()
|
||||
|
||||
journals[supplier.id] = {"account_id":supplier.id, "cost_centre_id": supplier.cost_centre_id, "debit":-1, "amount": sum(round(x["amount"], 2) for x in journals)}
|
||||
for item in journals:
|
||||
journal = Journal(
|
||||
debit=item["debit"],
|
||||
account_id=item["account_id"],
|
||||
cost_centre_id=item["cost_centre_id"],
|
||||
amount=round(item["amount"], 2),
|
||||
)
|
||||
|
||||
voucher.journals.append(item)
|
||||
db.add(item)
|
||||
|
||||
journals_valid(voucher)
|
||||
inventory_valid(voucher)
|
||||
for key, value in files.items():
|
||||
dbsession.add(DbImage(voucher.id, "voucher", value["f"], value["t"]))
|
||||
return voucher
|
||||
|
||||
|
||||
def purchase_create_journals(account_id: uuid.UUID, db: Session):
|
||||
amount = 0
|
||||
def save_inventories(voucher: Voucher, inventories: List[schema_in.Inventory], db: Session):
|
||||
for item in inventories:
|
||||
product = db.query(Product).filter(Product.id == item.product_id).first()
|
||||
account = product.account
|
||||
item_amount = round(item.amount, 2)
|
||||
amount += item_amount
|
||||
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)
|
||||
product.price = item.rate
|
||||
voucher.inventories.append(inventory)
|
||||
db.add(inventory)
|
||||
|
||||
|
||||
def save_journals(voucher: Voucher, ven: schema_in.AccountLink, db: Session):
|
||||
vendor = db.query(AccountBase).filter(AccountBase.id == ven.id_).first()
|
||||
journals = {}
|
||||
amount = 0
|
||||
for item in voucher.inventories:
|
||||
account = item.product.account
|
||||
amount += round(item.amount, 2)
|
||||
if account.id in journals:
|
||||
journals[account.id].amount += item_amount
|
||||
journals[account.id].amount += round(item.amount, 2)
|
||||
else:
|
||||
journals[other_account.id] = Journal(
|
||||
journals[account.id] = Journal(
|
||||
debit=1,
|
||||
cost_centre_id=account.cost_centre_id,
|
||||
account_id=account.id,
|
||||
amount=round(item.amount, 2),
|
||||
)
|
||||
journals[vendor.id] = Journal(
|
||||
debit=-1,
|
||||
cost_centre_id=other_account.cost_centre_id,
|
||||
account_id=other_account.id,
|
||||
cost_centre_id=vendor.cost_centre_id,
|
||||
account_id=vendor.id,
|
||||
amount=amount,
|
||||
)
|
||||
return list(journals.values())
|
||||
for item in journals.values():
|
||||
voucher.journals.append(item)
|
||||
db.add(item)
|
||||
|
||||
@router.get("/{id_}")
|
||||
|
||||
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.PurchaseIn = Depends(schema_in.PurchaseIn.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=["purchase"]),
|
||||
):
|
||||
try:
|
||||
item: Voucher = update(id_, data, files, user, db)
|
||||
i = i or []
|
||||
t = t or []
|
||||
item: Voucher = update(id_, data, user, db)
|
||||
update_inventory(item, data.inventories, db)
|
||||
update_journals(item, data.vendor, db)
|
||||
# journals_valid(voucher)
|
||||
update_files(data, i + t, db)
|
||||
db.commit()
|
||||
set_date(request.session, data.date_)
|
||||
# item: Voucher = db.query(Voucher).filter(Voucher.id == item.id).first()
|
||||
set_date(data.date_.strftime("%d-%b-%Y"), request.session)
|
||||
return voucher_info(item, db)
|
||||
except SQLAlchemyError as e:
|
||||
db.rollback()
|
||||
@ -151,18 +156,178 @@ 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 ["Purchase"]:
|
||||
voucher = purchase_update_voucher(item, data, files, user, db)
|
||||
elif data.type_ in ["Purchase Return"]:
|
||||
voucher = purchase_return_update_voucher(item, data, files, user, db)
|
||||
elif data.type_ in ["Issue"]:
|
||||
voucher = issue_update_voucher(item, data, files, user, db)
|
||||
elif data.type_ in ["Salary Deduction"]:
|
||||
voucher = salary_deduction_update_voucher(item, data, files, user, db)
|
||||
elif data.type_ in ["Incentive"]:
|
||||
voucher = incentive_update_voucher(item, data, files, user, db)
|
||||
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)
|
||||
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()
|
||||
return voucher
|
||||
|
||||
|
||||
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()
|
||||
found = True
|
||||
if item.product_id != new_inventory.product.id_:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
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):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail=f"{old_quantity - quantity_remaining} is the minimum as it has been issued",
|
||||
)
|
||||
item.batch.quantity_remaining -= old_quantity - new_inventory.quantity
|
||||
item.quantity = new_inventory.quantity
|
||||
if voucher.date != item.batch.name:
|
||||
item.batch.name = voucher.date
|
||||
if voucher.date < item.batch.name:
|
||||
# TODO: check for issued products which might have been in a back date
|
||||
pass
|
||||
item.rate = new_inventory.rate
|
||||
item.batch.rate = new_inventory.rate
|
||||
item.discount = new_inventory.discount
|
||||
item.batch.discount = new_inventory.discount
|
||||
item.tax = new_inventory.tax
|
||||
item.batch.tax = new_inventory.tax
|
||||
product.price = new_inventory.rate
|
||||
new_inventories.remove(new_inventory)
|
||||
# TODO: Update all references of the batch with the new rates
|
||||
break
|
||||
if not found:
|
||||
has_been_issued = (
|
||||
db.query(func.count(Inventory.id))
|
||||
.filter(Inventory.batch_id == item.batch.id)
|
||||
.filter(Inventory.id != item.id)
|
||||
.scalar()
|
||||
)
|
||||
if has_been_issued > 0:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail=f"{item.product.name} has been issued, it cannot be deleted",
|
||||
)
|
||||
else:
|
||||
db.delete(item.batch)
|
||||
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()
|
||||
batch = Batch(
|
||||
name=voucher.date,
|
||||
product_id=product.id,
|
||||
quantity_remaining=new_inventory.quantity,
|
||||
rate=new_inventory.rate,
|
||||
tax=new_inventory.tax,
|
||||
discount=new_inventory.discount,
|
||||
)
|
||||
inventory = Inventory(
|
||||
id_=None,
|
||||
product_id=product.id,
|
||||
batch=batch,
|
||||
quantity=new_inventory.quantity,
|
||||
rate=new_inventory.rate,
|
||||
tax=new_inventory.tax,
|
||||
discount=new_inventory.discount,
|
||||
)
|
||||
inventory.voucher_id = voucher.id
|
||||
db.add(batch)
|
||||
inventory.batch_id = batch.id
|
||||
product.price = new_inventory.rate
|
||||
voucher.inventories.append(inventory)
|
||||
db.add(inventory)
|
||||
|
||||
|
||||
def update_journals(voucher: Voucher, ven: schema_in.AccountLink, db):
|
||||
vendor = db.query(AccountBase).filter(AccountBase.id == ven.id_).first()
|
||||
journals = {}
|
||||
amount = 0
|
||||
for item in voucher.inventories:
|
||||
product = db.query(Product).filter(Product.id == item.product_id).first()
|
||||
account = product.account
|
||||
amount += item.amount
|
||||
if account.id in journals:
|
||||
journals[account.id].amount += item.amount
|
||||
else:
|
||||
journals[account.id] = Journal(
|
||||
debit=1,
|
||||
cost_centre_id=account.cost_centre_id,
|
||||
account_id=account.id,
|
||||
amount=item.amount,
|
||||
)
|
||||
journals[vendor.id] = Journal(
|
||||
debit=-1,
|
||||
cost_centre_id=vendor.cost_centre_id,
|
||||
account_id=vendor.id,
|
||||
amount=amount,
|
||||
)
|
||||
for i in range(len(voucher.journals), 0, -1):
|
||||
item = voucher.journals[i - 1]
|
||||
if item.account_id in journals:
|
||||
item.debit = journals[item.account_id].debit
|
||||
item.amount = round(journals[item.account_id].amount, 2)
|
||||
item.cost_centre_id = journals[item.account_id].cost_centre_id
|
||||
del journals[item.account_id]
|
||||
else:
|
||||
db.delete(item)
|
||||
voucher.journals.remove(item)
|
||||
for item in journals.values():
|
||||
item.amount = round(item.amount, 2)
|
||||
voucher.journals.append(item)
|
||||
db.add(item)
|
||||
|
||||
|
||||
def update_files(data: schema_in.PurchaseIn, 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=["purchase"]),
|
||||
):
|
||||
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,
|
||||
db: Session = Depends(get_db),
|
||||
user: UserToken = Security(get_user, scopes=["purchase"]),
|
||||
):
|
||||
additional_info = {"date": get_date(request.session), "type": "Purchase"}
|
||||
return blank_voucher(additional_info, db)
|
||||
|
@ -1,20 +1,22 @@
|
||||
import traceback
|
||||
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 sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from .voucher import journal_create_voucher, purchase_create_voucher, issue_create_voucher, incentive_create_voucher, \
|
||||
salary_deduction_create_voucher, voucher_info, check_voucher_lock_info, check_voucher_edit_allowed
|
||||
from .voucher.purchase_return import purchase_return_create_voucher
|
||||
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 Product, 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()
|
||||
|
||||
@ -28,20 +30,26 @@ 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.PurchaseIn = Depends(schema_in.PurchaseIn.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=["purchase-return"]),
|
||||
):
|
||||
try:
|
||||
item: Voucher = save(data, files, user, db)
|
||||
i = i or []
|
||||
t = t or []
|
||||
item: Voucher = save(data, user, db)
|
||||
save_inventories(item, data.inventories, db)
|
||||
save_journals(item, data.vendor, 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(
|
||||
@ -56,35 +64,95 @@ def save_route(
|
||||
)
|
||||
|
||||
|
||||
def save(data: schemas.Voucher, files: List[UploadFile], user: UserToken, db: Session) -> Voucher:
|
||||
def save(data: schema_in.PurchaseIn, user: UserToken, db: Session) -> Voucher:
|
||||
check_voucher_lock_info(None, data.date_, db)
|
||||
if data.type_ in ["Purchase"]:
|
||||
voucher = purchase_create_voucher(data, files, user, db)
|
||||
elif data.type_ in ["Purchase Return"]:
|
||||
voucher = purchase_return_create_voucher(data, files, user, db)
|
||||
elif data.type_ in ["Issue"]:
|
||||
voucher = issue_create_voucher(data, files, user, db)
|
||||
elif data.type_ in ["Salary Deduction"]:
|
||||
voucher = salary_deduction_create_voucher(data, files, user, db)
|
||||
elif data.type_ in ["Incentive"]:
|
||||
voucher = incentive_create_voucher(data, files, user, db)
|
||||
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)
|
||||
return voucher
|
||||
|
||||
|
||||
@router.get("/{id_}")
|
||||
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')}")
|
||||
|
||||
batch.quantity_remaining -= item.quantity
|
||||
|
||||
item = Inventory(
|
||||
product=batch.product,
|
||||
quantity=item.quantity,
|
||||
rate=batch.rate,
|
||||
tax=batch.tax,
|
||||
discount=batch.discount,
|
||||
batch=batch,
|
||||
)
|
||||
voucher.inventories.append(item)
|
||||
db.add(item)
|
||||
|
||||
|
||||
def save_journals(voucher: Voucher, ven: schema_in.AccountLink, db: Session):
|
||||
vendor = db.query(AccountBase).filter(AccountBase.id == ven.id_).first()
|
||||
journals = {}
|
||||
amount = 0
|
||||
for item in voucher.inventories:
|
||||
account = item.product.account
|
||||
amount += round(item.amount, 2)
|
||||
if account.id in journals:
|
||||
journals[account.id].amount += round(item.amount, 2)
|
||||
else:
|
||||
journals[account.id] = Journal(
|
||||
debit=-1,
|
||||
cost_centre_id=account.cost_centre_id,
|
||||
account_id=account.id,
|
||||
amount=round(item.amount, 2),
|
||||
)
|
||||
journals[vendor.id] = Journal(
|
||||
debit=1,
|
||||
cost_centre_id=vendor.cost_centre_id,
|
||||
account_id=vendor.id,
|
||||
amount=amount,
|
||||
)
|
||||
for item in journals.values():
|
||||
voucher.journals.append(item)
|
||||
db.add(item)
|
||||
|
||||
|
||||
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.PurchaseIn = Depends(schema_in.PurchaseIn.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=["purchase-return"]),
|
||||
):
|
||||
try:
|
||||
item: Voucher = update(id_, data, files, user, db)
|
||||
i = i or []
|
||||
t = t or []
|
||||
item: Voucher = update(id_, data, user, db)
|
||||
update_inventory(item, data.inventories, db)
|
||||
update_journals(item, data.vendor, db)
|
||||
# journals_valid(voucher)
|
||||
update_files(data, i + t, db)
|
||||
db.commit()
|
||||
set_date(request.session, data.date_)
|
||||
# item: Voucher = db.query(Voucher).filter(Voucher.id == item.id).first()
|
||||
set_date(data.date_.strftime("%d-%b-%Y"), request.session)
|
||||
return voucher_info(item, db)
|
||||
except SQLAlchemyError as e:
|
||||
db.rollback()
|
||||
@ -100,18 +168,129 @@ 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 ["Purchase"]:
|
||||
voucher = purchase_update_voucher(item, data, files, user, db)
|
||||
elif data.type_ in ["Purchase Return"]:
|
||||
voucher = purchase_return_update_voucher(item, data, files, user, db)
|
||||
elif data.type_ in ["Issue"]:
|
||||
voucher = issue_update_voucher(item, data, files, user, db)
|
||||
elif data.type_ in ["Salary Deduction"]:
|
||||
voucher = salary_deduction_update_voucher(item, data, files, user, db)
|
||||
elif data.type_ in ["Incentive"]:
|
||||
voucher = incentive_update_voucher(item, data, files, user, db)
|
||||
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)
|
||||
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()
|
||||
return voucher
|
||||
|
||||
|
||||
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_:
|
||||
found = True
|
||||
if item.product_id != new_inventory.product.id_:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
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:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
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')}")
|
||||
item.batch.quantity_remaining -= new_inventory.quantity - old_quantity
|
||||
item.quantity = new_inventory.quantity
|
||||
new_inventories.remove(new_inventory)
|
||||
break
|
||||
if not found:
|
||||
item.batch.quantity_remaining += item.quantity
|
||||
voucher.inventories.remove(item)
|
||||
db.delete(item)
|
||||
save_inventories(voucher, new_inventories, db)
|
||||
|
||||
|
||||
def update_journals(voucher: Voucher, ven: schema_in.AccountLink, db):
|
||||
vendor = db.query(AccountBase).filter(AccountBase.id == ven.id_).first()
|
||||
journals = {}
|
||||
amount = 0
|
||||
for item in voucher.inventories:
|
||||
account = item.product.account
|
||||
amount += item.amount
|
||||
if account.id in journals:
|
||||
journals[account.id].amount += item.amount
|
||||
else:
|
||||
journals[account.id] = Journal(
|
||||
debit=-1,
|
||||
cost_centre_id=account.cost_centre_id,
|
||||
account_id=account.id,
|
||||
amount=item.amount,
|
||||
)
|
||||
journals[vendor.id] = Journal(
|
||||
debit=1,
|
||||
cost_centre_id=vendor.cost_centre_id,
|
||||
account_id=vendor.id,
|
||||
amount=amount,
|
||||
)
|
||||
for i in range(len(voucher.journals), 0, -1):
|
||||
item = voucher.journals[i - 1]
|
||||
if item.account_id in journals:
|
||||
item.debit = journals[item.account_id].debit
|
||||
item.amount = round(journals[item.account_id].amount, 2)
|
||||
item.cost_centre_id = journals[item.account_id].cost_centre_id
|
||||
del journals[item.account_id]
|
||||
else:
|
||||
db.delete(item)
|
||||
voucher.journals.remove(item)
|
||||
for item in journals.values():
|
||||
item.amount = round(item.amount, 2)
|
||||
voucher.journals.append(item)
|
||||
db.add(item)
|
||||
|
||||
|
||||
def update_files(data: schema_in.PurchaseIn, 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=["purchase-return"]),
|
||||
):
|
||||
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,
|
||||
db: Session = Depends(get_db),
|
||||
user: UserToken = Security(get_user, scopes=["purchase-return"]),
|
||||
):
|
||||
additional_info = {"date": get_date(request.session), "type": "Purchase"}
|
||||
return blank_voucher(additional_info, db)
|
||||
|
@ -23,12 +23,10 @@ from brewman.models.voucher import (
|
||||
)
|
||||
from brewman.routers import get_lock_info
|
||||
from .issue import issue_create_voucher, issue_update_voucher
|
||||
from .purchase import purchase_create_voucher, purchase_update_voucher
|
||||
from .incentive import incentive_create_voucher, incentive_update_voucher
|
||||
from .salary_deduction import salary_deduction_create_voucher, salary_deduction_update_voucher
|
||||
from .employee_benefit import employee_benefit_create_voucher, employee_benefit_update_voucher
|
||||
from ...core.session import get_first_day
|
||||
|
||||
|
||||
from fastapi import APIRouter, Depends, Security, Request, HTTPException, status
|
||||
|
||||
from ...schemas.auth import UserToken
|
||||
@ -36,7 +34,6 @@ from ...schemas.auth import UserToken
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
|
||||
@router.post("/api/voucher/{id}") # , request_param="p" "Post Vouchers"
|
||||
def voucher_post(request):
|
||||
user = (
|
||||
@ -195,6 +192,10 @@ def voucher_info(voucher, db):
|
||||
json_voucher["reconcileDate"] = voucher.reconcile_date.strftime(
|
||||
"%d-%b-%Y"
|
||||
)
|
||||
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}
|
||||
else:
|
||||
for item in voucher.journals:
|
||||
json_voucher["journals"].append(
|
||||
{
|
||||
@ -205,7 +206,7 @@ def voucher_info(voucher, db):
|
||||
"costCentre": {"id": item.cost_centre_id},
|
||||
}
|
||||
)
|
||||
for item in voucher.salary_deductions:
|
||||
for item in voucher.employee_benefits:
|
||||
json_voucher["employeeBenefits"].append(
|
||||
{
|
||||
"grossSalary": item.gross_salary,
|
||||
@ -251,13 +252,7 @@ def voucher_info(voucher, db):
|
||||
if x.account_id == Account.incentive_id()
|
||||
][0]
|
||||
for item in voucher.inventories:
|
||||
text = "{0} ({1}) {2:.2f}@{3:.2f} from {4}".format(
|
||||
item.product.name,
|
||||
item.product.units,
|
||||
item.batch.quantity_remaining,
|
||||
item.batch.rate,
|
||||
item.batch.name.strftime("%d-%b-%Y"),
|
||||
)
|
||||
text = f"{item.product.name} ({item.product.units}) {item.batch.quantity_remaining:.2f}@{item.batch.rate:.2f} from {item.batch.name.strftime('%d-%b-%Y')}"
|
||||
json_voucher["inventories"].append(
|
||||
{
|
||||
"id": item.id,
|
||||
@ -294,12 +289,12 @@ def voucher_info(voucher, db):
|
||||
return json_voucher
|
||||
|
||||
|
||||
def blank_voucher(info, dbsession):
|
||||
def blank_voucher(info, db):
|
||||
if "type" not in info:
|
||||
raise ValidationError("Voucher Type is null")
|
||||
raise ValueError("Voucher Type is null")
|
||||
type_ = info["type"]
|
||||
if "date" not in info:
|
||||
raise ValidationError("Date cannot be null")
|
||||
raise ValueError("Date cannot be null")
|
||||
json_voucher = {
|
||||
"type": type_,
|
||||
"date": info["date"],
|
||||
@ -313,9 +308,9 @@ def blank_voucher(info, dbsession):
|
||||
pass
|
||||
elif type_ == "Payment":
|
||||
account = None
|
||||
if info is not None and "account" in info and info["account"] is not None:
|
||||
if info and "account" in info and info["account"]:
|
||||
account = (
|
||||
dbsession.query(AccountBase)
|
||||
db.query(AccountBase)
|
||||
.filter(AccountBase.id == uuid.UUID(info["account"]))
|
||||
.first()
|
||||
)
|
||||
@ -326,9 +321,9 @@ def blank_voucher(info, dbsession):
|
||||
json_voucher["journals"].append({"account": account, "amount": 0, "debit": -1})
|
||||
elif type_ == "Receipt":
|
||||
account = None
|
||||
if info is not None and "account" in info and info["account"] is not None:
|
||||
if info and "account" in info and info["account"]:
|
||||
account = (
|
||||
dbsession.query(AccountBase)
|
||||
db.query(AccountBase)
|
||||
.filter(AccountBase.id == uuid.UUID(info["account"]))
|
||||
.first()
|
||||
)
|
||||
@ -338,9 +333,8 @@ def blank_voucher(info, dbsession):
|
||||
account = AccountBase.cash_in_hand()
|
||||
json_voucher["journals"].append({"account": account, "amount": 0, "debit": 1})
|
||||
elif type_ == "Purchase":
|
||||
json_voucher["journals"].append(
|
||||
{"account": AccountBase.local_purchase(), "amount": 0, "debit": -1}
|
||||
)
|
||||
json_voucher["vendor"] = AccountBase.local_purchase()
|
||||
|
||||
elif type_ == "Purchase Return":
|
||||
json_voucher["journals"].append(
|
||||
{"account": AccountBase.local_purchase(), "amount": 0, "debit": 1}
|
||||
@ -392,7 +386,7 @@ def blank_voucher(info, dbsession):
|
||||
}
|
||||
)
|
||||
|
||||
elif type_ == "Salary Deduction":
|
||||
elif type_ == "Employee Benefit":
|
||||
json_voucher["employeeBenefits"] = []
|
||||
elif type_ == "Incentive":
|
||||
json_voucher["incentives"], json_voucher[
|
||||
|
@ -4,17 +4,17 @@ import uuid
|
||||
|
||||
from brewman.core.session import get_last_day
|
||||
from brewman.models.master import AccountBase, Employee
|
||||
from brewman.models.voucher import Journal, Voucher, VoucherType, SalaryDeduction
|
||||
from brewman.models.voucher import Journal, Voucher, VoucherType, EmployeeBenefit
|
||||
|
||||
|
||||
def salary_deduction_create_voucher(json, user, dbsession):
|
||||
def employee_benefit_create_voucher(json, user, dbsession):
|
||||
dt = get_last_day(datetime.datetime.strptime(json["date"], "%d-%b-%Y"))
|
||||
days_in_month = dt.day
|
||||
voucher = Voucher(date=dt, user_id=user.id, type=VoucherType.by_id(12))
|
||||
dbsession.add(voucher)
|
||||
exp, total = 0, 0
|
||||
for item in json["employeeBenefits"]:
|
||||
item_exp, item_total = add_salary_deduction(
|
||||
item_exp, item_total = add_employee_benefit(
|
||||
item, days_in_month, voucher, dbsession
|
||||
)
|
||||
exp += item_exp
|
||||
@ -50,10 +50,10 @@ def salary_deduction_create_voucher(json, user, dbsession):
|
||||
return voucher
|
||||
|
||||
|
||||
def salary_deduction_update_voucher(voucher, json, user, dbsession):
|
||||
def employee_benefit_update_voucher(voucher, json, user, dbsession):
|
||||
dt = get_last_day(datetime.datetime.strptime(json["date"], "%d-%b-%Y"))
|
||||
if dt != voucher.date.date():
|
||||
raise ValidationError("Date Cannot be changed for Salary Deduction voucher!")
|
||||
raise ValidationError("Date Cannot be changed for Employee Benefit voucher!")
|
||||
days_in_month = voucher.date.day
|
||||
voucher.user_id = user.id
|
||||
voucher.posted = False
|
||||
@ -61,8 +61,8 @@ def salary_deduction_update_voucher(voucher, json, user, dbsession):
|
||||
|
||||
new_deductions = json["employeeBenefits"]
|
||||
exp, total, journals = 0, 0, []
|
||||
for i in range(len(voucher.salary_deductions), 0, -1):
|
||||
item = voucher.salary_deductions[i - 1]
|
||||
for i in range(len(voucher.employee_benefits), 0, -1):
|
||||
item = voucher.employee_benefits[i - 1]
|
||||
found = False
|
||||
for j in range(len(new_deductions), 0, -1):
|
||||
new_item = new_deductions[j - 1]
|
||||
@ -77,10 +77,10 @@ def salary_deduction_update_voucher(voucher, json, user, dbsession):
|
||||
new_deductions.remove(new_item)
|
||||
break
|
||||
if not found:
|
||||
voucher.salary_deductions.remove(item)
|
||||
voucher.employee_benefits.remove(item)
|
||||
voucher.journals.remove(item.journal)
|
||||
for new_item in new_deductions:
|
||||
item_exp, item_total = add_salary_deduction(
|
||||
item_exp, item_total = add_employee_benefit(
|
||||
new_item, days_in_month, voucher, dbsession
|
||||
)
|
||||
exp += item_exp
|
||||
@ -101,7 +101,7 @@ def salary_deduction_update_voucher(voucher, json, user, dbsession):
|
||||
return voucher
|
||||
|
||||
|
||||
def add_salary_deduction(item, days_in_month, voucher, dbsession):
|
||||
def add_employee_benefit(item, days_in_month, voucher, dbsession):
|
||||
account = (
|
||||
dbsession.query(Employee)
|
||||
.filter(Employee.id == uuid.UUID(item["journal"]["account"]["id"]))
|
||||
@ -119,7 +119,7 @@ def add_salary_deduction(item, days_in_month, voucher, dbsession):
|
||||
account_id=account.id,
|
||||
cost_centre_id=account.cost_centre_id,
|
||||
)
|
||||
sd = SalaryDeduction(
|
||||
sd = EmployeeBenefit(
|
||||
journal=journal,
|
||||
gross_salary=gross_salary,
|
||||
days_worked=days_worked,
|
||||
@ -129,7 +129,7 @@ def add_salary_deduction(item, days_in_month, voucher, dbsession):
|
||||
pf_er=pf_er,
|
||||
)
|
||||
voucher.journals.append(journal)
|
||||
voucher.salary_deductions.append(sd)
|
||||
voucher.employee_benefits.append(sd)
|
||||
dbsession.add(journal)
|
||||
dbsession.add(sd)
|
||||
return esi_er + pf_er, esi_both + pf_both
|
@ -16,15 +16,11 @@ class EmptyVoucher(object):
|
||||
account = self.request.GET.get("a", None)
|
||||
return self.get_blank({"account": account})
|
||||
|
||||
@router.get("/api/voucher", request_param="t=Purchase") # "Purchase"
|
||||
def purchase(self):
|
||||
return self.get_blank()
|
||||
|
||||
@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=Salary Deduction") # "Purchase Return"
|
||||
@router.get("/api/voucher", request_param="t=Employee Benefit") # "Purchase Return"
|
||||
def purchase_return(self):
|
||||
return self.get_blank()
|
||||
|
||||
|
@ -5,7 +5,6 @@ import uuid
|
||||
from fastapi import HTTPException, status
|
||||
|
||||
from brewman.models.master import CostCentre, AccountBase
|
||||
from brewman.models.operations import inventory_valid
|
||||
from brewman.models.voucher import Voucher, VoucherType, Batch, Inventory, Journal
|
||||
|
||||
|
||||
|
@ -1,192 +0,0 @@
|
||||
import datetime
|
||||
import uuid
|
||||
from decimal import Decimal
|
||||
|
||||
from fastapi import HTTPException, status
|
||||
from sqlalchemy import func
|
||||
|
||||
from brewman.models.master import Product, AccountBase
|
||||
from brewman.models.operations import inventory_valid
|
||||
from brewman.models.voucher import (
|
||||
Voucher,
|
||||
VoucherType,
|
||||
Batch,
|
||||
Inventory,
|
||||
Journal,
|
||||
DbImage,
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def purchase_update_voucher(voucher, json, files, user, dbsession):
|
||||
voucher.date = datetime.datetime.strptime(json["date"], "%d-%b-%Y")
|
||||
voucher.is_starred = json["isStarred"]
|
||||
voucher.narration = json["narration"].strip()
|
||||
voucher.user_id = user.id
|
||||
voucher.posted = False
|
||||
voucher.last_edit_date = datetime.datetime.utcnow()
|
||||
|
||||
purchase_update_inventory(voucher, json["inventories"], dbsession)
|
||||
purchase_update_journals(voucher, json["journals"], dbsession)
|
||||
journals_valid(voucher)
|
||||
inventory_valid(voucher)
|
||||
|
||||
old_files = [
|
||||
uuid.UUID(f["id"]) for f in json["files"] if "id" in f and f["id"] is not None
|
||||
]
|
||||
images = dbsession.query(DbImage).filter(DbImage.resource_id == voucher.id).all()
|
||||
for image in [i for i in images if i.id not in old_files]:
|
||||
dbsession.delete(image)
|
||||
for key, value in files.items():
|
||||
dbsession.add(DbImage(voucher.id, "voucher", value["f"], value["t"]))
|
||||
return voucher
|
||||
|
||||
|
||||
def purchase_update_inventory(voucher, new_inventories, dbsession):
|
||||
for it in range(len(voucher.inventories), 0, -1):
|
||||
item = voucher.inventories[it - 1]
|
||||
found = False
|
||||
for j in range(len(new_inventories), 0, -1):
|
||||
i = new_inventories[j - 1]
|
||||
if "id" in i and i["id"] is not None and item.id == uuid.UUID(i["id"]):
|
||||
product = (
|
||||
dbsession.query(Product)
|
||||
.filter(Product.id == uuid.UUID(i["product"]["id"]))
|
||||
.first()
|
||||
)
|
||||
found = True
|
||||
if item.product_id != product.id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail="Product cannot be changed",
|
||||
)
|
||||
new_quantity = round(Decimal(i["quantity"]), 2)
|
||||
old_quantity = round(Decimal(item.quantity), 2)
|
||||
quantity_remaining = round(Decimal(item.batch.quantity_remaining), 2)
|
||||
if new_quantity <= 0:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail=f"Quantity of {item.product.name} cannot be zero",
|
||||
)
|
||||
if old_quantity > new_quantity and quantity_remaining < (
|
||||
old_quantity - new_quantity
|
||||
):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail=f"{old_quantity - quantity_remaining} has been issued, minimum quantity is",
|
||||
)
|
||||
item.batch.quantity_remaining -= old_quantity - new_quantity
|
||||
item.quantity = new_quantity
|
||||
rate = round(Decimal(i["rate"]), 2)
|
||||
discount = round(Decimal(i["discount"]), 5)
|
||||
tax = round(Decimal(i["tax"]), 5)
|
||||
if voucher.date != item.batch.name:
|
||||
item.batch.name = voucher.date
|
||||
if voucher.date < item.batch.name:
|
||||
# TODO: check for issued products which might have been in a back date
|
||||
pass
|
||||
item.rate = rate
|
||||
item.batch.rate = rate
|
||||
item.discount = discount
|
||||
item.batch.discount = discount
|
||||
item.tax = tax
|
||||
item.batch.tax = tax
|
||||
product.price = rate
|
||||
new_inventories.remove(i)
|
||||
# TODO: Update all references of the batch with the new rates
|
||||
break
|
||||
if not found:
|
||||
uses = (
|
||||
dbsession.query(func.count(Inventory.id))
|
||||
.filter(Inventory.batch_id == item.batch.id)
|
||||
.filter(Inventory.id != item.id)
|
||||
.scalar()
|
||||
)
|
||||
if uses > 0:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
||||
detail=f"{item.product.name} has been issued, it cannot be deleted",
|
||||
)
|
||||
else:
|
||||
dbsession.delete(item.batch)
|
||||
dbsession.delete(item)
|
||||
voucher.inventories.remove(item)
|
||||
for i in new_inventories:
|
||||
product = (
|
||||
dbsession.query(Product)
|
||||
.filter(Product.id == uuid.UUID(i["product"]["id"]))
|
||||
.first()
|
||||
)
|
||||
new_quantity = round(Decimal(i["quantity"]), 2)
|
||||
rate = round(Decimal(i["rate"]), 2)
|
||||
tax = round(Decimal(i["tax"]), 5)
|
||||
discount = round(Decimal(i["discount"]), 5)
|
||||
batch = Batch(
|
||||
name=voucher.date,
|
||||
product_id=product.id,
|
||||
quantity_remaining=new_quantity,
|
||||
rate=rate,
|
||||
tax=tax,
|
||||
discount=discount,
|
||||
)
|
||||
inventory = Inventory(
|
||||
id=None,
|
||||
product_id=product.id,
|
||||
batch=batch,
|
||||
quantity=new_quantity,
|
||||
rate=rate,
|
||||
tax=tax,
|
||||
discount=discount,
|
||||
)
|
||||
inventory.voucher_id = voucher.id
|
||||
dbsession.add(batch)
|
||||
inventory.batch_id = batch.id
|
||||
product.price = rate
|
||||
voucher.inventories.append(inventory)
|
||||
dbsession.add(inventory)
|
||||
|
||||
|
||||
def purchase_update_journals(voucher, journals, dbsession):
|
||||
other_account = [ff for ff in journals if ff["debit"] == -1]
|
||||
other_account = (
|
||||
dbsession.query(AccountBase)
|
||||
.filter(AccountBase.id == uuid.UUID(other_account[0]["account"]["id"]))
|
||||
.first()
|
||||
)
|
||||
journals = dict()
|
||||
amount = 0
|
||||
for item in voucher.inventories:
|
||||
product = dbsession.query(Product).filter(Product.id == item.product_id).first()
|
||||
account = product.account
|
||||
amount += item.amount
|
||||
if account.id in journals:
|
||||
journals[account.id].amount += item.amount
|
||||
else:
|
||||
journals[account.id] = Journal(
|
||||
debit=1,
|
||||
cost_centre_id=account.cost_centre_id,
|
||||
account_id=account.id,
|
||||
amount=item.amount,
|
||||
)
|
||||
journals[other_account.id] = Journal(
|
||||
debit=-1,
|
||||
cost_centre_id=other_account.cost_centre_id,
|
||||
account_id=other_account.id,
|
||||
amount=amount,
|
||||
)
|
||||
for i in range(len(voucher.journals), 0, -1):
|
||||
item = voucher.journals[i - 1]
|
||||
if item.account_id in journals:
|
||||
item.debit = journals[item.account_id].debit
|
||||
item.amount = round(journals[item.account_id].amount, 2)
|
||||
item.cost_centre_id = journals[item.account_id].cost_centre_id
|
||||
del journals[item.account_id]
|
||||
else:
|
||||
dbsession.delete(item)
|
||||
voucher.journals.remove(item)
|
||||
for item in journals.values():
|
||||
item.amount = round(item.amount, 2)
|
||||
voucher.journals.append(item)
|
||||
dbsession.add(item)
|
@ -1,218 +0,0 @@
|
||||
import datetime
|
||||
import uuid
|
||||
from decimal import Decimal
|
||||
|
||||
from brewman.models.master import Product, AccountBase
|
||||
from brewman.models.operations import inventory_valid, journals_valid
|
||||
from brewman.models.validation_exception import ValidationError
|
||||
from brewman.models.voucher import (
|
||||
Voucher,
|
||||
VoucherType,
|
||||
Batch,
|
||||
Inventory,
|
||||
Journal,
|
||||
DbImage,
|
||||
)
|
||||
|
||||
|
||||
def purchase_return_create_voucher(json, files, user, dbsession):
|
||||
dt = datetime.datetime.strptime(json["date"], "%d-%b-%Y")
|
||||
voucher = Voucher(
|
||||
date=dt,
|
||||
narration=json["narration"].strip(),
|
||||
is_starred=json["isStarred"],
|
||||
user_id=user.id,
|
||||
type=VoucherType.by_name(json["type"]),
|
||||
)
|
||||
dbsession.add(voucher)
|
||||
|
||||
for item in json["inventories"]:
|
||||
purchase_return_create_inventory(voucher, item, dbsession)
|
||||
for item in purchase_return_create_journals(
|
||||
voucher.inventories, json["journals"][0]["account"]["id"], dbsession
|
||||
):
|
||||
voucher.journals.append(item)
|
||||
dbsession.add(item)
|
||||
journals_valid(voucher)
|
||||
inventory_valid(voucher)
|
||||
for key, value in files.items():
|
||||
dbsession.add(DbImage(voucher.id, "voucher", value["f"], value["t"]))
|
||||
return voucher
|
||||
|
||||
|
||||
def purchase_return_create_inventory(voucher, item, 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 = Decimal(item["quantity"])
|
||||
|
||||
if quantity <= 0:
|
||||
raise ValidationError(f"Quantity of {item.product.name} cannot be zero")
|
||||
if quantity > batch.quantity_remaining:
|
||||
raise ValidationError(f"Quantity available is {batch.quantity_remaining} only")
|
||||
if batch.name > voucher.date:
|
||||
raise ValidationError("Batch of {batch.product.name} was purchased after the issue date")
|
||||
|
||||
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 purchase_return_create_journals(inventories, account_id, dbsession):
|
||||
other_account = (
|
||||
dbsession.query(AccountBase)
|
||||
.filter(AccountBase.id == uuid.UUID(account_id))
|
||||
.first()
|
||||
)
|
||||
journals = dict()
|
||||
amount = 0
|
||||
for item in inventories:
|
||||
product = dbsession.query(Product).filter(Product.id == item.product_id).first()
|
||||
account = product.account
|
||||
amount += round(item.amount, 2)
|
||||
if account.id in journals:
|
||||
journals[account.id].amount += round(item.amount, 2)
|
||||
else:
|
||||
journals[account.id] = Journal(
|
||||
debit=-1,
|
||||
cost_centre_id=account.cost_centre_id,
|
||||
account_id=account.id,
|
||||
amount=round(item.amount, 2),
|
||||
)
|
||||
journals[other_account.id] = Journal(
|
||||
debit=1,
|
||||
cost_centre_id=other_account.cost_centre_id,
|
||||
account_id=other_account.id,
|
||||
amount=amount,
|
||||
)
|
||||
return list(journals.values())
|
||||
|
||||
|
||||
def purchase_return_update_voucher(voucher, json, files, user, dbsession):
|
||||
voucher.date = datetime.datetime.strptime(json["date"], "%d-%b-%Y")
|
||||
voucher.is_starred = json["isStarred"]
|
||||
voucher.narration = json["narration"].strip()
|
||||
voucher.user_id = user.id
|
||||
voucher.posted = False
|
||||
voucher.last_edit_date = datetime.datetime.utcnow()
|
||||
|
||||
purchase_return_update_inventory(
|
||||
voucher, json["inventories"], json["date"], dbsession
|
||||
)
|
||||
purchase_return_update_journals(voucher, json["journals"], dbsession)
|
||||
journals_valid(voucher)
|
||||
inventory_valid(voucher)
|
||||
|
||||
old_files = [
|
||||
uuid.UUID(f["id"]) for f in json["files"] if "id" in f and f["id"] is not None
|
||||
]
|
||||
images = dbsession.query(DbImage).filter(DbImage.resource_id == voucher.id).all()
|
||||
for image in [i for i in images if i.id not in old_files]:
|
||||
dbsession.delete(image)
|
||||
for key, value in files.items():
|
||||
dbsession.add(DbImage(voucher.id, "voucher", value["f"], value["t"]))
|
||||
return voucher
|
||||
|
||||
|
||||
def purchase_return_update_inventory(voucher, new_inventories, date, dbsession):
|
||||
for it in range(len(voucher.inventories), 0, -1):
|
||||
item = voucher.inventories[it - 1]
|
||||
found = False
|
||||
for j in range(len(new_inventories), 0, -1):
|
||||
i = new_inventories[j - 1]
|
||||
if "id" in i and i["id"] is not None and item.id == uuid.UUID(i["id"]):
|
||||
product = (
|
||||
dbsession.query(Product)
|
||||
.filter(Product.id == uuid.UUID(i["product"]["id"]))
|
||||
.first()
|
||||
)
|
||||
found = True
|
||||
if item.product_id != product.id:
|
||||
raise ValidationError("Product cannot be changed")
|
||||
quantity = round(Decimal(i["quantity"]), 2)
|
||||
if quantity == 0:
|
||||
raise ValidationError(
|
||||
"Quantity of {0} cannot be zero".format(item.product.name)
|
||||
)
|
||||
if quantity - item.quantity > item.batch.quantity_remaining:
|
||||
raise ValidationError(
|
||||
"Maximum quantity available for {0} is {1}".format(
|
||||
item.product.full_name,
|
||||
item.quantity + item.batch.quantity_remaining,
|
||||
)
|
||||
)
|
||||
if item.batch.name > voucher.date:
|
||||
raise ValidationError(
|
||||
"Batch of {0} was purchased after the issue date".format(
|
||||
item.product.name
|
||||
)
|
||||
)
|
||||
item.batch.quantity_remaining -= quantity - item.quantity
|
||||
item.quantity = quantity
|
||||
new_inventories.remove(i)
|
||||
break
|
||||
if not found:
|
||||
item.batch.quantity_remaining += item.quantity
|
||||
voucher.inventories.remove(item)
|
||||
dbsession.delete(item)
|
||||
for i in new_inventories:
|
||||
purchase_return_create_inventory(voucher, i, dbsession)
|
||||
|
||||
|
||||
def purchase_return_update_journals(voucher, journals, dbsession):
|
||||
other_account = [ff for ff in journals if ff["debit"] == 1]
|
||||
other_account = (
|
||||
dbsession.query(AccountBase)
|
||||
.filter(AccountBase.id == uuid.UUID(other_account[0]["account"]["id"]))
|
||||
.first()
|
||||
)
|
||||
journals = dict()
|
||||
amount = 0
|
||||
for item in voucher.inventories:
|
||||
product = dbsession.query(Product).filter(Product.id == item.product_id).first()
|
||||
account = product.account
|
||||
amount += round(item.amount, 2)
|
||||
if account.id in journals:
|
||||
journals[account.id].amount += round(item.amount, 2)
|
||||
else:
|
||||
journals[account.id] = Journal(
|
||||
debit=-1,
|
||||
cost_centre_id=account.cost_centre_id,
|
||||
account_id=account.id,
|
||||
amount=round(item.amount, 2),
|
||||
)
|
||||
journals[other_account.id] = Journal(
|
||||
debit=1,
|
||||
cost_centre_id=other_account.cost_centre_id,
|
||||
account_id=other_account.id,
|
||||
amount=amount,
|
||||
)
|
||||
for i in range(len(voucher.journals), 0, -1):
|
||||
item = voucher.journals[i - 1]
|
||||
if item.account_id in journals:
|
||||
item.debit = journals[item.account_id].debit
|
||||
item.amount = journals[item.account_id].amount
|
||||
item.cost_centre_id = journals[item.account_id].cost_centre_id
|
||||
del journals[item.account_id]
|
||||
else:
|
||||
dbsession.delete(item)
|
||||
voucher.journals.remove(item)
|
||||
for item in journals.values():
|
||||
item.amount = item.amount
|
||||
voucher.journals.append(item)
|
||||
dbsession.add(item)
|
95
brewman/schemas/input.py
Normal file
95
brewman/schemas/input.py
Normal file
@ -0,0 +1,95 @@
|
||||
import uuid
|
||||
import json
|
||||
from datetime import datetime, date
|
||||
from decimal import Decimal
|
||||
from typing import List, Optional
|
||||
|
||||
from fastapi import Form
|
||||
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.voucher import VoucherIn, Journal, Inventory
|
||||
|
||||
|
||||
class JournalIn(VoucherIn):
|
||||
journals: List[Journal]
|
||||
|
||||
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("journals")
|
||||
def validate_signed_amount(cls, value: List[Journal]):
|
||||
if sum(x.debit * x.amount for x in value) != 0:
|
||||
raise ValueError("Journal amounts do no match")
|
||||
return value
|
||||
|
||||
@validator("journals")
|
||||
def is_distinct(cls, value: List[Journal]):
|
||||
journal_set = set(hash(x.account.id_) ^ hash(None if x.cost_centre is None else x.cost_centre.id_) for x in value)
|
||||
if len(value) != len(journal_set):
|
||||
raise ValueError("Duplicate journals")
|
||||
return value
|
||||
|
||||
@classmethod
|
||||
def load_form(cls, data: str = Form(...)):
|
||||
json_data = json.loads(data)
|
||||
return cls.parse_obj(json_data)
|
||||
|
||||
|
||||
class PurchaseIn(VoucherIn):
|
||||
vendor: AccountLink
|
||||
inventories: List[Inventory]
|
||||
|
||||
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
|
||||
|
||||
@classmethod
|
||||
def load_form(cls, data: str = Form(...)):
|
||||
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]
|
||||
|
||||
|
||||
pass
|
@ -2,7 +2,7 @@ import uuid
|
||||
import json
|
||||
from datetime import datetime, date
|
||||
from decimal import Decimal
|
||||
from typing import List, Optional
|
||||
from typing import List, Optional, Any
|
||||
|
||||
from fastapi import Form
|
||||
from pydantic import BaseModel, validator, Field
|
||||
@ -11,6 +11,14 @@ from brewman.schemas import to_camel
|
||||
from brewman.schemas.master import AccountLink, CostCentreLink, ProductLink
|
||||
|
||||
|
||||
class UserLink(BaseModel):
|
||||
id_: uuid.UUID
|
||||
name: str
|
||||
|
||||
class Config:
|
||||
alias_generator = to_camel
|
||||
|
||||
|
||||
class Journal(BaseModel):
|
||||
id_: Optional[uuid.UUID]
|
||||
debit: int = Field(ge=-1, le=1, multiple_of=1)
|
||||
@ -23,20 +31,34 @@ class Journal(BaseModel):
|
||||
alias_generator = to_camel
|
||||
|
||||
|
||||
class Inventory(BaseModel):
|
||||
class Batch(BaseModel):
|
||||
id_: uuid.UUID
|
||||
name: str
|
||||
product: ProductLink
|
||||
batch_id: uuid.UUID
|
||||
quantity: Decimal = Field(ge=0, multiple_of=0.01)
|
||||
rate: Decimal = Field(ge=0, multiple_of=0.01)
|
||||
tax: Decimal = Field(ge=0, multiple_of=0.00001)
|
||||
discount: Decimal = Field(ge=0, multiple_of=0.00001)
|
||||
quantity_remaining: Decimal
|
||||
rate: Decimal
|
||||
tax: Decimal
|
||||
discount: Decimal
|
||||
|
||||
class Config:
|
||||
alias_generator = to_camel
|
||||
|
||||
|
||||
class SalaryDeduction(BaseModel):
|
||||
class Inventory(BaseModel):
|
||||
id_: Optional[uuid.UUID]
|
||||
product: ProductLink
|
||||
batch: Optional[Batch]
|
||||
quantity: Decimal = Field(ge=0, multiple_of=0.01)
|
||||
rate: Decimal = Field(ge=0, multiple_of=0.01)
|
||||
tax: Decimal = Field(ge=0, multiple_of=0.00001, le=5)
|
||||
discount: Decimal = Field(ge=0, multiple_of=0.00001, le=1)
|
||||
amount: Optional[Decimal]
|
||||
|
||||
class Config:
|
||||
alias_generator = to_camel
|
||||
|
||||
|
||||
class EmployeeBenefit(BaseModel):
|
||||
id: uuid.UUID
|
||||
voucher_id: uuid.UUID
|
||||
journal_id: uuid.UUID
|
||||
@ -56,31 +78,31 @@ class Incentive(BaseModel):
|
||||
points: Decimal
|
||||
|
||||
|
||||
class Batch(BaseModel):
|
||||
id: uuid.UUID
|
||||
name: datetime
|
||||
product_id: uuid.UUID
|
||||
quantity_remaining: Decimal
|
||||
rate: Decimal
|
||||
tax: Decimal
|
||||
discount: Decimal
|
||||
|
||||
|
||||
class Voucher(BaseModel):
|
||||
id_: Optional[uuid.UUID]
|
||||
class VoucherIn(BaseModel):
|
||||
date_: date
|
||||
narration: str
|
||||
is_starred: bool
|
||||
type_: str
|
||||
|
||||
@classmethod
|
||||
def load_form(cls, data: str = Form(...)):
|
||||
json_data = json.loads(data)
|
||||
return cls.parse_obj(json_data)
|
||||
|
||||
|
||||
class Voucher(VoucherIn):
|
||||
id_: Optional[uuid.UUID]
|
||||
is_reconciled: Optional[bool]
|
||||
reconcile_date: Optional[date]
|
||||
is_starred: bool
|
||||
creation_date: Optional[datetime]
|
||||
last_edit_date: Optional[datetime]
|
||||
type_: str
|
||||
user_id: Optional[uuid.UUID]
|
||||
user: UserLink
|
||||
posted: Optional[bool]
|
||||
poster_id: Optional[uuid.UUID]
|
||||
journals: List[Journal]
|
||||
inventories: List[Inventory]
|
||||
vendor: Optional[AccountLink]
|
||||
files: List[Any]
|
||||
|
||||
class Config:
|
||||
anystr_strip_whitespace = True
|
||||
@ -121,7 +143,7 @@ class Voucher(BaseModel):
|
||||
|
||||
@validator("journals")
|
||||
def validate_enough_journals(cls, value: List[Journal]):
|
||||
if len(value) < 2:
|
||||
if 0 < len(value) < 2:
|
||||
raise ValueError("Not enough journals")
|
||||
return value
|
||||
|
||||
@ -138,11 +160,6 @@ class Voucher(BaseModel):
|
||||
raise ValueError("Duplicate journals")
|
||||
return value
|
||||
|
||||
@classmethod
|
||||
def load_form(cls, data: str = Form(...)):
|
||||
json_data = json.loads(data)
|
||||
return cls.parse_obj(json_data)
|
||||
|
||||
|
||||
class AttendanceType(BaseModel):
|
||||
id_: int
|
||||
|
@ -36,7 +36,7 @@ from brewman.models.voucher import (
|
||||
Inventory,
|
||||
Journal,
|
||||
Product,
|
||||
SalaryDeduction,
|
||||
EmployeeBenefit,
|
||||
Voucher,
|
||||
Incentive,
|
||||
DbImage,
|
||||
@ -125,7 +125,7 @@ def main(argv=sys.argv):
|
||||
uuid.UUID("a8328891-7ce2-a943-8c29-2eabc1ffeea3"),
|
||||
),
|
||||
Role("Clients", uuid.UUID("cfad44f0-f2a9-7045-89d7-9019cf0f371a")),
|
||||
Role("Salary Deduction", uuid.UUID("92d70e80-1c32-384d-959e-abf84b804696")),
|
||||
Role("Employee Benefit", uuid.UUID("92d70e80-1c32-384d-959e-abf84b804696")),
|
||||
Role("Messages", uuid.UUID("f586d128-b6d9-4090-a913-78fcbdb68e59")),
|
||||
Role("Lock Date", uuid.UUID("d52de0be-9388-4b0b-a359-7e122ab6e53a")),
|
||||
Role("Net Transactions", uuid.UUID("2c40f7cf-67fc-4efa-a670-8d16a2e7884d")),
|
||||
|
@ -3,7 +3,7 @@
|
||||
<mat-menu #voucherMenu="matMenu">
|
||||
<a mat-menu-item routerLink="/journal">Journal</a>
|
||||
<a mat-menu-item routerLink="/purchase">Purchase</a>
|
||||
<a mat-menu-item routerLink="/return">Purchase Return</a>
|
||||
<a mat-menu-item routerLink="/purchase-return">Purchase Return</a>
|
||||
<a mat-menu-item routerLink="/payment">Payment</a>
|
||||
<a mat-menu-item routerLink="/receipt">Receipt</a>
|
||||
<a mat-menu-item routerLink="/issue">Issue</a>
|
||||
|
@ -63,9 +63,16 @@ export class VoucherService {
|
||||
);
|
||||
}
|
||||
|
||||
save(voucher: Voucher): Observable<Voucher> {
|
||||
saveOrUpdate(voucher: Voucher): Observable<Voucher> {
|
||||
const endpoint = voucher.type.replace(/ /g, '-').toLowerCase();
|
||||
if (!voucher.id) {
|
||||
return this.save(voucher, endpoint);
|
||||
} else {
|
||||
return this.update(voucher, endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
save(voucher: Voucher, endpoint: string): Observable<Voucher> {
|
||||
const fd = new FormData();
|
||||
voucher.files.filter(x => !x.id).forEach((file) => {
|
||||
fd.append('i' , this.dataURLtoBlob(file.resized));
|
||||
@ -73,10 +80,23 @@ export class VoucherService {
|
||||
});
|
||||
voucher.files = voucher.files.filter(x => x.id);
|
||||
fd.append('data', JSON.stringify(voucher));
|
||||
const saveUrl: string = (voucher.id === undefined || voucher.id === null) ? `${url}/${endpoint}` : `${url}/${endpoint}/${voucher.id}`;
|
||||
return <Observable<Voucher>>this.http.post<Voucher>(saveUrl, fd)
|
||||
return <Observable<Voucher>>this.http.post<Voucher>(`${url}/${endpoint}`, fd)
|
||||
.pipe(
|
||||
catchError(this.log.handleError(serviceName, 'list'))
|
||||
catchError(this.log.handleError(serviceName, 'save'))
|
||||
);
|
||||
}
|
||||
|
||||
update(voucher: Voucher, endpoint: string): Observable<Voucher> {
|
||||
const fd = new FormData();
|
||||
voucher.files.filter(x => !x.id).forEach((file) => {
|
||||
fd.append('i' , this.dataURLtoBlob(file.resized));
|
||||
fd.append('t' , this.dataURLtoBlob(file.thumbnail));
|
||||
});
|
||||
voucher.files = voucher.files.filter(x => x.id);
|
||||
fd.append('data', JSON.stringify(voucher));
|
||||
return <Observable<Voucher>>this.http.put<Voucher>(`${url}/${endpoint}/${voucher.id}`, fd)
|
||||
.pipe(
|
||||
catchError(this.log.handleError(serviceName, 'update'))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ export class Voucher {
|
||||
posted: boolean;
|
||||
narration: string;
|
||||
incentive?: number;
|
||||
vendor?: Account;
|
||||
journals: Journal[];
|
||||
inventories: Inventory[];
|
||||
employeeBenefits: EmployeeBenefit[];
|
||||
|
@ -191,7 +191,7 @@ export class EmployeeBenefitsComponent implements OnInit, AfterViewInit {
|
||||
}
|
||||
|
||||
save() {
|
||||
this.ser.save(this.getVoucher())
|
||||
this.ser.saveOrUpdate(this.getVoucher())
|
||||
.subscribe(
|
||||
(result) => {
|
||||
this.toaster.show('Success', '');
|
||||
|
@ -141,7 +141,7 @@ export class IncentiveComponent implements OnInit {
|
||||
}
|
||||
|
||||
save() {
|
||||
this.ser.save(this.getVoucher())
|
||||
this.ser.saveOrUpdate(this.getVoucher())
|
||||
.subscribe(
|
||||
(result) => {
|
||||
this.toaster.show('Success', '');
|
||||
|
@ -223,7 +223,7 @@ export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
|
||||
save() {
|
||||
this.ser.save(this.getVoucher())
|
||||
this.ser.saveOrUpdate(this.getVoucher())
|
||||
.subscribe(
|
||||
(result) => {
|
||||
this.loadVoucher(result);
|
||||
|
@ -224,7 +224,7 @@ export class JournalComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
|
||||
save() {
|
||||
this.ser.save(this.getVoucher())
|
||||
this.ser.saveOrUpdate(this.getVoucher())
|
||||
.subscribe(
|
||||
(result) => {
|
||||
this.loadVoucher(result);
|
||||
|
@ -228,7 +228,7 @@ export class PaymentComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
|
||||
save() {
|
||||
this.ser.save(this.getVoucher())
|
||||
this.ser.saveOrUpdate(this.getVoucher())
|
||||
.subscribe(
|
||||
(result) => {
|
||||
this.loadVoucher(result);
|
||||
|
@ -8,7 +8,7 @@ import {PurchaseReturnDataSource} from './purchase-return-datasource';
|
||||
import {Account} from '../core/account';
|
||||
import {VoucherService} from '../core/voucher.service';
|
||||
import {AccountService} from '../core/account.service';
|
||||
import {Batch, DbFile, Inventory, Journal, Voucher} from '../core/voucher';
|
||||
import {Batch, DbFile, 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 {debounceTime, distinctUntilChanged, map, startWith, switchMap} from 'rxj
|
||||
import {PurchaseReturnDialogComponent} from './purchase-return-dialog.component';
|
||||
import {ImageDialogComponent} from '../shared/image-dialog/image-dialog.component';
|
||||
import {BatchService} from '../core/batch.service';
|
||||
import {Hotkey, HotkeysService} from "angular2-hotkeys";
|
||||
import {Hotkey, HotkeysService} from 'angular2-hotkeys';
|
||||
|
||||
@Component({
|
||||
selector: 'app-purchase-return',
|
||||
@ -31,9 +31,7 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
public inventoryObservable = new BehaviorSubject<Inventory[]>([]);
|
||||
dataSource: PurchaseReturnDataSource;
|
||||
form: FormGroup;
|
||||
purchaseReturnJournal: Journal;
|
||||
voucher: Voucher;
|
||||
account: Account;
|
||||
batch: Batch;
|
||||
accBal: any;
|
||||
|
||||
@ -71,13 +69,15 @@ export class PurchaseReturnComponent 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']));
|
||||
this.hotkeys.add(new Hotkey('ctrl+p', (event: KeyboardEvent): boolean => {
|
||||
if (this.voucher.id && !this.voucher.posted && this.auth.user.perms.indexOf('Post Vouchers') !== -1)
|
||||
if (this.voucher.id && !this.voucher.posted && this.auth.user.perms.indexOf('Post Vouchers') !== -1) {
|
||||
this.post();
|
||||
}
|
||||
return false; // Prevent bubbling
|
||||
}, ['INPUT', 'SELECT', 'TEXTAREA']));
|
||||
}
|
||||
@ -92,11 +92,10 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
|
||||
loadVoucher(voucher: Voucher) {
|
||||
this.voucher = voucher;
|
||||
this.purchaseReturnJournal = this.voucher.journals.filter(x => x.debit === 1)[0];
|
||||
this.form.setValue({
|
||||
date: moment(this.voucher.date, 'DD-MMM-YYYY').toDate(),
|
||||
account: this.purchaseReturnJournal.account,
|
||||
amount: this.purchaseReturnJournal.amount,
|
||||
account: this.voucher.vendor,
|
||||
amount: Math.abs(this.voucher.inventories.map((x) => x.amount).reduce((p, c) => p + c, 0)),
|
||||
addRow: {
|
||||
batch: '',
|
||||
quantity: ''
|
||||
@ -152,8 +151,7 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
|
||||
updateView() {
|
||||
this.inventoryObservable.next(this.voucher.inventories);
|
||||
this.purchaseReturnJournal.amount = Math.abs(this.voucher.inventories.map((x) => x.amount).reduce((p, c) => p + c, 0));
|
||||
this.form.get('amount').setValue(this.purchaseReturnJournal.amount);
|
||||
this.form.get('amount').setValue(Math.abs(this.voucher.inventories.map((x) => x.amount).reduce((p, c) => p + c, 0)));
|
||||
}
|
||||
|
||||
editRow(row: Inventory) {
|
||||
@ -217,12 +215,12 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
}
|
||||
|
||||
save() {
|
||||
this.ser.save(this.getVoucher())
|
||||
this.ser.saveOrUpdate(this.getVoucher())
|
||||
.subscribe(
|
||||
(result) => {
|
||||
this.loadVoucher(result);
|
||||
this.toaster.show('Success', '');
|
||||
this.router.navigate(['/return', result.id]);
|
||||
this.router.navigate(['/purchase-return', result.id]);
|
||||
},
|
||||
(error) => {
|
||||
this.toaster.show('Danger', error.error);
|
||||
@ -233,7 +231,7 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
getVoucher(): Voucher {
|
||||
const formModel = this.form.value;
|
||||
this.voucher.date = moment(formModel.date).format('DD-MMM-YYYY');
|
||||
this.purchaseReturnJournal.account = formModel.account;
|
||||
this.voucher.vendor = formModel.account;
|
||||
this.voucher.narration = formModel.narration;
|
||||
return this.voucher;
|
||||
}
|
||||
@ -243,7 +241,7 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
.subscribe(
|
||||
(result) => {
|
||||
this.toaster.show('Success', '');
|
||||
this.router.navigate(['/return'], {replaceUrl: true});
|
||||
this.router.navigate(['/purchase-return'], {replaceUrl: true});
|
||||
},
|
||||
(error) => {
|
||||
this.toaster.show('Danger', error.error);
|
||||
@ -297,7 +295,7 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy
|
||||
}
|
||||
|
||||
accountSelected(event: MatAutocompleteSelectedEvent): void {
|
||||
this.account = event.option.value;
|
||||
this.form.get('account').setValue(event.option.value);
|
||||
}
|
||||
|
||||
displayBatchName(batch?: Batch): string | undefined {
|
||||
|
@ -8,7 +8,7 @@ import {PurchaseDataSource} from './purchase-datasource';
|
||||
import {Account} from '../core/account';
|
||||
import {VoucherService} from '../core/voucher.service';
|
||||
import {AccountService} from '../core/account.service';
|
||||
import {DbFile, Inventory, Journal, Voucher} from '../core/voucher';
|
||||
import {DbFile, 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';
|
||||
@ -18,7 +18,7 @@ import {PurchaseDialogComponent} from './purchase-dialog.component';
|
||||
import {ImageDialogComponent} from '../shared/image-dialog/image-dialog.component';
|
||||
import {ProductService} from '../product/product.service';
|
||||
import {Product} from '../core/product';
|
||||
import {Hotkey, HotkeysService} from "angular2-hotkeys";
|
||||
import {Hotkey, HotkeysService} from 'angular2-hotkeys';
|
||||
|
||||
@Component({
|
||||
selector: 'app-purchase',
|
||||
@ -32,9 +32,7 @@ export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
public inventoryObservable = new BehaviorSubject<Inventory[]>([]);
|
||||
dataSource: PurchaseDataSource;
|
||||
form: FormGroup;
|
||||
purchaseJournal: Journal;
|
||||
voucher: Voucher;
|
||||
account: Account;
|
||||
product: Product;
|
||||
accBal: any;
|
||||
|
||||
@ -72,13 +70,15 @@ export class PurchaseComponent 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']));
|
||||
this.hotkeys.add(new Hotkey('ctrl+p', (event: KeyboardEvent): boolean => {
|
||||
if (this.voucher.id && !this.voucher.posted && this.auth.user.perms.indexOf('Post Vouchers') !== -1)
|
||||
if (this.voucher.id && !this.voucher.posted && this.auth.user.perms.indexOf('Post Vouchers') !== -1) {
|
||||
this.post();
|
||||
}
|
||||
return false; // Prevent bubbling
|
||||
}, ['INPUT', 'SELECT', 'TEXTAREA']));
|
||||
}
|
||||
@ -93,11 +93,10 @@ export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
loadVoucher(voucher) {
|
||||
this.voucher = voucher;
|
||||
this.purchaseJournal = this.voucher.journals.filter(x => x.debit === -1)[0];
|
||||
this.form.setValue({
|
||||
date: moment(this.voucher.date, 'DD-MMM-YYYY').toDate(),
|
||||
account: this.purchaseJournal.account,
|
||||
amount: this.purchaseJournal.amount,
|
||||
account: this.voucher.vendor,
|
||||
amount: Math.abs(this.voucher.inventories.map((x) => x.amount).reduce((p, c) => p + c, 0)),
|
||||
addRow: {
|
||||
product: '',
|
||||
quantity: '',
|
||||
@ -161,8 +160,7 @@ export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
updateView() {
|
||||
this.inventoryObservable.next(this.voucher.inventories);
|
||||
this.purchaseJournal.amount = Math.abs(this.voucher.inventories.map((x) => x.amount).reduce((p, c) => p + c, 0));
|
||||
this.form.get('amount').setValue(this.purchaseJournal.amount);
|
||||
this.form.get('amount').setValue(Math.abs(this.voucher.inventories.map((x) => x.amount).reduce((p, c) => p + c, 0)));
|
||||
}
|
||||
|
||||
editRow(row: Inventory) {
|
||||
@ -230,7 +228,7 @@ export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
|
||||
save() {
|
||||
this.ser.save(this.getVoucher())
|
||||
this.ser.saveOrUpdate(this.getVoucher())
|
||||
.subscribe(
|
||||
(result) => {
|
||||
this.loadVoucher(result);
|
||||
@ -246,7 +244,7 @@ export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
getVoucher(): Voucher {
|
||||
const formModel = this.form.value;
|
||||
this.voucher.date = moment(formModel.date).format('DD-MMM-YYYY');
|
||||
this.purchaseJournal.account = formModel.account;
|
||||
this.voucher.vendor = formModel.account;
|
||||
this.voucher.narration = formModel.narration;
|
||||
return this.voucher;
|
||||
}
|
||||
@ -306,7 +304,7 @@ export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
|
||||
accountSelected(event: MatAutocompleteSelectedEvent): void {
|
||||
this.account = event.option.value;
|
||||
this.form.get('account').setValue(event.option.value);
|
||||
}
|
||||
|
||||
displayProductName(product?: Product): string | undefined {
|
||||
|
@ -227,7 +227,7 @@ export class ReceiptComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
|
||||
save() {
|
||||
this.ser.save(this.getVoucher())
|
||||
this.ser.saveOrUpdate(this.getVoucher())
|
||||
.subscribe(
|
||||
(result) => {
|
||||
this.loadVoucher(result);
|
||||
|
Loading…
x
Reference in New Issue
Block a user