diff --git a/brewman/models/__init__.py b/brewman/models/__init__.py index 5bff5d17..15536c73 100644 --- a/brewman/models/__init__.py +++ b/brewman/models/__init__.py @@ -5,17 +5,29 @@ import zope.sqlalchemy # import or define all models here to ensure they are attached to the # Base.metadata prior to any initialization routines -from .voucher import Attendance, Batch, Fingerprint, Inventory, Journal, Product, SalaryDeduction, Voucher, VoucherType -from .master import (Product, - AttendanceType, - CostCentre, Employee, - Account, - AccountBase, - AccountType, - ProductGroup, - Recipe, - RecipeItem - ) +from .voucher import ( + Attendance, + Batch, + Fingerprint, + Inventory, + Journal, + Product, + SalaryDeduction, + Voucher, + VoucherType, +) +from .master import ( + Product, + AttendanceType, + CostCentre, + Employee, + Account, + AccountBase, + AccountType, + ProductGroup, + Recipe, + RecipeItem, +) from .auth import Client, Group, Role, User, role_group, user_group, LoginHistory # run configure_mappers after defining all of the models to ensure @@ -23,7 +35,7 @@ from .auth import Client, Group, Role, User, role_group, user_group, LoginHistor configure_mappers() -def get_engine(settings, prefix='sqlalchemy.'): +def get_engine(settings, prefix="sqlalchemy."): return engine_from_config(settings, prefix) @@ -55,8 +67,7 @@ def get_tm_session(session_factory, transaction_manager): """ dbsession = session_factory() - zope.sqlalchemy.register( - dbsession, transaction_manager=transaction_manager) + zope.sqlalchemy.register(dbsession, transaction_manager=transaction_manager) return dbsession @@ -70,15 +81,15 @@ def includeme(config): settings = config.get_settings() # use pyramid_tm to hook the transaction lifecycle to the request - config.include('pyramid_tm') + config.include("pyramid_tm") session_factory = get_session_factory(get_engine(settings)) - config.registry['dbsession_factory'] = session_factory + config.registry["dbsession_factory"] = session_factory # make request.dbsession available for use in Pyramid config.add_request_method( # r.tm is the transaction manager used by pyramid_tm lambda r: get_tm_session(session_factory, r.tm), - 'dbsession', - reify=True + "dbsession", + reify=True, ) diff --git a/brewman/models/auth.py b/brewman/models/auth.py index 64fe40be..63f9f62a 100644 --- a/brewman/models/auth.py +++ b/brewman/models/auth.py @@ -13,27 +13,31 @@ from .meta import Base def encrypt(val): - return md5(val.encode('utf-8') + "Salt".encode('utf-8')).hexdigest() + return md5(val.encode("utf-8") + "Salt".encode("utf-8")).hexdigest() class Client(Base): - __tablename__ = 'auth_clients' + __tablename__ = "auth_clients" - id = Column('client_id', GUID(), primary_key=True, default=uuid.uuid4) - code = Column('code', Integer, unique=True, nullable=False) - name = Column('name', Unicode(255), unique=True, nullable=False) - enabled = Column('enabled', Boolean, nullable=False) - otp = Column('otp', Integer) - creation_date = Column('creation_date', DateTime(timezone=True), nullable=False) + id = Column("client_id", GUID(), primary_key=True, default=uuid.uuid4) + code = Column("code", Integer, unique=True, nullable=False) + name = Column("name", Unicode(255), unique=True, nullable=False) + enabled = Column("enabled", Boolean, nullable=False) + otp = Column("otp", Integer) + creation_date = Column("creation_date", DateTime(timezone=True), nullable=False) - login_history = relationship('LoginHistory', backref='client') + login_history = relationship("LoginHistory", backref="client") - def __init__(self, code=None, name=None, enabled=False, otp=None, creation_date=None, id=None): + def __init__( + self, code=None, name=None, enabled=False, otp=None, creation_date=None, id=None + ): self.code = code self.name = name self.enabled = enabled self.otp = otp - self.creation_date = datetime.utcnow() if creation_date is None else creation_date + self.creation_date = ( + datetime.utcnow() if creation_date is None else creation_date + ) self.id = id @classmethod @@ -48,37 +52,41 @@ class Client(Base): def create(cls, dbsession): client_code = random.randint(1000, 9999) otp = random.randint(1000, 9999) - name = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(6)) + name = "".join( + random.choice(string.ascii_uppercase + string.digits) for x in range(6) + ) client = Client(client_code, name, False, otp) dbsession.add(client) return client user_group = Table( - 'auth_usergroups', Base.metadata, - Column('UserGroupID', GUID(), primary_key=True, default=uuid.uuid4), - Column('UserID', GUID(), ForeignKey('auth_users.UserID')), - Column('GroupID', GUID(), ForeignKey('auth_groups.GroupID')) + "auth_usergroups", + Base.metadata, + Column("UserGroupID", GUID(), primary_key=True, default=uuid.uuid4), + Column("UserID", GUID(), ForeignKey("auth_users.UserID")), + Column("GroupID", GUID(), ForeignKey("auth_groups.GroupID")), ) role_group = Table( - 'auth_rolegroups', Base.metadata, - Column('RoleGroupID', GUID(), primary_key=True, default=uuid.uuid4), - Column('RoleID', GUID(), ForeignKey('auth_roles.RoleID')), - Column('GroupID', GUID(), ForeignKey('auth_groups.GroupID')) + "auth_rolegroups", + Base.metadata, + Column("RoleGroupID", GUID(), primary_key=True, default=uuid.uuid4), + Column("RoleID", GUID(), ForeignKey("auth_roles.RoleID")), + Column("GroupID", GUID(), ForeignKey("auth_groups.GroupID")), ) class User(Base): - __tablename__ = 'auth_users' + __tablename__ = "auth_users" - id = Column('UserID', GUID(), primary_key=True, default=uuid.uuid4) - name = Column('Name', Unicode(255), unique=True) - _password = Column('Password', Unicode(60)) - locked_out = Column('LockedOut', Boolean) + id = Column("UserID", GUID(), primary_key=True, default=uuid.uuid4) + name = Column("Name", Unicode(255), unique=True) + _password = Column("Password", Unicode(60)) + locked_out = Column("LockedOut", Boolean) groups = relationship("Group", secondary=user_group) - login_history = relationship('LoginHistory', backref='user') + login_history = relationship("LoginHistory", backref="user") def _get_password(self): return self._password @@ -87,7 +95,7 @@ class User(Base): self._password = encrypt(password) password = property(_get_password, _set_password) - password = synonym('_password', descriptor=password) + password = synonym("_password", descriptor=password) @property def __name__(self): @@ -113,12 +121,14 @@ class User(Base): class LoginHistory(Base): - __tablename__ = 'auth_login_history' - __table_args__ = (UniqueConstraint('user_id', 'client_id', 'date'),) - id = Column('login_history_id', GUID(), primary_key=True, default=uuid.uuid4) - user_id = Column('user_id', GUID(), ForeignKey('auth_users.UserID'), nullable=False) - client_id = Column('client_id', GUID(), ForeignKey('auth_clients.client_id'), nullable=False) - date = Column('date', DateTime(timezone=True), nullable=False) + __tablename__ = "auth_login_history" + __table_args__ = (UniqueConstraint("user_id", "client_id", "date"),) + id = Column("login_history_id", GUID(), primary_key=True, default=uuid.uuid4) + user_id = Column("user_id", GUID(), ForeignKey("auth_users.UserID"), nullable=False) + client_id = Column( + "client_id", GUID(), ForeignKey("auth_clients.client_id"), nullable=False + ) + date = Column("date", DateTime(timezone=True), nullable=False) def __init__(self, user_id=None, client_id=None, date=None, id=None): self.user_id = user_id @@ -128,10 +138,10 @@ class LoginHistory(Base): class Group(Base): - __tablename__ = 'auth_groups' + __tablename__ = "auth_groups" - id = Column('GroupID', GUID(), primary_key=True, default=uuid.uuid4) - name = Column('Name', Unicode(255), unique=True) + id = Column("GroupID", GUID(), primary_key=True, default=uuid.uuid4) + name = Column("Name", Unicode(255), unique=True) def __init__(self, name=None, id=None): self.name = name @@ -139,10 +149,10 @@ class Group(Base): class Role(Base): - __tablename__ = 'auth_roles' + __tablename__ = "auth_roles" - id = Column('RoleID', GUID(), primary_key=True, default=uuid.uuid4) - name = Column('Name', Unicode(255), unique=True) + id = Column("RoleID", GUID(), primary_key=True, default=uuid.uuid4) + name = Column("Name", Unicode(255), unique=True) groups = relationship("Group", secondary=role_group, backref="roles") diff --git a/brewman/models/guidtype.py b/brewman/models/guidtype.py index 73aebbcd..44227001 100644 --- a/brewman/models/guidtype.py +++ b/brewman/models/guidtype.py @@ -11,6 +11,7 @@ class GUID(TypeDecorator): CHAR(32), storing as stringified hex values. """ + impl = Binary # if dialect.value == 'postgresql': @@ -23,9 +24,9 @@ class GUID(TypeDecorator): # impl = Binary def load_dialect_impl(self, dialect): - if dialect.name == 'postgresql': + if dialect.name == "postgresql": return dialect.type_descriptor(UUID()) - elif dialect.name == 'sqlite': + elif dialect.name == "sqlite": return dialect.type_descriptor(BLOB()) else: return dialect.type_descriptor(CHAR(32)) @@ -33,10 +34,10 @@ class GUID(TypeDecorator): def process_bind_param(self, value, dialect): if value is None: return None - elif dialect.name == 'postgresql': + elif dialect.name == "postgresql": return str(value) elif not isinstance(value, uuid.UUID): - raise ValueError('value %s is not a valid uuid.UUID' % value) + raise ValueError("value %s is not a valid uuid.UUID" % value) else: return value.bytes # if not isinstance(value, uuid.UUID): diff --git a/brewman/models/master.py b/brewman/models/master.py index c158bff8..861067d5 100644 --- a/brewman/models/master.py +++ b/brewman/models/master.py @@ -12,7 +12,7 @@ from sqlalchemy import ( func, DateTime, PickleType, - Date + Date, ) from sqlalchemy.orm import relationship @@ -21,34 +21,55 @@ from .meta import Base class Product(Base): - __tablename__ = 'products' - __table_args__ = (UniqueConstraint('Name', 'Units'),) + __tablename__ = "products" + __table_args__ = (UniqueConstraint("Name", "Units"),) - id = Column('ProductID', GUID(), primary_key=True, default=uuid.uuid4) - code = Column('Code', Integer, unique=True) - name = Column('Name', Unicode(255), nullable=False) - units = Column('Units', Unicode(255), nullable=False) - fraction = Column('Fraction', Numeric, nullable=False) - fraction_units = Column('FractionUnits', Unicode(255), nullable=False) - product_yield = Column('ProductYield', Numeric, nullable=False) - product_group_id = Column('ProductGroupID', GUID(), ForeignKey('product_groups.ProductGroupID'), - nullable=False) - account_id = Column('account_id', GUID(), ForeignKey('accounts.id'), nullable=False) - price = Column('cost_price', Numeric, nullable=False) - sale_price = Column('sale_price', Numeric, nullable=False) - is_active = Column('IsActive', Boolean, nullable=False) - is_fixture = Column('IsFixture', Boolean, nullable=False) - is_purchased = Column('is_purchased', Boolean, nullable=False) - is_sold = Column('is_sold', Boolean, nullable=False) + id = Column("ProductID", GUID(), primary_key=True, default=uuid.uuid4) + code = Column("Code", Integer, unique=True) + name = Column("Name", Unicode(255), nullable=False) + units = Column("Units", Unicode(255), nullable=False) + fraction = Column("Fraction", Numeric, nullable=False) + fraction_units = Column("FractionUnits", Unicode(255), nullable=False) + product_yield = Column("ProductYield", Numeric, nullable=False) + product_group_id = Column( + "ProductGroupID", + GUID(), + ForeignKey("product_groups.ProductGroupID"), + nullable=False, + ) + account_id = Column("account_id", GUID(), ForeignKey("accounts.id"), nullable=False) + price = Column("cost_price", Numeric, nullable=False) + sale_price = Column("sale_price", Numeric, nullable=False) + is_active = Column("IsActive", Boolean, nullable=False) + is_fixture = Column("IsFixture", Boolean, nullable=False) + is_purchased = Column("is_purchased", Boolean, nullable=False) + is_sold = Column("is_sold", Boolean, nullable=False) - batches = relationship('Batch', backref='product') - inventories = relationship('Inventory', backref='product') - recipes = relationship('Recipe', backref='product') - account = relationship('Account', primaryjoin="Account.id==Product.account_id", backref='products') + batches = relationship("Batch", backref="product") + inventories = relationship("Inventory", backref="product") + recipes = relationship("Recipe", backref="product") + account = relationship( + "Account", primaryjoin="Account.id==Product.account_id", backref="products" + ) - def __init__(self, code=None, name=None, units=None, fraction=None, fraction_units=None, product_yield=None, - product_group_id=None, account_id=None, price=None, sale_price=None, is_active=None, is_purchased=None, - is_sold=None, id=None, is_fixture=False): + def __init__( + self, + code=None, + name=None, + units=None, + fraction=None, + fraction_units=None, + product_yield=None, + product_group_id=None, + account_id=None, + price=None, + sale_price=None, + is_active=None, + is_purchased=None, + is_sold=None, + id=None, + is_fixture=False, + ): self.code = code self.name = name self.units = units @@ -80,64 +101,85 @@ class Product(Base): def can_delete(self, advanced_delete): if self.is_fixture: - return False, "{0} is a fixture and cannot be edited or deleted.".format(self.name) + return ( + False, + "{0} is a fixture and cannot be edited or deleted.".format(self.name), + ) if self.is_active: - return False, 'Product is active' + return False, "Product is active" if len(self.inventories) > 0 and not advanced_delete: - return False, 'Product has entries' - return True, '' + return False, "Product has entries" + return True, "" @classmethod def suspense(cls): - return uuid.UUID('aa79a643-9ddc-4790-ac7f-a41f9efb4c15') + return uuid.UUID("aa79a643-9ddc-4790-ac7f-a41f9efb4c15") class Recipe(Base): - __tablename__ = 'recipes' + __tablename__ = "recipes" - id = Column('recipe_id', GUID(), primary_key=True, default=uuid.uuid4) - product_id = Column('product_id', GUID(), ForeignKey('products.ProductID'), nullable=False) + id = Column("recipe_id", GUID(), primary_key=True, default=uuid.uuid4) + product_id = Column( + "product_id", GUID(), ForeignKey("products.ProductID"), nullable=False + ) - quantity = Column('quantity', Numeric, nullable=False) - cost_price = Column('cost_price', Numeric, nullable=False) - sale_price = Column('sale_price', Numeric, nullable=False) - notes = Column('notes', Unicode(255)) + quantity = Column("quantity", Numeric, nullable=False) + cost_price = Column("cost_price", Numeric, nullable=False) + sale_price = Column("sale_price", Numeric, nullable=False) + notes = Column("notes", Unicode(255)) - valid_from = Column('valid_from', Date, nullable=False) - valid_to = Column('valid_to', Date, nullable=False) + valid_from = Column("valid_from", Date, nullable=False) + valid_to = Column("valid_to", Date, nullable=False) - effective_from = Column('effective_from', Date, nullable=False) - effective_to = Column('effective_to', Date) + effective_from = Column("effective_from", Date, nullable=False) + effective_to = Column("effective_to", Date) - recipe_items = relationship('RecipeItem', backref='recipe') + recipe_items = relationship("RecipeItem", backref="recipe") - def __init__(self, product_id=None, quantity=None, cost_price=None, sale_price=None, valid_from=None, valid_to=None, - notes=None, effective_from=None, id=None): + def __init__( + self, + product_id=None, + quantity=None, + cost_price=None, + sale_price=None, + valid_from=None, + valid_to=None, + notes=None, + effective_from=None, + id=None, + ): self.product_id = product_id self.quantity = quantity self.cost_price = cost_price self.sale_price = sale_price self.valid_from = valid_from self.valid_to = valid_to - self.notes = '' if notes is None else notes + self.notes = "" if notes is None else notes self.effective_from = date.today() if effective_from is None else effective_from self.effective_to = None self.id = id class RecipeItem(Base): - __tablename__ = 'recipe_items' - __table_args__ = (UniqueConstraint('recipe_id', 'product_id'),) + __tablename__ = "recipe_items" + __table_args__ = (UniqueConstraint("recipe_id", "product_id"),) - id = Column('recipe_item_id', GUID(), primary_key=True, default=uuid.uuid4) - recipe_id = Column('recipe_id', GUID(), ForeignKey('recipes.recipe_id'), nullable=False) - product_id = Column('product_id', GUID(), ForeignKey('products.ProductID'), nullable=False) - quantity = Column('quantity', Integer, nullable=False) - price = Column('price', Integer, nullable=False) + id = Column("recipe_item_id", GUID(), primary_key=True, default=uuid.uuid4) + recipe_id = Column( + "recipe_id", GUID(), ForeignKey("recipes.recipe_id"), nullable=False + ) + product_id = Column( + "product_id", GUID(), ForeignKey("products.ProductID"), nullable=False + ) + quantity = Column("quantity", Integer, nullable=False) + price = Column("price", Integer, nullable=False) - product = relationship('Product') + product = relationship("Product") - def __init__(self, recipe_id=None, product_id=None, quantity=None, price=None, id=None): + def __init__( + self, recipe_id=None, product_id=None, quantity=None, price=None, id=None + ): self.recipe_id = recipe_id self.product_id = product_id self.quantity = quantity @@ -146,13 +188,13 @@ class RecipeItem(Base): class ProductGroup(Base): - __tablename__ = 'product_groups' + __tablename__ = "product_groups" - id = Column('ProductGroupID', GUID(), primary_key=True, default=uuid.uuid4) - name = Column('Name', Unicode(255), unique=True) - is_fixture = Column('IsFixture', Boolean, nullable=False) + id = Column("ProductGroupID", GUID(), primary_key=True, default=uuid.uuid4) + name = Column("Name", Unicode(255), unique=True) + is_fixture = Column("IsFixture", Boolean, nullable=False) - products = relationship('Product', backref='product_group') + products = relationship("Product", backref="product_group") def __init__(self, name=None, id=None, is_fixture=False): self.name = name @@ -161,22 +203,22 @@ class ProductGroup(Base): @classmethod def menu_item(cls): - return uuid.UUID('dad46805-f577-4e5b-8073-9b788e0173fc') + return uuid.UUID("dad46805-f577-4e5b-8073-9b788e0173fc") @classmethod def semi(cls): - return uuid.UUID('e6bf81b9-1e9b-499f-81d5-ab5662e9d9b1') + return uuid.UUID("e6bf81b9-1e9b-499f-81d5-ab5662e9d9b1") class CostCentre(Base): - __tablename__ = 'cost_centres' + __tablename__ = "cost_centres" - id = Column('CostCentreID', GUID(), primary_key=True, default=uuid.uuid4) - name = Column('Name', Unicode(255), unique=True) - is_fixture = Column('IsFixture', Boolean, nullable=False) + id = Column("CostCentreID", GUID(), primary_key=True, default=uuid.uuid4) + name = Column("Name", Unicode(255), unique=True) + is_fixture = Column("IsFixture", Boolean, nullable=False) - accounts = relationship('AccountBase', backref='cost_centre') - journals = relationship('Journal', backref='cost_centre') + accounts = relationship("AccountBase", backref="cost_centre") + journals = relationship("Journal", backref="cost_centre") @property def __name__(self): @@ -189,38 +231,46 @@ class CostCentre(Base): @classmethod def cost_centre_purchase(cls): - return uuid.UUID('7b845f95-dfef-fa4a-897c-f0baf15284a3') + return uuid.UUID("7b845f95-dfef-fa4a-897c-f0baf15284a3") @classmethod def cost_centre_kitchen(cls): - return uuid.UUID('b2d398ce-e3cc-c542-9feb-5d7783e899df') + return uuid.UUID("b2d398ce-e3cc-c542-9feb-5d7783e899df") @classmethod def cost_centre_overall(cls): - return uuid.UUID('36f59436-522a-0746-ae94-e0f746bf6c0d') + return uuid.UUID("36f59436-522a-0746-ae94-e0f746bf6c0d") @classmethod def overall(cls): - return {'id': uuid.UUID('36f59436-522a-0746-ae94-e0f746bf6c0d'), 'name': 'Overall'} + return { + "id": uuid.UUID("36f59436-522a-0746-ae94-e0f746bf6c0d"), + "name": "Overall", + } class AccountBase(Base): - __tablename__ = 'accounts' + __tablename__ = "accounts" - id = Column('id', GUID(), primary_key=True, default=uuid.uuid4) - code = Column('code', Integer, nullable=False) - name = Column('name', Unicode(255), unique=True, nullable=False) - type = Column('type', Integer, nullable=False) - account_type = Column('account_type', Unicode(50), nullable=False) - is_starred = Column('is_starred', Boolean, nullable=False) - is_active = Column('is_active', Boolean, nullable=False) - is_reconcilable = Column('is_reconcilable', Boolean, nullable=False) - cost_centre_id = Column('cost_centre_id', GUID(), ForeignKey('cost_centres.CostCentreID'), nullable=False) - is_fixture = Column('is_fixture', Boolean, nullable=False) + id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) + code = Column("code", Integer, nullable=False) + name = Column("name", Unicode(255), unique=True, nullable=False) + type = Column("type", Integer, nullable=False) + account_type = Column("account_type", Unicode(50), nullable=False) + is_starred = Column("is_starred", Boolean, nullable=False) + is_active = Column("is_active", Boolean, nullable=False) + is_reconcilable = Column("is_reconcilable", Boolean, nullable=False) + cost_centre_id = Column( + "cost_centre_id", + GUID(), + ForeignKey("cost_centres.CostCentreID"), + nullable=False, + ) + is_fixture = Column("is_fixture", Boolean, nullable=False) - __mapper_args__ = {'polymorphic_on': account_type} + __mapper_args__ = {"polymorphic_on": account_type} - journals = relationship('Journal', backref='account') + journals = relationship("Journal", backref="account") @property def __name__(self): @@ -230,8 +280,18 @@ class AccountBase(Base): def type_object(self): return AccountType.by_id(self.type) - def __init__(self, code=None, name=None, type=None, is_starred=None, is_active=None, is_reconcilable=False, - cost_centre_id=None, id=None, is_fixture=False): + def __init__( + self, + code=None, + name=None, + type=None, + is_starred=None, + is_active=None, + is_reconcilable=False, + cost_centre_id=None, + id=None, + is_fixture=False, + ): self.code = code self.name = name self.type = type @@ -255,11 +315,15 @@ class AccountBase(Base): query = query.filter(cls.is_active == active) if name is not None: for item in name.split(): - query = query.filter(cls.name.ilike('%' + item + '%')) + query = query.filter(cls.name.ilike("%" + item + "%")) return query.order_by(cls.name) def create(self, dbsession): - code = dbsession.query(func.max(AccountBase.code)).filter(AccountBase.type == self.type).one()[0] + code = ( + dbsession.query(func.max(AccountBase.code)) + .filter(AccountBase.type == self.type) + .one()[0] + ) if code is None: self.code = 1 else: @@ -269,86 +333,119 @@ class AccountBase(Base): def can_delete(self, advanced_delete): if self.is_fixture: - return False, "{0} is a fixture and cannot be edited or deleted.".format(self.name) + return ( + False, + "{0} is a fixture and cannot be edited or deleted.".format(self.name), + ) if self.is_active: - return False, 'Account is active' + return False, "Account is active" if len(self.journals) > 0 and not advanced_delete: - return False, 'Account has journal entries' - return True, '' + return False, "Account has journal entries" + return True, "" @classmethod def get_code(cls, type, dbsession): - code = dbsession.query(func.max(AccountBase.code)).filter(AccountBase.type == type).one()[0] + code = ( + dbsession.query(func.max(AccountBase.code)) + .filter(AccountBase.type == type) + .one()[0] + ) return 1 if code is None else code + 1 @classmethod def all_purchases(cls): - return uuid.UUID('240dd899-c413-854c-a7eb-67a29d154490') + return uuid.UUID("240dd899-c413-854c-a7eb-67a29d154490") @classmethod def cash_in_hand(cls): - return {'id': 'ed2341bb-80b8-9649-90db-f9aaca183bb3', 'name': 'Cash in Hand'} + return {"id": "ed2341bb-80b8-9649-90db-f9aaca183bb3", "name": "Cash in Hand"} @classmethod def local_purchase(cls): - return {'id': 'd2b75912-505f-2548-9093-466dfff6a0f9', 'name': 'Local Purchase'} + return {"id": "d2b75912-505f-2548-9093-466dfff6a0f9", "name": "Local Purchase"} @classmethod def salary(cls): - return {'id': '5c2b54d0-c174-004d-a0d5-92cdaadcefa7', 'name': 'Staff Salary'} + return {"id": "5c2b54d0-c174-004d-a0d5-92cdaadcefa7", "name": "Staff Salary"} @classmethod def service_charge(cls): - return {'id': 'b7eff754-e8ba-e047-ab06-9132c15c7640', 'name': 'Service Charges'} + return {"id": "b7eff754-e8ba-e047-ab06-9132c15c7640", "name": "Service Charges"} @classmethod def service_charge_id(cls): - return uuid.UUID('b7eff754-e8ba-e047-ab06-9132c15c7640') + return uuid.UUID("b7eff754-e8ba-e047-ab06-9132c15c7640") @classmethod def esi_pf_expense(cls): - return uuid.UUID('d2a1a286-e900-764b-a1a5-9f4b00dbb940') + return uuid.UUID("d2a1a286-e900-764b-a1a5-9f4b00dbb940") @classmethod def esi_pf_payable(cls): - return uuid.UUID('42277912-cc18-854b-b134-9f4b00dba419') + return uuid.UUID("42277912-cc18-854b-b134-9f4b00dba419") @classmethod def suspense(cls): - return uuid.UUID('3854e317-6f3b-5142-ab26-9c44d4cddd08') + return uuid.UUID("3854e317-6f3b-5142-ab26-9c44d4cddd08") class Employee(AccountBase): - __tablename__ = 'employees' - __mapper_args__ = {'polymorphic_identity': 'employees'} + __tablename__ = "employees" + __mapper_args__ = {"polymorphic_identity": "employees"} - id = Column('id', GUID(), ForeignKey(AccountBase.id), primary_key=True) - designation = Column('Designation', Unicode(255)) - salary = Column('Salary', Integer) - service_points = Column('ServicePoints', Numeric(precision=5, scale=2)) - joining_date = Column('JoiningDate', DateTime) - leaving_date = Column('LeavingDate', DateTime) + id = Column("id", GUID(), ForeignKey(AccountBase.id), primary_key=True) + designation = Column("Designation", Unicode(255)) + salary = Column("Salary", Integer) + service_points = Column("ServicePoints", Numeric(precision=5, scale=2)) + joining_date = Column("JoiningDate", DateTime) + leaving_date = Column("LeavingDate", DateTime) - attendances = relationship('Attendance', backref='employee', cascade=None, cascade_backrefs=False) - fingerprints = relationship('Fingerprint', backref='employee', cascade=None, cascade_backrefs=False) + attendances = relationship( + "Attendance", backref="employee", cascade=None, cascade_backrefs=False + ) + fingerprints = relationship( + "Fingerprint", backref="employee", cascade=None, cascade_backrefs=False + ) - def __init__(self, code=None, name=None, is_starred=None, is_active=None, cost_centre_id=None, designation=None, - salary=None, service_points=None, joining_date=None, leaving_date=None): + def __init__( + self, + code=None, + name=None, + is_starred=None, + is_active=None, + cost_centre_id=None, + designation=None, + salary=None, + service_points=None, + joining_date=None, + leaving_date=None, + ): self.designation = designation self.salary = salary self.service_points = service_points self.joining_date = joining_date self.leaving_date = leaving_date - super().__init__(code=code, name=name, type=10, is_starred=is_starred, is_active=is_active, - is_reconcilable=False, cost_centre_id=cost_centre_id) + super().__init__( + code=code, + name=name, + type=10, + is_starred=is_starred, + is_active=is_active, + is_reconcilable=False, + cost_centre_id=cost_centre_id, + ) def create(self, dbsession): - code = dbsession.query(func.max(AccountBase.code)).filter(AccountBase.type == self.type).one()[0] + code = ( + dbsession.query(func.max(AccountBase.code)) + .filter(AccountBase.type == self.type) + .one()[0] + ) if code is None: self.code = 1 else: self.code = code + 1 - self.name += ' (' + str(self.code) + ')' + self.name += " (" + str(self.code) + ")" dbsession.add(self) return self @@ -357,11 +454,11 @@ class Employee(AccountBase): class Account(AccountBase): - __mapper_args__ = {'polymorphic_identity': ''} + __mapper_args__ = {"polymorphic_identity": ""} def can_delete(self, advanced_delete): if len(self.products) > 0: - return False, 'Account has products' + return False, "Account has products" return super(Account, self).can_delete(advanced_delete) @@ -373,11 +470,20 @@ class AttendanceType: @classmethod def list(cls): - list = [AttendanceType(0, 'Not Set', 0), AttendanceType(1, 'Present', 1), AttendanceType(2, 'Off Day', 1), - AttendanceType(3, 'On Leave', 0), AttendanceType(4, 'Absent', 0), AttendanceType(5, 'Half Day', .5), - AttendanceType(6, 'Double Duty', 2), AttendanceType(7, 'Paid Leave Availed', 1), - AttendanceType(8, 'Casual Leave Availed', 1), AttendanceType(9, 'Compensatory Off', 1), - AttendanceType(10, 'Half Day + PL', 1), AttendanceType(11, 'Half Day + CL', 1)] + list = [ + AttendanceType(0, "Not Set", 0), + AttendanceType(1, "Present", 1), + AttendanceType(2, "Off Day", 1), + AttendanceType(3, "On Leave", 0), + AttendanceType(4, "Absent", 0), + AttendanceType(5, "Half Day", 0.5), + AttendanceType(6, "Double Duty", 2), + AttendanceType(7, "Paid Leave Availed", 1), + AttendanceType(8, "Casual Leave Availed", 1), + AttendanceType(9, "Compensatory Off", 1), + AttendanceType(10, "Half Day + PL", 1), + AttendanceType(11, "Half Day + CL", 1), + ] return list @classmethod @@ -396,8 +502,16 @@ class AttendanceType: class AccountType: - def __init__(self, id, name, balance_sheet=None, debit=None, cash_flow_classification=None, order=None, - show_in_list=None): + def __init__( + self, + id, + name, + balance_sheet=None, + debit=None, + cash_flow_classification=None, + order=None, + show_in_list=None, + ): self.id = id self.name = name self.balance_sheet = balance_sheet @@ -413,18 +527,20 @@ class AccountType: @classmethod def list(cls): - list = [AccountType(1, 'Cash', True, True, 'Cash', 10, True), - AccountType(2, 'Purchase', False, True, 'Operating', 20, True), - AccountType(3, 'Sale', False, False, 'Operating', 10, True), - AccountType(4, 'Assets', True, True, 'Investing', 20, True), - AccountType(5, 'Capital', True, False, 'Financing', 70, True), - AccountType(6, 'Debtors', True, True, 'Operating', 30, True), - AccountType(7, 'Expenses', False, True, 'Operating', 40, True), - AccountType(9, 'Creditors', True, False, 'Operating', 60, True), - AccountType(10, 'Salary', True, True, 'Operating', 40, False), - AccountType(11, 'Liabilities', True, False, 'Operating', 50, True), - AccountType(12, 'Revenue', False, False, 'Operating', 30, True), - AccountType(13, 'Tax', True, False, 'Operating', 80, True)] + list = [ + AccountType(1, "Cash", True, True, "Cash", 10, True), + AccountType(2, "Purchase", False, True, "Operating", 20, True), + AccountType(3, "Sale", False, False, "Operating", 10, True), + AccountType(4, "Assets", True, True, "Investing", 20, True), + AccountType(5, "Capital", True, False, "Financing", 70, True), + AccountType(6, "Debtors", True, True, "Operating", 30, True), + AccountType(7, "Expenses", False, True, "Operating", 40, True), + AccountType(9, "Creditors", True, False, "Operating", 60, True), + AccountType(10, "Salary", True, True, "Operating", 40, False), + AccountType(11, "Liabilities", True, False, "Operating", 50, True), + AccountType(12, "Revenue", False, False, "Operating", 30, True), + AccountType(13, "Tax", True, False, "Operating", 80, True), + ] # list.append(AccountType(8, 'Discount', False, False, True, 30, True)) # list.append(AccountType(14, 'Total', False, False, False, 900, False)) # list.append(AccountType(15, 'Net', False, False, False, 1000, False)) @@ -446,11 +562,11 @@ class AccountType: class DbSetting(Base): - __tablename__ = 'settings' + __tablename__ = "settings" - id = Column('SettingID', GUID(), primary_key=True, default=uuid.uuid4) - name = Column('Name', Unicode(255), unique=True, nullable=False) - data = Column('Data', PickleType) + id = Column("SettingID", GUID(), primary_key=True, default=uuid.uuid4) + name = Column("Name", Unicode(255), unique=True, nullable=False) + data = Column("Data", PickleType) def __init__(self, id=None, name=None, data=None): self.id = id diff --git a/brewman/models/meta.py b/brewman/models/meta.py index 0682247b..98c6156e 100644 --- a/brewman/models/meta.py +++ b/brewman/models/meta.py @@ -5,11 +5,11 @@ from sqlalchemy.schema import MetaData # providers will autogenerate vastly different names making migrations more # difficult. See: http://alembic.zzzcomputing.com/en/latest/naming.html NAMING_CONVENTION = { - "ix": 'ix_%(column_0_label)s', + "ix": "ix_%(column_0_label)s", "uq": "uq_%(table_name)s_%(column_0_name)s", "ck": "ck_%(table_name)s_%(constraint_name)s", "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s", - "pk": "pk_%(table_name)s" + "pk": "pk_%(table_name)s", } metadata = MetaData(naming_convention=NAMING_CONVENTION) diff --git a/brewman/models/operations.py b/brewman/models/operations.py index e9af80b0..2d6e75d9 100644 --- a/brewman/models/operations.py +++ b/brewman/models/operations.py @@ -29,8 +29,10 @@ def check_batch_insert(voucher): batch = item.batch if batch.quantity_remaining < item.quantity: raise ValidationError( - "Quantity of {0} ({1}) cannot be more than {2}".format(item.product.name, item.product.units, - batch.quantity_remaining)) + "Quantity of {0} ({1}) cannot be more than {2}".format( + item.product.name, item.product.units, batch.quantity_remaining + ) + ) if voucher.type == 3: # Issue purchase = None @@ -45,15 +47,20 @@ def check_batch_insert(voucher): batch = item.batch if batch.quantity_remaining < item.quantity: raise ValidationError( - "Quantity of {0} ({1}) cannot be more than {2}".format(item.product.name, item.product.units, - batch.quantity_remaining)) + "Quantity of {0} ({1}) cannot be more than {2}".format( + item.product.name, item.product.units, batch.quantity_remaining + ) + ) if voucher.type == 2: # Purchase pass def issue_new(voucher): - consuming = filter(lambda x: x.cost_centre_id == CostCentre.cost_centre_purchase(), voucher.journals) + consuming = filter( + lambda x: x.cost_centre_id == CostCentre.cost_centre_purchase(), + voucher.journals, + ) if not len(consuming): consuming = False elif consuming[0].debit == 1: @@ -68,12 +75,17 @@ def issue_new(voucher): batch = item.batch if batch.quantity_remaining < item.quantity: raise ValidationError( - "Quantity of {0} ({1}) cannot be more than {2}".format(item.product.name, item.product.units, - batch.quantity_remaining)) + "Quantity of {0} ({1}) cannot be more than {2}".format( + item.product.name, item.product.units, batch.quantity_remaining + ) + ) def issue_update(voucher): - consuming = filter(lambda x: x.cost_centre_id == CostCentre.cost_centre_purchase(), voucher.journals) + consuming = filter( + lambda x: x.cost_centre_id == CostCentre.cost_centre_purchase(), + voucher.journals, + ) if not len(consuming): consuming = False elif consuming[0].debit == 1: @@ -88,8 +100,10 @@ def issue_update(voucher): batch = item.batch if batch.quantity_remaining < item.quantity: raise ValidationError( - "Quantity of {0} ({1}) cannot be more than {2}".format(item.product.name, item.product.units, - batch.quantity_remaining)) + "Quantity of {0} ({1}) cannot be more than {2}".format( + item.product.name, item.product.units, batch.quantity_remaining + ) + ) def purchase_return_new(voucher): @@ -97,8 +111,10 @@ def purchase_return_new(voucher): batch = item.batch if batch.quantity_remaining < item.quantity: raise ValidationError( - "Quantity of {0} ({1}) cannot be more than {2}".format(item.product.name, item.product.units, - batch.quantity_remaining)) + "Quantity of {0} ({1}) cannot be more than {2}".format( + item.product.name, item.product.units, batch.quantity_remaining + ) + ) def purchase_return_update(voucher): @@ -106,8 +122,10 @@ def purchase_return_update(voucher): batch = item.batch if batch.quantity_remaining < item.quantity: raise ValidationError( - "Quantity of {0} ({1}) cannot be more than {2}".format(item.product.name, item.product.units, - batch.quantity_remaining)) + "Quantity of {0} ({1}) cannot be more than {2}".format( + item.product.name, item.product.units, batch.quantity_remaining + ) + ) def inventory_valid(voucher): diff --git a/brewman/models/tzinfoutc.py b/brewman/models/tzinfoutc.py index ae863175..7f6927c4 100644 --- a/brewman/models/tzinfoutc.py +++ b/brewman/models/tzinfoutc.py @@ -6,6 +6,7 @@ HOUR = timedelta(hours=1) # A UTC class. + class UTC(tzinfo): """UTC""" @@ -37,9 +38,9 @@ def get_age(old_date, now=None): delta = now - old_date if delta.days > 0: - return '{0} days'.format(delta.days) + return "{0} days".format(delta.days) if delta.seconds > 3600: - return '{0} hours'.format(delta.seconds // 3600) + return "{0} hours".format(delta.seconds // 3600) if delta.seconds > 60: - return '{0} minutes'.format(delta.seconds // 60) - return '{0} seconds'.format(delta.seconds) + return "{0} minutes".format(delta.seconds // 60) + return "{0} seconds".format(delta.seconds) diff --git a/brewman/models/voucher.py b/brewman/models/voucher.py index e903971c..30369975 100644 --- a/brewman/models/voucher.py +++ b/brewman/models/voucher.py @@ -1,7 +1,16 @@ import uuid from datetime import datetime -from sqlalchemy import Column, Integer, Boolean, Unicode, DateTime, Numeric, ForeignKey, UniqueConstraint +from sqlalchemy import ( + Column, + Integer, + Boolean, + Unicode, + DateTime, + Numeric, + ForeignKey, + UniqueConstraint, +) from sqlalchemy.dialects.postgresql import BYTEA from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.orm import relationship, synonym, backref @@ -18,11 +27,21 @@ class VoucherType: @classmethod def list(cls): - list = [VoucherType(1, 'Journal'), VoucherType(2, 'Purchase'), VoucherType(3, 'Issue'), - VoucherType(4, 'Payment'), VoucherType(5, 'Receipt'), VoucherType(6, 'Purchase Return'), - VoucherType(7, 'Opening Accounts'), VoucherType(8, 'Opening Batches'), VoucherType(9, 'Verification'), - VoucherType(10, 'Opening Balance'), VoucherType(11, 'Closing Balance'), - VoucherType(12, 'Salary Deduction'), VoucherType(13, 'Service Charge')] + list = [ + VoucherType(1, "Journal"), + VoucherType(2, "Purchase"), + VoucherType(3, "Issue"), + VoucherType(4, "Payment"), + VoucherType(5, "Receipt"), + VoucherType(6, "Purchase Return"), + VoucherType(7, "Opening Accounts"), + VoucherType(8, "Opening Batches"), + VoucherType(9, "Verification"), + VoucherType(10, "Opening Balance"), + VoucherType(11, "Closing Balance"), + VoucherType(12, "Salary Deduction"), + VoucherType(13, "Service Charge"), + ] return list @classmethod @@ -41,30 +60,50 @@ class VoucherType: class Voucher(Base): - __tablename__ = 'vouchers' + __tablename__ = "vouchers" - id = Column('VoucherID', GUID(), primary_key=True, default=uuid.uuid4) - date = Column('date', DateTime, 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) - 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) - _type = Column('voucher_type', Integer, nullable=False) - user_id = Column('user_id', GUID(), ForeignKey('auth_users.UserID'), nullable=False) - posted = Column('is_posted', Boolean, nullable=False) - poster_id = Column('poster_id', GUID(), ForeignKey('auth_users.UserID')) + id = Column("VoucherID", GUID(), primary_key=True, default=uuid.uuid4) + date = Column("date", DateTime, 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) + 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) + _type = Column("voucher_type", Integer, nullable=False) + user_id = Column("user_id", GUID(), ForeignKey("auth_users.UserID"), nullable=False) + posted = Column("is_posted", Boolean, nullable=False) + poster_id = Column("poster_id", GUID(), ForeignKey("auth_users.UserID")) - user = relationship('User', primaryjoin="User.id==Voucher.user_id", cascade=None) - poster = relationship('User', primaryjoin="User.id==Voucher.poster_id", cascade=None) + user = relationship("User", primaryjoin="User.id==Voucher.user_id", cascade=None) + poster = relationship( + "User", primaryjoin="User.id==Voucher.poster_id", cascade=None + ) - journals = relationship('Journal', backref='voucher', cascade="delete, delete-orphan", cascade_backrefs=False) - inventories = relationship('Inventory', backref='voucher', cascade="delete, delete-orphan", cascade_backrefs=False) - salary_deductions = relationship('SalaryDeduction', backref='voucher', cascade="delete, delete-orphan", - cascade_backrefs=False) - service_charges = relationship('ServiceCharge', backref='voucher', cascade="delete, delete-orphan", - cascade_backrefs=False) + journals = relationship( + "Journal", + backref="voucher", + cascade="delete, delete-orphan", + cascade_backrefs=False, + ) + inventories = relationship( + "Inventory", + backref="voucher", + cascade="delete, delete-orphan", + cascade_backrefs=False, + ) + salary_deductions = relationship( + "SalaryDeduction", + backref="voucher", + cascade="delete, delete-orphan", + cascade_backrefs=False, + ) + service_charges = relationship( + "ServiceCharge", + backref="voucher", + cascade="delete, delete-orphan", + cascade_backrefs=False, + ) def _get_type(self): return self._type @@ -79,36 +118,62 @@ class Voucher(Base): self._type = value.id type = property(_get_type, _set_type) - type = synonym('_type', descriptor=type) + type = synonym("_type", descriptor=type) @property def __name__(self): return self.name - def __init__(self, date=None, is_reconciled=False, reconcile_date=None, is_starred=None, narration='', posted=False, - creation_date=None, last_edit_date=None, type=None, user_id=None, poster_id=None): + def __init__( + self, + date=None, + is_reconciled=False, + reconcile_date=None, + is_starred=None, + narration="", + posted=False, + creation_date=None, + last_edit_date=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 if reconcile_date and is_reconciled else 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.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.user_id = user_id self.poster_id = poster_id class Journal(Base): - __tablename__ = 'journals' + __tablename__ = "journals" - id = Column('JournalID', GUID(), primary_key=True, default=uuid.uuid4) - debit = Column('Debit', Integer) - amount = Column('Amount', Numeric) - voucher_id = Column('VoucherID', GUID(), ForeignKey('vouchers.VoucherID'), nullable=False, index=True) - account_id = Column('account_id', GUID(), ForeignKey('accounts.id'), nullable=False) - cost_centre_id = Column('CostCentreID', GUID(), ForeignKey('cost_centres.CostCentreID'), nullable=False) + id = Column("JournalID", GUID(), primary_key=True, default=uuid.uuid4) + debit = Column("Debit", Integer) + amount = Column("Amount", Numeric) + voucher_id = Column( + "VoucherID", + GUID(), + ForeignKey("vouchers.VoucherID"), + nullable=False, + index=True, + ) + account_id = Column("account_id", GUID(), ForeignKey("accounts.id"), nullable=False) + cost_centre_id = Column( + "CostCentreID", GUID(), ForeignKey("cost_centres.CostCentreID"), nullable=False + ) @hybrid_property def signed_amount(self): @@ -118,7 +183,15 @@ class Journal(Base): def __name__(self): return self.name - def __init__(self, id=None, debit=None, amount=None, voucher_id=None, account_id=None, cost_centre_id=None): + def __init__( + self, + id=None, + debit=None, + amount=None, + voucher_id=None, + account_id=None, + cost_centre_id=None, + ): self.id = id self.debit = debit self.amount = amount @@ -128,22 +201,41 @@ class Journal(Base): class SalaryDeduction(Base): - __tablename__ = 'salary_deductions' - id = Column('SalaryDeductionID', GUID(), primary_key=True, default=uuid.uuid4) - voucher_id = Column('VoucherID', GUID(), ForeignKey('vouchers.VoucherID'), nullable=False) - journal_id = Column('JournalID', GUID(), ForeignKey('journals.JournalID'), nullable=False) - gross_salary = Column('GrossSalary', Integer) - days_worked = Column('DaysWorked', Integer) - esi_ee = Column('EsiEmployee', Integer) - pf_ee = Column('PfEmployee', Integer) - esi_er = Column('EsiEmployer', Integer) - pf_er = Column('PfEmployer', Integer) + __tablename__ = "salary_deductions" + id = Column("SalaryDeductionID", GUID(), primary_key=True, default=uuid.uuid4) + voucher_id = Column( + "VoucherID", GUID(), ForeignKey("vouchers.VoucherID"), nullable=False + ) + journal_id = Column( + "JournalID", GUID(), ForeignKey("journals.JournalID"), nullable=False + ) + gross_salary = Column("GrossSalary", Integer) + days_worked = Column("DaysWorked", Integer) + esi_ee = Column("EsiEmployee", Integer) + pf_ee = Column("PfEmployee", Integer) + esi_er = Column("EsiEmployer", Integer) + pf_er = Column("PfEmployer", Integer) - journal = relationship(Journal, backref=backref('salary_deduction', uselist=False), cascade=None, - cascade_backrefs=False) + journal = relationship( + Journal, + backref=backref("salary_deduction", uselist=False), + cascade=None, + cascade_backrefs=False, + ) - def __init__(self, id=None, voucher_id=None, journal_id=None, journal=None, gross_salary=None, days_worked=None, - esi_ee=None, pf_ee=None, esi_er=None, pf_er=None): + def __init__( + self, + id=None, + voucher_id=None, + journal_id=None, + journal=None, + gross_salary=None, + days_worked=None, + esi_ee=None, + pf_ee=None, + esi_er=None, + pf_er=None, + ): self.id = id self.voucher_id = voucher_id self.journal_id = journal_id @@ -158,17 +250,33 @@ class SalaryDeduction(Base): class ServiceCharge(Base): - __tablename__ = 'service_charges' - id = Column('id', GUID(), primary_key=True, default=uuid.uuid4) - voucher_id = Column('voucher_id', GUID(), ForeignKey('vouchers.VoucherID'), nullable=False) - journal_id = Column('journal_id', GUID(), ForeignKey('journals.JournalID'), nullable=False) - days_worked = Column('days_worked', Integer, nullable=False) - points = Column('points', Numeric(precision=5, scale=2), nullable=False) + __tablename__ = "service_charges" + id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) + voucher_id = Column( + "voucher_id", GUID(), ForeignKey("vouchers.VoucherID"), nullable=False + ) + journal_id = Column( + "journal_id", GUID(), ForeignKey("journals.JournalID"), nullable=False + ) + days_worked = Column("days_worked", Integer, nullable=False) + points = Column("points", Numeric(precision=5, scale=2), nullable=False) - journal = relationship(Journal, backref=backref('service_charge', uselist=False), cascade=None, - cascade_backrefs=False) + journal = relationship( + Journal, + backref=backref("service_charge", uselist=False), + cascade=None, + cascade_backrefs=False, + ) - def __init__(self, id=None, voucher_id=None, journal_id=None, journal=None, days_worked=None, points=None): + def __init__( + self, + id=None, + voucher_id=None, + journal_id=None, + journal=None, + days_worked=None, + points=None, + ): self.id = id self.voucher_id = voucher_id self.journal_id = journal_id @@ -179,19 +287,37 @@ class ServiceCharge(Base): class Inventory(Base): - __tablename__ = 'inventories' - __table_args__ = (UniqueConstraint('VoucherID', 'BatchID'),) - id = Column('InventoryID', GUID(), primary_key=True, default=uuid.uuid4) - voucher_id = Column('VoucherID', GUID(), ForeignKey('vouchers.VoucherID'), nullable=False, index=True) - product_id = Column('ProductID', GUID(), ForeignKey('products.ProductID'), nullable=False) - batch_id = Column('BatchID', GUID(), ForeignKey('batches.BatchID'), nullable=False) - quantity = Column('Quantity', Numeric) - rate = Column('Rate', Numeric) - tax = Column('Tax', Numeric) - discount = Column('Discount', Numeric) + __tablename__ = "inventories" + __table_args__ = (UniqueConstraint("VoucherID", "BatchID"),) + id = Column("InventoryID", GUID(), primary_key=True, default=uuid.uuid4) + voucher_id = Column( + "VoucherID", + GUID(), + ForeignKey("vouchers.VoucherID"), + nullable=False, + index=True, + ) + product_id = Column( + "ProductID", GUID(), ForeignKey("products.ProductID"), nullable=False + ) + batch_id = Column("BatchID", GUID(), ForeignKey("batches.BatchID"), nullable=False) + quantity = Column("Quantity", Numeric) + rate = Column("Rate", Numeric) + tax = Column("Tax", Numeric) + discount = Column("Discount", Numeric) - def __init__(self, id=None, voucher_id=None, product_id=None, batch_id=None, quantity=None, rate=None, - tax=None, discount=None, batch=None): + def __init__( + self, + id=None, + voucher_id=None, + product_id=None, + batch_id=None, + quantity=None, + rate=None, + tax=None, + discount=None, + batch=None, + ): self.id = id self.voucher_id = voucher_id self.product_id = product_id @@ -209,20 +335,31 @@ class Inventory(Base): class Batch(Base): - __tablename__ = 'batches' + __tablename__ = "batches" - id = Column('BatchID', GUID(), primary_key=True, default=uuid.uuid4) - name = Column('Name', DateTime) - product_id = Column('ProductID', GUID(), ForeignKey('products.ProductID'), nullable=False) - quantity_remaining = Column('QuantityRemaining', Numeric) - rate = Column('Rate', Numeric) - tax = Column('Tax', Numeric) - discount = Column('Discount', Numeric) + id = Column("BatchID", GUID(), primary_key=True, default=uuid.uuid4) + name = Column("Name", DateTime) + product_id = Column( + "ProductID", GUID(), ForeignKey("products.ProductID"), nullable=False + ) + quantity_remaining = Column("QuantityRemaining", Numeric) + rate = Column("Rate", Numeric) + tax = Column("Tax", Numeric) + discount = Column("Discount", Numeric) - inventories = relationship('Inventory', backref='batch', cascade=None, cascade_backrefs=False) + inventories = relationship( + "Inventory", backref="batch", cascade=None, cascade_backrefs=False + ) - def __init__(self, name=None, product_id=None, quantity_remaining=None, rate=None, tax=None, - discount=None): + def __init__( + self, + name=None, + product_id=None, + quantity_remaining=None, + rate=None, + tax=None, + discount=None, + ): self.name = name self.product_id = product_id self.quantity_remaining = quantity_remaining @@ -231,7 +368,9 @@ class Batch(Base): self.discount = discount def amount(self): - return self.quantity_remaining * self.rate * (1 + self.tax) * (1 - self.discount) + return ( + self.quantity_remaining * self.rate * (1 + self.tax) * (1 - self.discount) + ) @classmethod def list(cls, name, include_nil, date, dbsession): @@ -241,43 +380,58 @@ class Batch(Base): if date is not None: query = query.filter(cls.name <= date) for item in name.split(): - query = query.filter(Product.name.ilike('%' + item + '%')) + query = query.filter(Product.name.ilike("%" + item + "%")) return query.order_by(Product.name).order_by(cls.name).all() @classmethod def suspense(cls): - return uuid.UUID('a955790e-93cf-493c-a816-c7d92b127383') + return uuid.UUID("a955790e-93cf-493c-a816-c7d92b127383") class Attendance(Base): - __tablename__ = 'attendances' + __tablename__ = "attendances" - id = Column('AttendanceID', GUID(), primary_key=True, default=uuid.uuid4) - employee_id = Column('EmployeeID', GUID(), ForeignKey('employees.id')) - date = Column('Date', DateTime) - attendance_type = Column('AttendanceType', Integer) - amount = Column('Amount', Numeric) - creation_date = Column('CreationDate', DateTime(timezone=True)) - user_id = Column('UserID', GUID(), ForeignKey('auth_users.UserID')) - is_valid = Column('IsValid', Boolean) + id = Column("AttendanceID", GUID(), primary_key=True, default=uuid.uuid4) + employee_id = Column("EmployeeID", GUID(), ForeignKey("employees.id")) + date = Column("Date", DateTime) + attendance_type = Column("AttendanceType", Integer) + amount = Column("Amount", Numeric) + creation_date = Column("CreationDate", DateTime(timezone=True)) + user_id = Column("UserID", GUID(), ForeignKey("auth_users.UserID")) + is_valid = Column("IsValid", Boolean) - user = relationship('User', primaryjoin="User.id==Attendance.user_id") + user = relationship("User", primaryjoin="User.id==Attendance.user_id") - def __init__(self, id=None, employee_id=None, date=None, attendance_type=None, amount=None, creation_date=None, - user_id=None, is_valid=None): + def __init__( + self, + id=None, + employee_id=None, + date=None, + attendance_type=None, + amount=None, + creation_date=None, + user_id=None, + is_valid=None, + ): self.id = id self.employee_id = employee_id self.date = date self.attendance_type = attendance_type self.amount = amount if amount is not None else 0 - self.creation_date = datetime.utcnow() if creation_date is None else creation_date + self.creation_date = ( + datetime.utcnow() if creation_date is None else creation_date + ) self.user_id = user_id self.is_valid = is_valid if is_valid is not None else True def create(self, dbsession): - old = dbsession.query(Attendance).filter(Attendance.date == self.date) \ - .filter(Attendance.employee_id == self.employee_id) \ - .filter(Attendance.is_valid == True).first() + old = ( + dbsession.query(Attendance) + .filter(Attendance.date == self.date) + .filter(Attendance.employee_id == self.employee_id) + .filter(Attendance.is_valid == True) + .first() + ) if old is None or old.attendance_type != self.attendance_type: if old is not None: old.is_valid = False @@ -285,11 +439,11 @@ class Attendance(Base): class Fingerprint(Base): - __tablename__ = 'fingerprints' + __tablename__ = "fingerprints" - id = Column('FingerprintID', GUID(), primary_key=True, default=uuid.uuid4) - employee_id = Column('EmployeeID', GUID(), ForeignKey('employees.id')) - date = Column('Date', DateTime) + id = Column("FingerprintID", GUID(), primary_key=True, default=uuid.uuid4) + employee_id = Column("EmployeeID", GUID(), ForeignKey("employees.id")) + date = Column("Date", DateTime) def __init__(self, id=None, employee_id=None, date=None): self.id = id @@ -299,19 +453,29 @@ class Fingerprint(Base): class DbImage(Base): - __tablename__ = 'images' + __tablename__ = "images" - id = Column('id', GUID(), primary_key=True, default=uuid.uuid4) - resource_id = Column('resource_id', GUID(), nullable=False) - resource_type = Column('resource_type', Unicode(255), nullable=False) - image = Column('image', BYTEA, nullable=False) - thumbnail = Column('thumbnail', BYTEA, nullable=False) - creation_date = Column('creation_date', DateTime(timezone=True), nullable=False) + id = Column("id", GUID(), primary_key=True, default=uuid.uuid4) + resource_id = Column("resource_id", GUID(), nullable=False) + resource_type = Column("resource_type", Unicode(255), nullable=False) + image = Column("image", BYTEA, nullable=False) + thumbnail = Column("thumbnail", BYTEA, nullable=False) + creation_date = Column("creation_date", DateTime(timezone=True), nullable=False) - def __init__(self, resource_id=None, resource_type=None, image=None, thumbnail=None, creation_date=None, id=None): + def __init__( + self, + resource_id=None, + resource_type=None, + image=None, + thumbnail=None, + creation_date=None, + id=None, + ): self.resource_id = resource_id self.resource_type = resource_type self.image = image self.thumbnail = thumbnail - self.creation_date = datetime.utcnow() if creation_date is None else creation_date + self.creation_date = ( + datetime.utcnow() if creation_date is None else creation_date + ) self.id = id diff --git a/brewman/renderers.py b/brewman/renderers.py index 3491e54d..0b11e12f 100644 --- a/brewman/renderers.py +++ b/brewman/renderers.py @@ -6,30 +6,28 @@ import uuid from pyramid.renderers import JSON - - class CSVRenderer(object): def __init__(self, info): pass def __call__(self, value, system): csv_data = StringIO() - writer = csv.writer(csv_data, delimiter=',', quoting=csv.QUOTE_MINIMAL) + writer = csv.writer(csv_data, delimiter=",", quoting=csv.QUOTE_MINIMAL) - if 'header' in value: - writer.writerow(value['header']) - if 'rows' in value: - writer.writerows(value['rows']) - if 'footer' in value: - writer.writerows(value['footer']) + if "header" in value: + writer.writerow(value["header"]) + if "rows" in value: + writer.writerows(value["rows"]) + if "footer" in value: + writer.writerows(value["footer"]) - request = system.get('request') + request = system.get("request") if request is not None: response = request.response ct = response.content_type if ct == response.default_content_type: - response.content_type = 'text/csv' - filename = value['filename'] if 'filename' in value else 'report.csv' + response.content_type = "text/csv" + filename = value["filename"] if "filename" in value else "report.csv" response.content_disposition = 'attachment;filename="{0}"'.format(filename) return csv_data.getvalue() diff --git a/brewman/routes.py b/brewman/routes.py index 0d022dff..e49304f7 100644 --- a/brewman/routes.py +++ b/brewman/routes.py @@ -2,131 +2,133 @@ import datetime def includeme(config): - config.add_route('api_dashboard', '/api/Dashboard') - config.add_route('dashboard', '/Dashboard') + config.add_route("api_dashboard", "/api/Dashboard") + config.add_route("dashboard", "/Dashboard") - config.add_route('api_db_integrity', '/api/DbIntegrity') - config.add_route('api_login', '/api/login') - config.add_route('login', '/login') - config.add_route('logout', '/logout') - config.add_route('api_logout', '/api/logout') + config.add_route("api_db_integrity", "/api/DbIntegrity") + config.add_route("api_login", "/api/login") + config.add_route("login", "/login") + config.add_route("logout", "/logout") + config.add_route("api_logout", "/api/logout") - config.add_route('home', '/') + config.add_route("home", "/") - config.add_route('api_account_type_list', '/api/AccountTypes') + config.add_route("api_account_type_list", "/api/AccountTypes") - add_route(config, 'cost_centre', '/CostCentre') - add_route(config, 'account', '/Account') - add_route(config, 'employee', '/Employee') - add_route(config, 'user', '/User') - add_route(config, 'group', '/Group') - add_route(config, 'client', '/Client') - add_route(config, 'product', '/Product') - add_route(config, 'recipe', '/Recipe') - add_route(config, 'product_group', '/ProductGroup') + add_route(config, "cost_centre", "/CostCentre") + add_route(config, "account", "/Account") + add_route(config, "employee", "/Employee") + add_route(config, "user", "/User") + add_route(config, "group", "/Group") + add_route(config, "client", "/Client") + add_route(config, "product", "/Product") + add_route(config, "recipe", "/Recipe") + add_route(config, "product_group", "/ProductGroup") - config.add_route('journal_id', '/Journal/{id}') - config.add_route('journal', '/Journal') - config.add_route('purchase_id', '/Purchase/{id}') - config.add_route('purchase', '/Purchase') - config.add_route('purchase_return_id', '/Return/{id}') - config.add_route('purchase_return', '/Return') - config.add_route('payment_id', '/Payment/{id}') - config.add_route('payment', '/Payment') - config.add_route('receipt_id', '/Receipt/{id}') - config.add_route('receipt', '/Receipt') - config.add_route('issue_id', '/Issue/{id}') - config.add_route('issue', '/Issue') - config.add_route('api_issue_grid', '/api/IssueGrid/{date}') - config.add_route('employee_benefits_id', '/EmployeeBenefits/{id}') - config.add_route('employee_benefits', '/EmployeeBenefits') - config.add_route('incentive_id', '/Incentive/{id}') - config.add_route('incentive', '/Incentive') - config.add_route('db_image', '/api/DbImage/{id}/{type}') + config.add_route("journal_id", "/Journal/{id}") + config.add_route("journal", "/Journal") + config.add_route("purchase_id", "/Purchase/{id}") + config.add_route("purchase", "/Purchase") + config.add_route("purchase_return_id", "/Return/{id}") + config.add_route("purchase_return", "/Return") + config.add_route("payment_id", "/Payment/{id}") + config.add_route("payment", "/Payment") + config.add_route("receipt_id", "/Receipt/{id}") + config.add_route("receipt", "/Receipt") + config.add_route("issue_id", "/Issue/{id}") + config.add_route("issue", "/Issue") + config.add_route("api_issue_grid", "/api/IssueGrid/{date}") + config.add_route("employee_benefits_id", "/EmployeeBenefits/{id}") + config.add_route("employee_benefits", "/EmployeeBenefits") + config.add_route("incentive_id", "/Incentive/{id}") + config.add_route("incentive", "/Incentive") + config.add_route("db_image", "/api/DbImage/{id}/{type}") - config.add_route('api_voucher_id', '/api/Voucher/{id}') - config.add_route('api_voucher', '/api/Voucher') + config.add_route("api_voucher_id", "/api/Voucher/{id}") + config.add_route("api_voucher", "/api/Voucher") - config.add_route('message_id', '/Message/{id}') - config.add_route('message', '/Message') - config.add_route('api_message_id', '/api/Message/{id}') - config.add_route('api_message', '/api/Message') - config.add_route('api_tag_list', '/api/Tags') + config.add_route("message_id", "/Message/{id}") + config.add_route("message", "/Message") + config.add_route("api_message_id", "/api/Message/{id}") + config.add_route("api_message", "/api/Message") + config.add_route("api_tag_list", "/api/Tags") - config.add_route('settings', '/Settings') - config.add_route('api_lock_information', '/api/LockInformation') - config.add_route('api_maintenance', '/api/Maintenance') + config.add_route("settings", "/Settings") + config.add_route("api_lock_information", "/api/LockInformation") + config.add_route("api_maintenance", "/api/Maintenance") - add_route(config, 'attendance', '/Attendance', has_list=False, variable='date') - config.add_route('api_attendance_types', '/api/AttendanceTypes') + add_route(config, "attendance", "/Attendance", has_list=False, variable="date") + config.add_route("api_attendance_types", "/api/AttendanceTypes") - add_route(config, 'employee_attendance', '/EmployeeAttendance', has_list=False) + add_route(config, "employee_attendance", "/EmployeeAttendance", has_list=False) - config.add_route('attendance_report', '/AttendanceReport') - config.add_route('api_credit_salary', '/api/CreditSalary') - config.add_route('employee_functions', '/EmployeeFunctions') - config.add_route('api_fingerprint', '/api/Fingerprint') + config.add_route("attendance_report", "/AttendanceReport") + config.add_route("api_credit_salary", "/api/CreditSalary") + config.add_route("employee_functions", "/EmployeeFunctions") + config.add_route("api_fingerprint", "/api/Fingerprint") - add_route(config, 'ledger', '/Ledger', has_list=False) - add_route(config, 'reconcile', '/Reconcile', has_list=False) - add_route(config, 'product_ledger', '/ProductLedger', has_list=False) + add_route(config, "ledger", "/Ledger", has_list=False) + add_route(config, "reconcile", "/Reconcile", has_list=False) + add_route(config, "product_ledger", "/ProductLedger", has_list=False) - add_route(config, 'trial_balance', '/TrialBalance', has_list=False, variable='date') - config.add_route('api_net_transactions', '/api/NetTransactions') - config.add_route('net_transactions', '/NetTransactions') - config.add_route('api_purchases', '/api/Purchases') - config.add_route('purchases', '/Purchases') - add_route(config, 'closing_stock', '/ClosingStock', has_list=False, variable='date') + add_route(config, "trial_balance", "/TrialBalance", has_list=False, variable="date") + config.add_route("api_net_transactions", "/api/NetTransactions") + config.add_route("net_transactions", "/NetTransactions") + config.add_route("api_purchases", "/api/Purchases") + config.add_route("purchases", "/Purchases") + add_route(config, "closing_stock", "/ClosingStock", has_list=False, variable="date") - add_route(config, 'cash_flow', '/CashFlow', has_list=False) - add_route(config, 'raw_material_cost', '/RawMaterialCost', has_list=False) + add_route(config, "cash_flow", "/CashFlow", has_list=False) + add_route(config, "raw_material_cost", "/RawMaterialCost", has_list=False) - config.add_route('api_daybook', '/api/Daybook') - config.add_route('daybook', '/Daybook') + config.add_route("api_daybook", "/api/Daybook") + config.add_route("daybook", "/Daybook") - config.add_route('api_unposted', '/api/Unposted') - config.add_route('unposted', '/Unposted') + config.add_route("api_unposted", "/api/Unposted") + config.add_route("unposted", "/Unposted") - config.add_route('api_profit_loss', '/api/ProfitLoss') - config.add_route('profit_loss', '/ProfitLoss') + config.add_route("api_profit_loss", "/api/ProfitLoss") + config.add_route("profit_loss", "/ProfitLoss") - config.add_route('api_stock_movement', '/api/StockMovement') - config.add_route('stock_movement', '/StockMovement') + config.add_route("api_stock_movement", "/api/StockMovement") + config.add_route("stock_movement", "/StockMovement") - add_route(config, 'balance_sheet', '/BalanceSheet', has_list=False, variable='date') + add_route(config, "balance_sheet", "/BalanceSheet", has_list=False, variable="date") - config.add_route('api_purchase_entries', '/api/PurchaseEntries') - config.add_route('purchase_entries', '/PurchaseEntries') + config.add_route("api_purchase_entries", "/api/PurchaseEntries") + config.add_route("purchase_entries", "/PurchaseEntries") - config.add_route('api_auth', '/api/Auth') - config.add_route('api_rebase', '/api/Rebase/{date}') - config.add_route('api_reset_stock', '/api/ResetStock/{id}') + config.add_route("api_auth", "/api/Auth") + config.add_route("api_rebase", "/api/Rebase/{date}") + config.add_route("api_reset_stock", "/api/ResetStock/{id}") - config.add_route('api_batch', '/api/Batch') + config.add_route("api_batch", "/api/Batch") - config.add_static_view('', 'brewman:static') + config.add_static_view("", "brewman:static") -def add_route(config, name, url, has_list=True, variable='id'): - config.add_route(name + '_' + variable, url + '/{' + variable + '}') +def add_route(config, name, url, has_list=True, variable="id"): + config.add_route(name + "_" + variable, url + "/{" + variable + "}") config.add_route(name, url) if has_list: - config.add_route(name + '_list', pluralize(url)) + config.add_route(name + "_list", pluralize(url)) - config.add_route('api_' + name + '_' + variable, '/api' + url + '/{' + variable + '}') - config.add_route('api_' + name, '/api' + url) + config.add_route( + "api_" + name + "_" + variable, "/api" + url + "/{" + variable + "}" + ) + config.add_route("api_" + name, "/api" + url) def pluralize(word, num=None): if num is None or num != 1: - if word.endswith('y'): - return word[:-1] + 'ies' - elif word[-1] in 'sx' or word[-2:] in ['sh', 'ch']: - return word + 'es' - elif word.endswith('an'): - return word[:-2] + 'en' + if word.endswith("y"): + return word[:-1] + "ies" + elif word[-1] in "sx" or word[-2:] in ["sh", "ch"]: + return word + "es" + elif word.endswith("an"): + return word[:-2] + "en" else: - return word + 's' + return word + "s" return word diff --git a/brewman/scripts/initializedb.py b/brewman/scripts/initializedb.py index 685795b6..280f8bba 100644 --- a/brewman/scripts/initializedb.py +++ b/brewman/scripts/initializedb.py @@ -3,19 +3,12 @@ import sys import transaction import uuid -from pyramid.paster import ( - get_appsettings, - setup_logging, -) +from pyramid.paster import get_appsettings, setup_logging from pyramid.scripts.common import parse_vars from ..models.meta import Base -from ..models import ( - get_engine, - get_session_factory, - get_tm_session, -) +from ..models import get_engine, get_session_factory, get_tm_session from brewman.models.auth import ( Client, Group, @@ -23,7 +16,7 @@ from brewman.models.auth import ( User, role_group, user_group, - LoginHistory + LoginHistory, ) from brewman.models.master import ( Product, @@ -34,7 +27,7 @@ from brewman.models.master import ( ProductGroup, Recipe, RecipeItem, - DbSetting + DbSetting, ) from brewman.models.voucher import ( Attendance, @@ -46,14 +39,16 @@ from brewman.models.voucher import ( SalaryDeduction, Voucher, ServiceCharge, - DbImage + DbImage, ) def usage(argv): cmd = os.path.basename(argv[0]) - print('usage: %s [var=value]\n' - '(example: "%s development.ini")' % (cmd, cmd)) + print( + "usage: %s [var=value]\n" + '(example: "%s development.ini")' % (cmd, cmd) + ) sys.exit(1) @@ -73,117 +68,223 @@ def main(argv=sys.argv): with transaction.manager: dbsession = get_tm_session(session_factory, transaction.manager) - user = User('Admin', '123456', False, uuid.UUID('8de98592-76d9-c74d-bb3f-d6184d388b5a')) + user = User( + "Admin", "123456", False, uuid.UUID("8de98592-76d9-c74d-bb3f-d6184d388b5a") + ) dbsession.add(user) - - groups = [Group('Owner', uuid.UUID('52e08c0c-048a-784f-be10-6e129ad4b5d4')), - Group('Accountant', uuid.UUID('bc4c2d23-437a-984d-abd4-7d5fce677547')), - Group('Accounts Manager', uuid.UUID('cfc44fa7-3392-5b45-b311-5959333f568f'))] - + + groups = [ + Group("Owner", uuid.UUID("52e08c0c-048a-784f-be10-6e129ad4b5d4")), + Group("Accountant", uuid.UUID("bc4c2d23-437a-984d-abd4-7d5fce677547")), + Group( + "Accounts Manager", uuid.UUID("cfc44fa7-3392-5b45-b311-5959333f568f") + ), + ] + for group in groups: dbsession.add(group) user.groups.append(group) - - roles = [Role('Attendance', uuid.UUID('09d05434-a09a-fa45-963b-769a2e3fc667')), - Role('Trial Balance', uuid.UUID('3b099fec-ddc5-4243-b30e-afb78d9ca14a')), - Role('Cash Flow', uuid.UUID('c4d3ae29-420b-ea4c-ae90-00a356263fd9')), - Role('Cost Centres', uuid.UUID('6fcc1a20-6aec-e840-b334-1632b34aeab8')), - Role('Users', uuid.UUID('c5b7d9d7-f178-0e45-8ea4-bf4e08ec901b')), - Role('Daybook', uuid.UUID('c3edb554-a057-8942-8030-37b8e926d583')), - Role('Edit Posted Vouchers', uuid.UUID('d6675817-ddf5-bf40-9de6-fa223eb4aaa6')), - Role('Employees', uuid.UUID('e4edd0ac-7f5d-e64d-8611-73fdc4cd8ba2')), - Role('Fingerprints', uuid.UUID('d9c45323-f997-ba46-9407-8a7145f0828b')), - Role('Issue', uuid.UUID('03b602eb-f58a-b94f-af58-8cb47d7849d0')), - Role('Journal', uuid.UUID('7661388f-62ce-1c41-8e0d-0326ee5d4018')), - Role('Accounts', uuid.UUID('f438262f-72dd-2f4e-9186-5abc3af44fba')), - Role('Product Ledger', uuid.UUID('018a2408-e804-1446-90c5-b015829da6ba')), - Role('Backdated Vouchers', uuid.UUID('b67b2062-5ca7-134f-8258-5d284dd92426')), - Role('Payment', uuid.UUID('f85c0b52-c3fd-7141-8957-7a56cdc014a4')), - Role('Post Vouchers', uuid.UUID('36e741da-1a57-b047-a59e-dcd58fcf4338')), - Role('Products', uuid.UUID('74fa6d21-eebb-e14c-8153-bebc57190ab4')), - Role('Product Groups', uuid.UUID('08413a22-cf88-fd43-b2b7-365d2951d99f')), - Role('Profit & Loss', uuid.UUID('0492ebb3-76f3-204e-ab94-bbfe880f0691')), - Role('Purchase', uuid.UUID('12335acb-8630-2d41-a191-1517c8d172de')), - Role('Purchase Entries', uuid.UUID('78a6422b-aa11-174c-9dfa-412a99e87e02')), - Role('Purchase Return', uuid.UUID('ab33196e-d9e4-114c-ac8c-997954363756')), - Role('Receipt', uuid.UUID('1f1ce53e-76ff-a346-974a-65db6f606e5f')), - Role('Recipes', uuid.UUID('ffb7fb65-d42c-424d-9ff1-45069e3b4a29')), - Role('Closing Stock', uuid.UUID('97515732-24e4-c94d-9585-d4bd7f6c7891')), - Role('Ledger', uuid.UUID('a2120944-243f-3f49-be57-0ad633ce4801')), - Role('Raw Material Cost', uuid.UUID('d462842b-baf1-2343-95e5-ffdba9bbc163')), - Role('Edit Other User\'s Vouchers', 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('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')), - Role('Balance Sheet', uuid.UUID('40deb018-b8f2-460a-88be-8972c9fcdf04')), - Role('Advanced Delete', uuid.UUID('197ebcd2-bc4a-4b65-a138-ce942ece32ea')), - Role('Rebase', uuid.UUID('de204a88-5f9d-4579-a2d6-aa2f25efde42')), - Role('Reset Stock', uuid.UUID('aecaf82f-aa41-4634-b754-0c1308b621b1')), - Role('Reconcile', uuid.UUID('a5cb51cb-e38e-4705-84a7-cc1e9a8b866b')), - Role('Stock Movement', uuid.UUID('20b707ee-2b59-41ad-be87-76d5fe1efca8')), - Role('Purchases', uuid.UUID('cf7019c8-3fd3-45b0-9a42-601029ce5b71')), - Role('Dashboard', uuid.UUID('53eecc09-bd06-4890-b6f5-6885dda762d4')), - Role('Service Charge', uuid.UUID('99b56390-96c2-4f3d-8b0f-5ae3c868594f')), - Role('Maintenance', uuid.UUID('770532e4-21de-4712-8a6b-4ff9fd63a503'))] - + + roles = [ + Role("Attendance", uuid.UUID("09d05434-a09a-fa45-963b-769a2e3fc667")), + Role("Trial Balance", uuid.UUID("3b099fec-ddc5-4243-b30e-afb78d9ca14a")), + Role("Cash Flow", uuid.UUID("c4d3ae29-420b-ea4c-ae90-00a356263fd9")), + Role("Cost Centres", uuid.UUID("6fcc1a20-6aec-e840-b334-1632b34aeab8")), + Role("Users", uuid.UUID("c5b7d9d7-f178-0e45-8ea4-bf4e08ec901b")), + Role("Daybook", uuid.UUID("c3edb554-a057-8942-8030-37b8e926d583")), + Role( + "Edit Posted Vouchers", + uuid.UUID("d6675817-ddf5-bf40-9de6-fa223eb4aaa6"), + ), + Role("Employees", uuid.UUID("e4edd0ac-7f5d-e64d-8611-73fdc4cd8ba2")), + Role("Fingerprints", uuid.UUID("d9c45323-f997-ba46-9407-8a7145f0828b")), + Role("Issue", uuid.UUID("03b602eb-f58a-b94f-af58-8cb47d7849d0")), + Role("Journal", uuid.UUID("7661388f-62ce-1c41-8e0d-0326ee5d4018")), + Role("Accounts", uuid.UUID("f438262f-72dd-2f4e-9186-5abc3af44fba")), + Role("Product Ledger", uuid.UUID("018a2408-e804-1446-90c5-b015829da6ba")), + Role( + "Backdated Vouchers", uuid.UUID("b67b2062-5ca7-134f-8258-5d284dd92426") + ), + Role("Payment", uuid.UUID("f85c0b52-c3fd-7141-8957-7a56cdc014a4")), + Role("Post Vouchers", uuid.UUID("36e741da-1a57-b047-a59e-dcd58fcf4338")), + Role("Products", uuid.UUID("74fa6d21-eebb-e14c-8153-bebc57190ab4")), + Role("Product Groups", uuid.UUID("08413a22-cf88-fd43-b2b7-365d2951d99f")), + Role("Profit & Loss", uuid.UUID("0492ebb3-76f3-204e-ab94-bbfe880f0691")), + Role("Purchase", uuid.UUID("12335acb-8630-2d41-a191-1517c8d172de")), + Role("Purchase Entries", uuid.UUID("78a6422b-aa11-174c-9dfa-412a99e87e02")), + Role("Purchase Return", uuid.UUID("ab33196e-d9e4-114c-ac8c-997954363756")), + Role("Receipt", uuid.UUID("1f1ce53e-76ff-a346-974a-65db6f606e5f")), + Role("Recipes", uuid.UUID("ffb7fb65-d42c-424d-9ff1-45069e3b4a29")), + Role("Closing Stock", uuid.UUID("97515732-24e4-c94d-9585-d4bd7f6c7891")), + Role("Ledger", uuid.UUID("a2120944-243f-3f49-be57-0ad633ce4801")), + Role( + "Raw Material Cost", uuid.UUID("d462842b-baf1-2343-95e5-ffdba9bbc163") + ), + Role( + "Edit Other User's Vouchers", + 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("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")), + Role("Balance Sheet", uuid.UUID("40deb018-b8f2-460a-88be-8972c9fcdf04")), + Role("Advanced Delete", uuid.UUID("197ebcd2-bc4a-4b65-a138-ce942ece32ea")), + Role("Rebase", uuid.UUID("de204a88-5f9d-4579-a2d6-aa2f25efde42")), + Role("Reset Stock", uuid.UUID("aecaf82f-aa41-4634-b754-0c1308b621b1")), + Role("Reconcile", uuid.UUID("a5cb51cb-e38e-4705-84a7-cc1e9a8b866b")), + Role("Stock Movement", uuid.UUID("20b707ee-2b59-41ad-be87-76d5fe1efca8")), + Role("Purchases", uuid.UUID("cf7019c8-3fd3-45b0-9a42-601029ce5b71")), + Role("Dashboard", uuid.UUID("53eecc09-bd06-4890-b6f5-6885dda762d4")), + Role("Service Charge", uuid.UUID("99b56390-96c2-4f3d-8b0f-5ae3c868594f")), + Role("Maintenance", uuid.UUID("770532e4-21de-4712-8a6b-4ff9fd63a503")), + ] + for role in roles: dbsession.add(role) groups[0].roles.append(role) - - cost_centres = [CostCentre('Overall', uuid.UUID('36f59436-522a-0746-ae94-e0f746bf6c0d'), True), - CostCentre('Purchase', uuid.UUID('7b845f95-dfef-fa4a-897c-f0baf15284a3'), True), - CostCentre('Kitchen', uuid.UUID('b2d398ce-e3cc-c542-9feb-5d7783e899df'), True)] - + + cost_centres = [ + CostCentre( + "Overall", uuid.UUID("36f59436-522a-0746-ae94-e0f746bf6c0d"), True + ), + CostCentre( + "Purchase", uuid.UUID("7b845f95-dfef-fa4a-897c-f0baf15284a3"), True + ), + CostCentre( + "Kitchen", uuid.UUID("b2d398ce-e3cc-c542-9feb-5d7783e899df"), True + ), + ] + for cost_centre in cost_centres: dbsession.add(cost_centre) - + accounts = [ Account( - 1, 'All Purchases', 2, False, True, False, uuid.UUID('7b845f95-dfef-fa4a-897c-f0baf15284a3'), - uuid.UUID('240dd899-c413-854c-a7eb-67a29d154490'), True + 1, + "All Purchases", + 2, + False, + True, + False, + uuid.UUID("7b845f95-dfef-fa4a-897c-f0baf15284a3"), + uuid.UUID("240dd899-c413-854c-a7eb-67a29d154490"), + True, ), Account( - 1, 'Local Purchase', 9, False, True, False, uuid.UUID('36f59436-522a-0746-ae94-e0f746bf6c0d'), - uuid.UUID('d2b75912-505f-2548-9093-466dfff6a0f9'), True + 1, + "Local Purchase", + 9, + False, + True, + False, + uuid.UUID("36f59436-522a-0746-ae94-e0f746bf6c0d"), + uuid.UUID("d2b75912-505f-2548-9093-466dfff6a0f9"), + True, ), Account( - 1, 'ESI/PF - Payable', 11, False, True, False, uuid.UUID('36f59436-522a-0746-ae94-e0f746bf6c0d'), - uuid.UUID('42277912-cc18-854b-b134-9f4b00dba419'), True + 1, + "ESI/PF - Payable", + 11, + False, + True, + False, + uuid.UUID("36f59436-522a-0746-ae94-e0f746bf6c0d"), + uuid.UUID("42277912-cc18-854b-b134-9f4b00dba419"), + True, ), Account( - 2, 'ESI/PF - Expense', 7, False, True, False, uuid.UUID('36f59436-522a-0746-ae94-e0f746bf6c0d'), - uuid.UUID('d2a1a286-e900-764b-a1a5-9f4b00dbb940'), True + 2, + "ESI/PF - Expense", + 7, + False, + True, + False, + uuid.UUID("36f59436-522a-0746-ae94-e0f746bf6c0d"), + uuid.UUID("d2a1a286-e900-764b-a1a5-9f4b00dbb940"), + True, ), Account( - 1, 'Cash in Hand', 1, False, True, False, uuid.UUID('36f59436-522a-0746-ae94-e0f746bf6c0d'), - uuid.UUID('ed2341bb-80b8-9649-90db-f9aaca183bb3'), True + 1, + "Cash in Hand", + 1, + False, + True, + False, + uuid.UUID("36f59436-522a-0746-ae94-e0f746bf6c0d"), + uuid.UUID("ed2341bb-80b8-9649-90db-f9aaca183bb3"), + True, ), Account( - 1, 'Staff Salary', 7, False, True, False, uuid.UUID('36f59436-522a-0746-ae94-e0f746bf6c0d'), - uuid.UUID('5c2b54d0-c174-004d-a0d5-92cdaadcefa7'), True + 1, + "Staff Salary", + 7, + False, + True, + False, + uuid.UUID("36f59436-522a-0746-ae94-e0f746bf6c0d"), + uuid.UUID("5c2b54d0-c174-004d-a0d5-92cdaadcefa7"), + True, ), Account( - 2, 'Service Charges', 11, False, True, False, uuid.UUID('36f59436-522a-0746-ae94-e0f746bf6c0d'), - uuid.UUID('b7eff754-e8ba-e047-ab06-9132c15c7640'), True + 2, + "Service Charges", + 11, + False, + True, + False, + uuid.UUID("36f59436-522a-0746-ae94-e0f746bf6c0d"), + uuid.UUID("b7eff754-e8ba-e047-ab06-9132c15c7640"), + True, ), Account( - 1, 'Suspense', 4, False, True, False, uuid.UUID('36f59436-522a-0746-ae94-e0f746bf6c0d'), - uuid.UUID('3854e317-6f3b-5142-ab26-9c44d4cddd08'), True - ) + 1, + "Suspense", + 4, + False, + True, + False, + uuid.UUID("36f59436-522a-0746-ae94-e0f746bf6c0d"), + uuid.UUID("3854e317-6f3b-5142-ab26-9c44d4cddd08"), + True, + ), ] - + for account in accounts: dbsession.add(account) - - product_group = ProductGroup('Suspense', uuid.UUID('ae59a20c-87bb-444a-8abb-915ad5e58b83'), True) + + product_group = ProductGroup( + "Suspense", uuid.UUID("ae59a20c-87bb-444a-8abb-915ad5e58b83"), True + ) dbsession.add(product_group) - - dbsession.add(ProductGroup('Semi', uuid.UUID('e6bf81b9-1e9b-499f-81d5-ab5662e9d9b1'), True)) - dbsession.add(ProductGroup('Menu Items', uuid.UUID('dad46805-f577-4e5b-8073-9b788e0173fc'), True)) - - product = Product(1, 'Suspense', '', 1, '', 1, uuid.UUID('ae59a20c-87bb-444a-8abb-915ad5e58b83'), - uuid.UUID('240dd899-c413-854c-a7eb-67a29d154490'), 0, 0, False, False, False, - uuid.UUID('aa79a643-9ddc-4790-ac7f-a41f9efb4c15'), True) + + dbsession.add( + ProductGroup( + "Semi", uuid.UUID("e6bf81b9-1e9b-499f-81d5-ab5662e9d9b1"), True + ) + ) + dbsession.add( + ProductGroup( + "Menu Items", uuid.UUID("dad46805-f577-4e5b-8073-9b788e0173fc"), True + ) + ) + + product = Product( + 1, + "Suspense", + "", + 1, + "", + 1, + uuid.UUID("ae59a20c-87bb-444a-8abb-915ad5e58b83"), + uuid.UUID("240dd899-c413-854c-a7eb-67a29d154490"), + 0, + 0, + False, + False, + False, + uuid.UUID("aa79a643-9ddc-4790-ac7f-a41f9efb4c15"), + True, + ) dbsession.add(product) diff --git a/brewman/security/__init__.py b/brewman/security/__init__.py index b948155d..e5b6b130 100644 --- a/brewman/security/__init__.py +++ b/brewman/security/__init__.py @@ -1,6 +1,8 @@ import uuid from pyramid.authentication import AuthTktAuthenticationPolicy -from brewman.security.permission_authorization_policy import PermissionAuthorizationPolicy +from brewman.security.permission_authorization_policy import ( + PermissionAuthorizationPolicy, +) from ..models.auth import User @@ -12,8 +14,8 @@ def get_user(request): def groupfinder(user_id, request): - if 'perms' in request.session: - perms = request.session['perms'] + if "perms" in request.session: + perms = request.session["perms"] else: perms = [] user = request.dbsession.query(User).filter(User.id == uuid.UUID(user_id)).one() @@ -21,7 +23,7 @@ def groupfinder(user_id, request): for perm in item.roles: perms.append(perm.name) perms = sorted(f7(perms)) - request.session['perms'] = perms + request.session["perms"] = perms return perms @@ -32,8 +34,9 @@ def f7(seq): def includeme(config): - authn_policy = AuthTktAuthenticationPolicy('brewman', timeout=900, reissue_time=90, callback=groupfinder) + authn_policy = AuthTktAuthenticationPolicy( + "brewman", timeout=900, reissue_time=90, callback=groupfinder + ) config.set_authentication_policy(authn_policy) config.set_authorization_policy(PermissionAuthorizationPolicy()) - config.add_request_method(get_user, 'user', reify=True) - + config.add_request_method(get_user, "user", reify=True) diff --git a/brewman/security/permission_authorization_policy.py b/brewman/security/permission_authorization_policy.py index 252897b8..0d98e658 100644 --- a/brewman/security/permission_authorization_policy.py +++ b/brewman/security/permission_authorization_policy.py @@ -6,10 +6,10 @@ from pyramid.interfaces import IAuthorizationPolicy @implementer(IAuthorizationPolicy) class PermissionAuthorizationPolicy(object): def permits(self, context, principals, permission): - if permission == 'Authenticated': - permission = 'system.Authenticated' - if permission == 'Everyone': - permission = 'system.Everyone' + if permission == "Authenticated": + permission = "system.Authenticated" + if permission == "Everyone": + permission = "system.Everyone" allowed = permission in principals return allowed diff --git a/brewman/subscribers.py b/brewman/subscribers.py index b5cb2826..09494202 100644 --- a/brewman/subscribers.py +++ b/brewman/subscribers.py @@ -5,6 +5,13 @@ from brewman.models.master import DbSetting @subscriber(NewRequest) def maintenance_mode(event): - maintenance = event.request.dbsession.query(DbSetting).filter(DbSetting.name == 'Maintenance').first() - if maintenance is not None and maintenance.data != event.request.authenticated_userid: + maintenance = ( + event.request.dbsession.query(DbSetting) + .filter(DbSetting.name == "Maintenance") + .first() + ) + if ( + maintenance is not None + and maintenance.data != event.request.authenticated_userid + ): raise HTTPServiceUnavailable diff --git a/brewman/tests.py b/brewman/tests.py index 05e16179..de11ce63 100644 --- a/brewman/tests.py +++ b/brewman/tests.py @@ -2,6 +2,7 @@ import unittest from pyramid import testing + class ViewTests(unittest.TestCase): def setUp(self): self.config = testing.setUp() @@ -11,6 +12,7 @@ class ViewTests(unittest.TestCase): def test_my_view(self): from .views import my_view + request = testing.DummyRequest() info = my_view(request) - self.assertEqual(info['project'], 'brewman') + self.assertEqual(info["project"], "brewman") diff --git a/brewman/transactional_view_deriver.py b/brewman/transactional_view_deriver.py index a976ffbd..18ff593d 100644 --- a/brewman/transactional_view_deriver.py +++ b/brewman/transactional_view_deriver.py @@ -5,12 +5,21 @@ from brewman.models.validation_exception import ValidationError def transactional_view(view, info): - if info.options.get('trans'): + if info.options.get("trans"): + def wrapper_view(context, request): try: response = view(context, request) - except (ValidationError, ValueError, KeyError, AttributeError, TypeError, OperationalError, IntegrityError, - DBAPIError) as ex: + except ( + ValidationError, + ValueError, + KeyError, + AttributeError, + TypeError, + OperationalError, + IntegrityError, + DBAPIError, + ) as ex: transaction.abort() response = Response("Failed validation: {0}".format(str(ex))) response.status_int = 500 @@ -21,4 +30,4 @@ def transactional_view(view, info): return view -transactional_view.options = ('trans',) +transactional_view.options = ("trans",) diff --git a/brewman/views/Management/db_integrity.py b/brewman/views/Management/db_integrity.py index 19ef62ec..c3d2f3c3 100644 --- a/brewman/views/Management/db_integrity.py +++ b/brewman/views/Management/db_integrity.py @@ -5,30 +5,54 @@ import transaction from brewman.models.voucher import Attendance -@view_config(request_method='POST', route_name='api_db_integrity', renderer='json', permission='Authenticated') +@view_config( + request_method="POST", + route_name="api_db_integrity", + renderer="json", + permission="Authenticated", +) def post_check_db(request): info = {} duplicate_attendances = get_duplicate_attendances(request.dbsession) if duplicate_attendances > 0: fix_duplicate_attendances(request.dbsession) - info['Duplicate Attendances Fixed'] = duplicate_attendances + info["Duplicate Attendances Fixed"] = duplicate_attendances transaction.commit() return info def get_duplicate_attendances(dbsession): - sub_query = dbsession.query( - over(distinct(func.first_value(Attendance.id)), partition_by=[Attendance.employee_id, Attendance.date]) - ).filter(Attendance.is_valid == True).subquery() - query = dbsession.query(func.count(Attendance.id)). \ - filter(~Attendance.id.in_(sub_query)). \ - filter(Attendance.is_valid == True) + sub_query = ( + dbsession.query( + over( + distinct(func.first_value(Attendance.id)), + partition_by=[Attendance.employee_id, Attendance.date], + ) + ) + .filter(Attendance.is_valid == True) + .subquery() + ) + query = ( + dbsession.query(func.count(Attendance.id)) + .filter(~Attendance.id.in_(sub_query)) + .filter(Attendance.is_valid == True) + ) return query.scalar() def fix_duplicate_attendances(dbsession): - sub = dbsession.query(over(distinct(func.first_value(Attendance.id)), - partition_by=[Attendance.employee_id, Attendance.date], - order_by=desc(Attendance.creation_date))).filter(Attendance.is_valid == True).subquery() - dbsession.query(Attendance).filter(~Attendance.id.in_(sub)).filter(Attendance.is_valid == True).delete(False) + sub = ( + dbsession.query( + over( + distinct(func.first_value(Attendance.id)), + partition_by=[Attendance.employee_id, Attendance.date], + order_by=desc(Attendance.creation_date), + ) + ) + .filter(Attendance.is_valid == True) + .subquery() + ) + dbsession.query(Attendance).filter(~Attendance.id.in_(sub)).filter( + Attendance.is_valid == True + ).delete(False) diff --git a/brewman/views/Management/rebase.py b/brewman/views/Management/rebase.py index 9e542bc6..6a535711 100644 --- a/brewman/views/Management/rebase.py +++ b/brewman/views/Management/rebase.py @@ -8,15 +8,31 @@ from sqlalchemy import func, and_, distinct from sqlalchemy.orm import aliased, joinedload_all from brewman.models.master import AccountBase, CostCentre, Account, Employee -from brewman.models.voucher import Journal, Voucher, VoucherType, Batch, Inventory, SalaryDeduction, Fingerprint, \ - Attendance, DbImage, ServiceCharge +from brewman.models.voucher import ( + Journal, + Voucher, + VoucherType, + Batch, + Inventory, + SalaryDeduction, + Fingerprint, + Attendance, + DbImage, + ServiceCharge, +) -@view_config(request_method='POST', route_name='api_rebase', renderer='json', permission='Rebase', trans=True) +@view_config( + request_method="POST", + route_name="api_rebase", + renderer="json", + permission="Rebase", + trans=True, +) def rebase(request): # request.dbsession.execute('SET statement_timeout TO 300000;') # 5 minutes - date = request.matchdict.get('date', None) - date = datetime.datetime.strptime(date, '%d-%b-%Y') + date = request.matchdict.get("date", None) + date = datetime.datetime.strptime(date, "%d-%b-%Y") user_id = uuid.UUID(request.authenticated_userid) voucher_l = opening_accounts(date, user_id, request.dbsession) voucher_b = opening_batches(date, user_id, request.dbsession) @@ -39,21 +55,28 @@ def rebase(request): def save_starred(date, dbsession): - accounts = [i.id for i in dbsession.query(AccountBase.id).filter(AccountBase.is_starred == True).all()] + accounts = [ + i.id + for i in dbsession.query(AccountBase.id) + .filter(AccountBase.is_starred == True) + .all() + ] vouchers = [] - query = dbsession.query( - Voucher - ).options( - joinedload_all(Voucher.journals, Journal.account, innerjoin=True) - ).filter( - Voucher.date < date - ).filter( - Voucher.journals.any(Journal.account_id.in_(accounts)) - ).all() + query = ( + dbsession.query(Voucher) + .options(joinedload_all(Voucher.journals, Journal.account, innerjoin=True)) + .filter(Voucher.date < date) + .filter(Voucher.journals.any(Journal.account_id.in_(accounts))) + .all() + ) for voucher in query: vouchers.append(voucher.id) - others = [journal for journal in voucher.journals if journal.account_id not in accounts] + others = [ + journal + for journal in voucher.journals + if journal.account_id not in accounts + ] if len(others) == 0: continue amount = round(Decimal(sum(o.signed_amount for o in others)), 2) @@ -62,16 +85,18 @@ def save_starred(date, dbsession): amount=abs(amount), debit=-1 if amount < 0 else 1, account_id=AccountBase.suspense(), - cost_centre_id=CostCentre.cost_centre_overall() + cost_centre_id=CostCentre.cost_centre_overall(), ) voucher.journals.append(journal) dbsession.add(journal) for other in others: - if voucher.type != VoucherType.by_name('Opening Accounts').id: - voucher.narration += '\nSuspense \u20B9{0:,.2f} is {1}'.format(other.amount, other.account.name) + if voucher.type != VoucherType.by_name("Opening Accounts").id: + voucher.narration += "\nSuspense \u20B9{0:,.2f} is {1}".format( + other.amount, other.account.name + ) dbsession.delete(other) - voucher.type = VoucherType.by_name('Journal') + voucher.type = VoucherType.by_name("Journal") if len(voucher.narration) >= 1000: voucher.narration = voucher.narration[:1000] return vouchers @@ -80,41 +105,45 @@ def save_starred(date, dbsession): def opening_accounts(date, user_id, dbsession): running_total = 0 sum_func = func.sum(Journal.signed_amount) - query = dbsession.query( - AccountBase, sum_func - ).join( - Journal, Voucher.journals - ).join( - AccountBase, Journal.account - ).filter( - AccountBase.is_starred == False - ).filter( - AccountBase.id != AccountBase.suspense() - ).filter( - Voucher.date < date - ).filter( - Voucher.type != VoucherType.by_name('Issue').id - ).having( - sum_func != 0 - ).group_by(AccountBase).all() + query = ( + dbsession.query(AccountBase, sum_func) + .join(Journal, Voucher.journals) + .join(AccountBase, Journal.account) + .filter(AccountBase.is_starred == False) + .filter(AccountBase.id != AccountBase.suspense()) + .filter(Voucher.date < date) + .filter(Voucher.type != VoucherType.by_name("Issue").id) + .having(sum_func != 0) + .group_by(AccountBase) + .all() + ) dt = date - datetime.timedelta(days=1) voucher = Voucher( date=dt, - narration='Opening Accounts', - user_id=user_id, posted=True, - type=VoucherType.by_name('Opening Accounts') + narration="Opening Accounts", + user_id=user_id, + posted=True, + type=VoucherType.by_name("Opening Accounts"), ) for account, amount in query: amount = round(Decimal(amount), 2) if account.type_object.balance_sheet and amount != 0: running_total += amount - journal = Journal(amount=abs(amount), debit=-1 if amount < 0 else 1, account_id=account.id, - cost_centre_id=account.cost_centre_id) + journal = Journal( + amount=abs(amount), + debit=-1 if amount < 0 else 1, + account_id=account.id, + cost_centre_id=account.cost_centre_id, + ) voucher.journals.append(journal) if running_total != 0: - journal = Journal(amount=abs(amount), debit=-1 if amount * -1 < 0 else 1, account_id=AccountBase.suspense(), - cost_centre_id=CostCentre.cost_centre_overall()) + journal = Journal( + amount=abs(amount), + debit=-1 if amount * -1 < 0 else 1, + account_id=AccountBase.suspense(), + cost_centre_id=CostCentre.cost_centre_overall(), + ) voucher.journals.append(journal) return voucher @@ -122,64 +151,66 @@ def opening_accounts(date, user_id, dbsession): def opening_batches(date, user_id, dbsession): total = 0 sum_func = func.sum(Journal.debit * Inventory.quantity) - query = dbsession.query( - Batch, sum_func - ).join( - Journal, Voucher.journals - ).join( - Inventory, Voucher.inventories - ).join( - Batch, Inventory.batch - ).filter( - Voucher.date < date - ).filter( - Journal.cost_centre_id == CostCentre.cost_centre_purchase() - ).having( - sum_func != 0 - ).group_by(Batch).all() + query = ( + dbsession.query(Batch, sum_func) + .join(Journal, Voucher.journals) + .join(Inventory, Voucher.inventories) + .join(Batch, Inventory.batch) + .filter(Voucher.date < date) + .filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase()) + .having(sum_func != 0) + .group_by(Batch) + .all() + ) dt = date - datetime.timedelta(days=1) voucher = Voucher( date=dt, - narration='Opening Batches', + narration="Opening Batches", user_id=user_id, posted=True, - type=VoucherType.by_name('Opening Batches') + type=VoucherType.by_name("Opening Batches"), ) for batch, quantity in query: quantity = round(Decimal(quantity), 2) if quantity != 0: total += quantity * batch.rate * (1 + batch.tax) * (1 - batch.discount) - inventory = Inventory(product_id=batch.product_id, batch=batch, quantity=quantity, rate=batch.rate, - tax=batch.tax, discount=batch.discount) + inventory = Inventory( + product_id=batch.product_id, + batch=batch, + quantity=quantity, + rate=batch.rate, + tax=batch.tax, + discount=batch.discount, + ) voucher.inventories.append(inventory) - voucher.journals.append(Journal( - amount=abs(total), - debit=-1, - account_id=AccountBase.all_purchases(), - cost_centre_id=CostCentre.cost_centre_overall() - )) - voucher.journals.append(Journal( - amount=abs(total), - debit=1, - account_id=AccountBase.all_purchases(), - cost_centre_id=CostCentre.cost_centre_purchase() - )) + voucher.journals.append( + Journal( + amount=abs(total), + debit=-1, + account_id=AccountBase.all_purchases(), + cost_centre_id=CostCentre.cost_centre_overall(), + ) + ) + voucher.journals.append( + Journal( + amount=abs(total), + debit=1, + account_id=AccountBase.all_purchases(), + cost_centre_id=CostCentre.cost_centre_purchase(), + ) + ) return voucher def delete_data(date, vouchers, dbsession): sub_voucher = aliased(Voucher) - sub_query = dbsession.query( - sub_voucher.id - ).filter( - sub_voucher.date < date - ).subquery() - - dbsession.execute( - Inventory.__table__.delete(Inventory.voucher_id.in_(sub_query)) + sub_query = ( + dbsession.query(sub_voucher.id).filter(sub_voucher.date < date).subquery() ) + + dbsession.execute(Inventory.__table__.delete(Inventory.voucher_id.in_(sub_query))) dbsession.execute( SalaryDeduction.__table__.delete(SalaryDeduction.voucher_id.in_(sub_query)) ) @@ -188,27 +219,20 @@ def delete_data(date, vouchers, dbsession): ) dbsession.execute( Journal.__table__.delete( - and_( - Journal.voucher_id.in_(sub_query), - ~Journal.voucher_id.in_(vouchers) - ) + and_(Journal.voucher_id.in_(sub_query), ~Journal.voucher_id.in_(vouchers)) ) ) dbsession.execute( DbImage.__table__.delete( and_( - DbImage.resource_type == 'voucher', DbImage.resource_id.in_(sub_query), - ~DbImage.resource_id.in_(vouchers) + DbImage.resource_type == "voucher", + DbImage.resource_id.in_(sub_query), + ~DbImage.resource_id.in_(vouchers), ) ) ) dbsession.execute( - Voucher.__table__.delete( - and_( - Voucher.date < date, - ~Voucher.id.in_(vouchers) - ) - ) + Voucher.__table__.delete(and_(Voucher.date < date, ~Voucher.id.in_(vouchers))) ) @@ -219,29 +243,28 @@ def cleanup_lint(date, dbsession): ~Batch.id.in_(dbsession.query(distinct(Inventory.batch_id)).subquery()) ) ) - dbsession.execute( - Fingerprint.__table__.delete(Fingerprint.date < date) - ) - dbsession.execute( - Attendance.__table__.delete(Attendance.date < date) - ) + dbsession.execute(Fingerprint.__table__.delete(Fingerprint.date < date)) + dbsession.execute(Attendance.__table__.delete(Attendance.date < date)) dbsession.execute( Employee.__table__.delete( and_( - ~Employee.id.in_(dbsession.query(distinct(Journal.account_id)).subquery()), - ~Employee.id.in_(dbsession.query(distinct(Fingerprint.employee_id)).subquery()), - ~Employee.id.in_(dbsession.query(distinct(Attendance.employee_id)).subquery()), + ~Employee.id.in_( + dbsession.query(distinct(Journal.account_id)).subquery() + ), + ~Employee.id.in_( + dbsession.query(distinct(Fingerprint.employee_id)).subquery() + ), + ~Employee.id.in_( + dbsession.query(distinct(Attendance.employee_id)).subquery() + ), Employee.id.in_( - dbsession.query( - AccountBase.id - ).filter( - AccountBase.is_fixture == False - ).filter( - AccountBase.is_active == False - ).filter( - AccountBase.is_starred == False - ).subquery()), - Employee.leaving_date < date + dbsession.query(AccountBase.id) + .filter(AccountBase.is_fixture == False) + .filter(AccountBase.is_active == False) + .filter(AccountBase.is_starred == False) + .subquery() + ), + Employee.leaving_date < date, ) ) ) @@ -249,17 +272,20 @@ def cleanup_lint(date, dbsession): AccountBase.__table__.delete( and_( ~AccountBase.id.in_(dbsession.query(Employee.id).subquery()), - AccountBase.account_type == Employee.__mapper_args__['polymorphic_identity'] + AccountBase.account_type + == Employee.__mapper_args__["polymorphic_identity"], ) ) ) dbsession.execute( Account.__table__.delete( and_( - ~Account.id.in_(dbsession.query(distinct(Journal.account_id)).subquery()), + ~Account.id.in_( + dbsession.query(distinct(Journal.account_id)).subquery() + ), Account.is_fixture == False, Account.is_starred == False, - Account.account_type == Account.__mapper_args__['polymorphic_identity'] + Account.account_type == Account.__mapper_args__["polymorphic_identity"], ) ) ) diff --git a/brewman/views/Management/settings.py b/brewman/views/Management/settings.py index d46f03bf..8cd30beb 100644 --- a/brewman/views/Management/settings.py +++ b/brewman/views/Management/settings.py @@ -9,95 +9,139 @@ from brewman.models.auth import User from brewman.models.master import DbSetting -@view_config(route_name='settings', permission='Authenticated') +@view_config(route_name="settings", permission="Authenticated") def html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='POST', route_name='api_lock_information', renderer='json', permission='Lock Date', - trans=True) +@view_config( + request_method="POST", + route_name="api_lock_information", + renderer="json", + permission="Lock Date", + trans=True, +) def set_lock_info(request): - start_locked = request.json_body['lockOlder'] - finish_locked = request.json_body['lockNewer'] - data = {'Start': {'Locked': start_locked}, 'Finish': {'Locked': finish_locked}} + start_locked = request.json_body["lockOlder"] + finish_locked = request.json_body["lockNewer"] + data = {"Start": {"Locked": start_locked}, "Finish": {"Locked": finish_locked}} if start_locked: - rolling = request.json_body['olderRolling'] - data['Start']['Rolling'] = rolling + rolling = request.json_body["olderRolling"] + data["Start"]["Rolling"] = rolling if rolling: - data['Start']['Days'] = request.json_body['olderDays'] + data["Start"]["Days"] = request.json_body["olderDays"] else: - data['Start']['Date'] = datetime.datetime.strptime(request.json_body['olderDate'], '%d-%b-%Y') + data["Start"]["Date"] = datetime.datetime.strptime( + request.json_body["olderDate"], "%d-%b-%Y" + ) if finish_locked: - rolling = request.json_body['newerRolling'] - data['Finish']['Rolling'] = rolling + rolling = request.json_body["newerRolling"] + data["Finish"]["Rolling"] = rolling if rolling: - data['Finish']['Days'] = request.json_body['newerDays'] + data["Finish"]["Days"] = request.json_body["newerDays"] else: - data['Finish']['Date'] = datetime.datetime.strptime(request.json_body['newerDate'], '%d-%b-%Y') + data["Finish"]["Date"] = datetime.datetime.strptime( + request.json_body["newerDate"], "%d-%b-%Y" + ) - lock_date = request.dbsession.query(DbSetting).filter(DbSetting.name == 'Lock Info').first() + lock_date = ( + request.dbsession.query(DbSetting).filter(DbSetting.name == "Lock Info").first() + ) if lock_date is not None: lock_date.data = data else: - lock_date = DbSetting(name='Lock Info', data=data) + lock_date = DbSetting(name="Lock Info", data=data) request.dbsession.add(lock_date) transaction.commit() return get_lock_info(request) -@view_config(request_method='DELETE', route_name='api_lock_information', renderer='json', permission='Lock Date', - trans=True) +@view_config( + request_method="DELETE", + route_name="api_lock_information", + renderer="json", + permission="Lock Date", + trans=True, +) def clear_lock_info(request): - lock_date = request.dbsession.query(DbSetting).filter(DbSetting.name == 'Lock Info').first() + lock_date = ( + request.dbsession.query(DbSetting).filter(DbSetting.name == "Lock Info").first() + ) if lock_date is not None and lock_date.data is not None: lock_date.data = None transaction.commit() return {} -@view_config(request_method='GET', route_name='api_lock_information', renderer='json', permission='Authenticated') +@view_config( + request_method="GET", + route_name="api_lock_information", + renderer="json", + permission="Authenticated", +) def get_lock_info(request): - data = request.dbsession.query(DbSetting).filter(DbSetting.name == 'Lock Info').first() + data = ( + request.dbsession.query(DbSetting).filter(DbSetting.name == "Lock Info").first() + ) if data is None: - return {'lockOlder': False, 'lockNewer': False} + return {"lockOlder": False, "lockNewer": False} data = data.data - info = {'lockOlder': data['Start']['Locked'], 'lockNewer': data['Finish']['Locked']} - if data['Start']['Locked']: - info['olderRolling'] = data['Start']['Rolling'] - if data['Start']['Rolling']: - info['olderDays'] = data['Start']['Days'] + info = {"lockOlder": data["Start"]["Locked"], "lockNewer": data["Finish"]["Locked"]} + if data["Start"]["Locked"]: + info["olderRolling"] = data["Start"]["Rolling"] + if data["Start"]["Rolling"]: + info["olderDays"] = data["Start"]["Days"] else: - info['olderDate'] = data['Start']['Date'].strftime('%d-%b-%Y') + info["olderDate"] = data["Start"]["Date"].strftime("%d-%b-%Y") - if data['Finish']['Locked']: - info['newerRolling'] = data['Finish']['Rolling'] - if data['Finish']['Rolling']: - info['newerDays'] = data['Finish']['Days'] + if data["Finish"]["Locked"]: + info["newerRolling"] = data["Finish"]["Rolling"] + if data["Finish"]["Rolling"]: + info["newerDays"] = data["Finish"]["Days"] else: - info['newerDate'] = data['Finish']['Date'].strftime('%d-%b-%Y') + info["newerDate"] = data["Finish"]["Date"].strftime("%d-%b-%Y") return info -@view_config(request_method='GET', route_name='api_maintenance', renderer='json', permission='Authenticated') +@view_config( + request_method="GET", + route_name="api_maintenance", + renderer="json", + permission="Authenticated", +) def get_maintenance(request): - data = request.dbsession.query(DbSetting).filter(DbSetting.name == 'Maintenance').first() + data = ( + request.dbsession.query(DbSetting) + .filter(DbSetting.name == "Maintenance") + .first() + ) if data is None: - return {'enabled': False, 'user': ''} + return {"enabled": False, "user": ""} user = request.dbsession.query(User).filter(User.id == data.data).one() - return {'enabled': True, 'user': user.name} + return {"enabled": True, "user": user.name} -@view_config(request_method='POST', route_name='api_maintenance', renderer='json', permission='Maintenance', trans=True) +@view_config( + request_method="POST", + route_name="api_maintenance", + renderer="json", + permission="Maintenance", + trans=True, +) def set_maintenance(request): - status = request.json_body['enabled'] - maintenance = request.dbsession.query(DbSetting).filter(DbSetting.name == 'Maintenance').first() + status = request.json_body["enabled"] + maintenance = ( + request.dbsession.query(DbSetting) + .filter(DbSetting.name == "Maintenance") + .first() + ) if status is False and maintenance is not None: request.dbsession.delete(maintenance) elif status is True and maintenance is None: - maintenance = DbSetting(name='Maintenance', data=request.authenticated_userid) + maintenance = DbSetting(name="Maintenance", data=request.authenticated_userid) request.dbsession.add(maintenance) elif status is True and maintenance.data != request.authenticated_userid: maintenance.data = request.authenticated_userid diff --git a/brewman/views/Management/stock.py b/brewman/views/Management/stock.py index e77d66bc..2ce693f1 100644 --- a/brewman/views/Management/stock.py +++ b/brewman/views/Management/stock.py @@ -11,24 +11,36 @@ from brewman.models.validation_exception import ValidationError from brewman.models.voucher import Journal, Voucher, VoucherType, Batch, Inventory -@view_config(request_method='POST', route_name='api_reset_stock', renderer='json', permission='Reset Stock', trans=True) +@view_config( + request_method="POST", + route_name="api_reset_stock", + renderer="json", + permission="Reset Stock", + trans=True, +) def rebase(request): user_id = uuid.UUID(request.authenticated_userid) - product = request.dbsession.query(Product).filter(Product.id == uuid.UUID(request.matchdict['id'])).first() + product = ( + request.dbsession.query(Product) + .filter(Product.id == uuid.UUID(request.matchdict["id"])) + .first() + ) - quantity = round(Decimal(request.GET['Quantity']), 2) - stock_date = datetime.datetime.strptime(request.GET['StockDate'], '%d-%b-%Y') - reset_date = datetime.datetime.strptime(request.GET['ResetDate'], '%d-%b-%Y') + quantity = round(Decimal(request.GET["Quantity"]), 2) + stock_date = datetime.datetime.strptime(request.GET["StockDate"], "%d-%b-%Y") + reset_date = datetime.datetime.strptime(request.GET["ResetDate"], "%d-%b-%Y") if reset_date > stock_date: - raise ValidationError('Reset cannot be after the stock date') + raise ValidationError("Reset cannot be after the stock date") - change = quantity - get_closing_stock(product, stock_date, dbsession=request.dbsession) + change = quantity - get_closing_stock( + product, stock_date, dbsession=request.dbsession + ) if change == 0: - return {'No Change Needed'} + return {"No Change Needed"} final = get_closing_stock(product, dbsession=request.dbsession) if final + change < 0: - raise ValidationError('Current Quantity will get negative. Cannot proceed') + raise ValidationError("Current Quantity will get negative. Cannot proceed") batch = get_last_batch(product, request.dbsession) set_batches(batch, final + change, request.dbsession) @@ -39,12 +51,14 @@ def rebase(request): def get_closing_stock(product, finish_date=None, dbsession=None): - query = dbsession.query(func.sum(Inventory.quantity * Journal.debit)) \ - .join(Voucher) \ - .filter(Voucher.id == Inventory.voucher_id) \ - .filter(Voucher.id == Journal.voucher_id) \ - .filter(Inventory.product_id == product.id) \ + query = ( + dbsession.query(func.sum(Inventory.quantity * Journal.debit)) + .join(Voucher) + .filter(Voucher.id == Inventory.voucher_id) + .filter(Voucher.id == Journal.voucher_id) + .filter(Inventory.product_id == product.id) .filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase()) + ) if finish_date is not None: query = query.filter(Voucher.date <= finish_date) query = query.one() @@ -52,22 +66,38 @@ def get_closing_stock(product, finish_date=None, dbsession=None): def get_last_batch(product, dbsession): - batch = dbsession.query(Batch).filter(Batch.product_id == product.id).order_by(Batch.name.desc()).first() + batch = ( + dbsession.query(Batch) + .filter(Batch.product_id == product.id) + .order_by(Batch.name.desc()) + .first() + ) if batch is None: - raise ValidationError('Details for the product exist. Just add a purchase entry') + raise ValidationError( + "Details for the product exist. Just add a purchase entry" + ) return batch def set_batches(batch, quantity, dbsession): batch.quantity_remaining = quantity - batches = dbsession.query(Batch).filter(Batch.id != batch.id).filter(Batch.product_id == batch.product_id) + batches = ( + dbsession.query(Batch) + .filter(Batch.id != batch.id) + .filter(Batch.product_id == batch.product_id) + ) for item in batches: item.quantity_remaining = 0 pass def create_voucher(batch, quantity, date, user_id, dbsession): - voucher = Voucher(date=date, narration='Product Reset', user_id=user_id, type=VoucherType.by_name('Issue')) + voucher = Voucher( + date=date, + narration="Product Reset", + user_id=user_id, + type=VoucherType.by_name("Issue"), + ) dbsession.add(voucher) if quantity > 0: @@ -77,15 +107,31 @@ def create_voucher(batch, quantity, date, user_id, dbsession): destination = CostCentre.cost_centre_overall() source = CostCentre.cost_centre_purchase() - inventory = Inventory(product_id=batch.product.id, quantity=abs(quantity), rate=batch.rate, tax=batch.tax, - discount=batch.discount, batch=batch) + inventory = Inventory( + product_id=batch.product.id, + quantity=abs(quantity), + rate=batch.rate, + tax=batch.tax, + discount=batch.discount, + batch=batch, + ) voucher.inventories.append(inventory) dbsession.add(inventory) amount = round(inventory.amount, 2) - source = Journal(debit=-1, account_id=AccountBase.all_purchases(), amount=amount, cost_centre_id=source) + source = Journal( + debit=-1, + account_id=AccountBase.all_purchases(), + amount=amount, + cost_centre_id=source, + ) voucher.journals.append(source) dbsession.add(source) - destination = Journal(debit=1, account_id=AccountBase.all_purchases(), amount=amount, cost_centre_id=destination) + destination = Journal( + debit=1, + account_id=AccountBase.all_purchases(), + amount=amount, + cost_centre_id=destination, + ) voucher.journals.append(destination) dbsession.add(destination) diff --git a/brewman/views/__init__.py b/brewman/views/__init__.py index b5d8df13..0ec964c3 100644 --- a/brewman/views/__init__.py +++ b/brewman/views/__init__.py @@ -13,67 +13,81 @@ from brewman.models.master import DbSetting from brewman.models.voucher import DbImage -@view_config(route_name='home') -@view_config(request_method='GET', route_name='login') +@view_config(route_name="home") +@view_config(request_method="GET", route_name="login") def home(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) @view_config(context=HTTPForbidden) def forbidden_json(request): - if request.accept.quality('application/json') == 1: + if request.accept.quality("application/json") == 1: response = Response("Forbidden") response.status_int = 401 return response else: - ret = HTTPFound(location=request.route_url('login', _query={'returnUrl': request.path_qs})) + ret = HTTPFound( + location=request.route_url("login", _query={"returnUrl": request.path_qs}) + ) return ret -@view_config(route_name='db_image') +@view_config(route_name="db_image") def db_image(request): - item = request.dbsession.query(DbImage).filter(DbImage.id == uuid.UUID(request.matchdict['id'])).first() - if request.matchdict['type'] == 'thumbnail': + item = ( + request.dbsession.query(DbImage) + .filter(DbImage.id == uuid.UUID(request.matchdict["id"])) + .first() + ) + if request.matchdict["type"] == "thumbnail": item = BytesIO(item.thumbnail) else: item = BytesIO(item.image) - response = Response(content_type='image/jpeg') + response = Response(content_type="image/jpeg") response.app_iter = item return response def get_lock_info(dbsession): - data = dbsession.query(DbSetting).filter(DbSetting.name == 'Lock Info').first() + data = dbsession.query(DbSetting).filter(DbSetting.name == "Lock Info").first() if data is None: return None, None data = data.data - if not data['Start']['Locked']: + if not data["Start"]["Locked"]: start = None - elif data['Start']['Rolling']: - start = datetime.combine(date.today(), time()) - timedelta(days=data['Start']['Days']) + elif data["Start"]["Rolling"]: + start = datetime.combine(date.today(), time()) - timedelta( + days=data["Start"]["Days"] + ) else: - start = data['Start']['Date'] + start = data["Start"]["Date"] - if not data['Finish']['Locked']: + if not data["Finish"]["Locked"]: finish = None - elif data['Finish']['Rolling']: - finish = datetime.combine(date.today(), time()) + timedelta(days=data['Finish']['Days']) + elif data["Finish"]["Rolling"]: + finish = datetime.combine(date.today(), time()) + timedelta( + days=data["Finish"]["Days"] + ) else: - finish = data['Finish']['Date'] + finish = data["Finish"]["Date"] return start, finish def to_uuid(value): - p = re.compile('^[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}$') + p = re.compile( + "^[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}$" + ) return uuid.UUID(value) if p.match(value) else None def to_decimal(value, default=0): import re - _parser = re.compile(r""" # A numeric string consists of: + + _parser = re.compile( + r""" # A numeric string consists of: (?P[-+])? # an optional sign, followed by either... ( (?=\d|\.\d) # ...a number (with at least one digit) @@ -85,5 +99,7 @@ def to_decimal(value, default=0): (?P\d*) # with (possibly empty) diagnostic info. ) \Z - """, re.VERBOSE | re.IGNORECASE).match + """, + re.VERBOSE | re.IGNORECASE, + ).match return Decimal(value) if _parser(value.strip()) is not None else default diff --git a/brewman/views/account.py b/brewman/views/account.py index da3564bc..e0e06dc4 100644 --- a/brewman/views/account.py +++ b/brewman/views/account.py @@ -13,53 +13,80 @@ from brewman.models.validation_exception import ValidationError from brewman.models.voucher import Voucher, Journal, VoucherType -@view_config(route_name='account_list', permission='Accounts') -@view_config(request_method='GET', route_name='account_id', permission='Accounts') -@view_config(request_method='GET', route_name='account', permission='Accounts') +@view_config(route_name="account_list", permission="Accounts") +@view_config(request_method="GET", route_name="account_id", permission="Accounts") +@view_config(request_method="GET", route_name="account", permission="Accounts") def html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='POST', route_name='api_account', renderer='json', permission='Accounts', trans=True) +@view_config( + request_method="POST", + route_name="api_account", + renderer="json", + permission="Accounts", + trans=True, +) def save(request): json = request.json_body item = Account( code=0, - name=json['name'], - type=int(json['type']), - is_starred=json['isStarred'], - is_active=json['isActive'], - is_reconcilable=json['isReconcilable'], - cost_centre_id=uuid.UUID(json['costCentre']['id']) + name=json["name"], + type=int(json["type"]), + is_starred=json["isStarred"], + is_active=json["isActive"], + is_reconcilable=json["isReconcilable"], + cost_centre_id=uuid.UUID(json["costCentre"]["id"]), ).create(request.dbsession) transaction.commit() return account_info(item.id, request.dbsession) -@view_config(request_method='PUT', route_name='api_account_id', renderer='json', permission='Accounts', trans=True) +@view_config( + request_method="PUT", + route_name="api_account_id", + renderer="json", + permission="Accounts", + trans=True, +) def update(request): - item = request.dbsession.query(Account).filter(Account.id == uuid.UUID(request.matchdict['id'])).first() + item = ( + request.dbsession.query(Account) + .filter(Account.id == uuid.UUID(request.matchdict["id"])) + .first() + ) if item.is_fixture: - raise ValidationError("{0} is a fixture and cannot be edited or deleted.".format(item.name)) - new_type = int(request.json_body['type']) + raise ValidationError( + "{0} is a fixture and cannot be edited or deleted.".format(item.name) + ) + new_type = int(request.json_body["type"]) if not item.type == new_type: item.code = Account.get_code(new_type, request.dbsession) item.type = new_type - item.name = request.json_body['name'] - item.is_active = request.json_body['isActive'] - item.is_reconcilable = request.json_body['isReconcilable'] - item.is_starred = request.json_body['isStarred'] - item.cost_centre_id = uuid.UUID(request.json_body['costCentre']['id']) + item.name = request.json_body["name"] + item.is_active = request.json_body["isActive"] + item.is_reconcilable = request.json_body["isReconcilable"] + item.is_starred = request.json_body["isStarred"] + item.cost_centre_id = uuid.UUID(request.json_body["costCentre"]["id"]) transaction.commit() return account_info(item.id, request.dbsession) -@view_config(request_method='DELETE', route_name='api_account_id', renderer='json', permission='Accounts') +@view_config( + request_method="DELETE", + route_name="api_account_id", + renderer="json", + permission="Accounts", +) def delete(request): - account = request.dbsession.query(Account).filter(Account.id == uuid.UUID(request.matchdict['id'])).first() - can_delete, reason = account.can_delete(request.has_permission('Advanced Delete')) + account = ( + request.dbsession.query(Account) + .filter(Account.id == uuid.UUID(request.matchdict["id"])) + .first() + ) + can_delete, reason = account.can_delete(request.has_permission("Advanced Delete")) if can_delete: delete_with_data(account, request.dbsession) transaction.commit() @@ -71,13 +98,25 @@ def delete(request): return response -@view_config(request_method='GET', route_name='api_account_id', renderer='json', request_param='b', - permission='Authenticated') +@view_config( + request_method="GET", + route_name="api_account_id", + renderer="json", + request_param="b", + permission="Authenticated", +) def show_balance(request): - date = request.GET.get('d', None) - date = None if date is None or date == '' else datetime.datetime.strptime(date, '%d-%b-%Y') - id = uuid.UUID(request.matchdict['id']) - return {'date': balance(id, date, request.dbsession), 'total': balance(id, None, request.dbsession)} + date = request.GET.get("d", None) + date = ( + None + if date is None or date == "" + else datetime.datetime.strptime(date, "%d-%b-%Y") + ) + id = uuid.UUID(request.matchdict["id"]) + return { + "date": balance(id, date, request.dbsession), + "total": balance(id, None, request.dbsession), + } def balance(id_, date, dbsession): @@ -85,94 +124,153 @@ def balance(id_, date, dbsession): if not account.type_object.balance_sheet: return 0 - bal = dbsession.query(func.sum(Journal.amount * Journal.debit)).join(Journal.voucher) + bal = dbsession.query(func.sum(Journal.amount * Journal.debit)).join( + Journal.voucher + ) if date is not None: bal = bal.filter(Voucher.date <= date) - bal = bal.filter(Voucher.type != VoucherType.by_name('Issue').id) \ - .filter(Journal.account_id == id_) \ + bal = ( + bal.filter(Voucher.type != VoucherType.by_name("Issue").id) + .filter(Journal.account_id == id_) .scalar() + ) return 0 if bal is None else bal -@view_config(request_method='GET', route_name='api_account_id', renderer='json', permission='Accounts') +@view_config( + request_method="GET", + route_name="api_account_id", + renderer="json", + permission="Accounts", +) def show_id(request): - return account_info(uuid.UUID(request.matchdict.get('id', None)), request.dbsession) + return account_info(uuid.UUID(request.matchdict.get("id", None)), request.dbsession) -@view_config(request_method='GET', route_name='api_account', renderer='json', permission='Accounts') +@view_config( + request_method="GET", + route_name="api_account", + renderer="json", + permission="Accounts", +) def show_blank(request): return account_info(None, request.dbsession) -@view_config(request_method='GET', route_name='api_account', renderer='json', request_param='l', - permission='Authenticated') +@view_config( + request_method="GET", + route_name="api_account", + renderer="json", + request_param="l", + permission="Authenticated", +) def show_list(request): - list = request.dbsession.query(Account).order_by(Account.type).order_by(Account.name).order_by(Account.code).all() + list = ( + request.dbsession.query(Account) + .order_by(Account.type) + .order_by(Account.name) + .order_by(Account.code) + .all() + ) accounts = [] for item in list: accounts.append( { - 'id': item.id, 'name': item.name, 'type': item.type_object.name, 'isActive': item.is_active, - 'isReconcilable': item.is_reconcilable, 'isStarred': item.is_starred, - 'costCentre': item.cost_centre.name, 'isFixture': item.is_fixture + "id": item.id, + "name": item.name, + "type": item.type_object.name, + "isActive": item.is_active, + "isReconcilable": item.is_reconcilable, + "isStarred": item.is_starred, + "costCentre": item.cost_centre.name, + "isFixture": item.is_fixture, } ) return accounts -@view_config(request_method='GET', route_name='api_account', renderer='json', request_param='q', - permission='Authenticated') +@view_config( + request_method="GET", + route_name="api_account", + renderer="json", + request_param="q", + permission="Authenticated", +) def show_term(request): - type = request.GET.get('t', None) + type = request.GET.get("t", None) type = int(type) if type is not None else None - filter = request.GET.get('q', None) - filter = filter if filter is not None and filter is not '' else None - reconcilable = request.GET.get('r', None) + filter = request.GET.get("q", None) + filter = filter if filter is not None and filter is not "" else None + reconcilable = request.GET.get("r", None) reconcilable = reconcilable if reconcilable is not None else None - active = request.GET.get('a', None) + active = request.GET.get("a", None) active = active if active is not None else None - count = request.GET.get('c', None) - count = None if count is None or count == '' else int(count) + count = request.GET.get("c", None) + count = None if count is None or count == "" else int(count) list = [] - for index, item in enumerate(AccountBase.list(type, filter, reconcilable, active, request.dbsession)): - list.append({'id': item.id, 'name': item.name}) + for index, item in enumerate( + AccountBase.list(type, filter, reconcilable, active, request.dbsession) + ): + list.append({"id": item.id, "name": item.name}) if count is not None and index == count - 1: break return list -@view_config(request_method='GET', route_name='api_account_type_list', renderer='json', permission='Authenticated') +@view_config( + request_method="GET", + route_name="api_account_type_list", + renderer="json", + permission="Authenticated", +) def account_type_list(request): account_types = [] for item in AccountType.list(): - account_types.append({'id': item.id, 'name': item.name}) + account_types.append({"id": item.id, "name": item.name}) return account_types def account_info(id, dbsession): if id is None: account = { - 'code': '(Auto)', 'type': AccountType.by_name('Creditors').id, 'isActive': True, - 'isReconcilable': False, 'isStarred': False, 'costCentre': CostCentre.overall() + "code": "(Auto)", + "type": AccountType.by_name("Creditors").id, + "isActive": True, + "isReconcilable": False, + "isStarred": False, + "costCentre": CostCentre.overall(), } else: account = dbsession.query(Account).filter(Account.id == id).first() account = { - 'id': account.id, 'code': account.code, 'name': account.name, 'type': account.type, - 'isActive': account.is_active, 'isReconcilable': account.is_reconcilable, 'isStarred': account.is_starred, - 'isFixture': account.is_fixture, - 'costCentre': {'id': account.cost_centre_id, 'name': account.cost_centre.name} + "id": account.id, + "code": account.code, + "name": account.name, + "type": account.type, + "isActive": account.is_active, + "isReconcilable": account.is_reconcilable, + "isStarred": account.is_starred, + "isFixture": account.is_fixture, + "costCentre": { + "id": account.cost_centre_id, + "name": account.cost_centre.name, + }, } return account def delete_with_data(account, dbsession): - suspense_account = dbsession.query(Account).filter(Account.id == Account.suspense()).first() - query = dbsession.query(Voucher).options(joinedload_all(Voucher.journals, Journal.account, innerjoin=True)) \ - .filter(Voucher.journals.any(Journal.account_id == account.id)) \ + suspense_account = ( + dbsession.query(Account).filter(Account.id == Account.suspense()).first() + ) + query = ( + dbsession.query(Voucher) + .options(joinedload_all(Voucher.journals, Journal.account, innerjoin=True)) + .filter(Voucher.journals.any(Journal.account_id == account.id)) .all() + ) for voucher in query: others, sus_jnl, acc_jnl = False, None, None @@ -188,17 +286,25 @@ def delete_with_data(account, dbsession): else: if sus_jnl is None: acc_jnl.account = suspense_account - voucher.narration += '\nSuspense \u20B9{0:,.2f} is {1}'.format(acc_jnl.amount, account.name) + voucher.narration += "\nSuspense \u20B9{0:,.2f} is {1}".format( + acc_jnl.amount, account.name + ) else: - amount = (sus_jnl.debit * sus_jnl.amount) + (acc_jnl.debit * acc_jnl.amount) + amount = (sus_jnl.debit * sus_jnl.amount) + ( + acc_jnl.debit * acc_jnl.amount + ) dbsession.delete(acc_jnl) if amount == 0: dbsession.delete(sus_jnl) else: sus_jnl.amount = abs(amount) sus_jnl.debit = -1 if amount < 0 else 1 - voucher.narration += '\nDeleted \u20B9{0:,.2f} of {1}'.format(acc_jnl.amount * acc_jnl.debit, - account.name) - if voucher.type in (VoucherType.by_name('Payment').id, VoucherType.by_name('Receipt').id): - voucher.type = VoucherType.by_name('Journal') + voucher.narration += "\nDeleted \u20B9{0:,.2f} of {1}".format( + acc_jnl.amount * acc_jnl.debit, account.name + ) + if voucher.type in ( + VoucherType.by_name("Payment").id, + VoucherType.by_name("Receipt").id, + ): + voucher.type = VoucherType.by_name("Journal") dbsession.delete(account) diff --git a/brewman/views/attendance.py b/brewman/views/attendance.py index f340fdf6..ea42a66b 100644 --- a/brewman/views/attendance.py +++ b/brewman/views/attendance.py @@ -11,147 +11,250 @@ from brewman.models.master import AttendanceType, Employee from brewman.models.validation_exception import ValidationError from brewman.models.voucher import Attendance from brewman.views.fingerprint import get_prints -from brewman.views.services.session import session_period_start, session_period_finish, session_current_date +from brewman.views.services.session import ( + session_period_start, + session_period_finish, + session_current_date, +) -@view_config(request_method='GET', route_name='attendance_date', permission='Attendance') -@view_config(request_method='GET', route_name='attendance', permission='Attendance') -@view_config(request_method='GET', route_name='employee_attendance_id', permission='Attendance') -@view_config(request_method='GET', route_name='employee_attendance', permission='Attendance') +@view_config( + request_method="GET", route_name="attendance_date", permission="Attendance" +) +@view_config(request_method="GET", route_name="attendance", permission="Attendance") +@view_config( + request_method="GET", route_name="employee_attendance_id", permission="Attendance" +) +@view_config( + request_method="GET", route_name="employee_attendance", permission="Attendance" +) def html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='GET', route_name='api_attendance_types', renderer='json', permission='Authenticated') +@view_config( + request_method="GET", + route_name="api_attendance_types", + renderer="json", + permission="Authenticated", +) def show_list(request): list = AttendanceType.list() attendance_types = [] for item in list: - attendance_types.append({'id': item.id, 'name': item.name, 'value': item.value}) + attendance_types.append({"id": item.id, "name": item.name, "value": item.value}) return attendance_types -@view_config(request_method='GET', route_name='api_attendance', renderer='json', permission='Attendance') +@view_config( + request_method="GET", + route_name="api_attendance", + renderer="json", + permission="Attendance", +) def attendance_blank(request): - return {'date': session_current_date(request), 'body': []} + return {"date": session_current_date(request), "body": []} -@view_config(request_method='GET', route_name='api_attendance_date', renderer='json', permission='Attendance') +@view_config( + request_method="GET", + route_name="api_attendance_date", + renderer="json", + permission="Attendance", +) def attendance_date(request): - date = request.matchdict.get('date', None) + date = request.matchdict.get("date", None) return attendance_date_report(date, request.dbsession) def attendance_date_report(date, dbsession): - report = {'date': date, 'body': []} - date = datetime.datetime.strptime(date, '%d-%b-%Y') - employees = dbsession.query(Employee) \ - .filter(Employee.joining_date <= date) \ - .filter(or_(Employee.is_active, Employee.leaving_date >= date)) \ - .order_by(Employee.cost_centre_id).order_by(Employee.designation).order_by(Employee.name).all() + report = {"date": date, "body": []} + date = datetime.datetime.strptime(date, "%d-%b-%Y") + employees = ( + dbsession.query(Employee) + .filter(Employee.joining_date <= date) + .filter(or_(Employee.is_active, Employee.leaving_date >= date)) + .order_by(Employee.cost_centre_id) + .order_by(Employee.designation) + .order_by(Employee.name) + .all() + ) for item in employees: - att = dbsession.query(Attendance).filter(Attendance.employee_id == item.id).filter( - Attendance.date == date).filter(Attendance.is_valid == True).first() + att = ( + dbsession.query(Attendance) + .filter(Attendance.employee_id == item.id) + .filter(Attendance.date == date) + .filter(Attendance.is_valid == True) + .first() + ) att = 0 if att is None else att.attendance_type prints, hours, worked = get_prints(item.id, date, dbsession) - report['body'].append({ - 'id': item.id, 'code': item.code, 'name': item.name, 'designation': item.designation, - 'department': item.cost_centre.name, 'attendanceType': {'id': att}, 'prints': prints, - 'hours': hours, 'worked': worked - }) + report["body"].append( + { + "id": item.id, + "code": item.code, + "name": item.name, + "designation": item.designation, + "department": item.cost_centre.name, + "attendanceType": {"id": att}, + "prints": prints, + "hours": hours, + "worked": worked, + } + ) return report -@view_config(request_method='POST', route_name='api_attendance_date', renderer='json', permission='Attendance', - trans=True) +@view_config( + request_method="POST", + route_name="api_attendance_date", + renderer="json", + permission="Attendance", + trans=True, +) def save(request): user_id = uuid.UUID(request.authenticated_userid) - date = request.matchdict.get('date', None) - date_object = datetime.datetime.strptime(date, '%d-%b-%Y') + date = request.matchdict.get("date", None) + date_object = datetime.datetime.strptime(date, "%d-%b-%Y") - for item in request.json_body['body']: - employee_id = uuid.UUID(item['id']) - attendance_type = item['attendanceType']['id'] + for item in request.json_body["body"]: + employee_id = uuid.UUID(item["id"]) + attendance_type = item["attendanceType"]["id"] if attendance_type != 0: attendance = Attendance( - employee_id=employee_id, date=date_object, attendance_type=attendance_type, user_id=user_id + employee_id=employee_id, + date=date_object, + attendance_type=attendance_type, + user_id=user_id, ) attendance.create(request.dbsession) transaction.commit() return attendance_date_report(date, request.dbsession) -@view_config(request_method='GET', route_name='api_employee_attendance', renderer='json', permission='Attendance') +@view_config( + request_method="GET", + route_name="api_employee_attendance", + renderer="json", + permission="Attendance", +) def employee_attendance_blank(request): - return {'startDate': session_period_start(request), - 'finishDate': session_period_finish(request), 'employee': None, 'body': []} - - -@view_config(request_method='GET', route_name='api_employee_attendance_id', renderer='json', permission='Attendance') -def employee_attendance_report(request): - employee = request.dbsession.query(Employee).filter(Employee.id == uuid.UUID(request.matchdict['id'])).first() - if employee is None: - raise ValidationError('Employee id is wrong') - start_date = request.GET.get('s', session_period_start(request)) - finish_date = request.GET.get('f', session_period_finish(request)) - info = { - 'startDate': start_date, 'finishDate': finish_date, - 'employee': {'id': employee.id, 'name': employee.name} + return { + "startDate": session_period_start(request), + "finishDate": session_period_finish(request), + "employee": None, + "body": [], } - start_date = datetime.datetime.strptime(start_date, '%d-%b-%Y') - finish_date = datetime.datetime.strptime(finish_date, '%d-%b-%Y') - start_date = employee.joining_date if employee.joining_date > start_date else start_date - finish_date = employee.leaving_date if not employee.is_active and employee.leaving_date < finish_date else finish_date - info['body'] = employee_attendance(employee, start_date, finish_date, request.dbsession) + + +@view_config( + request_method="GET", + route_name="api_employee_attendance_id", + renderer="json", + permission="Attendance", +) +def employee_attendance_report(request): + employee = ( + request.dbsession.query(Employee) + .filter(Employee.id == uuid.UUID(request.matchdict["id"])) + .first() + ) + if employee is None: + raise ValidationError("Employee id is wrong") + start_date = request.GET.get("s", session_period_start(request)) + finish_date = request.GET.get("f", session_period_finish(request)) + info = { + "startDate": start_date, + "finishDate": finish_date, + "employee": {"id": employee.id, "name": employee.name}, + } + start_date = datetime.datetime.strptime(start_date, "%d-%b-%Y") + finish_date = datetime.datetime.strptime(finish_date, "%d-%b-%Y") + start_date = ( + employee.joining_date if employee.joining_date > start_date else start_date + ) + finish_date = ( + employee.leaving_date + if not employee.is_active and employee.leaving_date < finish_date + else finish_date + ) + info["body"] = employee_attendance( + employee, start_date, finish_date, request.dbsession + ) return info def employee_attendance(employee, start_date, finish_date, dbsession): if not isinstance(start_date, datetime.datetime): - start_date = datetime.datetime.strptime(start_date, '%d-%b-%Y') + start_date = datetime.datetime.strptime(start_date, "%d-%b-%Y") if not isinstance(finish_date, datetime.datetime): - finish_date = datetime.datetime.strptime(finish_date, '%d-%b-%Y') + finish_date = datetime.datetime.strptime(finish_date, "%d-%b-%Y") list = [] for item in daterange(start_date, finish_date, inclusive=True): - att = dbsession.query(Attendance) \ - .filter(Attendance.employee_id == employee.id) \ - .filter(Attendance.date == item) \ - .filter(Attendance.is_valid == True) \ + att = ( + dbsession.query(Attendance) + .filter(Attendance.employee_id == employee.id) + .filter(Attendance.date == item) + .filter(Attendance.is_valid == True) .first() + ) att = 0 if att is None else att.attendance_type prints, hours, worked = get_prints(employee.id, item, dbsession) - list.append({ - 'date': item.strftime('%d-%b-%Y'), 'attendanceType': {'id': att}, 'prints': prints, 'hours': hours, - 'worked': worked - }) + list.append( + { + "date": item.strftime("%d-%b-%Y"), + "attendanceType": {"id": att}, + "prints": prints, + "hours": hours, + "worked": worked, + } + ) return list -@view_config(request_method='POST', route_name='api_employee_attendance_id', renderer='json', permission='Attendance', - trans=True) +@view_config( + request_method="POST", + route_name="api_employee_attendance_id", + renderer="json", + permission="Attendance", + trans=True, +) def save_employee_attendance(request): start_date = None finish_date = None user_id = uuid.UUID(request.authenticated_userid) - employee = request.dbsession.query(Employee).filter(Employee.id == uuid.UUID(request.matchdict['id'])).first() - for item in request.json_body['body']: + employee = ( + request.dbsession.query(Employee) + .filter(Employee.id == uuid.UUID(request.matchdict["id"])) + .first() + ) + for item in request.json_body["body"]: if start_date is None: - start_date = item['date'] - finish_date = item['date'] + start_date = item["date"] + finish_date = item["date"] - attendance_type = item['attendanceType']['id'] + attendance_type = item["attendanceType"]["id"] if attendance_type != 0: - date = datetime.datetime.strptime(item['date'], '%d-%b-%Y') - attendance = Attendance(employee_id=employee.id, date=date, attendance_type=attendance_type, - user_id=user_id) + date = datetime.datetime.strptime(item["date"], "%d-%b-%Y") + attendance = Attendance( + employee_id=employee.id, + date=date, + attendance_type=attendance_type, + user_id=user_id, + ) attendance.create(request.dbsession) transaction.commit() - return {'startDate': start_date, 'finishDate': finish_date, - 'employee': {'id': employee.id, 'name': employee.name}, - 'body': employee_attendance(employee, start_date, finish_date, request.dbsession)} + return { + "startDate": start_date, + "finishDate": finish_date, + "employee": {"id": employee.id, "name": employee.name}, + "body": employee_attendance( + employee, start_date, finish_date, request.dbsession + ), + } def daterange(start, stop, step=datetime.timedelta(days=1), inclusive=False): diff --git a/brewman/views/attendance_report.py b/brewman/views/attendance_report.py index 83c0bf0a..ed872449 100644 --- a/brewman/views/attendance_report.py +++ b/brewman/views/attendance_report.py @@ -7,37 +7,50 @@ from .attendance import daterange from .services.session import session_period_start, session_period_finish -@view_config(route_name='attendance_report', renderer='csv', permission='Attendance') +@view_config(route_name="attendance_report", renderer="csv", permission="Attendance") def get_report(request): - start_date = request.GET.get('StartDate', session_period_start(request)) - finish_date = request.GET.get('FinishDate', session_period_finish(request)) - start_date = datetime.datetime.strptime(start_date, '%d-%b-%Y') - finish_date = datetime.datetime.strptime(finish_date, '%d-%b-%Y') + start_date = request.GET.get("StartDate", session_period_start(request)) + finish_date = request.GET.get("FinishDate", session_period_finish(request)) + start_date = datetime.datetime.strptime(start_date, "%d-%b-%Y") + finish_date = datetime.datetime.strptime(finish_date, "%d-%b-%Y") header, report = attendance_record(start_date, finish_date, request.dbsession) - return {'header': header, 'rows': report, 'filename': 'Attendance Record.csv'} + return {"header": header, "rows": report, "filename": "Attendance Record.csv"} def attendance_record(start_date, finish_date, dbsession): report = [] header = ["Code", "Name", "Designation", "Department", "Salary", "SC Points"] for date in daterange(start_date, finish_date, inclusive=True): - header.append(date.strftime('%d-%b')) + header.append(date.strftime("%d-%b")) not_set = AttendanceType.by_id(0) - employees = dbsession.query(Employee) \ - .filter(Employee.joining_date <= finish_date) \ - .filter(or_(Employee.is_active, Employee.leaving_date >= start_date)) \ - .order_by(Employee.cost_centre_id).order_by(Employee.designation).order_by(Employee.name).all() + employees = ( + dbsession.query(Employee) + .filter(Employee.joining_date <= finish_date) + .filter(or_(Employee.is_active, Employee.leaving_date >= start_date)) + .order_by(Employee.cost_centre_id) + .order_by(Employee.designation) + .order_by(Employee.name) + .all() + ) for employee in employees: - row_display = [employee.code, employee.name, employee.designation, employee.cost_centre.name, employee.salary, - employee.service_points] - row_value = ['', '', '', '', employee.salary, employee.service_points] + row_display = [ + employee.code, + employee.name, + employee.designation, + employee.cost_centre.name, + employee.salary, + employee.service_points, + ] + row_value = ["", "", "", "", employee.salary, employee.service_points] for date in daterange(start_date, finish_date, inclusive=True): - att = dbsession.query(Attendance) \ - .filter(Attendance.employee_id == employee.id) \ - .filter(Attendance.date == date) \ - .filter(Attendance.is_valid == True) \ + att = ( + dbsession.query(Attendance) + .filter(Attendance.employee_id == employee.id) + .filter(Attendance.date == date) + .filter(Attendance.is_valid == True) .first() + ) att = not_set if att is None else AttendanceType.by_id(att.attendance_type) row_display.append(att.name) row_value.append(att.value) diff --git a/brewman/views/auth/client.py b/brewman/views/auth/client.py index 173d1af3..3538af9d 100644 --- a/brewman/views/auth/client.py +++ b/brewman/views/auth/client.py @@ -9,55 +9,110 @@ import transaction from brewman.models.auth import Client, LoginHistory -@view_config(request_method='GET', route_name='client_list', permission='Clients') -@view_config(request_method='GET', route_name='client_id', permission='Clients') +@view_config(request_method="GET", route_name="client_list", permission="Clients") +@view_config(request_method="GET", route_name="client_id", permission="Clients") def html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='PUT', route_name='api_client_id', renderer='json', permission='Clients', trans=True) +@view_config( + request_method="PUT", + route_name="api_client_id", + renderer="json", + permission="Clients", + trans=True, +) def update(request): - item = request.dbsession.query(Client).filter(Client.id == uuid.UUID(request.matchdict['id'])).first() - item.enabled = request.json_body['enabled'] + item = ( + request.dbsession.query(Client) + .filter(Client.id == uuid.UUID(request.matchdict["id"])) + .first() + ) + item.enabled = request.json_body["enabled"] if item.enabled: item.otp = None - item.name = request.json_body['name'] + item.name = request.json_body["name"] transaction.commit() return {} -@view_config(request_method='DELETE', route_name='api_client_id', renderer='json', permission='Clients', trans=True) +@view_config( + request_method="DELETE", + route_name="api_client_id", + renderer="json", + permission="Clients", + trans=True, +) def delete(request): - id = request.matchdict.get('id', None) + id = request.matchdict.get("id", None) if id is None: response = Response("Client not found") response.status_int = 500 return response client = request.dbsession.query(Client).filter(Client.id == uuid.UUID(id)).first() - request.dbsession.execute(LoginHistory.__table__.delete(LoginHistory.client_id == client.id)) + request.dbsession.execute( + LoginHistory.__table__.delete(LoginHistory.client_id == client.id) + ) request.dbsession.delete(client) transaction.commit() return {} -@view_config(request_method='GET', route_name='api_client', request_param='l', renderer='json', permission='Clients') +@view_config( + request_method="GET", + route_name="api_client", + request_param="l", + renderer="json", + permission="Clients", +) def show_list(request): list = request.dbsession.query(Client).order_by(Client.name).all() clients = [] for item in list: - last_login = request.dbsession.query(LoginHistory) \ - .filter(LoginHistory.client_id == item.id).order_by(desc(LoginHistory.date)).first() - last_login = 'Never' if last_login is None else last_login.date.strftime('%d-%b-%Y %H:%M') + last_login = ( + request.dbsession.query(LoginHistory) + .filter(LoginHistory.client_id == item.id) + .order_by(desc(LoginHistory.date)) + .first() + ) + last_login = ( + "Never" + if last_login is None + else last_login.date.strftime("%d-%b-%Y %H:%M") + ) clients.append( - {'id': item.id, 'code': item.code, 'name': item.name, 'enabled': item.enabled, 'otp': item.otp, - 'creationDate': item.creation_date.strftime('%d-%b-%Y %H:%M'), 'lastLogin': last_login}) + { + "id": item.id, + "code": item.code, + "name": item.name, + "enabled": item.enabled, + "otp": item.otp, + "creationDate": item.creation_date.strftime("%d-%b-%Y %H:%M"), + "lastLogin": last_login, + } + ) return clients -@view_config(request_method='GET', route_name='api_client_id', renderer='json', permission='Clients') +@view_config( + request_method="GET", + route_name="api_client_id", + renderer="json", + permission="Clients", +) def show_id(request): - item = request.dbsession.query(Client).filter(Client.id == uuid.UUID(request.matchdict['id'])).first() - return {'id': item.id, 'code': item.code, 'name': item.name, 'enabled': item.enabled, 'otp': item.otp} + item = ( + request.dbsession.query(Client) + .filter(Client.id == uuid.UUID(request.matchdict["id"])) + .first() + ) + return { + "id": item.id, + "code": item.code, + "name": item.name, + "enabled": item.enabled, + "otp": item.otp, + } diff --git a/brewman/views/auth/group.py b/brewman/views/auth/group.py index 8825e4f7..40a185d0 100644 --- a/brewman/views/auth/group.py +++ b/brewman/views/auth/group.py @@ -8,48 +8,65 @@ from pyramid.view import view_config from brewman.models.auth import Group, Role -@view_config(route_name='group_list', permission='Users') -@view_config(request_method='GET', route_name='group_id', permission='Users') -@view_config(request_method='GET', route_name='group', permission='Users') +@view_config(route_name="group_list", permission="Users") +@view_config(request_method="GET", route_name="group_id", permission="Users") +@view_config(request_method="GET", route_name="group", permission="Users") def html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='POST', route_name='api_group', renderer='json', permission='Users', trans=True) +@view_config( + request_method="POST", + route_name="api_group", + renderer="json", + permission="Users", + trans=True, +) def save(request): - group = Group(request.json_body['name']) + group = Group(request.json_body["name"]) request.dbsession.add(group) - add_permissions(group, request.json_body['permissions'], request.dbsession) + add_permissions(group, request.json_body["permissions"], request.dbsession) transaction.commit() return group_info(group.id, request.dbsession) -@view_config(request_method='PUT', route_name='api_group_id', renderer='json', permission='Users', trans=True) +@view_config( + request_method="PUT", + route_name="api_group_id", + renderer="json", + permission="Users", + trans=True, +) def update(request): - id = request.matchdict.get('id', None) + id = request.matchdict.get("id", None) group = request.dbsession.query(Group).filter(Group.id == uuid.UUID(id)).one() - group.name = request.json_body['name'] - add_permissions(group, request.json_body['permissions'], request.dbsession) + group.name = request.json_body["name"] + add_permissions(group, request.json_body["permissions"], request.dbsession) transaction.commit() return group_info(group.id, request.dbsession) def add_permissions(group, permissions, dbsession): for permission in permissions: - id = uuid.UUID(permission['id']) + id = uuid.UUID(permission["id"]) gp = [p for p in group.roles if p.id == id] gp = None if len(gp) == 0 else gp[0] - if permission['enabled'] and gp is None: + if permission["enabled"] and gp is None: group.roles.append(dbsession.query(Role).filter(Role.id == id).one()) - elif not permission['enabled'] and gp: + elif not permission["enabled"] and gp: group.roles.remove(gp) -@view_config(request_method='DELETE', route_name='api_group_id', renderer='json', permission='Users') +@view_config( + request_method="DELETE", + route_name="api_group_id", + renderer="json", + permission="Users", +) def delete(request): - id = request.matchdict.get('id', None) + id = request.matchdict.get("id", None) if id is None: response = Response("Group is Null") response.status_int = 500 @@ -60,41 +77,55 @@ def delete(request): return response -@view_config(request_method='GET', route_name='api_group_id', renderer='json', permission='Users') +@view_config( + request_method="GET", route_name="api_group_id", renderer="json", permission="Users" +) def show_id(request): - return group_info(uuid.UUID(request.matchdict.get('id', None)), request.dbsession) + return group_info(uuid.UUID(request.matchdict.get("id", None)), request.dbsession) -@view_config(request_method='GET', route_name='api_group', renderer='json', permission='Users') +@view_config( + request_method="GET", route_name="api_group", renderer="json", permission="Users" +) def show_blank(request): return group_info(None, request.dbsession) -@view_config(request_method='GET', route_name='api_group', renderer='json', request_param='l', permission='Users') +@view_config( + request_method="GET", + route_name="api_group", + renderer="json", + request_param="l", + permission="Users", +) def show_list(request): list = request.dbsession.query(Group).order_by(Group.name).all() groups = [] for item in list: - group = {'id':item.id ,'name': item.name, 'permissions': []} + group = {"id": item.id, "name": item.name, "permissions": []} for permission in sorted(item.roles, key=lambda p: p.name): - group['permissions'].append(permission.name) + group["permissions"].append(permission.name) groups.append(group) return groups def group_info(id, dbsession): if id is None: - group = {'name': '', 'permissions': []} + group = {"name": "", "permissions": []} for item in dbsession.query(Role).order_by(Role.name).all(): - group['permissions'].append({'id': item.id, 'name': item.name, 'enabled': False}) + group["permissions"].append( + {"id": item.id, "name": item.name, "enabled": False} + ) else: group_object = dbsession.query(Group).filter(Group.id == id).one() - group = {'id': group_object.id, 'name': group_object.name, 'permissions': []} + group = {"id": group_object.id, "name": group_object.name, "permissions": []} for item in dbsession.query(Role).order_by(Role.name).all(): - group['permissions'].append({ - 'id': item.id, - 'name': item.name, - 'enabled': True if item in group_object.roles else False - }) + group["permissions"].append( + { + "id": item.id, + "name": item.name, + "enabled": True if item in group_object.roles else False, + } + ) return group diff --git a/brewman/views/auth/user.py b/brewman/views/auth/user.py index 37a62cd6..0ca30962 100644 --- a/brewman/views/auth/user.py +++ b/brewman/views/auth/user.py @@ -16,56 +16,90 @@ class UserView(object): self.user = request.authenticated_userid self.permissions = None if self.user is not None: - self.user = request.dbsession.query(User).filter(User.id == request.authenticated_userid).one() + self.user = ( + request.dbsession.query(User) + .filter(User.id == request.authenticated_userid) + .one() + ) - @view_config(route_name='user_list', permission='Users') - @view_config(request_method='GET', route_name='user_id', permission='Authenticated') - @view_config(request_method='GET', route_name='user', permission='Users') + @view_config(route_name="user_list", permission="Users") + @view_config(request_method="GET", route_name="user_id", permission="Authenticated") + @view_config(request_method="GET", route_name="user", permission="Users") def html(self): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=self.request) - @view_config(request_method='POST', route_name='api_user', renderer='json', permission='Users', trans=True) + @view_config( + request_method="POST", + route_name="api_user", + renderer="json", + permission="Users", + trans=True, + ) def save(self): return self.save_user() def save_user(self): - user = User(self.request.json_body['name'], self.request.json_body['password'], - self.request.json_body['lockedOut']) + user = User( + self.request.json_body["name"], + self.request.json_body["password"], + self.request.json_body["lockedOut"], + ) self.request.dbsession.add(user) - self.add_groups(user, self.request.json_body['groups']) + self.add_groups(user, self.request.json_body["groups"]) transaction.commit() return self.user_info(user.id) - @view_config(request_method='PUT', route_name='api_user_id', renderer='json', permission='Authenticated', - trans=True) + @view_config( + request_method="PUT", + route_name="api_user_id", + renderer="json", + permission="Authenticated", + trans=True, + ) def update(self): - id = self.request.matchdict['id'] - p = re.compile('^[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}$') + id = self.request.matchdict["id"] + p = re.compile( + "^[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}$" + ) if p.match(id): - user = self.request.dbsession.query(User).filter(User.id == uuid.UUID(id)).one() + user = ( + self.request.dbsession.query(User) + .filter(User.id == uuid.UUID(id)) + .one() + ) else: - user = self.request.dbsession.query(User).filter(User.name.ilike(id)).first() + user = ( + self.request.dbsession.query(User).filter(User.name.ilike(id)).first() + ) return self.update_user(user) def update_user(self, user): if user is None: - raise ValidationError('User name / id not found') - if self.request.has_permission('Users'): - user.name = self.request.json_body['name'] - user.locked_out = self.request.json_body['lockedOut'] - self.add_groups(user, self.request.json_body['groups']) + raise ValidationError("User name / id not found") + if self.request.has_permission("Users"): + user.name = self.request.json_body["name"] + user.locked_out = self.request.json_body["lockedOut"] + self.add_groups(user, self.request.json_body["groups"]) - if self.request.json_body['password'] != '' and self.request.json_body['password'] != user.password: - user.password = self.request.json_body['password'] + if ( + self.request.json_body["password"] != "" + and self.request.json_body["password"] != user.password + ): + user.password = self.request.json_body["password"] transaction.commit() return self.user_info(user.id) - @view_config(request_method='DELETE', route_name='api_user_id', renderer='json', permission='Users') + @view_config( + request_method="DELETE", + route_name="api_user_id", + renderer="json", + permission="Users", + ) def delete(self): - id = self.request.matchdict.get('id', None) - if id is None: + id_ = self.request.matchdict.get("id", None) + if id_ is None: response = Response("User is Null") response.status_int = 500 return response @@ -74,53 +108,103 @@ class UserView(object): response.status_int = 500 return response - @view_config(request_method='GET', route_name='api_user_id', renderer='json', permission='Authenticated') + @view_config( + request_method="GET", + route_name="api_user_id", + renderer="json", + permission="Authenticated", + ) def show_id(self): - id = self.request.matchdict['id'] - p = re.compile('^[A-Za-z0-9]{8}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{12}$') + id = self.request.matchdict["id"] + p = re.compile( + "^[A-Za-z0-9]{8}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{12}$" + ) if p.match(id): id = uuid.UUID(id) return self.user_info(id) - @view_config(request_method='GET', route_name='api_user', renderer='json', permission='Users') + @view_config( + request_method="GET", route_name="api_user", renderer="json", permission="Users" + ) def show_blank(self): return self.user_info(None) - @view_config(request_method='GET', route_name='api_user', renderer='json', request_param='l', permission='Users') + @view_config( + request_method="GET", + route_name="api_user", + renderer="json", + request_param="l", + permission="Users", + ) def show_list(self): list = self.request.dbsession.query(User).order_by(User.name).all() users = [] for item in list: - user = {'name': item.name, 'lockedOut': item.locked_out, 'groups': [g.name for g in item.groups]} + user = { + "name": item.name, + "lockedOut": item.locked_out, + "groups": [g.name for g in item.groups], + } users.append(user) return users - @view_config(request_method='GET', route_name='api_user', renderer='json', request_param='n', - permission='Authenticated') + @view_config( + request_method="GET", + route_name="api_user", + renderer="json", + request_param="n", + permission="Authenticated", + ) def show_name(self): - list = self.request.dbsession.query(User).filter(User.locked_out == False).order_by(User.name).all() - users = [{'name': item.name} for item in list] + list = ( + self.request.dbsession.query(User) + .filter(User.locked_out == False) + .order_by(User.name) + .all() + ) + users = [{"name": item.name} for item in list] return users def user_info(self, id): if id is None: - account = {'name': '', 'lockedOut': False, 'lockedOut': False, 'groups': []} + account = {"name": "", "lockedOut": False, "lockedOut": False, "groups": []} for item in self.request.dbsession.query(Group).order_by(Group.name).all(): - account['groups'].append({'id': item.id, 'name': item.name, 'enabled': False}) + account["groups"].append( + {"id": item.id, "name": item.name, "enabled": False} + ) return account if isinstance(id, uuid.UUID): user = self.request.dbsession.query(User).filter(User.id == id).one() else: - user = self.request.dbsession.query(User).filter(User.name.ilike(id)).first() + user = ( + self.request.dbsession.query(User).filter(User.name.ilike(id)).first() + ) - if self.request.has_permission('Users'): - account = {'id': user.id, 'name': user.name, 'password': '', 'lockedOut': user.locked_out, 'groups': []} + if self.request.has_permission("Users"): + account = { + "id": user.id, + "name": user.name, + "password": "", + "lockedOut": user.locked_out, + "groups": [], + } for item in self.request.dbsession.query(Group).order_by(Group.name).all(): - account['groups'].append( - {'id': item.id, 'name': item.name, 'enabled': True if item in user.groups else False}) + account["groups"].append( + { + "id": item.id, + "name": item.name, + "enabled": True if item in user.groups else False, + } + ) elif self.user.id == user.id: - account = {'id': user.id, 'name': user.name, 'password': '', 'lockedOut': user.locked_out, 'groups': []} + account = { + "id": user.id, + "name": user.name, + "password": "", + "lockedOut": user.locked_out, + "groups": [], + } else: response = Response("User can only update his/her password") response.status_int = 500 @@ -129,11 +213,13 @@ class UserView(object): def add_groups(self, user, groups): for group in groups: - id = uuid.UUID(group['id']) - ug = [g for g in user.groups if g.id == id] + id_ = uuid.UUID(group["id"]) + ug = [g for g in user.groups if g.id == id_] ug = None if len(ug) == 0 else ug[0] - if group['enabled'] and ug is None: - group_object = self.request.dbsession.query(Group).filter(Group.id == id).one() + if group["enabled"] and ug is None: + group_object = ( + self.request.dbsession.query(Group).filter(Group.id == id_).one() + ) user.groups.append(group_object) - elif not group['enabled'] and ug: + elif not group["enabled"] and ug: user.groups.remove(ug) diff --git a/brewman/views/cost_centre.py b/brewman/views/cost_centre.py index 011e92b2..155bfc9a 100644 --- a/brewman/views/cost_centre.py +++ b/brewman/views/cost_centre.py @@ -9,68 +9,116 @@ from brewman.models.master import CostCentre from brewman.models.validation_exception import ValidationError -@view_config(route_name='cost_centre_list', permission='Authenticated') -@view_config(request_method='GET', route_name='cost_centre_id', permission='Cost Centres') -@view_config(request_method='GET', route_name='cost_centre', permission='Cost Centres') +@view_config(route_name="cost_centre_list", permission="Authenticated") +@view_config( + request_method="GET", route_name="cost_centre_id", permission="Cost Centres" +) +@view_config(request_method="GET", route_name="cost_centre", permission="Cost Centres") def html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='POST', route_name='api_cost_centre', renderer='json', permission='Cost Centres', - trans=True) +@view_config( + request_method="POST", + route_name="api_cost_centre", + renderer="json", + permission="Cost Centres", + trans=True, +) def save(request): - item = CostCentre(request.json_body['name']) + item = CostCentre(request.json_body["name"]) request.dbsession.add(item) transaction.commit() return cost_centre_info(item.id, request.dbsession) -@view_config(request_method='PUT', route_name='api_cost_centre_id', renderer='json', permission='Cost Centres', - trans=True) +@view_config( + request_method="PUT", + route_name="api_cost_centre_id", + renderer="json", + permission="Cost Centres", + trans=True, +) def update(request): - item = request.dbsession.query(CostCentre).filter(CostCentre.id == uuid.UUID(request.matchdict['id'])).first() + item = ( + request.dbsession.query(CostCentre) + .filter(CostCentre.id == uuid.UUID(request.matchdict["id"])) + .first() + ) if item.is_fixture: - raise ValidationError("{0} is a fixture and cannot be edited or deleted.".format(item.name)) - item.name = request.json_body['name'] + raise ValidationError( + "{0} is a fixture and cannot be edited or deleted.".format(item.name) + ) + item.name = request.json_body["name"] transaction.commit() return cost_centre_info(item.id, request.dbsession) -@view_config(request_method='DELETE', route_name='api_cost_centre_id', renderer='json', permission='Cost Centres') +@view_config( + request_method="DELETE", + route_name="api_cost_centre_id", + renderer="json", + permission="Cost Centres", +) def delete(request): - item = request.dbsession.query(CostCentre).filter(CostCentre.id == uuid.UUID(request.matchdict['id'])).first() + item = ( + request.dbsession.query(CostCentre) + .filter(CostCentre.id == uuid.UUID(request.matchdict["id"])) + .first() + ) if item is None: response = Response("Cost Centre not found") response.status_int = 500 return response elif item.is_fixture: - raise ValidationError("{0} is a fixture and cannot be edited or deleted.".format(item.name)) + raise ValidationError( + "{0} is a fixture and cannot be edited or deleted.".format(item.name) + ) else: response = Response("Cost Centre deletion not implemented") response.status_int = 500 return response -@view_config(request_method='GET', route_name='api_cost_centre_id', renderer='json', permission='Cost Centres') +@view_config( + request_method="GET", + route_name="api_cost_centre_id", + renderer="json", + permission="Cost Centres", +) def show_id(request): - return cost_centre_info(uuid.UUID(request.matchdict.get('id', None)), request.dbsession) + return cost_centre_info( + uuid.UUID(request.matchdict.get("id", None)), request.dbsession + ) -@view_config(request_method='GET', route_name='api_cost_centre', renderer='json', permission='Cost Centres') +@view_config( + request_method="GET", + route_name="api_cost_centre", + renderer="json", + permission="Cost Centres", +) def show_blank(request): return cost_centre_info(None, request.dbsession) -@view_config(request_method='GET', route_name='api_cost_centre', request_param='l', renderer='json', - permission='Authenticated') +@view_config( + request_method="GET", + route_name="api_cost_centre", + request_param="l", + renderer="json", + permission="Authenticated", +) def show_list(request): list = request.dbsession.query(CostCentre).order_by(CostCentre.name).all() cost_centres = [] for item in list: - cost_centres.append({'id': item.id, 'name': item.name, 'isFixture': item.is_fixture}) + cost_centres.append( + {"id": item.id, "name": item.name, "isFixture": item.is_fixture} + ) return cost_centres @@ -79,4 +127,8 @@ def cost_centre_info(id, dbsession): return {} else: cost_centre = dbsession.query(CostCentre).filter(CostCentre.id == id).first() - return {'id': cost_centre.id, 'name': cost_centre.name, 'isFixture': cost_centre.is_fixture} + return { + "id": cost_centre.id, + "name": cost_centre.name, + "isFixture": cost_centre.is_fixture, + } diff --git a/brewman/views/employee.py b/brewman/views/employee.py index ff0ffb94..0f3cdb04 100644 --- a/brewman/views/employee.py +++ b/brewman/views/employee.py @@ -15,101 +15,139 @@ from brewman.models.voucher import Voucher, Journal, VoucherType from brewman.views import to_uuid -@view_config(route_name='employee_list', permission='Authenticated') -@view_config(request_method='GET', route_name='employee_id', permission='Employees') -@view_config(request_method='GET', route_name='employee', permission='Employees') -@view_config(request_method='GET', route_name='employee_functions', permission='Employees') +@view_config(route_name="employee_list", permission="Authenticated") +@view_config(request_method="GET", route_name="employee_id", permission="Employees") +@view_config(request_method="GET", route_name="employee", permission="Employees") +@view_config( + request_method="GET", route_name="employee_functions", permission="Employees" +) def html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='POST', route_name='api_employee', renderer='json', permission='Employees', trans=True) +@view_config( + request_method="POST", + route_name="api_employee", + renderer="json", + permission="Employees", + trans=True, +) def save(request): - name = request.json_body.get('name', '').strip() - if name == '': - raise ValidationError('Name cannot be blank') + name = request.json_body.get("name", "").strip() + if name == "": + raise ValidationError("Name cannot be blank") - cost_centre_id = uuid.UUID(request.json_body['costCentre']['id']) - designation = request.json_body.get('designation', '').strip() + cost_centre_id = uuid.UUID(request.json_body["costCentre"]["id"]) + designation = request.json_body.get("designation", "").strip() try: - salary = int(request.json_body['salary']) + salary = int(request.json_body["salary"]) if salary < 0: raise ValidationError("Salary must be an integer >= 0") except (ValueError, KeyError): raise ValidationError("Salary must be an integer >= 0") try: - service_points = round(Decimal(request.json_body['points']), 2) + service_points = round(Decimal(request.json_body["points"]), 2) if service_points < 0: raise ValidationError("Points must be a decimal >= 0 and < 1000") except (ValueError, KeyError): raise ValidationError("Points must be a decimal >= 0 and < 1000") try: - joining_date = datetime.datetime.strptime(request.json_body['joiningDate'], '%d-%b-%Y') + joining_date = datetime.datetime.strptime( + request.json_body["joiningDate"], "%d-%b-%Y" + ) except (ValueError, KeyError, TypeError): raise ValidationError("Joining Date is not a valid date") - is_starred = request.json_body['isStarred'] - is_active = request.json_body['isActive'] + is_starred = request.json_body["isStarred"] + is_active = request.json_body["isActive"] try: if is_active: leaving_date = None else: - leaving_date = datetime.datetime.strptime(request.json_body['leavingDate'], '%d-%b-%Y') + leaving_date = datetime.datetime.strptime( + request.json_body["leavingDate"], "%d-%b-%Y" + ) if leaving_date < joining_date: raise ValidationError("Leaving Date cannot be less than Joining Date") except (ValueError, KeyError, TypeError): raise ValidationError("Leaving Date is not a valid date") - item = Employee(0, name, is_starred, is_active, cost_centre_id, designation, salary, service_points, joining_date, - leaving_date).create(request.dbsession) + item = Employee( + 0, + name, + is_starred, + is_active, + cost_centre_id, + designation, + salary, + service_points, + joining_date, + leaving_date, + ).create(request.dbsession) transaction.commit() return employee_info(item.id, request.dbsession) -@view_config(request_method='PUT', route_name='api_employee_id', renderer='json', permission='Employees', trans=True) +@view_config( + request_method="PUT", + route_name="api_employee_id", + renderer="json", + permission="Employees", + trans=True, +) def update(request): - item = request.dbsession.query(Employee).filter(Employee.id == uuid.UUID(request.matchdict['id'])).first() + item = ( + request.dbsession.query(Employee) + .filter(Employee.id == uuid.UUID(request.matchdict["id"])) + .first() + ) if item.is_fixture: - raise ValidationError("{0} is a fixture and cannot be edited or deleted.".format(item.name)) + raise ValidationError( + "{0} is a fixture and cannot be edited or deleted.".format(item.name) + ) - item.name = request.json_body.get('name', '').strip() - if item.name == '': - raise ValidationError('Name cannot be blank') + item.name = request.json_body.get("name", "").strip() + if item.name == "": + raise ValidationError("Name cannot be blank") - item.cost_centre_id = uuid.UUID(request.json_body['costCentre']['id']) - item.designation = request.json_body.get('designation', '').strip() + item.cost_centre_id = uuid.UUID(request.json_body["costCentre"]["id"]) + item.designation = request.json_body.get("designation", "").strip() try: - item.salary = int(request.json_body['salary']) + item.salary = int(request.json_body["salary"]) if item.salary < 0: raise ValidationError("Salary must be an integer >= 0") except (ValueError, KeyError): raise ValidationError("Salary must be an integer >= 0") try: - item.service_points = round(Decimal(request.json_body['points']), 2) + item.service_points = round(Decimal(request.json_body["points"]), 2) if item.service_points < 0: raise ValidationError("Points must be a decimal >= 0") except (ValueError, KeyError): raise ValidationError("Points must be a decimal >= 0") try: - item.joining_date = datetime.datetime.strptime(request.json_body['joiningDate'], '%d-%b-%Y') + item.joining_date = datetime.datetime.strptime( + request.json_body["joiningDate"], "%d-%b-%Y" + ) except (ValueError, KeyError, TypeError): raise ValidationError("Joining Date is not a valid date") - item.is_starred = request.json_body['isStarred'] - item.is_active = request.json_body['isActive'] + item.is_starred = request.json_body["isStarred"] + item.is_active = request.json_body["isActive"] try: if item.is_active: item.leaving_date = None else: - item.leaving_date = datetime.datetime.strptime(request.json_body['leavingDate'], '%d-%b-%Y') + item.leaving_date = datetime.datetime.strptime( + request.json_body["leavingDate"], "%d-%b-%Y" + ) if item.leaving_date < item.joining_date: raise ValidationError("Leaving Date cannot be less than Joining Date") except (ValueError, KeyError, TypeError): @@ -119,10 +157,20 @@ def update(request): return employee_info(item.id, request.dbsession) -@view_config(request_method='DELETE', route_name='api_employee_id', renderer='json', permission='Employees', trans=True) +@view_config( + request_method="DELETE", + route_name="api_employee_id", + renderer="json", + permission="Employees", + trans=True, +) def delete(request): - employee = request.dbsession.query(Employee).filter(Employee.id == uuid.UUID(request.matchdict['id'])).first() - can_delete, reason = employee.can_delete(request.has_permission('Advanced Delete')) + employee = ( + request.dbsession.query(Employee) + .filter(Employee.id == uuid.UUID(request.matchdict["id"])) + .first() + ) + can_delete, reason = employee.can_delete(request.has_permission("Advanced Delete")) if can_delete: delete_with_data(employee, request.dbsession) transaction.commit() @@ -134,47 +182,96 @@ def delete(request): return response -@view_config(request_method='GET', route_name='api_employee_id', renderer='json', permission='Employees', trans=True) +@view_config( + request_method="GET", + route_name="api_employee_id", + renderer="json", + permission="Employees", + trans=True, +) def show_id(request): - id = to_uuid(request.matchdict['id']) + id = to_uuid(request.matchdict["id"]) if id is None: raise ValidationError("Invalid Employee") return employee_info(id, request.dbsession) -@view_config(request_method='GET', route_name='api_employee', renderer='json', permission='Employees') +@view_config( + request_method="GET", + route_name="api_employee", + renderer="json", + permission="Employees", +) def show_blank(request): return employee_info(None, request.dbsession) -@view_config(request_method='GET', route_name='api_employee', request_param='l', renderer='json', - permission='Authenticated') +@view_config( + request_method="GET", + route_name="api_employee", + request_param="l", + renderer="json", + permission="Authenticated", +) def show_list(request): - list = request.dbsession.query(Employee).order_by(desc(Employee.is_active)).order_by( - Account.cost_centre_id).order_by(Employee.designation).order_by(Employee.name).all() + list = ( + request.dbsession.query(Employee) + .order_by(desc(Employee.is_active)) + .order_by(Account.cost_centre_id) + .order_by(Employee.designation) + .order_by(Employee.name) + .all() + ) accounts = [] for item in list: - accounts.append({ - 'id': item.id, 'code': item.code, 'name': item.name, 'designation': item.designation, 'salary': item.salary, - 'points': item.service_points, 'isActive': item.is_active, 'costCentre': item.cost_centre.name, - 'url': request.route_url('employee_id', id=item.id), 'joiningDate': item.joining_date.strftime('%d-%b-%Y'), - 'leavingDate': '' if item.is_active else item.leaving_date.strftime('%d-%b-%Y') - }) + accounts.append( + { + "id": item.id, + "code": item.code, + "name": item.name, + "designation": item.designation, + "salary": item.salary, + "points": item.service_points, + "isActive": item.is_active, + "costCentre": item.cost_centre.name, + "url": request.route_url("employee_id", id=item.id), + "joiningDate": item.joining_date.strftime("%d-%b-%Y"), + "leavingDate": "" + if item.is_active + else item.leaving_date.strftime("%d-%b-%Y"), + } + ) return accounts -@view_config(request_method='GET', route_name='api_employee', renderer='json', request_param='q', - permission='Authenticated') +@view_config( + request_method="GET", + route_name="api_employee", + renderer="json", + request_param="q", + permission="Authenticated", +) def show_term(request): - filter = request.GET.get('q', None) - filter = None if filter == '' else filter - count = request.GET.get('c', None) - count = None if count is None or count == '' else int(count) + filter = request.GET.get("q", None) + filter = None if filter == "" else filter + count = request.GET.get("c", None) + count = None if count is None or count == "" else int(count) list = [] - for index, item in enumerate(AccountBase.list(10, filter, dbsession=request.dbsession)): - list.append({'id': item.id, 'name': item.name, 'designation': item.designation, - 'costCentre': {'id': item.cost_centre.id, 'name': item.cost_centre.name}}) + for index, item in enumerate( + AccountBase.list(10, filter, dbsession=request.dbsession) + ): + list.append( + { + "id": item.id, + "name": item.name, + "designation": item.designation, + "costCentre": { + "id": item.cost_centre.id, + "name": item.cost_centre.name, + }, + } + ) if count is not None and index == count - 1: break return list @@ -182,27 +279,47 @@ def show_term(request): def employee_info(id, dbsession): if id is None: - employee = {'code': '(Auto)', 'isStarred': False, 'isActive': True, 'costCentre': CostCentre.overall()} + employee = { + "code": "(Auto)", + "isStarred": False, + "isActive": True, + "costCentre": CostCentre.overall(), + } else: employee = dbsession.query(Employee).filter(Employee.id == id).first() if employee is None: raise ValidationError("Invalid Employee") employee = { - 'id': employee.id, 'code': employee.code, 'name': employee.name, - 'isActive': employee.is_active, 'isStarred': employee.is_starred, - 'designation': employee.designation, 'salary': employee.salary, 'points': employee.service_points, - 'joiningDate': employee.joining_date.strftime('%d-%b-%Y'), - 'leavingDate': None if employee.is_active else employee.leaving_date.strftime('%d-%b-%Y'), - 'costCentre': {'id': employee.cost_centre_id, 'name': employee.cost_centre.name} + "id": employee.id, + "code": employee.code, + "name": employee.name, + "isActive": employee.is_active, + "isStarred": employee.is_starred, + "designation": employee.designation, + "salary": employee.salary, + "points": employee.service_points, + "joiningDate": employee.joining_date.strftime("%d-%b-%Y"), + "leavingDate": None + if employee.is_active + else employee.leaving_date.strftime("%d-%b-%Y"), + "costCentre": { + "id": employee.cost_centre_id, + "name": employee.cost_centre.name, + }, } return employee def delete_with_data(employee, dbsession): - suspense_account = dbsession.query(Account).filter(Account.id == Account.suspense()).first() - query = dbsession.query(Voucher).options(joinedload_all(Voucher.journals, Journal.account, innerjoin=True)) \ - .filter(Voucher.journals.any(Journal.account_id == employee.id)) \ + suspense_account = ( + dbsession.query(Account).filter(Account.id == Account.suspense()).first() + ) + query = ( + dbsession.query(Voucher) + .options(joinedload_all(Voucher.journals, Journal.account, innerjoin=True)) + .filter(Voucher.journals.any(Journal.account_id == employee.id)) .all() + ) for voucher in query: others, sus_jnl, acc_jnl = False, None, None @@ -218,9 +335,13 @@ def delete_with_data(employee, dbsession): else: if sus_jnl is None: acc_jnl.account = suspense_account - voucher.narration += '\nSuspense \u20B9 {0:,.2f} is {1}'.format(acc_jnl.amount, employee.name) + voucher.narration += "\nSuspense \u20B9 {0:,.2f} is {1}".format( + acc_jnl.amount, employee.name + ) else: - amount = (sus_jnl.debit * sus_jnl.amount) + (acc_jnl.debit * acc_jnl.amount) + amount = (sus_jnl.debit * sus_jnl.amount) + ( + acc_jnl.debit * acc_jnl.amount + ) if acc_jnl.salary_deduction is not None: dbsession.delete(acc_jnl.salary_deduction) dbsession.delete(acc_jnl) @@ -229,10 +350,14 @@ def delete_with_data(employee, dbsession): else: sus_jnl.amount = abs(amount) sus_jnl.debit = -1 if amount < 0 else 1 - voucher.narration += '\nDeleted \u20B9 {0:,.2f} of {1}'.format(acc_jnl.amount * acc_jnl.debit, - employee.name) - if voucher.type in (VoucherType.by_name('Payment').id, VoucherType.by_name('Receipt').id): - voucher.type = VoucherType.by_name('Journal') + voucher.narration += "\nDeleted \u20B9 {0:,.2f} of {1}".format( + acc_jnl.amount * acc_jnl.debit, employee.name + ) + if voucher.type in ( + VoucherType.by_name("Payment").id, + VoucherType.by_name("Receipt").id, + ): + voucher.type = VoucherType.by_name("Journal") for fingerprint in employee.fingerprints: dbsession.delete(fingerprint) for attendance in employee.attendances: diff --git a/brewman/views/fingerprint.py b/brewman/views/fingerprint.py index 21518a24..e4d6157f 100644 --- a/brewman/views/fingerprint.py +++ b/brewman/views/fingerprint.py @@ -11,19 +11,27 @@ from zope.sqlalchemy import mark_changed from brewman.models.master import Employee from brewman.models.voucher import Fingerprint +from brewman.views import get_lock_info -@view_config(request_method='POST', route_name='api_fingerprint', renderer='json', permission='Authenticated', - trans=True) -def show_list(request): - fingerprints_file = request.POST['uploadedFile'].file +@view_config( + request_method="POST", + route_name="api_fingerprint", + renderer="json", + permission="Authenticated", + trans=True, +) +def upload_prints(request): + fingerprints_file = request.POST["uploadedFile"].file + start, finish = get_lock_info(request.dbsession) employees = {} - for id, code in request.dbsession.query(Employee.id, Employee.code).all(): - employees[code] = id - data = fp(csv.reader(read_file(fingerprints_file), delimiter="\t"), employees) - paged_data = [data[i:i + 100] for i in range(0, len(data), 100)] + for id_, code in request.dbsession.query(Employee.id, Employee.code).all(): + employees[code] = id_ + file_data = read_file(fingerprints_file) + prints = [d for d in fp(file_data, employees) if start <= d["date"] <= finish] + paged_data = [prints[i : i + 100] for i in range(0, len(prints), 100)] for i, page in enumerate(paged_data): - print('Processing page ', i, ' of ', len(paged_data)) + print("Processing page ", i, " of ", len(paged_data)) request.dbsession.execute(get_query(9.4), page) mark_changed(request.dbsession) @@ -33,49 +41,70 @@ def show_list(request): def get_query(version): if version == 9.5: - return pg_insert(Fingerprint).values( - { - 'FingerprintID': bindparam('id'), - 'EmployeeID': bindparam('employee_id'), - 'Date': bindparam('date') - } - - ).on_conflict_do_nothing() + return ( + pg_insert(Fingerprint) + .values( + { + "FingerprintID": bindparam("id"), + "EmployeeID": bindparam("employee_id"), + "Date": bindparam("date"), + } + ) + .on_conflict_do_nothing() + ) else: - sel = select([bindparam('id'), bindparam('employee_id'), bindparam('date')]).where( + sel = select( + [bindparam("id"), bindparam("employee_id"), bindparam("date")] + ).where( ~exists([Fingerprint.id]).where( and_( - Fingerprint.employee_id == bindparam('employee_id'), Fingerprint.date == bindparam('date') + Fingerprint.employee_id == bindparam("employee_id"), + Fingerprint.date == bindparam("date"), ) ) ) - return Fingerprint.__table__.insert().from_select([Fingerprint.id, Fingerprint.employee_id, Fingerprint.date], - sel) + return Fingerprint.__table__.insert().from_select( + [Fingerprint.id, Fingerprint.employee_id, Fingerprint.date], sel + ) def read_file(input_file): input_file.seek(0) - output = "" + output = bytearray() while 1: data = input_file.read(2 << 16) if not data: break - output += data.decode('utf-8') - return StringIO(output) + output.extend(data) + if output[0:3] == b"\xef\xbb\xbf": + encoding = "utf-8" + elif output[0:2] == b"\xfe\xff" or output[0:2] == b"\xff\xfe": + encoding = "utf-16" + else: + encoding = "ascii" + # raise ValidationError("The encoding of the attendance file is not correct") + return StringIO(output.decode(encoding)) -def fp(reader, employees): +def fp(file_data, employees): fingerprints = [] + reader = csv.reader(file_data, delimiter="\t") + header = next(reader, None) + employee_column = 2 + date_column = len(header) - 1 + date_format = "%Y/%m/%d %H:%M:%S" if date_column == 6 else "%Y-%m-%d %H:%M:%S" for row in reader: try: - employee_code = int(row[2]) - date = datetime.datetime.strptime(row[6], '%Y/%m/%d %H:%M:%S') + employee_code = int(row[employee_column]) # EnNo + date = datetime.datetime.strptime(row[date_column], date_format) if employee_code in employees.keys(): - fingerprints.append({ - 'id': uuid.uuid4(), - 'employee_id': employees[employee_code], - 'date': date - }) + fingerprints.append( + { + "id": uuid.uuid4(), + "employee_id": employees[employee_code], + "date": date, + } + ) except ValueError: continue return fingerprints @@ -95,8 +124,14 @@ def fp(reader, employees): def get_prints(employee_id, date, dbsession): start_fp = date + datetime.timedelta(hours=7) finish_fp = date + datetime.timedelta(hours=7, days=1) - prints = dbsession.query(Fingerprint).filter(Fingerprint.employee_id == employee_id) \ - .filter(Fingerprint.date >= start_fp).filter(Fingerprint.date < finish_fp).order_by(Fingerprint.date).all() + prints = ( + dbsession.query(Fingerprint) + .filter(Fingerprint.employee_id == employee_id) + .filter(Fingerprint.date >= start_fp) + .filter(Fingerprint.date < finish_fp) + .order_by(Fingerprint.date) + .all() + ) last = None for i in range(len(prints), 0, -1): @@ -107,7 +142,7 @@ def get_prints(employee_id, date, dbsession): last = item if len(prints) == 0: - hours = '', '' + hours = "", "" elif len(prints) == 2: hours = prints[1].date - prints[0].date hours = working_hours(hours) @@ -115,13 +150,17 @@ def get_prints(employee_id, date, dbsession): hours = (prints[1].date - prints[0].date) + (prints[3].date - prints[2].date) hours = working_hours(hours) else: - hours = 'Error', 'Error' - return ', '.join([x.date.strftime('%H:%M') for x in prints]) + ' ', hours[0], hours[1] + hours = "Error", "Error" + return ( + ", ".join([x.date.strftime("%H:%M") for x in prints]) + " ", + hours[0], + hours[1], + ) def working_hours(delta): minutes = (delta.seconds // 60) % 60 minutes = int(5 * round(float(minutes) / 5)) hours = delta.seconds // 3600 - worked = str(hours).zfill(2) + ':' + str(minutes).zfill(2) + worked = str(hours).zfill(2) + ":" + str(minutes).zfill(2) return worked, delta.seconds >= 60 * 60 * 9 # 9hrs diff --git a/brewman/views/product.py b/brewman/views/product.py index a37f6955..2b3cf052 100644 --- a/brewman/views/product.py +++ b/brewman/views/product.py @@ -13,114 +13,155 @@ from brewman.models.validation_exception import ValidationError from brewman.models.voucher import Voucher, Batch, Inventory, VoucherType -@view_config(route_name='product_list', permission='Authenticated') -@view_config(request_method='GET', route_name='product_id', permission='Products') -@view_config(request_method='GET', route_name='product', permission='Products') +@view_config(route_name="product_list", permission="Authenticated") +@view_config(request_method="GET", route_name="product_id", permission="Products") +@view_config(request_method="GET", route_name="product", permission="Products") def html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='POST', route_name='api_product', renderer='json', permission='Products', trans=True) +@view_config( + request_method="POST", + route_name="api_product", + renderer="json", + permission="Products", + trans=True, +) def save(request): json = request.json_body - name = json.get('name', '').strip() - if name == '': - raise ValidationError('Name cannot be blank') + name = json.get("name", "").strip() + if name == "": + raise ValidationError("Name cannot be blank") - units = json.get('units', '').strip() + units = json.get("units", "").strip() try: - fraction = Decimal(json.get('fraction', 0)) + fraction = Decimal(json.get("fraction", 0)) if fraction <= 0: raise ValidationError("Fraction must be a decimal > 0") except (ValueError, InvalidOperation): raise ValidationError("Fraction must be a decimal > 0") - fraction_units = json.get('fractionUnits', '').strip() + fraction_units = json.get("fractionUnits", "").strip() try: - product_yield = Decimal(json.get('productYield', 1)) + product_yield = Decimal(json.get("productYield", 1)) if product_yield <= 0 or product_yield > 1: raise ValidationError("Yield must be a decimal > 0 <= 1") except (ValueError, InvalidOperation): raise ValidationError("Yield must be a decimal > 0 <= 1") - product_group = json.get('productGroup', None) + product_group = json.get("productGroup", None) if product_group is None: - raise ValidationError('please choose a product group') - product_group_id = uuid.UUID(product_group['id']) + raise ValidationError("please choose a product group") + product_group_id = uuid.UUID(product_group["id"]) try: - price = Decimal(json.get('price', 0)) + price = Decimal(json.get("price", 0)) if price < 0: raise ValidationError("Price must be a decimal >= 0") except (ValueError, InvalidOperation): raise ValidationError("Price must be a decimal >= 0") try: - sale_price = Decimal(json.get('salePrice', 0)) + sale_price = Decimal(json.get("salePrice", 0)) if price < 0: raise ValidationError("Sale Price must be a decimal >= 0") except (ValueError, InvalidOperation): raise ValidationError("Price must be a decimal >= 0") - is_active = json.get('isActive', True) - is_purchased = json.get('isPurchased', True) - is_sold = json.get('isSold', True) - item = Product(0, name, units, fraction, fraction_units, product_yield, product_group_id, Account.all_purchases(), - price, sale_price, is_active, is_purchased, is_sold).create(request.dbsession) + is_active = json.get("isActive", True) + is_purchased = json.get("isPurchased", True) + is_sold = json.get("isSold", True) + item = Product( + 0, + name, + units, + fraction, + fraction_units, + product_yield, + product_group_id, + Account.all_purchases(), + price, + sale_price, + is_active, + is_purchased, + is_sold, + ).create(request.dbsession) transaction.commit() return product_info(item.id, request.dbsession) -@view_config(request_method='PUT', route_name='api_product_id', renderer='json', permission='Products', trans=True) +@view_config( + request_method="PUT", + route_name="api_product_id", + renderer="json", + permission="Products", + trans=True, +) def update(request): - item = request.dbsession.query(Product).filter(Product.id == uuid.UUID(request.matchdict['id'])).first() + item = ( + request.dbsession.query(Product) + .filter(Product.id == uuid.UUID(request.matchdict["id"])) + .first() + ) if item.is_fixture: - raise ValidationError("{0} is a fixture and cannot be edited or deleted.".format(item.full_name)) - item.name = request.json_body['name'].strip() - item.units = request.json_body['units'].strip() + raise ValidationError( + "{0} is a fixture and cannot be edited or deleted.".format(item.full_name) + ) + item.name = request.json_body["name"].strip() + item.units = request.json_body["units"].strip() try: - item.fraction = Decimal(request.json_body['fraction']) + item.fraction = Decimal(request.json_body["fraction"]) if item.fraction <= 0: raise ValidationError("Fraction must be a decimal > 0") except (ValueError, InvalidOperation): raise ValidationError("Fraction must be a decimal > 0") - item.fraction_units = request.json_body['fractionUnits'] + item.fraction_units = request.json_body["fractionUnits"] try: - item.product_yield = Decimal(request.json_body['productYield']) + item.product_yield = Decimal(request.json_body["productYield"]) if item.product_yield <= 0 or item.product_yield > 1: raise ValidationError("Yield must be a decimal > 0 <= 1") except (ValueError, InvalidOperation): raise ValidationError("Yield must be a decimal > 0 <= 1") - item.product_group_id = uuid.UUID(request.json_body['productGroup']['id']) + item.product_group_id = uuid.UUID(request.json_body["productGroup"]["id"]) item.account_id = Account.all_purchases() try: - item.price = Decimal(request.json_body['price']) + item.price = Decimal(request.json_body["price"]) if item.price < 0: raise ValidationError("Price must be a decimal >= 0") except (ValueError, InvalidOperation): raise ValidationError("Price must be a decimal >= 0") try: - item.sale_price = Decimal(request.json_body['salePrice']) + item.sale_price = Decimal(request.json_body["salePrice"]) if item.sale_price < 0: raise ValidationError("Sale Price must be a decimal >= 0") except (ValueError, InvalidOperation): raise ValidationError("Sale Price must be a decimal >= 0") - item.is_active = request.json_body['isActive'] - item.is_fixture = request.json_body['isFixture'] - item.is_purchased = request.json_body['isPurchased'] - item.is_sold = request.json_body['isSold'] + item.is_active = request.json_body["isActive"] + item.is_fixture = request.json_body["isFixture"] + item.is_purchased = request.json_body["isPurchased"] + item.is_sold = request.json_body["isSold"] transaction.commit() return product_info(item.id, request.dbsession) -@view_config(request_method='DELETE', route_name='api_product_id', renderer='json', permission='Products', trans=True) +@view_config( + request_method="DELETE", + route_name="api_product_id", + renderer="json", + permission="Products", + trans=True, +) def delete(request): - product = request.dbsession.query(Product).filter(Product.id == uuid.UUID(request.matchdict['id'])).first() - can_delete, reason = product.can_delete(request.has_permission('Advanced Delete')) + product = ( + request.dbsession.query(Product) + .filter(Product.id == uuid.UUID(request.matchdict["id"])) + .first() + ) + can_delete, reason = product.can_delete(request.has_permission("Advanced Delete")) if can_delete: delete_with_data(product, request) @@ -133,54 +174,99 @@ def delete(request): return response -@view_config(request_method='GET', route_name='api_product_id', renderer='json', permission='Products') +@view_config( + request_method="GET", + route_name="api_product_id", + renderer="json", + permission="Products", +) def show_id(request): - return product_info(uuid.UUID(request.matchdict.get('id', None)), request.dbsession) + return product_info(uuid.UUID(request.matchdict.get("id", None)), request.dbsession) -@view_config(request_method='GET', route_name='api_product', renderer='json', permission='Products') +@view_config( + request_method="GET", + route_name="api_product", + renderer="json", + permission="Products", +) def show_blank(request): return product_info(None, request.dbsession) -@view_config(request_method='GET', route_name='api_product', request_param='l', renderer='json', - permission='Authenticated') +@view_config( + request_method="GET", + route_name="api_product", + request_param="l", + renderer="json", + permission="Authenticated", +) def show_list(request): - list = request.dbsession.query(Product).order_by(desc(Product.is_active)).order_by( - Product.product_group_id).order_by(Product.name).all() + list = ( + request.dbsession.query(Product) + .order_by(desc(Product.is_active)) + .order_by(Product.product_group_id) + .order_by(Product.name) + .all() + ) products = [] for item in list: - products.append({ - 'id': item.id, 'code': item.code, 'name': item.name, 'units': item.units, 'costPrice': item.price, - 'salePrice': item.sale_price, 'productGroup': item.product_group.name, - 'isActive': item.is_active, 'fraction': item.fraction, 'fractionUnits': item.fraction_units, - 'isPurchased': item.is_purchased, 'isSold': item.is_sold, 'productYield': item.product_yield, - 'isFixture': item.is_fixture}) + products.append( + { + "id": item.id, + "code": item.code, + "name": item.name, + "units": item.units, + "costPrice": item.price, + "salePrice": item.sale_price, + "productGroup": item.product_group.name, + "isActive": item.is_active, + "fraction": item.fraction, + "fractionUnits": item.fraction_units, + "isPurchased": item.is_purchased, + "isSold": item.is_sold, + "productYield": item.product_yield, + "isFixture": item.is_fixture, + } + ) return products -@view_config(request_method='GET', route_name='api_product', renderer='json', request_param='t', - permission='Authenticated') +@view_config( + request_method="GET", + route_name="api_product", + renderer="json", + request_param="t", + permission="Authenticated", +) def show_term(request): - term = request.GET.get('t', None) - term = term.strip() if term is not None and term.strip() is not '' else None - active = request.GET.get('a', None) + term = request.GET.get("t", None) + term = term.strip() if term is not None and term.strip() is not "" else None + active = request.GET.get("a", None) active = active if active is not None else None - count = request.GET.get('c', None) - count = None if count is None or count == '' else int(count) - is_purchased = request.GET.get('p', None) + count = request.GET.get("c", None) + count = None if count is None or count == "" else int(count) + is_purchased = request.GET.get("p", None) is_purchased = is_purchased if is_purchased is not None else None - extended = request.GET.get('e', False) + extended = request.GET.get("e", False) def add_list(query): local_results = [] for index, item in enumerate(query): if extended: - product = {'id': item.id, 'name': item.full_name, 'price': item.price, 'units': item.units, - 'fraction': item.fraction, 'fractionUnits': item.fraction_units, - 'productYield': item.product_yield, 'isSold': item.is_sold, 'salePrice': item.sale_price} + product = { + "id": item.id, + "name": item.full_name, + "price": item.price, + "units": item.units, + "fraction": item.fraction, + "fractionUnits": item.fraction_units, + "productYield": item.product_yield, + "isSold": item.is_sold, + "salePrice": item.sale_price, + } else: - product = {'id': item.id, 'name': item.full_name, 'price': item.price} + product = {"id": item.id, "name": item.full_name, "price": item.price} local_results.append(product) if count is not None and index == count - 1: break @@ -195,34 +281,59 @@ def show_term(request): query = query.filter(Product.is_purchased == is_purchased) if term is not None: for item in term.split(): - if item.strip() != '': - query = query.filter(Product.name.ilike('%' + item + '%')) + if item.strip() != "": + query = query.filter(Product.name.ilike("%" + item + "%")) result_list += add_list(query) - return sorted(result_list, key=lambda k: k['name']) + return sorted(result_list, key=lambda k: k["name"]) def product_info(id, dbsession): if id is None: - product = {'code': '(Auto)', 'productGroup': {}, 'isActive': True, 'isPurchased': True, 'isSold': False} + product = { + "code": "(Auto)", + "productGroup": {}, + "isActive": True, + "isPurchased": True, + "isSold": False, + } else: product = dbsession.query(Product).filter(Product.id == id).first() - product = {'id': product.id, 'code': product.code, 'name': product.name, 'units': product.units, - 'fraction': product.fraction, 'fractionUnits': product.fraction_units, - 'productYield': product.product_yield, 'price': product.price, 'salePrice': product.sale_price, - 'isActive': product.is_active, 'isFixture': product.is_fixture, - 'isPurchased': product.is_purchased, 'isSold': product.is_sold, - 'productGroup': {'id': product.product_group_id}, - 'account': {'id': product.account_id}} + product = { + "id": product.id, + "code": product.code, + "name": product.name, + "units": product.units, + "fraction": product.fraction, + "fractionUnits": product.fraction_units, + "productYield": product.product_yield, + "price": product.price, + "salePrice": product.sale_price, + "isActive": product.is_active, + "isFixture": product.is_fixture, + "isPurchased": product.is_purchased, + "isSold": product.is_sold, + "productGroup": {"id": product.product_group_id}, + "account": {"id": product.account_id}, + } return product def delete_with_data(product, request): - suspense_product = request.dbsession.query(Product).filter(Product.id == Product.suspense()).first() - suspense_batch = request.dbsession.query(Batch).filter(Batch.id == Batch.suspense()).first() - query = request.dbsession.query(Voucher).options( - joinedload_all(Voucher.inventories, Inventory.product, innerjoin=True)).filter( - Voucher.inventories.any(Inventory.product_id == product.id)).all() + suspense_product = ( + request.dbsession.query(Product) + .filter(Product.id == Product.suspense()) + .first() + ) + suspense_batch = ( + request.dbsession.query(Batch).filter(Batch.id == Batch.suspense()).first() + ) + query = ( + request.dbsession.query(Voucher) + .options(joinedload_all(Voucher.inventories, Inventory.product, innerjoin=True)) + .filter(Voucher.inventories.any(Inventory.product_id == product.id)) + .all() + ) for voucher in query: others, sus_inv, prod_inv = False, None, None @@ -233,7 +344,7 @@ def delete_with_data(product, request): sus_inv = inventory else: others = True - if not others and voucher.type == VoucherType.by_id('Issue'): + if not others and voucher.type == VoucherType.by_id("Issue"): request.dbsession.delete(voucher) else: if sus_inv is None: @@ -243,11 +354,15 @@ def delete_with_data(product, request): prod_inv.tax = 0 prod_inv.discount = 0 prod_inv.batch = suspense_batch - voucher.narration += '\nSuspense \u20B9{0:,.2f} is {1}'.format(prod_inv.amount, product.name) + voucher.narration += "\nSuspense \u20B9{0:,.2f} is {1}".format( + prod_inv.amount, product.name + ) else: sus_inv.quantity += prod_inv.amount request.dbsession.delete(prod_inv) - voucher.narration += '\nDeleted \u20B9{0:,.2f} of {1}'.format(prod_inv.amount, product.name) + voucher.narration += "\nDeleted \u20B9{0:,.2f} of {1}".format( + prod_inv.amount, product.name + ) for batch in product.batches: request.dbsession.delete(batch) request.dbsession.delete(product) diff --git a/brewman/views/product_group.py b/brewman/views/product_group.py index 20226eaf..0e3e795e 100644 --- a/brewman/views/product_group.py +++ b/brewman/views/product_group.py @@ -9,68 +9,118 @@ from brewman.models.master import ProductGroup from brewman.models.validation_exception import ValidationError -@view_config(route_name='product_group_list', permission='Authenticated') -@view_config(request_method='GET', route_name='product_group_id', permission='Product Groups') -@view_config(request_method='GET', route_name='product_group', permission='Product Groups') +@view_config(route_name="product_group_list", permission="Authenticated") +@view_config( + request_method="GET", route_name="product_group_id", permission="Product Groups" +) +@view_config( + request_method="GET", route_name="product_group", permission="Product Groups" +) def html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='POST', route_name='api_product_group', renderer='json', permission='Product Groups', - trans=True) +@view_config( + request_method="POST", + route_name="api_product_group", + renderer="json", + permission="Product Groups", + trans=True, +) def save(request): - item = ProductGroup(request.json_body['name']) + item = ProductGroup(request.json_body["name"]) request.dbsession.add(item) transaction.commit() return product_group_info(item.id, request.dbsession) -@view_config(request_method='PUT', route_name='api_product_group_id', renderer='json', permission='Product Groups', - trans=True) +@view_config( + request_method="PUT", + route_name="api_product_group_id", + renderer="json", + permission="Product Groups", + trans=True, +) def update(request): - item = request.dbsession.query(ProductGroup).filter(ProductGroup.id == uuid.UUID(request.matchdict['id'])).first() + item = ( + request.dbsession.query(ProductGroup) + .filter(ProductGroup.id == uuid.UUID(request.matchdict["id"])) + .first() + ) if item.is_fixture: - raise ValidationError("{0} is a fixture and cannot be edited or deleted.".format(item.name)) - item.name = request.json_body['name'] + raise ValidationError( + "{0} is a fixture and cannot be edited or deleted.".format(item.name) + ) + item.name = request.json_body["name"] transaction.commit() return product_group_info(item.id, request.dbsession) -@view_config(request_method='DELETE', route_name='api_product_group_id', renderer='json', permission='Product Groups') +@view_config( + request_method="DELETE", + route_name="api_product_group_id", + renderer="json", + permission="Product Groups", +) def delete(request): - item = request.dbsession.query(ProductGroup).filter(ProductGroup.id == uuid.UUID(request.matchdict['id'])).first() + item = ( + request.dbsession.query(ProductGroup) + .filter(ProductGroup.id == uuid.UUID(request.matchdict["id"])) + .first() + ) if item is None: response = Response("Product Group not Found") response.status_int = 500 return response elif item.is_fixture: - raise ValidationError("{0} is a fixture and cannot be edited or deleted.".format(item.name)) + raise ValidationError( + "{0} is a fixture and cannot be edited or deleted.".format(item.name) + ) else: response = Response("Product Group deletion not implemented") response.status_int = 500 return response -@view_config(request_method='GET', route_name='api_product_group_id', renderer='json', permission='Product Groups') +@view_config( + request_method="GET", + route_name="api_product_group_id", + renderer="json", + permission="Product Groups", +) def show_id(request): - return product_group_info(uuid.UUID(request.matchdict.get('id', None)), request.dbsession) + return product_group_info( + uuid.UUID(request.matchdict.get("id", None)), request.dbsession + ) -@view_config(request_method='GET', route_name='api_product_group', renderer='json', permission='Product Groups') +@view_config( + request_method="GET", + route_name="api_product_group", + renderer="json", + permission="Product Groups", +) def show_blank(request): return product_group_info(None, request.dbsession) -@view_config(request_method='GET', route_name='api_product_group', request_param='l', renderer='json', - permission='Authenticated') +@view_config( + request_method="GET", + route_name="api_product_group", + request_param="l", + renderer="json", + permission="Authenticated", +) def show_list(request): list = request.dbsession.query(ProductGroup).order_by(ProductGroup.name).all() product_groups = [] for item in list: - product_groups.append({'id': item.id, 'name': item.name, 'isFixture': item.is_fixture}) + product_groups.append( + {"id": item.id, "name": item.name, "isFixture": item.is_fixture} + ) return product_groups @@ -78,5 +128,11 @@ def product_group_info(id, dbsession): if id is None: return {} else: - product_group = dbsession.query(ProductGroup).filter(ProductGroup.id == id).first() - return {'id': product_group.id, 'name': product_group.name, 'isFixture': product_group.is_fixture} + product_group = ( + dbsession.query(ProductGroup).filter(ProductGroup.id == id).first() + ) + return { + "id": product_group.id, + "name": product_group.name, + "isFixture": product_group.is_fixture, + } diff --git a/brewman/views/recipe.py b/brewman/views/recipe.py index 91f5034c..a2416cae 100644 --- a/brewman/views/recipe.py +++ b/brewman/views/recipe.py @@ -13,38 +13,60 @@ import transaction from brewman.models.master import Recipe, Product, RecipeItem, CostCentre from brewman.models.validation_exception import ValidationError from brewman.models.voucher import Voucher, Inventory, VoucherType, Journal -from brewman.views.services.session import session_period_start, session_period_finish, session_period_set +from brewman.views.services.session import ( + session_period_start, + session_period_finish, + session_period_set, +) -@view_config(route_name='recipe_list', permission='Recipes') -@view_config(request_method='GET', route_name='recipe_id', permission='Recipes') -@view_config(request_method='GET', route_name='recipe', permission='Recipes') +@view_config(route_name="recipe_list", permission="Recipes") +@view_config(request_method="GET", route_name="recipe_id", permission="Recipes") +@view_config(request_method="GET", route_name="recipe", permission="Recipes") def html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='POST', route_name='api_recipe', renderer='json', permission='Recipes') -@view_config(request_method='POST', route_name='api_recipe_id', renderer='json', permission='Recipes', trans=True) +@view_config( + request_method="POST", + route_name="api_recipe", + renderer="json", + permission="Recipes", +) +@view_config( + request_method="POST", + route_name="api_recipe_id", + renderer="json", + permission="Recipes", + trans=True, +) def save(request): json = request.json_body - recipe_product = request.dbsession.query(Product).filter( - Product.id == uuid.UUID(json['Product']['ProductID'])).first() + recipe_product = ( + request.dbsession.query(Product) + .filter(Product.id == uuid.UUID(json["Product"]["ProductID"])) + .first() + ) try: - valid_from = datetime.date(*(time.strptime(request.json_body['ValidFrom'], '%d-%b-%Y')[0:3])) + valid_from = datetime.date( + *(time.strptime(request.json_body["ValidFrom"], "%d-%b-%Y")[0:3]) + ) except (ValueError, KeyError, TypeError): raise ValidationError("Valid From is not a valid date") try: - valid_to = datetime.date(*(time.strptime(request.json_body['ValidTo'], '%d-%b-%Y')[0:3])) + valid_to = datetime.date( + *(time.strptime(request.json_body["ValidTo"], "%d-%b-%Y")[0:3]) + ) except (ValueError, KeyError, TypeError): raise ValidationError("Valid To is not a valid date") if valid_to < valid_from: raise ValidationError("Valid To cannot be less than valid from") try: - recipe_quantity = Decimal(json.get('Quantity', 0)) + recipe_quantity = Decimal(json.get("Quantity", 0)) if recipe_quantity < 0: raise ValidationError("Quantity must be a decimal >= 0") except (ValueError, InvalidOperation): @@ -53,27 +75,42 @@ def save(request): sale_price = 0 if recipe_product.is_sold: try: - sale_price = Decimal(json.get('SalePrice', 0)) + sale_price = Decimal(json.get("SalePrice", 0)) if sale_price < 0: raise ValidationError("Sale Price must be a decimal >= 0") except (ValueError, InvalidOperation): raise ValidationError("Sale Price must be a decimal >= 0") recipe_cost = 0 - if len(json['RecipeItems']) == 0: + if len(json["RecipeItems"]) == 0: raise ValidationError("Recipe has no ingredients") - recipe = Recipe(product_id=recipe_product.id, quantity=recipe_quantity, sale_price=sale_price, - valid_from=valid_from, valid_to=valid_to) - for item in json['RecipeItems']: - product = request.dbsession.query(Product).filter(Product.id == uuid.UUID(item['Product']['ProductID'])).first() - quantity = round(Decimal(item['Quantity']), 2) + recipe = Recipe( + product_id=recipe_product.id, + quantity=recipe_quantity, + sale_price=sale_price, + valid_from=valid_from, + valid_to=valid_to, + ) + for item in json["RecipeItems"]: + product = ( + request.dbsession.query(Product) + .filter(Product.id == uuid.UUID(item["Product"]["ProductID"])) + .first() + ) + quantity = round(Decimal(item["Quantity"]), 2) if product.is_purchased: - ingredient_cost = get_purchased_product_cost(product.id, valid_from, valid_to, request.dbsession) + ingredient_cost = get_purchased_product_cost( + product.id, valid_from, valid_to, request.dbsession + ) else: - ingredient_cost = get_sub_product_cost(product.id, valid_from, valid_to, request.dbsession) + ingredient_cost = get_sub_product_cost( + product.id, valid_from, valid_to, request.dbsession + ) cost_per_unit = ingredient_cost / (product.fraction * product.product_yield) recipe_cost += cost_per_unit * quantity - recipe.recipe_items.append(RecipeItem(None, product.id, quantity, ingredient_cost)) + recipe.recipe_items.append( + RecipeItem(None, product.id, quantity, ingredient_cost) + ) recipe.cost_price = round(recipe_cost / recipe_quantity, 2) if recipe_product.is_sold: @@ -88,7 +125,13 @@ def save(request): def save_recipe(recipe, dbsession): product = dbsession.query(Product).filter(Product.id == recipe.product_id).first() product.price = recipe.cost_price - update_old_rows(recipe.product_id, recipe.valid_from, recipe.valid_to, recipe.effective_from, dbsession) + update_old_rows( + recipe.product_id, + recipe.valid_from, + recipe.valid_to, + recipe.effective_from, + dbsession, + ) dbsession.add(recipe) for item in recipe.recipe_items: item.recipe_id = recipe.id @@ -96,18 +139,27 @@ def save_recipe(recipe, dbsession): def get_purchased_product_cost(product_id, start_date, finish_date, dbsession): - quantity_sum = func.sum(Journal.debit * Inventory.quantity).label('quantity') + quantity_sum = func.sum(Journal.debit * Inventory.quantity).label("quantity") amount_sum = func.sum( - Journal.debit * Inventory.quantity * Inventory.rate * (1 + Inventory.tax) * (1 - Inventory.discount)).label( - 'amount') - costing = dbsession.query(quantity_sum, amount_sum) \ - .join(Product.inventories).join(Inventory.voucher).join(Voucher.journals) \ - .filter(Inventory.product_id == product_id) \ - .filter(Voucher.date >= start_date) \ - .filter(Voucher.date <= finish_date) \ - .filter(Voucher.type == VoucherType.by_name('Issue').id) \ - .filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase()) \ - .group_by(Product).first() + Journal.debit + * Inventory.quantity + * Inventory.rate + * (1 + Inventory.tax) + * (1 - Inventory.discount) + ).label("amount") + costing = ( + dbsession.query(quantity_sum, amount_sum) + .join(Product.inventories) + .join(Inventory.voucher) + .join(Voucher.journals) + .filter(Inventory.product_id == product_id) + .filter(Voucher.date >= start_date) + .filter(Voucher.date <= finish_date) + .filter(Voucher.type == VoucherType.by_name("Issue").id) + .filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase()) + .group_by(Product) + .first() + ) if costing is None: product = dbsession.query(Product).filter(Product.id == product_id).first() return product.price @@ -118,34 +170,53 @@ def get_purchased_product_cost(product_id, start_date, finish_date, dbsession): def get_sub_product_cost(product_id, start_date, finish_date, dbsession): product = dbsession.query(Product).filter(Product.id == product_id).first() - old_recipe = dbsession.query(Recipe).filter(Recipe.product_id == product_id) \ - .filter(Recipe.effective_to == None) \ - .filter(Recipe.valid_from == start_date) \ - .filter(Recipe.valid_to == finish_date) \ + old_recipe = ( + dbsession.query(Recipe) + .filter(Recipe.product_id == product_id) + .filter(Recipe.effective_to == None) + .filter(Recipe.valid_from == start_date) + .filter(Recipe.valid_to == finish_date) .first() + ) if old_recipe is not None: return old_recipe.cost_price - old_recipe = dbsession.query(Recipe).filter(Recipe.product_id == product_id) \ - .filter(Recipe.effective_to == None) \ - .order_by(desc(Recipe.valid_to)) \ + old_recipe = ( + dbsession.query(Recipe) + .filter(Recipe.product_id == product_id) + .filter(Recipe.effective_to == None) + .order_by(desc(Recipe.valid_to)) .first() + ) if old_recipe is None: raise ValidationError("Ingredient XXX has no recipe, cannot determine cost") recipe_cost = 0 - recipe = Recipe(product_id=product_id, quantity=old_recipe.quantity, sale_price=product.sale_price, - valid_from=start_date, valid_to=finish_date) + recipe = Recipe( + product_id=product_id, + quantity=old_recipe.quantity, + sale_price=product.sale_price, + valid_from=start_date, + valid_to=finish_date, + ) for item in old_recipe.recipe_items: if item.product.is_purchased: - ingredient_cost = get_purchased_product_cost(item.product_id, start_date, finish_date, dbsession) + ingredient_cost = get_purchased_product_cost( + item.product_id, start_date, finish_date, dbsession + ) else: - ingredient_cost = get_sub_product_cost(item.product_id, start_date, finish_date, dbsession) - cost_per_unit = ingredient_cost / (item.product.fraction * item.product.product_yield) + ingredient_cost = get_sub_product_cost( + item.product_id, start_date, finish_date, dbsession + ) + cost_per_unit = ingredient_cost / ( + item.product.fraction * item.product.product_yield + ) recipe_cost += cost_per_unit * item.quantity - recipe.recipe_items.append(RecipeItem(None, item.product_id, item.quantity, ingredient_cost)) + recipe.recipe_items.append( + RecipeItem(None, item.product_id, item.quantity, ingredient_cost) + ) recipe.cost_price = round(recipe_cost / old_recipe.quantity, 2) @@ -154,27 +225,48 @@ def get_sub_product_cost(product_id, start_date, finish_date, dbsession): def update_old_rows(product_id, valid_from, valid_to, effective_date, dbsession): - old = dbsession.query(Recipe).filter(Recipe.product_id == product_id) \ - .filter(Recipe.valid_from < valid_to).filter(Recipe.valid_to > valid_from) \ - .filter(or_(Recipe.effective_to == None, Recipe.effective_to >= effective_date)) \ - .order_by(Recipe.effective_from).all() + old = ( + dbsession.query(Recipe) + .filter(Recipe.product_id == product_id) + .filter(Recipe.valid_from < valid_to) + .filter(Recipe.valid_to > valid_from) + .filter(or_(Recipe.effective_to == None, Recipe.effective_to >= effective_date)) + .order_by(Recipe.effective_from) + .all() + ) new_recipes = [] for item in old: if item.valid_from < valid_from: - recipe = Recipe(product_id=item.product_id, quantity=item.quantity, cost_price=item.cost_price, - sale_price=item.sale_price, valid_from=item.valid_from, - valid_to=valid_from - datetime.timedelta(days=1), effective_from=effective_date) + recipe = Recipe( + product_id=item.product_id, + quantity=item.quantity, + cost_price=item.cost_price, + sale_price=item.sale_price, + valid_from=item.valid_from, + valid_to=valid_from - datetime.timedelta(days=1), + effective_from=effective_date, + ) for ri in item.recipe_items: - recipe.recipe_items.append(RecipeItem(None, ri.product_id, ri.quantity, ri.price)) + recipe.recipe_items.append( + RecipeItem(None, ri.product_id, ri.quantity, ri.price) + ) new_recipes.append(recipe) if item.valid_to > valid_to: - recipe = Recipe(product_id=item.product_id, quantity=item.quantity, cost_price=item.cost_price, - sale_price=item.sale_price, valid_from=valid_to + datetime.timedelta(days=1), - valid_to=item.valid_to, effective_from=effective_date) + recipe = Recipe( + product_id=item.product_id, + quantity=item.quantity, + cost_price=item.cost_price, + sale_price=item.sale_price, + valid_from=valid_to + datetime.timedelta(days=1), + valid_to=item.valid_to, + effective_from=effective_date, + ) for ri in item.recipe_items: - recipe.recipe_items.append(RecipeItem(None, ri.product_id, ri.quantity, ri.price)) + recipe.recipe_items.append( + RecipeItem(None, ri.product_id, ri.quantity, ri.price) + ) new_recipes.append(recipe) if item.effective_from == effective_date and item.effective_to is None: @@ -191,9 +283,18 @@ def update_old_rows(product_id, valid_from, valid_to, effective_date, dbsession) dbsession.add(item) -@view_config(request_method='DELETE', route_name='api_recipe_id', renderer='json', permission='Recipes') +@view_config( + request_method="DELETE", + route_name="api_recipe_id", + renderer="json", + permission="Recipes", +) def delete(request): - recipe = request.dbsession.query(Recipe).filter(Recipe.id == uuid.UUID(request.matchdict['id'])).first() + recipe = ( + request.dbsession.query(Recipe) + .filter(Recipe.id == uuid.UUID(request.matchdict["id"])) + .first() + ) if len(recipe.product.recipes) > 1: request.dbsession.delete(recipe) else: @@ -203,58 +304,106 @@ def delete(request): return recipe_info(None, request) -@view_config(request_method='GET', route_name='api_recipe_id', renderer='json', permission='Recipes') +@view_config( + request_method="GET", + route_name="api_recipe_id", + renderer="json", + permission="Recipes", +) def show_id(request): - return recipe_info(uuid.UUID(request.matchdict['id']), request) + return recipe_info(uuid.UUID(request.matchdict["id"]), request) -@view_config(request_method='GET', route_name='api_recipe', renderer='json', permission='Recipes') +@view_config( + request_method="GET", route_name="api_recipe", renderer="json", permission="Recipes" +) def show_blank(request): return recipe_info(None, request) -@view_config(request_method='GET', route_name='api_recipe', renderer='json', request_param='list', - permission='Authenticated') +@view_config( + request_method="GET", + route_name="api_recipe", + renderer="json", + request_param="list", + permission="Authenticated", +) def show_list(request): - list = request.dbsession.query(Recipe).join(Recipe.product) \ - .filter(Recipe.effective_to == None) \ - .order_by(Recipe.product_id) \ - .order_by(desc(Recipe.valid_to)) \ + list = ( + request.dbsession.query(Recipe) + .join(Recipe.product) + .filter(Recipe.effective_to == None) + .order_by(Recipe.product_id) + .order_by(desc(Recipe.valid_to)) .all() + ) recipes = [] product_id = None for item in list: if item.product_id != product_id: - recipe = {'ProductID': item.product_id, 'Name': item.product.name, - 'ProductGroup': item.product.product_group.name, 'Prices': []} + recipe = { + "ProductID": item.product_id, + "Name": item.product.name, + "ProductGroup": item.product.product_group.name, + "Prices": [], + } recipes.append(recipe) product_id = item.product_id costing = 0 if item.product.is_sold and item.sale_price != 0 and item.cost_price != 0: costing = item.cost_price / item.sale_price - recipe['Prices'].append( - {'ValidFrom': item.valid_from.strftime('%d-%b-%Y'), 'ValidTo': item.valid_to.strftime('%d-%b-%Y'), - 'CostPrice': item.cost_price, 'SalePrice': item.sale_price, 'Costing': costing, - 'Url': request.route_url('recipe_id', id=item.id)}) + recipe["Prices"].append( + { + "ValidFrom": item.valid_from.strftime("%d-%b-%Y"), + "ValidTo": item.valid_to.strftime("%d-%b-%Y"), + "CostPrice": item.cost_price, + "SalePrice": item.sale_price, + "Costing": costing, + "Url": request.route_url("recipe_id", id=item.id), + } + ) return recipes def recipe_info(id, request): if id is None: - info = {'Quantity': 1, 'ValidFrom': session_period_start(request), 'ValidTo': session_period_finish(request), - 'RecipeItems': []} + info = { + "Quantity": 1, + "ValidFrom": session_period_start(request), + "ValidTo": session_period_finish(request), + "RecipeItems": [], + } else: recipe = request.dbsession.query(Recipe).filter(Recipe.id == id).one() - info = {'RecipeID': recipe.id, - 'Product': {'ProductID': recipe.product_id, 'Name': recipe.product.name, 'Units': recipe.product.units, - 'SalePrice': recipe.product.sale_price, 'IsSold': recipe.product.is_sold}, - 'Quantity': recipe.quantity, 'SalePrice': recipe.sale_price, 'CostPrice': recipe.cost_price, - 'ValidFrom': recipe.valid_from.strftime('%d-%b-%Y'), 'ValidTo': recipe.valid_to.strftime('%d-%b-%Y'), - 'RecipeItems': []} + info = { + "RecipeID": recipe.id, + "Product": { + "ProductID": recipe.product_id, + "Name": recipe.product.name, + "Units": recipe.product.units, + "SalePrice": recipe.product.sale_price, + "IsSold": recipe.product.is_sold, + }, + "Quantity": recipe.quantity, + "SalePrice": recipe.sale_price, + "CostPrice": recipe.cost_price, + "ValidFrom": recipe.valid_from.strftime("%d-%b-%Y"), + "ValidTo": recipe.valid_to.strftime("%d-%b-%Y"), + "RecipeItems": [], + } for item in recipe.recipe_items: - info['RecipeItems'].append({ - 'Product': {'ProductID': item.product.id, 'Name': item.product.name, 'Units': item.product.units, - 'FractionUnits': item.product.fraction_units, 'Fraction': item.product.fraction, - 'ProductYield': item.product.product_yield}, - 'Quantity': item.quantity, 'Price': item.price}) + info["RecipeItems"].append( + { + "Product": { + "ProductID": item.product.id, + "Name": item.product.name, + "Units": item.product.units, + "FractionUnits": item.product.fraction_units, + "Fraction": item.product.fraction, + "ProductYield": item.product.product_yield, + }, + "Quantity": item.quantity, + "Price": item.price, + } + ) return info diff --git a/brewman/views/reports/balance_sheet.py b/brewman/views/reports/balance_sheet.py index a7d7e1f1..b9881a75 100644 --- a/brewman/views/reports/balance_sheet.py +++ b/brewman/views/reports/balance_sheet.py @@ -13,29 +13,43 @@ from brewman.views.reports.profit_loss import get_accumulated_profit from brewman.views.services.session import session_period_finish -@view_config(request_method='GET', route_name='balance_sheet', permission='Balance Sheet') -@view_config(request_method='GET', route_name='balance_sheet_date', permission='Balance Sheet') +@view_config( + request_method="GET", route_name="balance_sheet", permission="Balance Sheet" +) +@view_config( + request_method="GET", route_name="balance_sheet_date", permission="Balance Sheet" +) def html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='GET', route_name='api_balance_sheet', renderer='json', permission='Balance Sheet') +@view_config( + request_method="GET", + route_name="api_balance_sheet", + renderer="json", + permission="Balance Sheet", +) def report_blank(request): - return {'date': session_period_finish(request), 'body': [], 'footer': []} + return {"date": session_period_finish(request), "body": [], "footer": []} -@view_config(request_method='GET', route_name='api_balance_sheet_date', renderer='json', permission='Balance Sheet') +@view_config( + request_method="GET", + route_name="api_balance_sheet_date", + renderer="json", + permission="Balance Sheet", +) def report_data(request): - date = request.matchdict.get('date', None) + date = request.matchdict.get("date", None) body, footer = build_balance_sheet(date, request.dbsession) - return {'date': date, 'body': body, 'footer': footer} + return {"date": date, "body": body, "footer": footer} def build_balance_sheet(finish_date, dbsession): if not isinstance(finish_date, datetime.datetime): - finish_date = datetime.datetime.strptime(finish_date, '%d-%b-%Y') + finish_date = datetime.datetime.strptime(finish_date, "%d-%b-%Y") type_list = [i.id for i in AccountType.list() if i.balance_sheet == True] report = [] groups = dict() @@ -43,24 +57,46 @@ def build_balance_sheet(finish_date, dbsession): closing_stock = get_closing_stock(finish_date, dbsession) net_profit = get_accumulated_profit(finish_date, dbsession) - closing_stock total_amount = net_profit - report.append({'name': 'Net Loss' if net_profit >= 0 else 'Net Profit', 'subAmount': net_profit, 'order': 79}) + report.append( + { + "name": "Net Loss" if net_profit >= 0 else "Net Profit", + "subAmount": net_profit, + "order": 79, + } + ) capital_group = AccountType.by_id(5) - groups[capital_group.id] = {'group': capital_group.name, 'amount': total_amount, 'order': capital_group.order} + groups[capital_group.id] = { + "group": capital_group.name, + "amount": total_amount, + "order": capital_group.order, + } total_amount += closing_stock - report.append({'name': 'Closing Stock', 'subAmount': closing_stock, 'order': 20.001}) + report.append( + {"name": "Closing Stock", "subAmount": closing_stock, "order": 20.001} + ) asset_group = AccountType.by_id(4) - groups[asset_group.id] = {'group': asset_group.name, 'amount': closing_stock, 'order': asset_group.order} + groups[asset_group.id] = { + "group": asset_group.name, + "amount": closing_stock, + "order": asset_group.order, + } amount_sum = func.sum(Journal.amount * Journal.debit) - query = dbsession.query(AccountBase, amount_sum) \ - .join(Journal.voucher).join(Journal.account) \ - .filter(Voucher.date <= finish_date) \ - .filter(Voucher.type != VoucherType.by_name('Issue').id) \ - .filter(AccountBase.type.in_(type_list)) \ - .group_by(AccountBase).order_by(AccountBase.type).order_by(desc(func.abs(amount_sum))).all() + query = ( + dbsession.query(AccountBase, amount_sum) + .join(Journal.voucher) + .join(Journal.account) + .filter(Voucher.date <= finish_date) + .filter(Voucher.type != VoucherType.by_name("Issue").id) + .filter(AccountBase.type.in_(type_list)) + .group_by(AccountBase) + .order_by(AccountBase.type) + .order_by(desc(func.abs(amount_sum))) + .all() + ) counter = 0 sss = 0 @@ -70,17 +106,26 @@ def build_balance_sheet(finish_date, dbsession): sss += amount total_amount += amount if amount != 0: - counter += .001 + counter += 0.001 report.append( - {'name': account.name, 'subAmount': amount, 'order': account_type.order + counter}) + { + "name": account.name, + "subAmount": amount, + "order": account_type.order + counter, + } + ) if account_type.id in groups: - groups[account_type.id]['amount'] += amount + groups[account_type.id]["amount"] += amount else: - groups[account_type.id] = {'group': account_type.name, 'amount': amount, 'order': account_type.order} + groups[account_type.id] = { + "group": account_type.name, + "amount": amount, + "order": account_type.order, + } # Add Subtotals for item in groups.values(): report.append(item) - footer = {'name': 'Total', 'amount': total_amount, 'order': 100} - return sorted(report, key=lambda d: d['order']), footer + footer = {"name": "Total", "amount": total_amount, "order": 100} + return sorted(report, key=lambda d: d["order"]), footer diff --git a/brewman/views/reports/cash_flow.py b/brewman/views/reports/cash_flow.py index 8f5db123..8c80f403 100644 --- a/brewman/views/reports/cash_flow.py +++ b/brewman/views/reports/cash_flow.py @@ -11,147 +11,165 @@ from brewman.models.voucher import Voucher, Journal, VoucherType from brewman.views.services.session import session_period_start, session_period_finish -@view_config(request_method='GET', route_name='cash_flow', permission='Cash Flow') -@view_config(request_method='GET', route_name='cash_flow_id', permission='Cash Flow') +@view_config(request_method="GET", route_name="cash_flow", permission="Cash Flow") +@view_config(request_method="GET", route_name="cash_flow_id", permission="Cash Flow") def get_html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='GET', route_name='api_cash_flow', renderer='json', permission='Cash Flow') +@view_config( + request_method="GET", + route_name="api_cash_flow", + renderer="json", + permission="Cash Flow", +) def get_cash_flow(request): - start_date = request.GET.get('s', None) - finish_date = request.GET.get('f', None) + start_date = request.GET.get("s", None) + finish_date = request.GET.get("f", None) if start_date and finish_date: return build_report(request, start_date, finish_date) else: - return {'startDate': session_period_start(request), - 'finishDate': session_period_finish(request), 'body': [], 'footer': {}} + return { + "startDate": session_period_start(request), + "finishDate": session_period_finish(request), + "body": [], + "footer": {}, + } -@view_config(request_method='GET', route_name='api_cash_flow_id', renderer='json', permission='Cash Flow') +@view_config( + request_method="GET", + route_name="api_cash_flow_id", + renderer="json", + permission="Cash Flow", +) def get_cash_flow_id(request): - id = request.matchdict.get('id', None) - start_date = request.GET.get('s', None) - finish_date = request.GET.get('f', None) + id = request.matchdict.get("id", None) + start_date = request.GET.get("s", None) + finish_date = request.GET.get("f", None) return build_report_id(request, int(id), start_date, finish_date) def build_report(request, start_date, finish_date): - report = {'startDate': start_date, 'finishDate': finish_date} + report = {"startDate": start_date, "finishDate": finish_date} sub_voucher = aliased(Voucher) sub_journal = aliased(Journal) sub_account = aliased(AccountBase) - sub_query = request.dbsession.query(sub_voucher.id) \ - .join(sub_journal, sub_voucher.journals) \ - .join(sub_account, sub_journal.account) \ - .filter(sub_account.type == AccountType.by_name('Cash').id) \ - .filter(sub_voucher.date >= datetime.datetime.strptime(start_date, '%d-%b-%Y')) \ - .filter(sub_voucher.date <= datetime.datetime.strptime(finish_date, '%d-%b-%Y')).subquery() + sub_query = ( + request.dbsession.query(sub_voucher.id) + .join(sub_journal, sub_voucher.journals) + .join(sub_account, sub_journal.account) + .filter(sub_account.type == AccountType.by_name("Cash").id) + .filter(sub_voucher.date >= datetime.datetime.strptime(start_date, "%d-%b-%Y")) + .filter(sub_voucher.date <= datetime.datetime.strptime(finish_date, "%d-%b-%Y")) + .subquery() + ) - query = request.dbsession.query( - AccountBase.type, func.sum(Journal.signed_amount) - ).join( - Journal, Voucher.journals - ).join( - AccountBase, Journal.account - ).filter( - Voucher.id.in_(sub_query) - ).filter( - AccountBase.type != AccountType.by_name('Cash').id - ).group_by( - AccountBase.type - ).order_by( - func.sum(Journal.signed_amount) - ).all() + query = ( + request.dbsession.query(AccountBase.type, func.sum(Journal.signed_amount)) + .join(Journal, Voucher.journals) + .join(AccountBase, Journal.account) + .filter(Voucher.id.in_(sub_query)) + .filter(AccountBase.type != AccountType.by_name("Cash").id) + .group_by(AccountBase.type) + .order_by(func.sum(Journal.signed_amount)) + .all() + ) total_amount = 0 - cf = {'operating': [], 'investing': [], 'financing': []} + cf = {"operating": [], "investing": [], "financing": []} for account_type, amount in query: lt = AccountType.by_id(account_type) - total_amount += (amount * -1) + total_amount += amount * -1 cf[lt.cash_flow_classification.lower()].append( { - 'name': lt.name, - 'url': request.route_url( - 'cash_flow_id', + "name": lt.name, + "url": request.route_url( + "cash_flow_id", id=str(lt.id), - _query={'startDate': start_date, 'finishDate': finish_date} + _query={"startDate": start_date, "finishDate": finish_date}, ), - 'amount': amount * -1 + "amount": amount * -1, } ) - report['body'] = cf + report["body"] = cf - opening = request.dbsession.query( - func.sum(Journal.amount * Journal.debit) - ).join(Journal.voucher).join( - Journal.account - ).filter(Voucher.date < start_date).filter( - Voucher.type != VoucherType.by_name('Issue').id - ).filter( - AccountBase.type == AccountType.by_name('Cash').id - ).scalar() + opening = ( + request.dbsession.query(func.sum(Journal.amount * Journal.debit)) + .join(Journal.voucher) + .join(Journal.account) + .filter(Voucher.date < start_date) + .filter(Voucher.type != VoucherType.by_name("Issue").id) + .filter(AccountBase.type == AccountType.by_name("Cash").id) + .scalar() + ) - closing = request.dbsession.query( - func.sum(Journal.amount * Journal.debit) - ).join(Journal.voucher).join( - Journal.account - ).filter(Voucher.date <= finish_date).filter( - Voucher.type != VoucherType.by_name('Issue').id - ).filter( - AccountBase.type == AccountType.by_name('Cash').id - ).scalar() + closing = ( + request.dbsession.query(func.sum(Journal.amount * Journal.debit)) + .join(Journal.voucher) + .join(Journal.account) + .filter(Voucher.date <= finish_date) + .filter(Voucher.type != VoucherType.by_name("Issue").id) + .filter(AccountBase.type == AccountType.by_name("Cash").id) + .scalar() + ) - report['Footer'] = [{'name': 'Net increase in cash and cash equivalents', 'amount': total_amount}, - {'name': 'Cash and cash equivalents at beginning of period', 'amount': opening}, - {'name': 'Cash and cash equivalents at end of period', 'amount': closing}] + report["Footer"] = [ + {"name": "Net increase in cash and cash equivalents", "amount": total_amount}, + {"name": "Cash and cash equivalents at beginning of period", "amount": opening}, + {"name": "Cash and cash equivalents at end of period", "amount": closing}, + ] return report def build_report_id(request, account_type, start_date, finish_date): - report = {'startDate': start_date, 'finishDate': finish_date, 'body': {'details': []}} + report = { + "startDate": start_date, + "finishDate": finish_date, + "body": {"details": []}, + } sub_voucher = aliased(Voucher) sub_journal = aliased(Journal) sub_account = aliased(AccountBase) - sub_query = request.dbsession.query( - sub_voucher.id - ).join( - sub_journal, sub_voucher.journals - ).join( - sub_account, sub_journal.account - ).filter( - sub_account.type == AccountType.by_name('Cash').id - ).filter( - sub_voucher.date >= datetime.datetime.strptime(start_date, '%d-%b-%Y') - ).filter( - sub_voucher.date <= datetime.datetime.strptime(finish_date, '%d-%b-%Y') - ).subquery() + sub_query = ( + request.dbsession.query(sub_voucher.id) + .join(sub_journal, sub_voucher.journals) + .join(sub_account, sub_journal.account) + .filter(sub_account.type == AccountType.by_name("Cash").id) + .filter(sub_voucher.date >= datetime.datetime.strptime(start_date, "%d-%b-%Y")) + .filter(sub_voucher.date <= datetime.datetime.strptime(finish_date, "%d-%b-%Y")) + .subquery() + ) - query = request.dbsession.query(AccountBase, func.sum(Journal.signed_amount)) \ - .join(Journal, Voucher.journals) \ - .join(AccountBase, Journal.account) \ - .filter(Voucher.id.in_(sub_query)) \ - .filter(AccountBase.type == account_type) \ - .group_by(AccountBase) \ - .order_by(desc(func.sum(Journal.amount))).all() + query = ( + request.dbsession.query(AccountBase, func.sum(Journal.signed_amount)) + .join(Journal, Voucher.journals) + .join(AccountBase, Journal.account) + .filter(Voucher.id.in_(sub_query)) + .filter(AccountBase.type == account_type) + .group_by(AccountBase) + .order_by(desc(func.sum(Journal.amount))) + .all() + ) total_amount = 0 for account, amount in query: - total_amount += (amount * -1) - report['body']['details'].append( + total_amount += amount * -1 + report["body"]["details"].append( { - 'name': account.name, - 'url': request.route_url( - 'ledger_id', id=account.id, - _query={'startDate': start_date, 'finishDate': finish_date} + "name": account.name, + "url": request.route_url( + "ledger_id", + id=account.id, + _query={"startDate": start_date, "finishDate": finish_date}, ), - 'amount': amount * -1 + "amount": amount * -1, } ) - report['footer'] = [{'name': 'total', 'amount': total_amount}] + report["footer"] = [{"name": "total", "amount": total_amount}] return report diff --git a/brewman/views/reports/closing_stock.py b/brewman/views/reports/closing_stock.py index 8c772adf..1512e006 100644 --- a/brewman/views/reports/closing_stock.py +++ b/brewman/views/reports/closing_stock.py @@ -10,73 +10,106 @@ from brewman.models.voucher import Voucher, Journal, Inventory from brewman.views.services.session import session_period_finish -@view_config(request_method='GET', route_name='closing_stock', permission='Closing Stock') -@view_config(request_method='GET', route_name='closing_stock_date', permission='Closing Stock') +@view_config( + request_method="GET", route_name="closing_stock", permission="Closing Stock" +) +@view_config( + request_method="GET", route_name="closing_stock_date", permission="Closing Stock" +) def html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='GET', route_name='api_closing_stock', renderer='json', permission='Closing Stock') +@view_config( + request_method="GET", + route_name="api_closing_stock", + renderer="json", + permission="Closing Stock", +) def report_blank(request): - return {'date': session_period_finish(request), 'body': []} + return {"date": session_period_finish(request), "body": []} -@view_config(request_method='GET', route_name='api_closing_stock_date', renderer='json', permission='Closing Stock') +@view_config( + request_method="GET", + route_name="api_closing_stock_date", + renderer="json", + permission="Closing Stock", +) def report_data(request): - date = request.matchdict.get('date', None) - return {'date': date, 'body': build_report(date, request.dbsession)} + date = request.matchdict.get("date", None) + return {"date": date, "body": build_report(date, request.dbsession)} def build_report(date, dbsession): - date = datetime.datetime.strptime(date, '%d-%b-%Y') - amount_sum = func.sum(Journal.debit * Inventory.quantity * Inventory.rate * (1 + Inventory.tax)).label('amount') - quantity_sum = func.sum(Journal.debit * Inventory.quantity).label('quantity') - query = dbsession.query(Product, quantity_sum, amount_sum) \ - .join(Product.inventories).join(Inventory.voucher).join(Voucher.journals) \ - .filter(Voucher.date <= date) \ - .filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase()) \ - .group_by(Product) \ - .order_by(amount_sum.desc()).all() + date = datetime.datetime.strptime(date, "%d-%b-%Y") + amount_sum = func.sum( + Journal.debit * Inventory.quantity * Inventory.rate * (1 + Inventory.tax) + ).label("amount") + quantity_sum = func.sum(Journal.debit * Inventory.quantity).label("quantity") + query = ( + dbsession.query(Product, quantity_sum, amount_sum) + .join(Product.inventories) + .join(Inventory.voucher) + .join(Voucher.journals) + .filter(Voucher.date <= date) + .filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase()) + .group_by(Product) + .order_by(amount_sum.desc()) + .all() + ) body = [] for product, quantity, amount in query: if quantity != 0 and amount != 0: - body.append({'product': product.full_name, 'group': product.product_group.name, - 'quantity': quantity, 'amount': amount}) + body.append( + { + "product": product.full_name, + "group": product.product_group.name, + "quantity": quantity, + "amount": amount, + } + ) return body def get_opening_stock(start_date, dbsession): - opening_stock = dbsession.query( - func.sum(Inventory.quantity * Inventory.rate * (1 + Inventory.tax) * Journal.debit) - ).join( - Journal.voucher - ).join( - Journal.account - ).join( - Voucher.inventories - ).filter( - Voucher.date < start_date - ).filter( - Journal.cost_centre_id == CostCentre.cost_centre_purchase() - ).scalar() + opening_stock = ( + dbsession.query( + func.sum( + Inventory.quantity + * Inventory.rate + * (1 + Inventory.tax) + * Journal.debit + ) + ) + .join(Journal.voucher) + .join(Journal.account) + .join(Voucher.inventories) + .filter(Voucher.date < start_date) + .filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase()) + .scalar() + ) return 0 if opening_stock is None else opening_stock def get_closing_stock(finish_date, dbsession): - closing_stock = dbsession.query( - func.sum(Inventory.quantity * Inventory.rate * (1 + Inventory.tax) * Journal.debit) - ).join( - Journal.voucher - ).join( - Journal.account - ).join( - Voucher.inventories - ).filter( - Voucher.date <= finish_date - ).filter( - Journal.cost_centre_id == CostCentre.cost_centre_purchase() - ).scalar() + closing_stock = ( + dbsession.query( + func.sum( + Inventory.quantity + * Inventory.rate + * (1 + Inventory.tax) + * Journal.debit + ) + ) + .join(Journal.voucher) + .join(Journal.account) + .join(Voucher.inventories) + .filter(Voucher.date <= finish_date) + .filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase()) + .scalar() + ) return 0 if closing_stock is None else closing_stock diff --git a/brewman/views/reports/daybook.py b/brewman/views/reports/daybook.py index 8397e1ad..72d5f9d3 100644 --- a/brewman/views/reports/daybook.py +++ b/brewman/views/reports/daybook.py @@ -10,32 +10,45 @@ from brewman.views.services.session import session_period_finish, session_period from brewman.views.services.voucher import get_edit_url -@view_config(request_method='GET', route_name='daybook', permission='Daybook') +@view_config(request_method="GET", route_name="daybook", permission="Daybook") def daybook_get(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='GET', route_name='api_daybook', renderer='json', permission='Daybook') +@view_config( + request_method="GET", + route_name="api_daybook", + renderer="json", + permission="Daybook", +) def daybook_report(request): - start_date = request.GET.get('s', None) - finish_date = request.GET.get('f', None) + start_date = request.GET.get("s", None) + finish_date = request.GET.get("f", None) if start_date and finish_date: return build_report(request, start_date, finish_date) else: - return {'startDate': session_period_start(request), - 'finishDate': session_period_finish(request), 'body': []} + return { + "startDate": session_period_start(request), + "finishDate": session_period_finish(request), + "body": [], + } def build_report(request, start_date, finish_date): - report = {'startDate': start_date, 'finishDate': finish_date, 'body': []} + report = {"startDate": start_date, "finishDate": finish_date, "body": []} - query = request.dbsession.query(Voucher).options(joinedload_all(Voucher.journals, Journal.account, innerjoin=True)) \ - .filter(Voucher.date >= datetime.datetime.strptime(start_date, '%d-%b-%Y')) \ - .filter(Voucher.date <= datetime.datetime.strptime(finish_date, '%d-%b-%Y')) \ - .filter(Voucher.type != VoucherType.by_name('Issue').id) \ - .order_by(Voucher.date).order_by(Voucher.last_edit_date).all() + query = ( + request.dbsession.query(Voucher) + .options(joinedload_all(Voucher.journals, Journal.account, innerjoin=True)) + .filter(Voucher.date >= datetime.datetime.strptime(start_date, "%d-%b-%Y")) + .filter(Voucher.date <= datetime.datetime.strptime(finish_date, "%d-%b-%Y")) + .filter(Voucher.type != VoucherType.by_name("Issue").id) + .order_by(Voucher.date) + .order_by(Voucher.last_edit_date) + .all() + ) for voucher in query: debit = 0 @@ -52,11 +65,18 @@ def build_report(request, start_date, finish_date): name_debit = name_debit[:-3] name_credit = name_credit[:-3] - report['body'].append({ - 'id': voucher.id, 'date': voucher.date.strftime('%d-%b-%Y'), 'url': get_edit_url(request, voucher), - 'type': VoucherType.by_id(voucher.type).name, - 'narration': voucher.narration, 'posted': voucher.posted, - 'debitText': name_debit, 'debitAmount': debit, - 'creditText': name_credit, 'creditAmount': credit - }) + report["body"].append( + { + "id": voucher.id, + "date": voucher.date.strftime("%d-%b-%Y"), + "url": get_edit_url(request, voucher), + "type": VoucherType.by_id(voucher.type).name, + "narration": voucher.narration, + "posted": voucher.posted, + "debitText": name_debit, + "debitAmount": debit, + "creditText": name_credit, + "creditAmount": credit, + } + ) return report diff --git a/brewman/views/reports/ledger.py b/brewman/views/reports/ledger.py index e3951f1d..c68e6794 100644 --- a/brewman/views/reports/ledger.py +++ b/brewman/views/reports/ledger.py @@ -13,45 +13,69 @@ from brewman.views.services.session import session_period_start, session_period_ from brewman.views.services.voucher import get_edit_url -@view_config(request_method='GET', route_name='ledger_id', permission='Ledger') -@view_config(request_method='GET', route_name='ledger', permission='Ledger') +@view_config(request_method="GET", route_name="ledger_id", permission="Ledger") +@view_config(request_method="GET", route_name="ledger", permission="Ledger") def html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='GET', route_name='api_ledger', renderer='json', permission='Ledger') +@view_config( + request_method="GET", route_name="api_ledger", renderer="json", permission="Ledger" +) def show_blank(request): - return {'startDate': session_period_start(request), - 'finishDate': session_period_finish(request), 'account': None, 'body': []} + return { + "startDate": session_period_start(request), + "finishDate": session_period_finish(request), + "account": None, + "body": [], + } -@view_config(request_method='GET', route_name='api_ledger_id', renderer='json', permission='Ledger', trans=True) +@view_config( + request_method="GET", + route_name="api_ledger_id", + renderer="json", + permission="Ledger", + trans=True, +) def show_data(request): - account = request.dbsession.query(AccountBase).filter(AccountBase.id == uuid.UUID(request.matchdict['id'])).first() - start_date = request.GET.get('s', session_period_start(request)) - finish_date = request.GET.get('f', session_period_finish(request)) - info = {'startDate': start_date, 'finishDate': finish_date, - 'account': {'id': account.id, 'name': account.name}, - 'body': []} + account = ( + request.dbsession.query(AccountBase) + .filter(AccountBase.id == uuid.UUID(request.matchdict["id"])) + .first() + ) + start_date = request.GET.get("s", session_period_start(request)) + finish_date = request.GET.get("f", session_period_finish(request)) + info = { + "startDate": start_date, + "finishDate": finish_date, + "account": {"id": account.id, "name": account.name}, + "body": [], + } build_report(request, info) return info def build_report(request, info): - account_id = info['account']['id'] - start_date = info['startDate'] - finish_date = info['finishDate'] + account_id = info["account"]["id"] + start_date = info["startDate"] + finish_date = info["finishDate"] opening = opening_balance(account_id, start_date, request.dbsession) - info['body'].append(opening) + info["body"].append(opening) - query = request.dbsession.query(Voucher).options(joinedload_all(Voucher.journals, Journal.account, innerjoin=True)) \ - .filter(Voucher.journals.any(Journal.account_id == account_id)) \ - .filter(Voucher.date >= datetime.datetime.strptime(start_date, '%d-%b-%Y')) \ - .filter(Voucher.date <= datetime.datetime.strptime(finish_date, '%d-%b-%Y')) \ - .filter(Voucher.type != VoucherType.by_name('Issue').id) \ - .order_by(Voucher.date).order_by(Voucher.last_edit_date).all() + query = ( + request.dbsession.query(Voucher) + .options(joinedload_all(Voucher.journals, Journal.account, innerjoin=True)) + .filter(Voucher.journals.any(Journal.account_id == account_id)) + .filter(Voucher.date >= datetime.datetime.strptime(start_date, "%d-%b-%Y")) + .filter(Voucher.date <= datetime.datetime.strptime(finish_date, "%d-%b-%Y")) + .filter(Voucher.type != VoucherType.by_name("Issue").id) + .order_by(Voucher.date) + .order_by(Voucher.last_edit_date) + .all() + ) for voucher in query: debit = 0 @@ -71,19 +95,30 @@ def build_report(request, info): if journal.debit != journal_debit: name += "{0} / ".format(journal.account.name) name = name[:-3] - info['body'].append( - {'id': voucher.id, 'date': voucher.date.strftime('%d-%b-%Y'), 'name': name, - 'url': get_edit_url(request, voucher), 'type': VoucherType.by_id(voucher.type).name, - 'narration': voucher.narration, 'debit': debit, 'credit': credit, 'posted': voucher.posted}) + info["body"].append( + { + "id": voucher.id, + "date": voucher.date.strftime("%d-%b-%Y"), + "name": name, + "url": get_edit_url(request, voucher), + "type": VoucherType.by_id(voucher.type).name, + "narration": voucher.narration, + "debit": debit, + "credit": credit, + "posted": voucher.posted, + } + ) def opening_balance(account_id, start_date, dbsession): - opening = dbsession.query(func.sum(Journal.amount * Journal.debit)) \ - .join(Journal.voucher) \ - .filter(Voucher.date < datetime.datetime.strptime(start_date, '%d-%b-%Y')) \ - .filter(Voucher.type != VoucherType.by_name('Issue').id) \ - .filter(Journal.account_id == account_id) \ + opening = ( + dbsession.query(func.sum(Journal.amount * Journal.debit)) + .join(Journal.voucher) + .filter(Voucher.date < datetime.datetime.strptime(start_date, "%d-%b-%Y")) + .filter(Voucher.type != VoucherType.by_name("Issue").id) + .filter(Journal.account_id == account_id) .scalar() + ) opening = 0 if opening is None else opening if opening < 0: credit = opening * -1 @@ -91,5 +126,13 @@ def opening_balance(account_id, start_date, dbsession): else: debit = opening credit = 0 - return {'date': start_date, 'id': 'OB', 'name': 'Opening Balance', 'type': 'Opening Balance', - 'narration': '', 'debit': debit, 'credit': credit, 'posted': True} + return { + "date": start_date, + "id": "OB", + "name": "Opening Balance", + "type": "Opening Balance", + "narration": "", + "debit": debit, + "credit": credit, + "posted": True, + } diff --git a/brewman/views/reports/net_transactions.py b/brewman/views/reports/net_transactions.py index a8c42924..da64619a 100644 --- a/brewman/views/reports/net_transactions.py +++ b/brewman/views/reports/net_transactions.py @@ -11,42 +11,63 @@ from brewman.models.voucher import Voucher, Journal, VoucherType from brewman.views.services.session import session_period_finish, session_period_start -@view_config(request_method='GET', route_name='net_transactions', permission='Net Transactions') +@view_config( + request_method="GET", route_name="net_transactions", permission="Net Transactions" +) def html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='GET', route_name='api_net_transactions', renderer='json', permission='Net Transactions') +@view_config( + request_method="GET", + route_name="api_net_transactions", + renderer="json", + permission="Net Transactions", +) def report(request): - start_date = request.GET.get('s', None) - finish_date = request.GET.get('f', None) + start_date = request.GET.get("s", None) + finish_date = request.GET.get("f", None) if start_date and finish_date: - return {'startDate': start_date, 'finishDate': finish_date, - 'body': build_report(start_date, finish_date, request.dbsession)} + return { + "startDate": start_date, + "finishDate": finish_date, + "body": build_report(start_date, finish_date, request.dbsession), + } else: - return {'startDate': session_period_start(request), - 'finishDate': session_period_finish(request), 'body': []} + return { + "startDate": session_period_start(request), + "finishDate": session_period_finish(request), + "body": [], + } def build_report(start_date, finish_date, dbsession): if not isinstance(start_date, datetime.datetime): - start_date = datetime.datetime.strptime(start_date, '%d-%b-%Y') + start_date = datetime.datetime.strptime(start_date, "%d-%b-%Y") if not isinstance(finish_date, datetime.datetime): - finish_date = datetime.datetime.strptime(finish_date, '%d-%b-%Y') + finish_date = datetime.datetime.strptime(finish_date, "%d-%b-%Y") - amount_sum = func.sum(Journal.amount * Journal.debit).label('amount') - query = dbsession.query(AccountBase, amount_sum) \ - .join(Journal.voucher).join(Journal.account) \ - .filter(Voucher.date >= start_date) \ - .filter(Voucher.date <= finish_date) \ - .filter(Voucher.type != VoucherType.by_name('Issue').id) \ - .group_by(AccountBase).order_by(AccountBase.type).order_by(desc(func.abs(amount_sum))).all() + amount_sum = func.sum(Journal.amount * Journal.debit).label("amount") + query = ( + dbsession.query(AccountBase, amount_sum) + .join(Journal.voucher) + .join(Journal.account) + .filter(Voucher.date >= start_date) + .filter(Voucher.date <= finish_date) + .filter(Voucher.type != VoucherType.by_name("Issue").id) + .group_by(AccountBase) + .order_by(AccountBase.type) + .order_by(desc(func.abs(amount_sum))) + .all() + ) body = [] for account, amount in query: if amount != 0: - tag = 'debit' if amount > 0 else 'credit' - body.append({'type': account.type_object.name, 'name': account.name, tag: amount}) + tag = "debit" if amount > 0 else "credit" + body.append( + {"type": account.type_object.name, "name": account.name, tag: amount} + ) return body diff --git a/brewman/views/reports/product_ledger.py b/brewman/views/reports/product_ledger.py index 09b43c08..5ae46a3c 100644 --- a/brewman/views/reports/product_ledger.py +++ b/brewman/views/reports/product_ledger.py @@ -14,71 +14,103 @@ from brewman.views.services.session import session_period_start, session_period_ from brewman.views.services.voucher import get_edit_url -@view_config(request_method='GET', route_name='product_ledger_id', permission='Product Ledger') -@view_config(request_method='GET', route_name='product_ledger', permission='Product Ledger') +@view_config( + request_method="GET", route_name="product_ledger_id", permission="Product Ledger" +) +@view_config( + request_method="GET", route_name="product_ledger", permission="Product Ledger" +) def html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='GET', route_name='api_product_ledger', renderer='json', permission='Product Ledger') +@view_config( + request_method="GET", + route_name="api_product_ledger", + renderer="json", + permission="Product Ledger", +) def show_blank(request): - return {'startDate': session_period_start(request), - 'finishDate': session_period_finish(request), 'product': None, 'body': []} + return { + "startDate": session_period_start(request), + "finishDate": session_period_finish(request), + "product": None, + "body": [], + } -@view_config(request_method='GET', route_name='api_product_ledger_id', renderer='json', permission='Product Ledger', - trans=True) +@view_config( + request_method="GET", + route_name="api_product_ledger_id", + renderer="json", + permission="Product Ledger", + trans=True, +) def show_data(request): - id = to_uuid(request.matchdict['id']) + id = to_uuid(request.matchdict["id"]) if id is None: raise ValidationError("Invalid Product") product = request.dbsession.query(Product).filter(Product.id == id).first() - start_date = request.GET.get('s', session_period_start(request)) - finish_date = request.GET.get('f', session_period_finish(request)) - info = {'startDate': start_date, 'finishDate': finish_date, - 'product': {'id': product.id, 'name': product.name}, - 'body': []} + start_date = request.GET.get("s", session_period_start(request)) + finish_date = request.GET.get("f", session_period_finish(request)) + info = { + "startDate": start_date, + "finishDate": finish_date, + "product": {"id": product.id, "name": product.name}, + "body": [], + } build_report(request, info, request.dbsession) return info def build_report(request, info, dbsession): - product_id = info['product']['id'] - start_date = info['startDate'] - finish_date = info['finishDate'] + product_id = info["product"]["id"] + start_date = info["startDate"] + finish_date = info["finishDate"] - running_total_q, running_total_a, opening = opening_balance(product_id, start_date, dbsession) + running_total_q, running_total_a, opening = opening_balance( + product_id, start_date, dbsession + ) total_debit_q = running_total_q total_debit_a = running_total_a total_credit_q = 0 total_credit_a = 0 - info['body'].append(opening) + info["body"].append(opening) - query = request.dbsession.query(Voucher, Inventory, Journal).options( - joinedload(Journal.account, innerjoin=True), - joinedload(Journal.cost_centre, innerjoin=True)) \ - .filter(Voucher.id == Inventory.voucher_id) \ - .filter(Voucher.id == Journal.voucher_id) \ - .filter(Inventory.product_id == product_id) \ - .filter(Journal.cost_centre_id != CostCentre.cost_centre_purchase()) \ - .filter(Voucher.date >= datetime.datetime.strptime(start_date, '%d-%b-%Y')) \ - .filter(Voucher.date <= datetime.datetime.strptime(finish_date, '%d-%b-%Y')) \ - .order_by(Voucher.date).order_by(Voucher.last_edit_date).all() + query = ( + request.dbsession.query(Voucher, Inventory, Journal) + .options( + joinedload(Journal.account, innerjoin=True), + joinedload(Journal.cost_centre, innerjoin=True), + ) + .filter(Voucher.id == Inventory.voucher_id) + .filter(Voucher.id == Journal.voucher_id) + .filter(Inventory.product_id == product_id) + .filter(Journal.cost_centre_id != CostCentre.cost_centre_purchase()) + .filter(Voucher.date >= datetime.datetime.strptime(start_date, "%d-%b-%Y")) + .filter(Voucher.date <= datetime.datetime.strptime(finish_date, "%d-%b-%Y")) + .order_by(Voucher.date) + .order_by(Voucher.last_edit_date) + .all() + ) for row in query: journal_debit = row.Journal.debit * -1 - name = row.Journal.cost_centre.name if row.Voucher.type == VoucherType.by_name( - 'Issue').id else row.Journal.account.name + name = ( + row.Journal.cost_centre.name + if row.Voucher.type == VoucherType.by_name("Issue").id + else row.Journal.account.name + ) debit_q = row.Inventory.quantity if journal_debit == 1 else 0 debit_a = row.Inventory.amount if journal_debit == 1 else 0 credit_q = row.Inventory.quantity if journal_debit != 1 else 0 credit_a = row.Inventory.amount if journal_debit != 1 else 0 - running_total_q += (row.Inventory.quantity * journal_debit) - running_total_a += (row.Inventory.amount * journal_debit) + running_total_q += row.Inventory.quantity * journal_debit + running_total_a += row.Inventory.amount * journal_debit if journal_debit == 1: total_debit_q += row.Inventory.quantity @@ -87,54 +119,79 @@ def build_report(request, info, dbsession): total_credit_q += row.Inventory.quantity total_credit_a += row.Inventory.amount - info['body'].append({ - 'id': row.Voucher.id, 'date': row.Voucher.date.strftime('%d-%b-%Y'), 'name': name, - 'url': get_edit_url(request, row.Voucher), 'type': VoucherType.by_id(row.Voucher.type).name, - 'narration': row.Voucher.narration, - 'posted': row.Voucher.posted or VoucherType.by_id(row.Voucher.type).name == 'Issue', - 'debitQuantity': debit_q, 'debitAmount': debit_a, - 'creditQuantity': credit_q, 'creditAmount': credit_a, - 'runningQuantity': running_total_q, 'runningAmount': running_total_a - }) + info["body"].append( + { + "id": row.Voucher.id, + "date": row.Voucher.date.strftime("%d-%b-%Y"), + "name": name, + "url": get_edit_url(request, row.Voucher), + "type": VoucherType.by_id(row.Voucher.type).name, + "narration": row.Voucher.narration, + "posted": row.Voucher.posted + or VoucherType.by_id(row.Voucher.type).name == "Issue", + "debitQuantity": debit_q, + "debitAmount": debit_a, + "creditQuantity": credit_q, + "creditAmount": credit_a, + "runningQuantity": running_total_q, + "runningAmount": running_total_a, + } + ) - info['Footer'] = { - 'Date': finish_date, 'Name': 'Closing Balance', 'Type': 'Closing Balance', 'Narration': '', - 'DebitQ': total_debit_q, 'DebitA': total_debit_a, 'CreditQ': total_credit_q, 'CreditA': total_credit_a, - 'RunningQ': running_total_q, 'RunningA': running_total_a + info["Footer"] = { + "Date": finish_date, + "Name": "Closing Balance", + "Type": "Closing Balance", + "Narration": "", + "DebitQ": total_debit_q, + "DebitA": total_debit_a, + "CreditQ": total_credit_q, + "CreditA": total_credit_a, + "RunningQ": running_total_q, + "RunningA": running_total_a, } def opening_balance(product_id, start_date, dbsession): - quantity, amount = dbsession.query( - func.sum(Inventory.quantity * Journal.debit), func.sum(Inventory.amount * Journal.debit) - ).join( - Voucher - ).filter( - Voucher.id == Inventory.voucher_id - ).filter( - Voucher.id == Journal.voucher_id - ).filter( - Inventory.product_id == product_id - ).filter( - Journal.cost_centre_id == CostCentre.cost_centre_purchase() - ).filter( - Voucher.date < datetime.datetime.strptime(start_date, '%d-%b-%Y') - ).one() + quantity, amount = ( + dbsession.query( + func.sum(Inventory.quantity * Journal.debit), + func.sum(Inventory.amount * Journal.debit), + ) + .join(Voucher) + .filter(Voucher.id == Inventory.voucher_id) + .filter(Voucher.id == Journal.voucher_id) + .filter(Inventory.product_id == product_id) + .filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase()) + .filter(Voucher.date < datetime.datetime.strptime(start_date, "%d-%b-%Y")) + .one() + ) if quantity and quantity > 0: debit_quantity = quantity debit_amount = amount else: - debit_quantity = '' - debit_amount = '' + debit_quantity = "" + debit_amount = "" if quantity is None: quantity = 0 amount = 0 - return quantity, amount, { - 'date': start_date, 'name': 'Opening Balance', 'type': 'Opening Balance', 'narration': '', 'posted': True, - 'debitQuantity': debit_quantity, 'debitAmount': debit_amount, - 'creditQuantity': 0, 'creditAmount': 0, - 'runningQuantity': quantity, 'runningAmount': amount - } + return ( + quantity, + amount, + { + "date": start_date, + "name": "Opening Balance", + "type": "Opening Balance", + "narration": "", + "posted": True, + "debitQuantity": debit_quantity, + "debitAmount": debit_amount, + "creditQuantity": 0, + "creditAmount": 0, + "runningQuantity": quantity, + "runningAmount": amount, + }, + ) diff --git a/brewman/views/reports/profit_loss.py b/brewman/views/reports/profit_loss.py index c5a5f80b..0842eb4b 100644 --- a/brewman/views/reports/profit_loss.py +++ b/brewman/views/reports/profit_loss.py @@ -11,26 +11,37 @@ from brewman.views.reports.closing_stock import get_opening_stock, get_closing_s from brewman.views.services.session import session_period_start, session_period_finish -@view_config(request_method='GET', route_name='profit_loss', permission='Profit & Loss') +@view_config(request_method="GET", route_name="profit_loss", permission="Profit & Loss") def html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='GET', route_name='api_profit_loss', renderer='json', permission='Profit & Loss') +@view_config( + request_method="GET", + route_name="api_profit_loss", + renderer="json", + permission="Profit & Loss", +) def get_profit_loss(request): - start_date = request.GET.get('s', None) - finish_date = request.GET.get('f', None) + start_date = request.GET.get("s", None) + finish_date = request.GET.get("f", None) if start_date and finish_date: - report = {'startDate': start_date, 'finishDate': finish_date} - start_date = datetime.datetime.strptime(start_date, '%d-%b-%Y') - finish_date = datetime.datetime.strptime(finish_date, '%d-%b-%Y') - report['body'], report['footer'] = build_profit_loss(start_date, finish_date, request.dbsession) + report = {"startDate": start_date, "finishDate": finish_date} + start_date = datetime.datetime.strptime(start_date, "%d-%b-%Y") + finish_date = datetime.datetime.strptime(finish_date, "%d-%b-%Y") + report["body"], report["footer"] = build_profit_loss( + start_date, finish_date, request.dbsession + ) return report else: - return {'startDate': session_period_start(request), - 'finishDate': session_period_finish(request), 'body': [], 'footer': {}} + return { + "startDate": session_period_start(request), + "finishDate": session_period_finish(request), + "body": [], + "footer": {}, + } def build_profit_loss(start_date, finish_date, dbsession): @@ -39,23 +50,35 @@ def build_profit_loss(start_date, finish_date, dbsession): groups = dict() amount_sum = func.sum(Journal.amount * Journal.debit) - query = dbsession.query(AccountBase, amount_sum) \ - .join(Journal.voucher).join(Journal.account) \ - .filter(Voucher.date >= start_date) \ - .filter(Voucher.date <= finish_date) \ - .filter(Voucher.type != VoucherType.by_name('Issue').id) \ - .filter(AccountBase.type.in_(profit_type_list)) \ - .group_by(AccountBase).order_by(AccountBase.type).order_by(desc(func.abs(amount_sum))).all() + query = ( + dbsession.query(AccountBase, amount_sum) + .join(Journal.voucher) + .join(Journal.account) + .filter(Voucher.date >= start_date) + .filter(Voucher.date <= finish_date) + .filter(Voucher.type != VoucherType.by_name("Issue").id) + .filter(AccountBase.type.in_(profit_type_list)) + .group_by(AccountBase) + .order_by(AccountBase.type) + .order_by(desc(func.abs(amount_sum))) + .all() + ) # Get opening / closing stock opening_stock = get_opening_stock(start_date, dbsession) closing_stock = get_closing_stock(finish_date, dbsession) total_amount = (opening_stock - closing_stock) * -1 - report.append({'name': 'Opening Stock', 'amount': opening_stock * -1, 'order': 20.0001}) - report.append({'name': 'Closing Stock', 'amount': closing_stock, 'order': 29}) + report.append( + {"name": "Opening Stock", "amount": opening_stock * -1, "order": 20.0001} + ) + report.append({"name": "Closing Stock", "amount": closing_stock, "order": 29}) purchase_group = AccountType.by_id(2) - groups[purchase_group.id] = {'group': purchase_group.name, 'total': total_amount, 'order': purchase_group.order} + groups[purchase_group.id] = { + "group": purchase_group.name, + "total": total_amount, + "order": purchase_group.order, + } counter = 0 for account, amount in query: @@ -65,30 +88,47 @@ def build_profit_loss(start_date, finish_date, dbsession): total_amount += amount if amount != 0: - counter += .001 - report.append({'name': account.name, 'amount': amount, 'order': account_type.order + counter}) + counter += 0.001 + report.append( + { + "name": account.name, + "amount": amount, + "order": account_type.order + counter, + } + ) if account_type.id in groups: - groups[account_type.id]['total'] += amount + groups[account_type.id]["total"] += amount else: - groups[account_type.id] = {'group': account_type.name, 'total': amount, 'order': account_type.order} + groups[account_type.id] = { + "group": account_type.name, + "total": amount, + "order": account_type.order, + } # Add Subtotals for item in groups.values(): report.append(item) # Add Net - footer = footer = {'group': 'Net Profit' if total_amount > 0 else 'Net Loss', 'total': total_amount, 'order': 100} + footer = footer = { + "group": "Net Profit" if total_amount > 0 else "Net Loss", + "total": total_amount, + "order": 100, + } - return sorted(report, key=lambda d: d['order']), footer + return sorted(report, key=lambda d: d["order"]), footer def get_accumulated_profit(finish_date, dbsession): type_list = [i.id for i in AccountType.list() if i.balance_sheet is False] - accumulated_profit = dbsession.query(func.sum(Journal.amount * Journal.debit)) \ - .join(Journal.voucher).join(Journal.account) \ - .filter(Voucher.date <= finish_date) \ - .filter(Voucher.type != VoucherType.by_name('Issue').id) \ - .filter(AccountBase.type.in_(type_list)) \ + accumulated_profit = ( + dbsession.query(func.sum(Journal.amount * Journal.debit)) + .join(Journal.voucher) + .join(Journal.account) + .filter(Voucher.date <= finish_date) + .filter(Voucher.type != VoucherType.by_name("Issue").id) + .filter(AccountBase.type.in_(type_list)) .scalar() + ) return 0 if accumulated_profit is None else accumulated_profit diff --git a/brewman/views/reports/purchase_entries.py b/brewman/views/reports/purchase_entries.py index 5f7a98e1..ec3dda95 100644 --- a/brewman/views/reports/purchase_entries.py +++ b/brewman/views/reports/purchase_entries.py @@ -9,52 +9,70 @@ from brewman.views.services.session import session_period_start, session_period_ from brewman.views.services.voucher import get_edit_url -@view_config(request_method='GET', route_name='purchase_entries', permission='Purchase Entries') +@view_config( + request_method="GET", route_name="purchase_entries", permission="Purchase Entries" +) def html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='GET', route_name='api_purchase_entries', renderer='json', permission='Purchase Entries') +@view_config( + request_method="GET", + route_name="api_purchase_entries", + renderer="json", + permission="Purchase Entries", +) def report_blank(request): - return {'startDate': session_period_start(request), - 'finishDate': session_period_finish(request), 'body': []} + return { + "startDate": session_period_start(request), + "finishDate": session_period_finish(request), + "body": [], + } -@view_config(request_method='GET', route_name='api_purchase_entries', request_param='s', renderer='json', - permission='Purchase Entries') +@view_config( + request_method="GET", + route_name="api_purchase_entries", + request_param="s", + renderer="json", + permission="Purchase Entries", +) def report_data(request): - start_date = request.GET.get('s', None) - finish_date = request.GET.get('f', None) + start_date = request.GET.get("s", None) + finish_date = request.GET.get("f", None) return build_report(request, start_date, finish_date) def build_report(request, start_date, finish_date): - report = {'startDate': start_date, 'finishDate': finish_date, 'body': []} - start_date = datetime.datetime.strptime(start_date, '%d-%b-%Y') - finish_date = datetime.datetime.strptime(finish_date, '%d-%b-%Y') + report = {"startDate": start_date, "finishDate": finish_date, "body": []} + start_date = datetime.datetime.strptime(start_date, "%d-%b-%Y") + finish_date = datetime.datetime.strptime(finish_date, "%d-%b-%Y") - query = request.dbsession.query(Voucher) \ - .filter(Voucher.date >= start_date) \ - .filter(Voucher.date <= finish_date) \ - .filter(Voucher.type == VoucherType.by_name('Purchase').id) \ - .order_by(Voucher.date).all() + query = ( + request.dbsession.query(Voucher) + .filter(Voucher.date >= start_date) + .filter(Voucher.date <= finish_date) + .filter(Voucher.type == VoucherType.by_name("Purchase").id) + .order_by(Voucher.date) + .all() + ) for voucher in query: journal = [j for j in voucher.journals if j.debit == -1] journal = journal[0] for item in voucher.inventories: row = { - 'date': voucher.date.strftime('%d-%b-%Y'), - 'supplier': journal.account.name, - 'url': get_edit_url(request, voucher), - 'products': [], - 'product': item.product.full_name, - 'quantity': item.quantity, - 'rate': item.rate, - 'tax': item.tax, - 'amount': item.amount + "date": voucher.date.strftime("%d-%b-%Y"), + "supplier": journal.account.name, + "url": get_edit_url(request, voucher), + "products": [], + "product": item.product.full_name, + "quantity": item.quantity, + "rate": item.rate, + "tax": item.tax, + "amount": item.amount, } - report['body'].append(row) + report["body"].append(row) return report diff --git a/brewman/views/reports/purchases.py b/brewman/views/reports/purchases.py index 49905a18..f7135687 100644 --- a/brewman/views/reports/purchases.py +++ b/brewman/views/reports/purchases.py @@ -10,51 +10,82 @@ from brewman.models.voucher import Voucher, Journal, Inventory, VoucherType from brewman.views.services.session import session_period_start, session_period_finish -@view_config(request_method='GET', route_name='purchases', permission='Purchases') +@view_config(request_method="GET", route_name="purchases", permission="Purchases") def html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='GET', route_name='api_purchases', renderer='json', permission='Purchases') +@view_config( + request_method="GET", + route_name="api_purchases", + renderer="json", + permission="Purchases", +) def report_blank(request): return { - 'startDate': session_period_start(request), - 'finishDate': session_period_finish(request), - 'body': [], - 'footer': {} + "startDate": session_period_start(request), + "finishDate": session_period_finish(request), + "body": [], + "footer": {}, } -@view_config(request_method='GET', route_name='api_purchases', request_param='s', renderer='json', - permission='Purchases') +@view_config( + request_method="GET", + route_name="api_purchases", + request_param="s", + renderer="json", + permission="Purchases", +) def report_data(request): - start_date = request.GET.get('s', None) - finish_date = request.GET.get('f', None) + start_date = request.GET.get("s", None) + finish_date = request.GET.get("f", None) return build_report(request, start_date, finish_date) def build_report(request, start_date, finish_date): - report = {'startDate': start_date, 'finishDate': finish_date, 'body': [], 'footer':{}} + report = { + "startDate": start_date, + "finishDate": finish_date, + "body": [], + "footer": {}, + } - quantity_sum = func.sum(Journal.debit * Inventory.quantity).label('quantity') - amount_sum = func.sum(Journal.debit * Inventory.quantity * Inventory.rate * (1 + Inventory.tax)).label('amount') - query = request.dbsession.query(Product, quantity_sum, amount_sum) \ - .join(Product.inventories).join(Inventory.voucher).join(Voucher.journals) \ - .filter(Voucher.date >= datetime.datetime.strptime(start_date, '%d-%b-%Y')) \ - .filter(Voucher.date <= datetime.datetime.strptime(finish_date, '%d-%b-%Y')) \ - .filter(Voucher.type != VoucherType.by_name('Issue').id) \ - .filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase()) \ - .group_by(Product).order_by(desc(amount_sum)).all() + quantity_sum = func.sum(Journal.debit * Inventory.quantity).label("quantity") + amount_sum = func.sum( + Journal.debit * Inventory.quantity * Inventory.rate * (1 + Inventory.tax) + ).label("amount") + query = ( + request.dbsession.query(Product, quantity_sum, amount_sum) + .join(Product.inventories) + .join(Inventory.voucher) + .join(Voucher.journals) + .filter(Voucher.date >= datetime.datetime.strptime(start_date, "%d-%b-%Y")) + .filter(Voucher.date <= datetime.datetime.strptime(finish_date, "%d-%b-%Y")) + .filter(Voucher.type != VoucherType.by_name("Issue").id) + .filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase()) + .group_by(Product) + .order_by(desc(amount_sum)) + .all() + ) total_amount = 0 for product, quantity, amount in query: rate = amount / quantity if quantity != 0 else 0 total_amount += amount - row = {'name': product.full_name, 'quantity': quantity, 'rate': rate, 'amount': amount, - 'url': request.route_url('product_ledger_id', id=product.id, - _query={'startDate': start_date, 'finishDate': finish_date})} - report['body'].append(row) - report['footer'] = {'name': "Total", 'amount': total_amount} + row = { + "name": product.full_name, + "quantity": quantity, + "rate": rate, + "amount": amount, + "url": request.route_url( + "product_ledger_id", + id=product.id, + _query={"startDate": start_date, "finishDate": finish_date}, + ), + } + report["body"].append(row) + report["footer"] = {"name": "Total", "amount": total_amount} return report diff --git a/brewman/views/reports/raw_material_cost.py b/brewman/views/reports/raw_material_cost.py index 040afd05..b1ac50f5 100644 --- a/brewman/views/reports/raw_material_cost.py +++ b/brewman/views/reports/raw_material_cost.py @@ -11,51 +11,90 @@ from brewman.models.voucher import Voucher, Journal, Inventory from brewman.views.services.session import session_period_start, session_period_finish -@view_config(request_method='GET', route_name='raw_material_cost', permission='Raw Material Cost') -@view_config(request_method='GET', route_name='raw_material_cost_id', permission='Raw Material Cost') +@view_config( + request_method="GET", route_name="raw_material_cost", permission="Raw Material Cost" +) +@view_config( + request_method="GET", + route_name="raw_material_cost_id", + permission="Raw Material Cost", +) def get_html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='GET', route_name='api_raw_material_cost', renderer='json', permission='Raw Material Cost') +@view_config( + request_method="GET", + route_name="api_raw_material_cost", + renderer="json", + permission="Raw Material Cost", +) def report_blank(request): - return {'startDate': session_period_start(request), - 'finishDate': session_period_finish(request), 'body': [], 'footer': {}} + return { + "startDate": session_period_start(request), + "finishDate": session_period_finish(request), + "body": [], + "footer": {}, + } -@view_config(request_method='GET', route_name='api_raw_material_cost', request_param='s', renderer='json', - permission='Raw Material Cost') +@view_config( + request_method="GET", + route_name="api_raw_material_cost", + request_param="s", + renderer="json", + permission="Raw Material Cost", +) def report_data(request): - start_date = request.GET.get('s', None) - finish_date = request.GET.get('f', None) + start_date = request.GET.get("s", None) + finish_date = request.GET.get("f", None) return build_report(request, start_date, finish_date) -@view_config(request_method='GET', route_name='api_raw_material_cost_id', request_param='s', renderer='json', - permission='Raw Material Cost') +@view_config( + request_method="GET", + route_name="api_raw_material_cost_id", + request_param="s", + renderer="json", + permission="Raw Material Cost", +) def report_id(request): - id = request.matchdict.get('id', None) - start_date = request.GET.get('s', None) - finish_date = request.GET.get('f', None) + id = request.matchdict.get("id", None) + start_date = request.GET.get("s", None) + finish_date = request.GET.get("f", None) return build_report_id(request, uuid.UUID(id), start_date, finish_date) def build_report(request, start_date, finish_date): - report = {'startDate': start_date, 'finishDate': finish_date, 'body': [], 'footer': {}} + report = { + "startDate": start_date, + "finishDate": finish_date, + "body": [], + "footer": {}, + } - sum_issue = func.sum(case([(AccountBase.type == 2, Journal.signed_amount)], else_=0)).label('issue') - sum_sale = func.sum(case([(AccountBase.type == 3, Journal.signed_amount * -1)], else_=0)).label('sale') + sum_issue = func.sum( + case([(AccountBase.type == 2, Journal.signed_amount)], else_=0) + ).label("issue") + sum_sale = func.sum( + case([(AccountBase.type == 3, Journal.signed_amount * -1)], else_=0) + ).label("sale") - query = request.dbsession.query(CostCentre, sum_issue, sum_sale) \ - .join(CostCentre.journals).join(Journal.voucher).join(Journal.account) \ - .filter(Voucher.date >= datetime.datetime.strptime(start_date, '%d-%b-%Y')) \ - .filter(Voucher.date <= datetime.datetime.strptime(finish_date, '%d-%b-%Y')) \ - .filter(Journal.cost_centre_id != CostCentre.cost_centre_purchase()) \ - .filter(AccountBase.type.in_([2, 3])) \ - .group_by(CostCentre) \ - .order_by(sum_sale.desc()).all() + query = ( + request.dbsession.query(CostCentre, sum_issue, sum_sale) + .join(CostCentre.journals) + .join(Journal.voucher) + .join(Journal.account) + .filter(Voucher.date >= datetime.datetime.strptime(start_date, "%d-%b-%Y")) + .filter(Voucher.date <= datetime.datetime.strptime(finish_date, "%d-%b-%Y")) + .filter(Journal.cost_centre_id != CostCentre.cost_centre_purchase()) + .filter(AccountBase.type.in_([2, 3])) + .group_by(CostCentre) + .order_by(sum_sale.desc()) + .all() + ) issues = 0 sales = 0 @@ -63,32 +102,55 @@ def build_report(request, start_date, finish_date): issues += issue sales += sale rmc = 0 if sale == 0 else issue / sale - report['body'].append( - {'name': cost_centre.name, 'issue': issue, 'sale': sale, 'rmc': rmc, - 'url': request.route_url('raw_material_cost_id', id=str(cost_centre.id), - _query={'startDate': start_date, 'finishDate': finish_date})}) + report["body"].append( + { + "name": cost_centre.name, + "issue": issue, + "sale": sale, + "rmc": rmc, + "url": request.route_url( + "raw_material_cost_id", + id=str(cost_centre.id), + _query={"startDate": start_date, "finishDate": finish_date}, + ), + } + ) rmc = 0 if sales == 0 else issues / sales - report['footer'] = {'name': 'Total', 'issue': issues, 'sale': sales, 'rmc': rmc} + report["footer"] = {"name": "Total", "issue": issues, "sale": sales, "rmc": rmc} return report def build_report_id(request, cost_centre_id, start_date, finish_date): - report = {'id': cost_centre_id, 'startDate': start_date, 'finishDate': finish_date, 'body': []} + report = { + "id": cost_centre_id, + "startDate": start_date, + "finishDate": finish_date, + "body": [], + } - sum_quantity = func.sum(Inventory.quantity * Journal.debit).label('quantity') - sum_net = func.sum(Inventory.rate * Inventory.quantity * Journal.debit).label('net') - sum_gross = func.sum(Inventory.amount * Journal.debit).label('gross') + sum_quantity = func.sum(Inventory.quantity * Journal.debit).label("quantity") + sum_net = func.sum(Inventory.rate * Inventory.quantity * Journal.debit).label("net") + sum_gross = func.sum(Inventory.amount * Journal.debit).label("gross") - query = request.dbsession.query(Product, sum_quantity, sum_net, sum_gross) \ - .join(Product.inventories).join(Inventory.voucher).join(Voucher.journals).join(Product.product_group) \ - .filter(Voucher.date >= datetime.datetime.strptime(start_date, '%d-%b-%Y')) \ - .filter(Voucher.date <= datetime.datetime.strptime(finish_date, '%d-%b-%Y')) \ - .filter(Voucher.type == 3) \ - .filter(Journal.cost_centre_id == cost_centre_id) \ - .group_by(Product).group_by(Journal.debit).group_by(ProductGroup.name) \ - .order_by(ProductGroup.name).order_by(sum_net.desc()).all() + query = ( + request.dbsession.query(Product, sum_quantity, sum_net, sum_gross) + .join(Product.inventories) + .join(Inventory.voucher) + .join(Voucher.journals) + .join(Product.product_group) + .filter(Voucher.date >= datetime.datetime.strptime(start_date, "%d-%b-%Y")) + .filter(Voucher.date <= datetime.datetime.strptime(finish_date, "%d-%b-%Y")) + .filter(Voucher.type == 3) + .filter(Journal.cost_centre_id == cost_centre_id) + .group_by(Product) + .group_by(Journal.debit) + .group_by(ProductGroup.name) + .order_by(ProductGroup.name) + .order_by(sum_net.desc()) + .all() + ) groups = {} counter = 0 @@ -96,19 +158,33 @@ def build_report_id(request, cost_centre_id, start_date, finish_date): for product, quantity, net, gross in query: if product.product_group_id in groups: group = groups[product.product_group_id] - group['net'] += net - group['gross'] += gross + group["net"] += net + group["gross"] += gross else: counter += 500 - group = {'group': product.product_group.name, 'net': net, 'gross': gross, 'order': counter, 'heading': True} + group = { + "group": product.product_group.name, + "net": net, + "gross": gross, + "order": counter, + "heading": True, + } groups[product.product_group_id] = group counter += 1 list.append( - {'name': product.full_name, 'group': product.product_group.name, 'quantity': quantity, 'net': net, - 'gross': gross, 'order': counter, 'heading': False}) + { + "name": product.full_name, + "group": product.product_group.name, + "quantity": quantity, + "net": net, + "gross": gross, + "order": counter, + "heading": False, + } + ) for item in groups.values(): list.append(item) - report['body'] = sorted(list, key=lambda d: d['order']) + report["body"] = sorted(list, key=lambda d: d["order"]) return report diff --git a/brewman/views/reports/reconcile.py b/brewman/views/reports/reconcile.py index 8e134b64..0a5dc9ff 100644 --- a/brewman/views/reports/reconcile.py +++ b/brewman/views/reports/reconcile.py @@ -14,53 +14,82 @@ from brewman.views.services.session import session_period_start, session_period_ from brewman.views.services.voucher import get_edit_url -@view_config(request_method='GET', route_name='reconcile_id', permission='Reconcile') -@view_config(request_method='GET', route_name='reconcile', permission='Reconcile') +@view_config(request_method="GET", route_name="reconcile_id", permission="Reconcile") +@view_config(request_method="GET", route_name="reconcile", permission="Reconcile") def html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='GET', route_name='api_reconcile', renderer='json', permission='Reconcile') +@view_config( + request_method="GET", + route_name="api_reconcile", + renderer="json", + permission="Reconcile", +) def show_blank(request): - return {'startDate': session_period_start(request), - 'finishDate': session_period_finish(request), 'account': None, 'body': []} + return { + "startDate": session_period_start(request), + "finishDate": session_period_finish(request), + "account": None, + "body": [], + } -@view_config(request_method='GET', route_name='api_reconcile_id', renderer='json', permission='Reconcile', trans=True) +@view_config( + request_method="GET", + route_name="api_reconcile_id", + renderer="json", + permission="Reconcile", + trans=True, +) def show_data(request): - account = request.dbsession.query(AccountBase).filter(AccountBase.id == uuid.UUID(request.matchdict['id'])).first() - start_date = request.GET.get('s', session_period_start(request)) - finish_date = request.GET.get('f', session_period_finish(request)) - info = {'startDate': start_date, 'finishDate': finish_date, - 'account': {'id': account.id, 'name': account.name}, 'body': []} + account = ( + request.dbsession.query(AccountBase) + .filter(AccountBase.id == uuid.UUID(request.matchdict["id"])) + .first() + ) + start_date = request.GET.get("s", session_period_start(request)) + finish_date = request.GET.get("f", session_period_finish(request)) + info = { + "startDate": start_date, + "finishDate": finish_date, + "account": {"id": account.id, "name": account.name}, + "body": [], + } build_report(request, info, request.dbsession) return info def build_report(request, info, dbsession): - account_id = info['a`ccount']['id'] - start_date = info['startDate'] - finish_date = info['finishDate'] + account_id = info["a`ccount"]["id"] + start_date = info["startDate"] + finish_date = info["finishDate"] opening = opening_balance(account_id, start_date, dbsession) - info['body'].append(opening) + info["body"].append(opening) - query = request.dbsession.query(Voucher).options( - joinedload_all(Voucher.journals, Journal.account, innerjoin=True) - ).filter( - Voucher.journals.any(Journal.account_id == account_id) - ).filter( - or_( - Voucher.is_reconciled == False, - and_( - Voucher.reconcile_date >= datetime.datetime.strptime(start_date, '%d-%b-%Y'), - Voucher.reconcile_date <= datetime.datetime.strptime(finish_date, '%d-%b-%Y') + query = ( + request.dbsession.query(Voucher) + .options(joinedload_all(Voucher.journals, Journal.account, innerjoin=True)) + .filter(Voucher.journals.any(Journal.account_id == account_id)) + .filter( + or_( + Voucher.is_reconciled == False, + and_( + Voucher.reconcile_date + >= datetime.datetime.strptime(start_date, "%d-%b-%Y"), + Voucher.reconcile_date + <= datetime.datetime.strptime(finish_date, "%d-%b-%Y"), + ), ) ) - ).filter( - Voucher.type != VoucherType.by_name('Issue').id - ).order_by(Voucher.is_reconciled).order_by(Voucher.reconcile_date).order_by(Voucher.last_edit_date).all() + .filter(Voucher.type != VoucherType.by_name("Issue").id) + .order_by(Voucher.is_reconciled) + .order_by(Voucher.reconcile_date) + .order_by(Voucher.last_edit_date) + .all() + ) for voucher in query: debit = 0 @@ -80,21 +109,34 @@ def build_report(request, info, dbsession): if journal.debit != journal_debit: name += "{0} / ".format(journal.account.name) name = name[:-3] - info['body'].append( - {'id': voucher.id, 'date': voucher.date.strftime('%d-%b-%Y'), 'name': name, - 'url': get_edit_url(request, voucher), 'type': VoucherType.by_id(voucher.type).name, - 'narration': voucher.narration, 'debit': debit, 'credit': credit, 'isReconciled': voucher.is_reconciled, - 'reconcileDate': voucher.reconcile_date.strftime('%d-%b-%Y')}) + info["body"].append( + { + "id": voucher.id, + "date": voucher.date.strftime("%d-%b-%Y"), + "name": name, + "url": get_edit_url(request, voucher), + "type": VoucherType.by_id(voucher.type).name, + "narration": voucher.narration, + "debit": debit, + "credit": credit, + "isReconciled": voucher.is_reconciled, + "reconcileDate": voucher.reconcile_date.strftime("%d-%b-%Y"), + } + ) def opening_balance(account_id, start_date, dbsession): - opening = dbsession.query(func.sum(Journal.amount * Journal.debit)) \ - .join(Journal.voucher) \ - .filter(Voucher.reconcile_date < datetime.datetime.strptime(start_date, '%d-%b-%Y')) \ - .filter(Voucher.is_reconciled == True) \ - .filter(Voucher.type != VoucherType.by_name('Issue').id) \ - .filter(Journal.account_id == account_id) \ + opening = ( + dbsession.query(func.sum(Journal.amount * Journal.debit)) + .join(Journal.voucher) + .filter( + Voucher.reconcile_date < datetime.datetime.strptime(start_date, "%d-%b-%Y") + ) + .filter(Voucher.is_reconciled == True) + .filter(Voucher.type != VoucherType.by_name("Issue").id) + .filter(Journal.account_id == account_id) .scalar() + ) opening = 0 if opening is None else opening if opening < 0: credit = opening * -1 @@ -103,29 +145,54 @@ def opening_balance(account_id, start_date, dbsession): debit = opening credit = 0 return { - 'date': start_date, 'id': None, 'name': 'Opening Balance', 'type': 'Opening Balance', 'narration': '', - 'debit': debit, 'credit': credit, 'running': opening, 'isReconciled': True, 'reconcileDate': start_date + "date": start_date, + "id": None, + "name": "Opening Balance", + "type": "Opening Balance", + "narration": "", + "debit": debit, + "credit": credit, + "running": opening, + "isReconciled": True, + "reconcileDate": start_date, } -@view_config(request_method='POST', route_name='api_reconcile_id', renderer='json', permission='Reconcile') +@view_config( + request_method="POST", + route_name="api_reconcile_id", + renderer="json", + permission="Reconcile", +) def save(request): - account = request.dbsession.query(AccountBase).filter(AccountBase.id == uuid.UUID(request.matchdict['id'])).first() - start_date = request.GET.get('s', session_period_start(request)) - finish_date = request.GET.get('f', session_period_finish(request)) - for item in request.json_body['body']: - if 'id' not in item or item['id'] is None: + account = ( + request.dbsession.query(AccountBase) + .filter(AccountBase.id == uuid.UUID(request.matchdict["id"])) + .first() + ) + start_date = request.GET.get("s", session_period_start(request)) + finish_date = request.GET.get("f", session_period_finish(request)) + for item in request.json_body["body"]: + if "id" not in item or item["id"] is None: continue - voucher = request.dbsession.query(Voucher).filter(Voucher.id == uuid.UUID(item['id'])).first() - is_reconciled = item['isReconciled'] - reconcile_date = datetime.datetime.strptime(item['reconcileDate'], '%d-%b-%Y') + voucher = ( + request.dbsession.query(Voucher) + .filter(Voucher.id == uuid.UUID(item["id"])) + .first() + ) + is_reconciled = item["isReconciled"] + reconcile_date = datetime.datetime.strptime(item["reconcileDate"], "%d-%b-%Y") voucher.is_reconciled = is_reconciled voucher.reconcile_date = reconcile_date transaction.commit() - info = {'startDate': start_date, 'finishDate': finish_date, - 'account': {'id': account.id, 'name': account.name}, - 'body': [], 'footer': {}} + info = { + "startDate": start_date, + "finishDate": finish_date, + "account": {"id": account.id, "name": account.name}, + "body": [], + "footer": {}, + } build_report(request, info, request.dbsession) return info diff --git a/brewman/views/reports/stock_movement.py b/brewman/views/reports/stock_movement.py index b08f639a..f7680589 100644 --- a/brewman/views/reports/stock_movement.py +++ b/brewman/views/reports/stock_movement.py @@ -10,77 +10,116 @@ from brewman.models.voucher import Voucher, Journal, VoucherType, Inventory from brewman.views.services.session import session_period_start, session_period_finish -@view_config(request_method='GET', route_name='stock_movement', permission='Stock Movement') +@view_config( + request_method="GET", route_name="stock_movement", permission="Stock Movement" +) def html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='GET', route_name='api_stock_movement', renderer='json', permission='Stock Movement') +@view_config( + request_method="GET", + route_name="api_stock_movement", + renderer="json", + permission="Stock Movement", +) def get_stock_movement(request): - start_date = request.GET.get('s', None) - finish_date = request.GET.get('f', None) + start_date = request.GET.get("s", None) + finish_date = request.GET.get("f", None) if start_date and finish_date: - report = {'startDate': start_date, 'finishDate': finish_date} - start_date = datetime.datetime.strptime(start_date, '%d-%b-%Y') - finish_date = datetime.datetime.strptime(finish_date, '%d-%b-%Y') - report['body'] = build_stock_movement(start_date, finish_date, request.dbsession) + report = {"startDate": start_date, "finishDate": finish_date} + start_date = datetime.datetime.strptime(start_date, "%d-%b-%Y") + finish_date = datetime.datetime.strptime(finish_date, "%d-%b-%Y") + report["body"] = build_stock_movement( + start_date, finish_date, request.dbsession + ) return report else: - return {'startDate': session_period_start(request), - 'finishDate': session_period_finish(request), 'body': []} + return { + "startDate": session_period_start(request), + "finishDate": session_period_finish(request), + "body": [], + } def build_stock_movement(start_date, finish_date, dbsession): dict = {} - quantity_sum = func.sum(Journal.debit * Inventory.quantity).label('quantity') - openings = dbsession.query(Product, quantity_sum) \ - .join(Product.inventories).join(Inventory.voucher).join(Voucher.journals) \ - .filter(Voucher.date < start_date) \ - .filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase()) \ - .group_by(Product).all() + quantity_sum = func.sum(Journal.debit * Inventory.quantity).label("quantity") + openings = ( + dbsession.query(Product, quantity_sum) + .join(Product.inventories) + .join(Inventory.voucher) + .join(Voucher.journals) + .filter(Voucher.date < start_date) + .filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase()) + .group_by(Product) + .all() + ) for product, quantity in openings: - dict[product.id] = {'id': product.id, 'name': product.full_name, 'group': product.product_group.name, - 'opening': quantity} - purchases = dbsession.query(Product, quantity_sum) \ - .join(Product.inventories).join(Inventory.voucher).join(Voucher.journals) \ - .filter(Voucher.date >= start_date) \ - .filter(Voucher.date <= finish_date) \ - .filter(Voucher.type != VoucherType.by_name('Issue').id) \ - .filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase()) \ - .group_by(Product).all() + dict[product.id] = { + "id": product.id, + "name": product.full_name, + "group": product.product_group.name, + "opening": quantity, + } + purchases = ( + dbsession.query(Product, quantity_sum) + .join(Product.inventories) + .join(Inventory.voucher) + .join(Voucher.journals) + .filter(Voucher.date >= start_date) + .filter(Voucher.date <= finish_date) + .filter(Voucher.type != VoucherType.by_name("Issue").id) + .filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase()) + .group_by(Product) + .all() + ) for product, quantity in purchases: if product.id in dict: - dict[product.id]['purchase'] = quantity + dict[product.id]["purchase"] = quantity else: - dict[product.id] = {'id': product.id, 'name': product.full_name, 'group': product.product_group.name, - 'purchase': quantity} - issues = dbsession.query(Product, quantity_sum) \ - .join(Product.inventories).join(Inventory.voucher).join(Voucher.journals) \ - .filter(Voucher.date >= start_date) \ - .filter(Voucher.date <= finish_date) \ - .filter(Voucher.type == VoucherType.by_name('Issue').id) \ - .filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase()) \ - .group_by(Product).all() + dict[product.id] = { + "id": product.id, + "name": product.full_name, + "group": product.product_group.name, + "purchase": quantity, + } + issues = ( + dbsession.query(Product, quantity_sum) + .join(Product.inventories) + .join(Inventory.voucher) + .join(Voucher.journals) + .filter(Voucher.date >= start_date) + .filter(Voucher.date <= finish_date) + .filter(Voucher.type == VoucherType.by_name("Issue").id) + .filter(Journal.cost_centre_id == CostCentre.cost_centre_purchase()) + .group_by(Product) + .all() + ) for product, quantity in issues: if product.id in dict: - dict[product.id]['issue'] = quantity * -1 + dict[product.id]["issue"] = quantity * -1 else: - dict[product.id] = {'id': product.id, 'name': product.full_name, 'group': product.product_group.name, - 'issue': quantity * -1} + dict[product.id] = { + "id": product.id, + "name": product.full_name, + "group": product.product_group.name, + "issue": quantity * -1, + } list = [value for key, value in dict.items()] - list = sorted(list, key=lambda x: x['name'].lower()) - list = sorted(list, key=lambda x: x['group'].lower()) + list = sorted(list, key=lambda x: x["name"].lower()) + list = sorted(list, key=lambda x: x["group"].lower()) for i in range(len(list), 0, -1): item = list[i - 1] - opening = item['opening'] if 'opening' in item else 0 - purchase = item['purchase'] if 'purchase' in item else 0 - issue = item['issue'] if 'issue' in item else 0 + opening = item["opening"] if "opening" in item else 0 + purchase = item["purchase"] if "purchase" in item else 0 + issue = item["issue"] if "issue" in item else 0 closing = opening + purchase - issue if opening == 0 and purchase == 0 and issue == 0: list.remove(item) else: - item['closing'] = closing + item["closing"] = closing return list diff --git a/brewman/views/reports/trial_balance.py b/brewman/views/reports/trial_balance.py index d1494503..12f2baf7 100644 --- a/brewman/views/reports/trial_balance.py +++ b/brewman/views/reports/trial_balance.py @@ -10,36 +10,59 @@ from brewman.models.voucher import Voucher, Journal, VoucherType from brewman.views.services.session import session_period_finish -@view_config(request_method='GET', route_name='trial_balance', permission='Trial Balance') -@view_config(request_method='GET', route_name='trial_balance_date', permission='Trial Balance') +@view_config( + request_method="GET", route_name="trial_balance", permission="Trial Balance" +) +@view_config( + request_method="GET", route_name="trial_balance_date", permission="Trial Balance" +) def html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='GET', route_name='api_trial_balance', renderer='json', permission='Trial Balance') +@view_config( + request_method="GET", + route_name="api_trial_balance", + renderer="json", + permission="Trial Balance", +) def report_blank(request): - return {'date': session_period_finish(request), 'body': []} + return {"date": session_period_finish(request), "body": []} -@view_config(request_method='GET', route_name='api_trial_balance_date', renderer='json', permission='Trial Balance') +@view_config( + request_method="GET", + route_name="api_trial_balance_date", + renderer="json", + permission="Trial Balance", +) def report_data(request): - date = request.matchdict.get('date', None) - return {'date': date, 'body': build_report(date, request.dbsession)} + date = request.matchdict.get("date", None) + return {"date": date, "body": build_report(date, request.dbsession)} def build_report(date, dbsession): - date = datetime.datetime.strptime(date, '%d-%b-%Y') - amount_sum = func.sum(Journal.amount * Journal.debit).label('amount') - query = dbsession.query(AccountBase, amount_sum) \ - .join(Journal.voucher).join(Journal.account) \ - .filter(Voucher.date <= date).filter(Voucher.type != VoucherType.by_name('Issue').id).group_by(AccountBase) \ - .order_by(AccountBase.type).order_by(func.abs(amount_sum).desc()).all() + date = datetime.datetime.strptime(date, "%d-%b-%Y") + amount_sum = func.sum(Journal.amount * Journal.debit).label("amount") + query = ( + dbsession.query(AccountBase, amount_sum) + .join(Journal.voucher) + .join(Journal.account) + .filter(Voucher.date <= date) + .filter(Voucher.type != VoucherType.by_name("Issue").id) + .group_by(AccountBase) + .order_by(AccountBase.type) + .order_by(func.abs(amount_sum).desc()) + .all() + ) body = [] for account, amount in query: if amount != 0: - tag = 'debit' if amount > 0 else 'credit' - body.append({'type': account.type_object.name, 'name': account.name, tag: amount}) + tag = "debit" if amount > 0 else "credit" + body.append( + {"type": account.type_object.name, "name": account.name, tag: amount} + ) return body diff --git a/brewman/views/reports/unposted.py b/brewman/views/reports/unposted.py index b2cda25a..27bf121c 100644 --- a/brewman/views/reports/unposted.py +++ b/brewman/views/reports/unposted.py @@ -7,14 +7,19 @@ from brewman.models.voucher import Voucher, Journal, VoucherType from brewman.views.services.voucher import get_edit_url -@view_config(request_method='GET', route_name='unposted', permission='Post Vouchers') +@view_config(request_method="GET", route_name="unposted", permission="Post Vouchers") def html(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='GET', route_name='api_unposted', renderer='json', permission='Post Vouchers') +@view_config( + request_method="GET", + route_name="api_unposted", + renderer="json", + permission="Post Vouchers", +) def report_data(request): return build_report(request) @@ -22,15 +27,15 @@ def report_data(request): def build_report(request): body = [] - query = request.dbsession.query( - Voucher - ).options( - joinedload_all(Voucher.journals, Journal.account, innerjoin=True) - ).filter( - Voucher.posted == False - ).filter( - Voucher.type != VoucherType.by_name('Issue').id - ).order_by(Voucher.date).order_by(Voucher.last_edit_date).all() + query = ( + request.dbsession.query(Voucher) + .options(joinedload_all(Voucher.journals, Journal.account, innerjoin=True)) + .filter(Voucher.posted == False) + .filter(Voucher.type != VoucherType.by_name("Issue").id) + .order_by(Voucher.date) + .order_by(Voucher.last_edit_date) + .all() + ) for voucher in query: debit = 0 @@ -47,9 +52,18 @@ def build_report(request): name_debit = name_debit[:-3] name_credit = name_credit[:-3] - body.append({'date': voucher.date.strftime('%d-%b-%Y'), 'Url': get_edit_url(request, voucher), - 'voucherType': VoucherType.by_id(voucher.type).name, - 'narration': voucher.narration, 'isPosted': voucher.posted, - 'debitName': name_debit, 'debitAmount': debit, 'creditName': name_credit, 'creditAmount': credit}) + body.append( + { + "date": voucher.date.strftime("%d-%b-%Y"), + "Url": get_edit_url(request, voucher), + "voucherType": VoucherType.by_id(voucher.type).name, + "narration": voucher.narration, + "isPosted": voucher.posted, + "debitName": name_debit, + "debitAmount": debit, + "creditName": name_credit, + "creditAmount": credit, + } + ) return body diff --git a/brewman/views/services/batch.py b/brewman/views/services/batch.py index 1c5ec095..b82460c0 100644 --- a/brewman/views/services/batch.py +++ b/brewman/views/services/batch.py @@ -5,28 +5,49 @@ from pyramid.view import view_config from brewman.models.voucher import Batch -@view_config(request_method='GET', route_name='api_batch', renderer='json', permission='Authenticated') +@view_config( + request_method="GET", + route_name="api_batch", + renderer="json", + permission="Authenticated", +) def batch_term(request): - filter = request.GET.get('t', None) - filter = filter if filter is not None and filter.strip() is not '' else None - count = request.GET.get('c', None) - count = None if count is None or count == '' else int(count) - date = request.GET.get('d', None) - date = None if date is None or date == '' else datetime.datetime.strptime(date, '%d-%b-%Y') - list = [] - for index, item in enumerate(Batch.list(filter, include_nil=False, date=date, dbsession=request.dbsession)): + filter_ = request.GET.get("t", None) + filter_ = filter_ if filter_ is not None and filter_.strip() is not "" else None + count = request.GET.get("c", None) + count = None if count is None or count == "" else int(count) + date = request.GET.get("d", None) + date = ( + None + if date is None or date == "" + else datetime.datetime.strptime(date, "%d-%b-%Y") + ) + list_ = [] + for index, item in enumerate( + Batch.list(filter_, include_nil=False, date=date, dbsession=request.dbsession) + ): text = "{0} ({1}) {2:.2f}@{3:.2f} from {4}".format( item.product.name, item.product.units, item.quantity_remaining, item.rate, - item.name.strftime('%d-%b-%Y') + item.name.strftime("%d-%b-%Y"), + ) + list_.append( + { + "id": item.id, + "name": text, + "quantityRemaining": item.quantity_remaining, + "rate": item.rate, + "tax": item.tax, + "discount": item.discount, + "product": { + "id": item.product.id, + "name": item.product.name, + "units": item.product.units, + }, + } ) - list.append({ - 'id': item.id, 'name': text, 'quantityRemaining': item.quantity_remaining, 'rate': item.rate, - 'tax': item.tax, 'discount': item.discount, - 'product': {'id': item.product.id, 'name': item.product.name, 'units': item.product.units} - }) if count is not None and index == count - 1: break - return list + return list_ diff --git a/brewman/views/services/cost_centre.py b/brewman/views/services/cost_centre.py index 42925a58..3975dceb 100644 --- a/brewman/views/services/cost_centre.py +++ b/brewman/views/services/cost_centre.py @@ -1,16 +1,16 @@ import datetime -import uuid from pyramid.view import view_config from sqlalchemy.orm.util import aliased -from sqlalchemy.sql.expression import and_ from brewman.models.voucher import Voucher, Journal, VoucherType -@view_config(route_name='api_issue_grid', renderer='json', permission='Issue', trans=True) +@view_config( + route_name="api_issue_grid", renderer="json", permission="Issue", trans=True +) def grid_date(request): - date = datetime.datetime.strptime(request.matchdict['date'], '%d-%b-%Y') + date = datetime.datetime.strptime(request.matchdict["date"], "%d-%b-%Y") return get_grid(date, request.dbsession) @@ -19,19 +19,27 @@ def get_grid(date, dbsession): source_journal = aliased(Journal) destination_journal = aliased(Journal) - query = dbsession.query(Voucher, source_journal.amount) \ - .join(source_journal, Voucher.journals) \ - .join(destination_journal, Voucher.journals) \ - .filter(Voucher.date == date) \ - .filter(Voucher.type == VoucherType.by_name('Issue').id) \ - .order_by(Voucher.creation_date) \ + query = ( + dbsession.query(Voucher, source_journal.amount) + .join(source_journal, Voucher.journals) + .join(destination_journal, Voucher.journals) + .filter(Voucher.date == date) + .filter(Voucher.type == VoucherType.by_name("Issue").id) + .order_by(Voucher.creation_date) .all() + ) for voucher, amount in query: - list.append({ - 'id': str(voucher.id), - 'amount': amount, - 'source': [j.cost_centre.name for j in voucher.journals if j.debit == -1], - 'destination': [j.cost_centre.name for j in voucher.journals if j.debit == 1] - }) + list.append( + { + "id": str(voucher.id), + "amount": amount, + "source": [ + j.cost_centre.name for j in voucher.journals if j.debit == -1 + ], + "destination": [ + j.cost_centre.name for j in voucher.journals if j.debit == 1 + ], + } + ) return list diff --git a/brewman/views/services/login.py b/brewman/views/services/login.py index 67e6e106..2219c0bb 100644 --- a/brewman/views/services/login.py +++ b/brewman/views/services/login.py @@ -11,44 +11,48 @@ from brewman.models.auth import User, Client, LoginHistory from brewman.security import f7 -@view_config(route_name='logout') +@view_config(route_name="logout") def logout(request): request.session.invalidate() headers = forget(request) - return HTTPFound(location=request.route_url('home'), headers=headers) + return HTTPFound(location=request.route_url("home"), headers=headers) -@view_config(request_method='POST', route_name='api_logout', renderer='json') +@view_config(request_method="POST", route_name="api_logout", renderer="json") def api_logout(request): request.session.invalidate() request.response.headers = forget(request) - return {'isAuthenticated': False, 'perms': {}} + return {"isAuthenticated": False, "perms": {}} -@view_config(request_method='POST', route_name='api_login', renderer='json', trans=True) +@view_config(request_method="POST", route_name="api_login", renderer="json", trans=True) def login(request): - username = request.json_body.get('name', None) - password = request.json_body.get('password', None) + username = request.json_body.get("name", None) + password = request.json_body.get("password", None) found, user = User.auth(username, password, request.dbsession) - client = Client.by_code(request.cookies.get('ClientID', None), request.dbsession) - otp = request.json_body.get('otp', None) - client_name = request.json_body.get('clientName', None) + client = Client.by_code(request.cookies.get("ClientID", None), request.dbsession) + otp = request.json_body.get("otp", None) + client_name = request.json_body.get("clientName", None) if user is not None: - allowed, client, response = check_client(client, otp, client_name, user, request.dbsession) + allowed, client, response = check_client( + client, otp, client_name, user, request.dbsession + ) if found and allowed: headers = remember(request, str(user.id)) request.response.headers = headers - request.response.set_cookie('ClientID', value=str(client.code), max_age=365 * 24 * 60 * 60) + request.response.set_cookie( + "ClientID", value=str(client.code), max_age=365 * 24 * 60 * 60 + ) record_login(user.id, client, request.dbsession) transaction.commit() return { - 'id': user.id, - 'name': user.name, - 'isAuthenticated': True, - 'perms': sorted(f7([p.name for g in user.groups for p in g.roles])) + "id": user.id, + "name": user.name, + "isAuthenticated": True, + "perms": sorted(f7([p.name for g in user.groups for p in g.roles])), } elif not found: response = Response("Login failed") @@ -64,13 +68,16 @@ def check_client(client, otp, client_name, user, dbsession): outside_login_allowed = False for group in user.groups: for perm in group.roles: - if perm.name == 'Clients': + if perm.name == "Clients": outside_login_allowed = True - if dbsession.query(Client).filter(Client.enabled == True).count() == 0 and outside_login_allowed: + if ( + dbsession.query(Client).filter(Client.enabled == True).count() == 0 + and outside_login_allowed + ): client = Client.create(dbsession) client.otp = None - client.name = 'Created on login by ' + user.name + client.name = "Created on login by " + user.name client.enabled = True return True, client, None @@ -82,7 +89,9 @@ def check_client(client, otp, client_name, user, dbsession): client = Client.create(dbsession) response = Response("Unknown Client") response.status_int = 403 - response.set_cookie('ClientID', value=str(client.code), max_age=10 * 365 * 24 * 60 * 60) + response.set_cookie( + "ClientID", value=str(client.code), max_age=10 * 365 * 24 * 60 * 60 + ) return False, None, response if client.enabled or outside_login_allowed: @@ -113,18 +122,24 @@ def record_login(user_id, client, dbsession): history.client = client dbsession.add(history) - recent_logins = dbsession.query(LoginHistory.client_id.distinct()) \ - .filter(LoginHistory.date > datetime.utcnow() - timedelta(days=90)).subquery() + recent_logins = ( + dbsession.query(LoginHistory.client_id.distinct()) + .filter(LoginHistory.date > datetime.utcnow() - timedelta(days=90)) + .subquery() + ) - deletable_clients = dbsession.query(Client.id) \ - .filter(Client.creation_date < datetime.utcnow() - timedelta(days=3)) \ - .filter(Client.enabled == False).subquery() + deletable_clients = ( + dbsession.query(Client.id) + .filter(Client.creation_date < datetime.utcnow() - timedelta(days=3)) + .filter(Client.enabled == False) + .subquery() + ) dbsession.execute( LoginHistory.__table__.delete( and_( ~LoginHistory.client_id.in_(recent_logins), - LoginHistory.client_id.in_(deletable_clients) + LoginHistory.client_id.in_(deletable_clients), ) ) ) @@ -134,7 +149,7 @@ def record_login(user_id, client, dbsession): and_( Client.creation_date < datetime.utcnow() - timedelta(days=3), Client.enabled == False, - ~Client.id.in_(recent_logins) + ~Client.id.in_(recent_logins), ) ) ) diff --git a/brewman/views/services/session.py b/brewman/views/services/session.py index 281f7f34..b70456e0 100644 --- a/brewman/views/services/session.py +++ b/brewman/views/services/session.py @@ -9,53 +9,57 @@ from brewman.security import f7 def session_current_date(request): session = request.session - if 'currentDate' not in session: - session['currentDate'] = date.today().strftime('%d-%b-%Y') - return session['currentDate'] + if "currentDate" not in session: + session["currentDate"] = date.today().strftime("%d-%b-%Y") + return session["currentDate"] def session_current_date_set(request, date): session = request.session - session['currentDate'] = date - return session['currentDate'] + session["currentDate"] = date + return session["currentDate"] def session_period_start(request): session = request.session - if 'periodStart' not in session: - session['periodStart'] = get_first_day(date.today()).strftime('%d-%b-%Y') - return session['periodStart'] + if "periodStart" not in session: + session["periodStart"] = get_first_day(date.today()).strftime("%d-%b-%Y") + return session["periodStart"] def session_period_finish(request): session = request.session - if 'periodFinish' not in session: - session['periodFinish'] = get_last_day(date.today()).strftime('%d-%b-%Y') - return session['periodFinish'] + if "periodFinish" not in session: + session["periodFinish"] = get_last_day(date.today()).strftime("%d-%b-%Y") + return session["periodFinish"] def session_period_set(request, start, finish): session = request.session - session['periodStart'] = start if isinstance(start, str) else start.strftime('%d-%b-%Y') - session['periodFinish'] = finish if isinstance(finish, str) else finish.strftime('%d-%b-%Y') + session["periodStart"] = ( + start if isinstance(start, str) else start.strftime("%d-%b-%Y") + ) + session["periodFinish"] = ( + finish if isinstance(finish, str) else finish.strftime("%d-%b-%Y") + ) -@view_config(route_name='api_auth', renderer='json') +@view_config(route_name="api_auth", renderer="json") def user_permission(request): user_id = request.authenticated_userid if user_id is None: - auth = {'isAuthenticated': False, 'perms': {}} - elif 'auth' in request.session: - auth = request.session['auth'] + auth = {"isAuthenticated": False, "perms": {}} + elif "auth" in request.session: + auth = request.session["auth"] else: user = request.dbsession.query(User).filter(User.id == uuid.UUID(user_id)).one() auth = { - 'id': user.id, - 'name': user.name, - 'isAuthenticated': True, - 'perms': sorted(f7([p.name for g in user.groups for p in g.roles])) + "id": user.id, + "name": user.name, + "isAuthenticated": True, + "perms": sorted(f7([p.name for g in user.groups for p in g.roles])), } - request.session['auth'] = auth + request.session["auth"] = auth return auth diff --git a/brewman/views/services/voucher/__init__.py b/brewman/views/services/voucher/__init__.py index 60676e0f..3469635d 100644 --- a/brewman/views/services/voucher/__init__.py +++ b/brewman/views/services/voucher/__init__.py @@ -9,9 +9,22 @@ from pyramid.view import view_config from sqlalchemy import func, or_ from brewman.models.auth import User -from brewman.models.master import AccountBase, CostCentre, Employee, AttendanceType, Account +from brewman.models.master import ( + AccountBase, + CostCentre, + Employee, + AttendanceType, + Account, +) from brewman.models.validation_exception import ValidationError -from brewman.models.voucher import Voucher, VoucherType, Inventory, DbImage, Attendance, Journal +from brewman.models.voucher import ( + Voucher, + VoucherType, + Inventory, + DbImage, + Attendance, + Journal, +) from brewman.views import get_lock_info from .issue import issue_create_voucher, issue_update_voucher from .journal import journal_update_voucher, journal_create_voucher @@ -20,81 +33,131 @@ from .service_charge import service_charge_create_voucher, service_charge_update from ..session import get_first_day -@view_config(request_method='GET', route_name='journal_id', permission='Journal') -@view_config(request_method='GET', route_name='journal', permission='Journal') -@view_config(request_method='GET', route_name='payment_id', permission='Payment') -@view_config(request_method='GET', route_name='payment', permission='Payment') -@view_config(request_method='GET', route_name='receipt_id', permission='Receipt') -@view_config(request_method='GET', route_name='receipt', permission='Receipt') -@view_config(request_method='GET', route_name='purchase_id', permission='Purchase') -@view_config(request_method='GET', route_name='purchase', permission='Purchase') -@view_config(request_method='GET', route_name='purchase_return_id', permission='Purchase Return') -@view_config(request_method='GET', route_name='purchase_return', permission='Purchase Return') -@view_config(request_method='GET', route_name='issue_id', permission='Issue') -@view_config(request_method='GET', route_name='issue', permission='Issue') -@view_config(request_method='GET', route_name='employee_benefits_id', permission='Issue') -@view_config(request_method='GET', route_name='employee_benefits', permission='Issue') -@view_config(request_method='GET', route_name='incentive_id', permission='Service Charge') -@view_config(request_method='GET', route_name='incentive', permission='Service Charge') +@view_config(request_method="GET", route_name="journal_id", permission="Journal") +@view_config(request_method="GET", route_name="journal", permission="Journal") +@view_config(request_method="GET", route_name="payment_id", permission="Payment") +@view_config(request_method="GET", route_name="payment", permission="Payment") +@view_config(request_method="GET", route_name="receipt_id", permission="Receipt") +@view_config(request_method="GET", route_name="receipt", permission="Receipt") +@view_config(request_method="GET", route_name="purchase_id", permission="Purchase") +@view_config(request_method="GET", route_name="purchase", permission="Purchase") +@view_config( + request_method="GET", route_name="purchase_return_id", permission="Purchase Return" +) +@view_config( + request_method="GET", route_name="purchase_return", permission="Purchase Return" +) +@view_config(request_method="GET", route_name="issue_id", permission="Issue") +@view_config(request_method="GET", route_name="issue", permission="Issue") +@view_config( + request_method="GET", route_name="employee_benefits_id", permission="Issue" +) +@view_config(request_method="GET", route_name="employee_benefits", permission="Issue") +@view_config( + request_method="GET", route_name="incentive_id", permission="Service Charge" +) +@view_config(request_method="GET", route_name="incentive", permission="Service Charge") def journal_get(request): - package, resource = 'brewman:static/index.html'.split(':', 1) + package, resource = "brewman:static/index.html".split(":", 1) file = pkg_resources.resource_filename(package, resource) return FileResponse(file, request=request) -@view_config(request_method='POST', route_name='api_voucher_id', request_param='p', renderer='json', - permission='Post Vouchers', trans=True) +@view_config( + request_method="POST", + route_name="api_voucher_id", + request_param="p", + renderer="json", + permission="Post Vouchers", + trans=True, +) def voucher_post(request): - user = request.dbsession.query(User).filter(User.id == uuid.UUID(request.authenticated_userid)).one() - voucher = request.dbsession.query(Voucher).filter(Voucher.id == uuid.UUID(request.matchdict['id'])).first() + user = ( + request.dbsession.query(User) + .filter(User.id == uuid.UUID(request.authenticated_userid)) + .one() + ) + voucher = ( + request.dbsession.query(Voucher) + .filter(Voucher.id == uuid.UUID(request.matchdict["id"])) + .first() + ) start, finish = get_lock_info(request.dbsession) if start is not None and start > voucher.date: - raise ValidationError("Vouchers before {0} have been locked.".format(start.strftime('%d-%b-%Y'))) + raise ValidationError( + "Vouchers before {0} have been locked.".format(start.strftime("%d-%b-%Y")) + ) elif finish is not None and finish < voucher.date: - raise ValidationError("Vouchers after {0} have been locked.".format(finish.strftime('%d-%b-%Y'))) + raise ValidationError( + "Vouchers after {0} have been locked.".format(finish.strftime("%d-%b-%Y")) + ) voucher.posted = True voucher.poster_id = user.id transaction.commit() - new_voucher = request.dbsession.query(Voucher).filter(Voucher.id == voucher.id).first() + new_voucher = ( + request.dbsession.query(Voucher).filter(Voucher.id == voucher.id).first() + ) return voucher_info(new_voucher, request) def check_delete_permissions(request, voucher): - user = request.dbsession.query(User).filter(User.id == uuid.UUID(request.authenticated_userid)).one() + user = ( + request.dbsession.query(User) + .filter(User.id == uuid.UUID(request.authenticated_userid)) + .one() + ) - if voucher.posted and not request.has_permission('Edit Posted Vouchers'): + if voucher.posted and not request.has_permission("Edit Posted Vouchers"): response = Response("You are not allowed to edit posted vouchers") response.status_int = 403 return response - elif voucher.user_id != user.id and not request.has_permission("Edit Other User's Vouchers"): + elif voucher.user_id != user.id and not request.has_permission( + "Edit Other User's Vouchers" + ): response = Response("You are not allowed to edit other user's vouchers") response.status_int = 403 return response elif not request.has_permission(VoucherType.by_id(voucher.type).name): - response = Response("You are not allowed (0) vouchers".format(VoucherType.by_id(voucher.type).name)) + response = Response( + "You are not allowed (0) vouchers".format( + VoucherType.by_id(voucher.type).name + ) + ) response.status_int = 403 return response start, finish = get_lock_info(request.dbsession) if start is not None and start > voucher.date: - response = Response("Vouchers before {0} have been locked.".format(start.strftime('%d-%b-%Y'))) + response = Response( + "Vouchers before {0} have been locked.".format(start.strftime("%d-%b-%Y")) + ) response.status_int = 403 return response elif finish is not None and finish < voucher.date: - response = Response("Vouchers after {0} have been locked.".format(finish.strftime('%d-%b-%Y'))) + response = Response( + "Vouchers after {0} have been locked.".format(finish.strftime("%d-%b-%Y")) + ) response.status_int = 403 return response -@view_config(request_method='DELETE', route_name='api_voucher_id', renderer='json', trans=True) +@view_config( + request_method="DELETE", route_name="api_voucher_id", renderer="json", trans=True +) def delete(request): - voucher = request.dbsession.query(Voucher).filter(Voucher.id == uuid.UUID(request.matchdict['id'])).first() - images = request.dbsession.query(DbImage).filter(DbImage.resource_id == voucher.id).all() + voucher = ( + request.dbsession.query(Voucher) + .filter(Voucher.id == uuid.UUID(request.matchdict["id"])) + .first() + ) + images = ( + request.dbsession.query(DbImage).filter(DbImage.resource_id == voucher.id).all() + ) permission = check_delete_permissions(request, voucher) if permission is not None: return permission json_voucher = voucher_info(voucher, request) batches_to_delete = [] - if voucher.type == VoucherType.by_name('Issue').id: + if voucher.type == VoucherType.by_name("Issue").id: for item in voucher.journals: if item.debit == 1: destination = item.cost_centre_id @@ -116,18 +179,27 @@ def delete(request): for item in voucher.inventories: if item.batch.quantity_remaining < item.batch.quantity_remaining: raise ValueError( - 'Quantity remaining for {0} is less than issued, hence cannot be deleted'.format( - item.product.name)) + "Quantity remaining for {0} is less than issued, hence cannot be deleted".format( + item.product.name + ) + ) item.batch.quantity_remaining -= item.quantity - elif voucher.type == VoucherType.by_name('Purchase').id: + elif voucher.type == VoucherType.by_name("Purchase").id: for item in voucher.inventories: - uses = request.dbsession.query(func.count(Inventory.id)) \ - .filter(Inventory.batch_id == item.batch.id) \ - .filter(Inventory.id != item.id).scalar() + uses = ( + request.dbsession.query(func.count(Inventory.id)) + .filter(Inventory.batch_id == item.batch.id) + .filter(Inventory.id != item.id) + .scalar() + ) if uses > 0: - raise ValueError('{0} has been issued and cannot be deleted'.format(item.product.name)) + raise ValueError( + "{0} has been issued and cannot be deleted".format( + item.product.name + ) + ) batches_to_delete.append(item.batch) - elif voucher.type == VoucherType.by_name('Purchase Return').id: + elif voucher.type == VoucherType.by_name("Purchase Return").id: for item in voucher.inventories: item.batch.quantity_remaining += item.quantity for b in batches_to_delete: @@ -139,217 +211,315 @@ def delete(request): return blank_voucher(info=json_voucher, dbsession=request.dbsession) -@view_config(request_method='GET', route_name='api_voucher_id', renderer='json', trans=True) +@view_config( + request_method="GET", route_name="api_voucher_id", renderer="json", trans=True +) def get_old(request): - id = request.matchdict.get('id', None) - voucher = request.dbsession.query(Voucher).filter(Voucher.id == uuid.UUID(id)).first() + id = request.matchdict.get("id", None) + voucher = ( + request.dbsession.query(Voucher).filter(Voucher.id == uuid.UUID(id)).first() + ) return voucher_info(voucher, request) def voucher_info(voucher, request): - json_voucher = {'id': voucher.id, - 'date': voucher.date.strftime('%d-%b-%Y'), - 'isStarred': voucher.is_starred, - 'type': VoucherType.by_id(voucher.type).name, - 'posted': voucher.posted, - 'narration': voucher.narration, - 'journals': [], - 'inventories': [], - 'employeeBenefits': [], - 'incentives': [], - 'files': [], - 'creationDate': voucher.creation_date.strftime('%d-%b-%Y %H:%M'), - 'lastEditDate': voucher.last_edit_date.strftime('%d-%b-%Y %H:%M'), - 'user': {'id': voucher.user.id, 'name': voucher.user.name}, - 'poster': voucher.poster.name if voucher.posted else ''} + json_voucher = { + "id": voucher.id, + "date": voucher.date.strftime("%d-%b-%Y"), + "isStarred": voucher.is_starred, + "type": VoucherType.by_id(voucher.type).name, + "posted": voucher.posted, + "narration": voucher.narration, + "journals": [], + "inventories": [], + "employeeBenefits": [], + "incentives": [], + "files": [], + "creationDate": voucher.creation_date.strftime("%d-%b-%Y %H:%M"), + "lastEditDate": voucher.last_edit_date.strftime("%d-%b-%Y %H:%M"), + "user": {"id": voucher.user.id, "name": voucher.user.name}, + "poster": voucher.poster.name if voucher.posted else "", + } if voucher.reconcile_date is not None: - json_voucher['reconcileDate'] = voucher.reconcile_date.strftime('%d-%b-%Y %H:%M') + json_voucher["reconcileDate"] = voucher.reconcile_date.strftime( + "%d-%b-%Y %H:%M" + ) for item in voucher.journals: - json_voucher['journals'].append({'id': item.id, 'debit': item.debit, 'amount': item.amount, - 'account': {'id': item.account.id, 'name': item.account.name}, - 'costCentre': {'id': item.cost_centre_id}}) - for item in voucher.salary_deductions: - json_voucher['employeeBenefits'].append( - {'grossSalary': item.gross_salary, - 'daysWorked': item.days_worked, - 'esiEmployee': item.esi_ee, - 'pfEmployee': item.pf_ee, - 'esiEmployer': item.esi_er, - 'pfEmployer': item.pf_er, - 'journal': {'id': item.journal.id, - 'account': {'id': item.journal.account.id, 'name': item.journal.account.name, - 'designation': item.journal.account.designation, - 'costCentre': {'id': item.journal.account.cost_centre.id, - 'name': item.journal.account.cost_centre.name}}}}) - for item in voucher.service_charges: - employee = request.dbsession.query(Employee).filter(Employee.id == item.journal.account_id).first() - json_voucher['incentives'].append( + json_voucher["journals"].append( { - 'id': item.journal.account_id, 'name': item.journal.account.name, 'designation': employee.designation, - 'department': item.journal.account.cost_centre.name, 'daysWorked': item.days_worked, - 'points': item.points + "id": item.id, + "debit": item.debit, + "amount": item.amount, + "account": {"id": item.account.id, "name": item.account.name}, + "costCentre": {"id": item.cost_centre_id}, } ) - if len(json_voucher['incentives']) > 0: - json_voucher['incentive'] = [x.amount for x in voucher.journals if - x.account_id == Account.service_charge_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')) - json_voucher['inventories'].append({ - 'id': item.id, - 'quantity': item.quantity, - 'rate': item.rate, - 'tax': item.tax, - 'discount': item.discount, - 'amount': item.amount, - 'product': { - 'id': item.product.id, - 'name': item.product.full_name, - 'units': item.product.units, - 'price': item.rate - }, - 'batch': { - 'id': item.batch.id, - 'name': text, - 'quantityRemaining': item.batch.quantity_remaining, - 'tax': item.batch.tax, - 'discount': item.batch.discount, - 'rate': item.batch.rate, - 'product': { - 'id': item.batch.product.id, 'name': item.batch.product.full_name - } + for item in voucher.salary_deductions: + json_voucher["employeeBenefits"].append( + { + "grossSalary": item.gross_salary, + "daysWorked": item.days_worked, + "esiEmployee": item.esi_ee, + "pfEmployee": item.pf_ee, + "esiEmployer": item.esi_er, + "pfEmployer": item.pf_er, + "journal": { + "id": item.journal.id, + "account": { + "id": item.journal.account.id, + "name": item.journal.account.name, + "designation": item.journal.account.designation, + "costCentre": { + "id": item.journal.account.cost_centre.id, + "name": item.journal.account.cost_centre.name, + }, + }, + }, } - }) - images = request.dbsession.query(DbImage).filter(DbImage.resource_id == voucher.id).all() + ) + for item in voucher.service_charges: + employee = ( + request.dbsession.query(Employee) + .filter(Employee.id == item.journal.account_id) + .first() + ) + json_voucher["incentives"].append( + { + "id": item.journal.account_id, + "name": item.journal.account.name, + "designation": employee.designation, + "department": item.journal.account.cost_centre.name, + "daysWorked": item.days_worked, + "points": item.points, + } + ) + if len(json_voucher["incentives"]) > 0: + json_voucher["incentive"] = [ + x.amount + for x in voucher.journals + if x.account_id == Account.service_charge_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"), + ) + json_voucher["inventories"].append( + { + "id": item.id, + "quantity": item.quantity, + "rate": item.rate, + "tax": item.tax, + "discount": item.discount, + "amount": item.amount, + "product": { + "id": item.product.id, + "name": item.product.full_name, + "units": item.product.units, + "price": item.rate, + }, + "batch": { + "id": item.batch.id, + "name": text, + "quantityRemaining": item.batch.quantity_remaining, + "tax": item.batch.tax, + "discount": item.batch.discount, + "rate": item.batch.rate, + "product": { + "id": item.batch.product.id, + "name": item.batch.product.full_name, + }, + }, + } + ) + images = ( + request.dbsession.query(DbImage).filter(DbImage.resource_id == voucher.id).all() + ) for image in images: - resized = request.route_url('db_image', id=image.id, type='resized') - thumbnail = request.route_url('db_image', id=image.id, type='thumbnail') - json_voucher['files'].append({'id': image.id, 'resized': resized, 'thumbnail': thumbnail}) + resized = request.route_url("db_image", id=image.id, type="resized") + thumbnail = request.route_url("db_image", id=image.id, type="thumbnail") + json_voucher["files"].append( + {"id": image.id, "resized": resized, "thumbnail": thumbnail} + ) return json_voucher def blank_voucher(info, dbsession): - if 'type' not in info: - raise ValidationError('Voucher Type is null') - type = info['type'] - if 'date' not in info: - raise ValidationError('Date cannot be null') + if "type" not in info: + raise ValidationError("Voucher Type is null") + type = info["type"] + if "date" not in info: + raise ValidationError("Date cannot be null") json_voucher = { - 'type': type, 'date': info['date'], - 'isStarred': False, 'posted': False, - 'narration': "", 'journals': [], 'inventories': [] + "type": type, + "date": info["date"], + "isStarred": False, + "posted": False, + "narration": "", + "journals": [], + "inventories": [], } - if type == 'Journal': + if type == "Journal": pass - elif type == 'Payment': + elif type == "Payment": account = None - if info is not None and 'account' in info and info['account'] is not None: - account = dbsession.query(AccountBase).filter(AccountBase.id == uuid.UUID(info['account'])).first() + if info is not None and "account" in info and info["account"] is not None: + account = ( + dbsession.query(AccountBase) + .filter(AccountBase.id == uuid.UUID(info["account"])) + .first() + ) if account is not None: - account = {'id': account.id, 'name': account.name} + account = {"id": account.id, "name": account.name} else: account = AccountBase.cash_in_hand() - json_voucher['journals'].append({'account': account, 'amount': 0, 'debit': -1}) - elif type == 'Receipt': + 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: - account = dbsession.query(AccountBase).filter(AccountBase.id == uuid.UUID(info['account'])).first() + if info is not None and "account" in info and info["account"] is not None: + account = ( + dbsession.query(AccountBase) + .filter(AccountBase.id == uuid.UUID(info["account"])) + .first() + ) if account is not None: - account = {'id': account.id, 'name': account.name} + account = {"id": account.id, "name": account.name} else: 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}) - elif type == 'Purchase Return': - json_voucher['journals'].append({'account': AccountBase.local_purchase(), 'amount': 0, 'debit': 1}) - elif type == 'Issue': - if 'dource' in info and 'destination' in info: - json_voucher['journals'].append({'account': {'id': AccountBase.all_purchases()}, - 'amount': 0, - 'debit': -1, - 'costCentre': {'id': info['source']}}) - json_voucher['journals'].append({'account': {'id': AccountBase.all_purchases()}, - 'amount': 0, - 'debit': 1, - 'costCentre': {'id': info['destination']}}) - elif 'journals' not in info: - json_voucher['journals'].append({'account': {'id': AccountBase.all_purchases()}, - 'amount': 0, - 'debit': -1, - 'costCentre': {'id': CostCentre.cost_centre_purchase()}}) - json_voucher['journals'].append({'account': {'id': AccountBase.all_purchases()}, - 'amount': 0, - 'debit': 1, - 'costCentre': {'id': CostCentre.cost_centre_kitchen()}}) - else: - json_voucher['date'] = info['date'] - for item in info['journals']: - json_voucher['journals'].append({'account': {'id': item['account']['id']}, - 'amount': 0, - 'debit': item['debit'], - 'costCentre': {'id': item['costCentre']['id']}}) - - elif type == 'Salary Deduction': - json_voucher['employeeBenefits'] = [] - elif type == 'Service Charge': - json_voucher['incentives'], json_voucher['incentive'] = service_charge_employees( - info['date'], dbsession + 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} ) + elif type == "Purchase Return": + json_voucher["journals"].append( + {"account": AccountBase.local_purchase(), "amount": 0, "debit": 1} + ) + elif type == "Issue": + if "dource" in info and "destination" in info: + json_voucher["journals"].append( + { + "account": {"id": AccountBase.all_purchases()}, + "amount": 0, + "debit": -1, + "costCentre": {"id": info["source"]}, + } + ) + json_voucher["journals"].append( + { + "account": {"id": AccountBase.all_purchases()}, + "amount": 0, + "debit": 1, + "costCentre": {"id": info["destination"]}, + } + ) + elif "journals" not in info: + json_voucher["journals"].append( + { + "account": {"id": AccountBase.all_purchases()}, + "amount": 0, + "debit": -1, + "costCentre": {"id": CostCentre.cost_centre_purchase()}, + } + ) + json_voucher["journals"].append( + { + "account": {"id": AccountBase.all_purchases()}, + "amount": 0, + "debit": 1, + "costCentre": {"id": CostCentre.cost_centre_kitchen()}, + } + ) + else: + json_voucher["date"] = info["date"] + for item in info["journals"]: + json_voucher["journals"].append( + { + "account": {"id": item["account"]["id"]}, + "amount": 0, + "debit": item["debit"], + "costCentre": {"id": item["costCentre"]["id"]}, + } + ) + + elif type == "Salary Deduction": + json_voucher["employeeBenefits"] = [] + elif type == "Service Charge": + json_voucher["incentives"], json_voucher[ + "incentive" + ] = service_charge_employees(info["date"], dbsession) else: - raise ValidationError("Voucher of type \"{0}\" does not exist.".format(type)) - json_voucher['files'] = [] + raise ValidationError('Voucher of type "{0}" does not exist.'.format(type)) + json_voucher["files"] = [] return json_voucher def service_charge_employees(date, dbsession): - date = datetime.datetime.strptime(date, '%d-%b-%Y') + date = datetime.datetime.strptime(date, "%d-%b-%Y") start_date = get_first_day(date) finish_date = date + datetime.timedelta(1) details = [] - employees = dbsession.query(Employee) \ - .filter(Employee.joining_date <= finish_date) \ - .filter(or_(Employee.is_active, Employee.leaving_date >= start_date)) \ - .order_by(Employee.cost_centre_id).order_by(Employee.designation).order_by(Employee.name).all() + employees = ( + dbsession.query(Employee) + .filter(Employee.joining_date <= finish_date) + .filter(or_(Employee.is_active, Employee.leaving_date >= start_date)) + .order_by(Employee.cost_centre_id) + .order_by(Employee.designation) + .order_by(Employee.name) + .all() + ) for employee in employees: - att = dbsession.query(Attendance) \ - .filter(Attendance.employee_id == employee.id) \ - .filter(Attendance.date >= start_date) \ - .filter(Attendance.date < finish_date) \ - .filter(Attendance.is_valid == True) \ + att = ( + dbsession.query(Attendance) + .filter(Attendance.employee_id == employee.id) + .filter(Attendance.date >= start_date) + .filter(Attendance.date < finish_date) + .filter(Attendance.is_valid == True) .all() + ) att = sum(map(lambda x: AttendanceType.by_id(x.attendance_type).value, att)) - details.append({'id': employee.id, 'name': employee.name, 'designation': employee.designation, - 'department': employee.cost_centre.name, 'daysWorked': att, 'points': employee.service_points}) + details.append( + { + "id": employee.id, + "name": employee.name, + "designation": employee.designation, + "department": employee.cost_centre.name, + "daysWorked": att, + "points": employee.service_points, + } + ) - amount = dbsession.query(func.sum(Journal.amount * Journal.debit)) \ - .join(Journal.voucher) \ - .filter(Voucher.date < finish_date) \ - .filter(Voucher.type != VoucherType.by_name('Issue').id) \ - .filter(Journal.account_id == Account.service_charge_id()) \ + amount = ( + dbsession.query(func.sum(Journal.amount * Journal.debit)) + .join(Journal.voucher) + .filter(Voucher.date < finish_date) + .filter(Voucher.type != VoucherType.by_name("Issue").id) + .filter(Journal.account_id == Account.service_charge_id()) .scalar() - amount = 0 if amount is None else amount * Decimal(.9) * -1 + ) + amount = 0 if amount is None else amount * Decimal(0.9) * -1 return details, amount def get_edit_url(request, voucher): if voucher.type == 1: - return request.route_url('journal_id', id=voucher.id) + return request.route_url("journal_id", id=voucher.id) elif voucher.type == 2: - return request.route_url('purchase_id', id=voucher.id) + return request.route_url("purchase_id", id=voucher.id) elif voucher.type == 3: - return request.route_url('issue_id', id=voucher.id) + return request.route_url("issue_id", id=voucher.id) elif voucher.type == 4: - return request.route_url('payment_id', id=voucher.id) + return request.route_url("payment_id", id=voucher.id) elif voucher.type == 5: - return request.route_url('receipt_id', id=voucher.id) + return request.route_url("receipt_id", id=voucher.id) elif voucher.type == 6: - return request.route_url('purchase_return_id', id=voucher.id) + return request.route_url("purchase_return_id", id=voucher.id) elif voucher.type == 12: - return request.route_url('employee_benefits_id', id=voucher.id) + return request.route_url("employee_benefits_id", id=voucher.id) elif voucher.type == 13: - return request.route_url('incentive_id', id=voucher.id) + return request.route_url("incentive_id", id=voucher.id) else: - return '#' + return "#" diff --git a/brewman/views/services/voucher/credit_salary.py b/brewman/views/services/voucher/credit_salary.py index 5aee6c02..58cf9227 100644 --- a/brewman/views/services/voucher/credit_salary.py +++ b/brewman/views/services/voucher/credit_salary.py @@ -12,22 +12,37 @@ from ....models.voucher import Voucher, VoucherType, Attendance, Journal from ..session import get_first_day, get_last_day -@view_config(request_method='POST', route_name='api_credit_salary', renderer='json', permission='Attendance', - trans=True) +@view_config( + request_method="POST", + route_name="api_credit_salary", + renderer="json", + permission="Attendance", + trans=True, +) def credit_salary(request): - user = request.dbsession.query(User).filter(User.id == uuid.UUID(request.authenticated_userid)).one() - month = datetime.datetime.strptime(request.json_body['month'], '%d-%b-%Y') + user = ( + request.dbsession.query(User) + .filter(User.id == uuid.UUID(request.authenticated_userid)) + .one() + ) + month = datetime.datetime.strptime(request.json_body["month"], "%d-%b-%Y") start_date = get_first_day(month) finish_date = get_last_day(month) - voucher = Voucher(date=finish_date, narration='Auto Generated Salary Entry', user_id=user.id, - type=VoucherType.by_name('Journal'), posted=True, poster_id=user.id) + voucher = Voucher( + date=finish_date, + narration="Auto Generated Salary Entry", + user_id=user.id, + type=VoucherType.by_name("Journal"), + posted=True, + poster_id=user.id, + ) request.dbsession.add(voucher) for item in salary_journals(start_date, finish_date, request.dbsession): voucher.journals.append(item) request.dbsession.add(item) transaction.commit() - return {'message': 'Salary Entry created'} + return {"message": "Salary Entry created"} def salary_journals(start_date, finish_date, dbsession): @@ -35,23 +50,47 @@ def salary_journals(start_date, finish_date, dbsession): finish_date = finish_date + datetime.timedelta(1) amount = 0 journals = [] - employees = dbsession.query(Employee) \ - .filter(Employee.joining_date <= finish_date) \ - .filter(or_(Employee.is_active, Employee.leaving_date >= start_date)) \ - .order_by(Employee.cost_centre_id).order_by(Employee.designation).order_by(Employee.name).all() + employees = ( + dbsession.query(Employee) + .filter(Employee.joining_date <= finish_date) + .filter(or_(Employee.is_active, Employee.leaving_date >= start_date)) + .order_by(Employee.cost_centre_id) + .order_by(Employee.designation) + .order_by(Employee.name) + .all() + ) for employee in employees: - att = dbsession.query(Attendance) \ - .filter(Attendance.employee_id == employee.id) \ - .filter(Attendance.date >= start_date) \ - .filter(Attendance.date < finish_date) \ - .filter(Attendance.is_valid == True) \ + att = ( + dbsession.query(Attendance) + .filter(Attendance.employee_id == employee.id) + .filter(Attendance.date >= start_date) + .filter(Attendance.date < finish_date) + .filter(Attendance.is_valid == True) .all() + ) att = sum(map(lambda x: AttendanceType.by_id(x.attendance_type).value, att)) att = round(att * employee.salary / days) if att != 0: amount += att journals.append( - Journal(amount=att, debit=-1, account_id=employee.id, cost_centre_id=employee.cost_centre_id)) - salary = dbsession.query(Account).filter(Account.id == uuid.UUID(Account.salary()['id'])).first() - journals.append(Journal(amount=amount, debit=1, account_id=salary.id, cost_centre_id=salary.cost_centre_id)) + Journal( + amount=att, + debit=-1, + account_id=employee.id, + cost_centre_id=employee.cost_centre_id, + ) + ) + salary = ( + dbsession.query(Account) + .filter(Account.id == uuid.UUID(Account.salary()["id"])) + .first() + ) + journals.append( + Journal( + amount=amount, + debit=1, + account_id=salary.id, + cost_centre_id=salary.cost_centre_id, + ) + ) return journals diff --git a/brewman/views/services/voucher/emptyvoucher.py b/brewman/views/services/voucher/emptyvoucher.py index 785a7394..c5fd3e32 100644 --- a/brewman/views/services/voucher/emptyvoucher.py +++ b/brewman/views/services/voucher/emptyvoucher.py @@ -3,63 +3,72 @@ from brewman.views.services.session import session_current_date from brewman.views.services.voucher import blank_voucher -@view_defaults(request_method='GET', route_name='api_voucher', renderer='json') +@view_defaults(request_method="GET", route_name="api_voucher", renderer="json") class EmptyVoucher(object): def __init__(self, request): self.request = request - @view_config(request_param='t=Journal', permission='Journal') + @view_config(request_param="t=Journal", permission="Journal") def journal(self): return self.get_blank() - @view_config(request_param='t=Payment', permission='Payment') + @view_config(request_param="t=Payment", permission="Payment") def payment(self): - account = self.request.GET.get('a', None) - return self.get_blank({'account': account}) + account = self.request.GET.get("a", None) + return self.get_blank({"account": account}) - @view_config(request_param='t=Receipt', permission='Receipt') + @view_config(request_param="t=Receipt", permission="Receipt") def receipt(self): - account = self.request.GET.get('a', None) - return self.get_blank({'account': account}) + account = self.request.GET.get("a", None) + return self.get_blank({"account": account}) - @view_config(request_param='t=Purchase', permission='Purchase') + @view_config(request_param="t=Purchase", permission="Purchase") def purchase(self): return self.get_blank() - @view_config(request_param='t=Purchase Return', permission='Purchase Return') + @view_config(request_param="t=Purchase Return", permission="Purchase Return") def purchase_return(self): return self.get_blank() - @view_config(request_param='t=Salary Deduction', permission='Purchase Return') + @view_config(request_param="t=Salary Deduction", permission="Purchase Return") def purchase_return(self): return self.get_blank() - @view_config(request_param='t=Issue', permission='Issue') + @view_config(request_param="t=Issue", permission="Issue") def issue(self): - voucher_type = self.request.GET.get('t', None) - date = self.request.GET.get('date', None) - source = self.request.GET.get('source', None) - destination = self.request.GET.get('destination', None) + voucher_type = self.request.GET.get("t", None) + date = self.request.GET.get("date", None) + source = self.request.GET.get("source", None) + destination = self.request.GET.get("destination", None) if date is not None and source is not None and destination is not None: - return blank_voucher({'type': voucher_type, 'date': date, 'source': source, 'destination': destination}, - self.request.dbsession) + return blank_voucher( + { + "type": voucher_type, + "date": date, + "source": source, + "destination": destination, + }, + self.request.dbsession, + ) else: return self.get_blank() - @view_config(request_param='t=Service Charge', permission='Service Charge') + @view_config(request_param="t=Service Charge", permission="Service Charge") def service_charge(self): - voucher_type = self.request.GET.get('t', None) - date = self.request.GET.get('d', None) + voucher_type = self.request.GET.get("t", None) + date = self.request.GET.get("d", None) if date is not None: - return blank_voucher({'type': voucher_type, 'date': date}, self.request.dbsession) + return blank_voucher( + {"type": voucher_type, "date": date}, self.request.dbsession + ) else: return self.get_blank() def get_blank(self, additional_info=None): - voucher_type = self.request.GET.get('t', None) + voucher_type = self.request.GET.get("t", None) if additional_info is None: additional_info = {} - additional_info['date'] = session_current_date(self.request) - additional_info['type'] = voucher_type + additional_info["date"] = session_current_date(self.request) + additional_info["type"] = voucher_type return blank_voucher(additional_info, self.request.dbsession) diff --git a/brewman/views/services/voucher/issue.py b/brewman/views/services/voucher/issue.py index 18c08a41..d8277fea 100644 --- a/brewman/views/services/voucher/issue.py +++ b/brewman/views/services/voucher/issue.py @@ -8,15 +8,20 @@ from brewman.models.voucher import Voucher, VoucherType, Batch, Inventory, Journ def issue_create_voucher(json, user, dbsession): - dt = datetime.datetime.strptime(json['date'], '%d-%b-%Y') - voucher = Voucher(date=dt, narration=json['narration'], user_id=user.id, type=VoucherType.by_name('Issue')) + dt = datetime.datetime.strptime(json["date"], "%d-%b-%Y") + voucher = Voucher( + date=dt, + narration=json["narration"], + user_id=user.id, + type=VoucherType.by_name("Issue"), + ) dbsession.add(voucher) - for item in json['journals']: - if int(item['debit']) == 1: - destination = uuid.UUID(item['costCentre']['id']) + for item in json["journals"]: + if int(item["debit"]) == 1: + destination = uuid.UUID(item["costCentre"]["id"]) else: - source = uuid.UUID(item['costCentre']['id']) + source = uuid.UUID(item["costCentre"]["id"]) if source == destination: raise ValidationError("Source cannot be the same as destination") if source == CostCentre.cost_centre_purchase(): @@ -25,7 +30,7 @@ def issue_create_voucher(json, user, dbsession): batch_consumed = False else: batch_consumed = None - for item in json['inventories']: + for item in json["inventories"]: issue_create_inventory(voucher, item, batch_consumed, dbsession) for item in issue_create_journals(voucher.inventories, source, destination): voucher.journals.append(item) @@ -36,16 +41,28 @@ def issue_create_voucher(json, user, dbsession): def issue_create_inventory(voucher, item, batch_consumed, dbsession): - batch = dbsession.query(Batch).filter(Batch.id == uuid.UUID(item['batch']['id'])).first() - inventory_id = uuid.UUID(item['id']) if 'id' in item and item['id'] is not None else None - quantity = round(Decimal(item['quantity']), 2) + batch = ( + dbsession.query(Batch) + .filter(Batch.id == uuid.UUID(item["batch"]["id"])) + .first() + ) + inventory_id = ( + uuid.UUID(item["id"]) if "id" in item and item["id"] is not None else None + ) + quantity = round(Decimal(item["quantity"]), 2) if quantity <= 0: - raise ValidationError("Quantity of {0} cannot be zero".format(item.product.name)) + raise ValidationError( + "Quantity of {0} cannot be zero".format(item.product.name) + ) if batch_consumed == True and quantity > batch.quantity_remaining: - raise ValidationError("Quantity available is {0} only".format(batch.quantity_remaining)) + raise ValidationError( + "Quantity available is {0} only".format(batch.quantity_remaining) + ) if batch.name > voucher.date: - raise ValidationError("Batch of {0} was purchased after the issue date".format(batch.product.name)) + raise ValidationError( + "Batch of {0} was purchased after the issue date".format(batch.product.name) + ) if batch_consumed is None: pass elif batch_consumed: @@ -53,8 +70,15 @@ def issue_create_inventory(voucher, item, batch_consumed, dbsession): else: batch.quantity_remaining += quantity - item = Inventory(id=inventory_id, product_id=batch.product.id, quantity=quantity, rate=batch.rate, tax=batch.tax, - discount=batch.discount, batch=batch) + 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) @@ -63,15 +87,25 @@ def issue_create_journals(inventories, source, destination): amount = 0 for item in inventories: amount += item.amount - return [Journal(debit=-1, account_id=AccountBase.all_purchases(), amount=round(amount, 2), - cost_centre_id=source), - Journal(debit=1, account_id=AccountBase.all_purchases(), amount=round(amount, 2), - cost_centre_id=destination)] + return [ + Journal( + debit=-1, + account_id=AccountBase.all_purchases(), + amount=round(amount, 2), + cost_centre_id=source, + ), + Journal( + debit=1, + account_id=AccountBase.all_purchases(), + amount=round(amount, 2), + cost_centre_id=destination, + ), + ] def issue_update_voucher(voucher, json, user, dbsession): - voucher.date = datetime.datetime.strptime(json['date'], '%d-%b-%Y') - voucher.narration = json['narration'] + voucher.date = datetime.datetime.strptime(json["date"], "%d-%b-%Y") + voucher.narration = json["narration"] voucher.user_id = user.id voucher.last_edit_date = datetime.datetime.utcnow() @@ -87,11 +121,11 @@ def issue_update_voucher(voucher, json, user, dbsession): else: old_batch_consumed = None - for item in json['journals']: - if int(item['debit']) == 1: - destination = uuid.UUID(item['costCentre']['id']) + for item in json["journals"]: + if int(item["debit"]) == 1: + destination = uuid.UUID(item["costCentre"]["id"]) else: - source = uuid.UUID(item['costCentre']['id']) + source = uuid.UUID(item["costCentre"]["id"]) if source == destination: raise ValidationError("Source cannot be the same as destination") @@ -105,7 +139,7 @@ def issue_update_voucher(voucher, json, user, dbsession): if new_batch_consumed != old_batch_consumed: raise ValidationError("Purchase cost centre cannot be changed") - issue_update_inventory(voucher, json['inventories'], old_batch_consumed, dbsession) + issue_update_inventory(voucher, json["inventories"], old_batch_consumed, dbsession) issue_update_journals(voucher, source, destination) journals_valid(voucher) inventory_valid(voucher) @@ -118,30 +152,44 @@ def issue_update_inventory(voucher, new_inventories, batch_consumed, dbsession): found = False for j in range(len(new_inventories), 0, -1): i = new_inventories[j - 1] - if 'id' in i and i['id'] is not None and item.id == uuid.UUID(i['id']): - batch = dbsession.query(Batch).filter(Batch.id == uuid.UUID(i['batch']['id'])).first() + if "id" in i and i["id"] is not None and item.id == uuid.UUID(i["id"]): + batch = ( + dbsession.query(Batch) + .filter(Batch.id == uuid.UUID(i["batch"]["id"])) + .first() + ) found = True if item.batch_id != batch.id: - raise ValidationError('Product / Batch cannot be changed') - new_quantity = round(Decimal(i['quantity']), 2) + raise ValidationError("Product / Batch cannot be changed") + new_quantity = round(Decimal(i["quantity"]), 2) old_quantity = round(Decimal(item.quantity), 2) quantity_remaining = round(Decimal(item.batch.quantity_remaining), 2) if new_quantity <= 0: - raise ValidationError("Quantity of {0} cannot be zero".format(item.product.name)) - if batch_consumed is True and new_quantity - old_quantity > quantity_remaining: - raise ValidationError("Maximum quantity available for {0} is {1}".format( - item.product.full_name, old_quantity + quantity_remaining + raise ValidationError( + "Quantity of {0} cannot be zero".format(item.product.name) ) + if ( + batch_consumed is True + and new_quantity - old_quantity > quantity_remaining + ): + raise ValidationError( + "Maximum quantity available for {0} is {1}".format( + item.product.full_name, old_quantity + quantity_remaining + ) ) if item.batch.name > voucher.date: - raise ValidationError("Batch of {0} was purchased after the issue date".format(item.product.name)) + raise ValidationError( + "Batch of {0} was purchased after the issue date".format( + item.product.name + ) + ) if batch_consumed is None: pass elif batch_consumed: - item.batch.quantity_remaining -= (new_quantity - old_quantity) + item.batch.quantity_remaining -= new_quantity - old_quantity else: - item.batch.quantity_remaining += (new_quantity - old_quantity) + item.batch.quantity_remaining += new_quantity - old_quantity item.quantity = new_quantity item.rate = batch.rate @@ -158,8 +206,10 @@ def issue_update_inventory(voucher, new_inventories, batch_consumed, dbsession): else: if item.batch.quantity_remaining < item.quantity: raise ValidationError( - "Product {0} cannot be removed, minimum quantity is {1}".format(item.product.name, - item.batch.quantity_remaining)) + "Product {0} cannot be removed, minimum quantity is {1}".format( + item.product.name, item.batch.quantity_remaining + ) + ) item.batch.quantity_remaining -= item.quantity dbsession.delete(item) voucher.inventories.remove(item) diff --git a/brewman/views/services/voucher/journal.py b/brewman/views/services/voucher/journal.py index 8e19d61d..8f180423 100644 --- a/brewman/views/services/voucher/journal.py +++ b/brewman/views/services/voucher/journal.py @@ -8,48 +8,67 @@ from brewman.models.voucher import Journal, Voucher, VoucherType, DbImage def journal_create_voucher(json, files, user, dbsession): - dt = datetime.datetime.strptime(json['date'], '%d-%b-%Y') + dt = datetime.datetime.strptime(json["date"], "%d-%b-%Y") voucher = Voucher( - date=dt, narration=json['narration'], - is_starred=json['isStarred'], - user_id=user.id, type=VoucherType.by_name(json['type']) + date=dt, + narration=json["narration"], + is_starred=json["isStarred"], + user_id=user.id, + type=VoucherType.by_name(json["type"]), ) dbsession.add(voucher) - for item in json['journals']: - account = dbsession.query(AccountBase).filter(AccountBase.id == uuid.UUID(item['account']['id'])).first() - journal_id = uuid.UUID(item['id']) if 'id' in item and item['id'] is not None else None - amount = round(Decimal(item['amount']), 2) - journal = Journal(id=journal_id, amount=amount, debit=int(item['debit']), account_id=account.id, - cost_centre_id=account.cost_centre_id) + for item in json["journals"]: + account = ( + dbsession.query(AccountBase) + .filter(AccountBase.id == uuid.UUID(item["account"]["id"])) + .first() + ) + journal_id = ( + uuid.UUID(item["id"]) if "id" in item and item["id"] is not None else None + ) + amount = round(Decimal(item["amount"]), 2) + journal = Journal( + id=journal_id, + amount=amount, + debit=int(item["debit"]), + account_id=account.id, + cost_centre_id=account.cost_centre_id, + ) voucher.journals.append(journal) dbsession.add(journal) journals_valid(voucher) for key, value in files.items(): - dbsession.add(DbImage(voucher.id, 'voucher', value['f'], value['t'])) + dbsession.add(DbImage(voucher.id, "voucher", value["f"], value["t"])) return voucher def journal_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'] + voucher.date = datetime.datetime.strptime(json["date"], "%d-%b-%Y") + voucher.is_starred = json["isStarred"] + voucher.narration = json["narration"] voucher.user_id = user.id voucher.posted = False voucher.last_edit_date = datetime.datetime.utcnow() - new_journals = json['journals'] + new_journals = json["journals"] for i in range(len(voucher.journals), 0, -1): item = voucher.journals[i - 1] found = False for j in range(len(new_journals), 0, -1): new_item = new_journals[j - 1] - if 'id' in new_item and new_item['id'] is not None and item.id == uuid.UUID(new_item['id']): - account = dbsession.query(AccountBase).filter( - AccountBase.id == uuid.UUID(new_item['account']['id']) - ).first() + if ( + "id" in new_item + and new_item["id"] is not None + and item.id == uuid.UUID(new_item["id"]) + ): + account = ( + dbsession.query(AccountBase) + .filter(AccountBase.id == uuid.UUID(new_item["account"]["id"])) + .first() + ) found = True - item.debit = int(new_item['debit']) - item.amount = round(Decimal(new_item['amount']), 2) + item.debit = int(new_item["debit"]) + item.amount = round(Decimal(new_item["amount"]), 2) item.account_id = account.id item.cost_centre_id = account.cost_centre_id new_journals.remove(new_item) @@ -57,18 +76,28 @@ def journal_update_voucher(voucher, json, files, user, dbsession): if not found: voucher.journals.remove(item) for new_item in new_journals: - account = dbsession.query(AccountBase).filter(AccountBase.id == uuid.UUID(new_item['account']['id'])).first() - journal = Journal(id=None, amount=round(Decimal(new_item['amount']), 2), debit=int(new_item['debit']), - account_id=account.id, - cost_centre_id=account.cost_centre_id) + account = ( + dbsession.query(AccountBase) + .filter(AccountBase.id == uuid.UUID(new_item["account"]["id"])) + .first() + ) + journal = Journal( + id=None, + amount=round(Decimal(new_item["amount"]), 2), + debit=int(new_item["debit"]), + account_id=account.id, + cost_centre_id=account.cost_centre_id, + ) dbsession.add(journal) voucher.journals.append(journal) journals_valid(voucher) - old_files = [uuid.UUID(f['id']) for f in json['files'] if 'id' in f and f['id'] is not None] + 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'])) + dbsession.add(DbImage(voucher.id, "voucher", value["f"], value["t"])) return voucher diff --git a/brewman/views/services/voucher/purchase.py b/brewman/views/services/voucher/purchase.py index 23fb22c9..2b80ba28 100644 --- a/brewman/views/services/voucher/purchase.py +++ b/brewman/views/services/voucher/purchase.py @@ -7,53 +7,87 @@ from sqlalchemy import func from brewman.models.master import Product, AccountBase from brewman.models.operations import journals_valid, inventory_valid from brewman.models.validation_exception import ValidationError -from brewman.models.voucher import Voucher, VoucherType, Batch, Inventory, Journal, DbImage +from brewman.models.voucher import ( + Voucher, + VoucherType, + Batch, + Inventory, + Journal, + DbImage, +) def purchase_create_voucher(json, files, user, dbsession): - dt = datetime.datetime.strptime(json['date'], '%d-%b-%Y') + dt = datetime.datetime.strptime(json["date"], "%d-%b-%Y") voucher = Voucher( - date=dt, narration=json['narration'], - is_starred=json['isStarred'], - user_id=user.id, type=VoucherType.by_name(json['type']) + date=dt, + narration=json["narration"], + is_starred=json["isStarred"], + user_id=user.id, + type=VoucherType.by_name(json["type"]), ) dbsession.add(voucher) - for item in json['inventories']: + for item in json["inventories"]: purchase_create_inventory(voucher, item, dt, dbsession) - for item in purchase_create_journals(voucher.inventories, json['journals'][0]['account']['id'], dbsession): + for item in purchase_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'])) + dbsession.add(DbImage(voucher.id, "voucher", value["f"], value["t"])) return voucher def purchase_create_inventory(voucher, item, date, dbsession): - if 'product' not in item or 'id' not in item['product']: - raise ValidationError('No Product in item') - product = dbsession.query(Product).filter(Product.id == uuid.UUID(item['product']['id'])).first() + if "product" not in item or "id" not in item["product"]: + raise ValidationError("No Product in item") + product = ( + dbsession.query(Product) + .filter(Product.id == uuid.UUID(item["product"]["id"])) + .first() + ) if product is None: - raise ValidationError('No Product in item') - inventory_id = uuid.UUID(item['id']) if 'id' in item and item['id'] is not None else None - quantity = round(Decimal(item['quantity']), 2) - rate = round(Decimal(item['rate']), 2) - tax = round(Decimal(item['tax']), 5) - discount = round(Decimal(item['discount']), 5) - batch = Batch(name=date, product_id=product.id, quantity_remaining=quantity, rate=rate, tax=tax, - discount=discount) + raise ValidationError("No Product in item") + inventory_id = ( + uuid.UUID(item["id"]) if "id" in item and item["id"] is not None else None + ) + quantity = round(Decimal(item["quantity"]), 2) + rate = round(Decimal(item["rate"]), 2) + tax = round(Decimal(item["tax"]), 5) + discount = round(Decimal(item["discount"]), 5) + batch = Batch( + name=date, + product_id=product.id, + quantity_remaining=quantity, + rate=rate, + tax=tax, + discount=discount, + ) dbsession.add(batch) - inventory = Inventory(id=inventory_id, product_id=product.id, batch=batch, quantity=quantity, rate=rate, tax=tax, - discount=discount) + inventory = Inventory( + id=inventory_id, + product_id=product.id, + batch=batch, + quantity=quantity, + rate=rate, + tax=tax, + discount=discount, + ) product.price = rate voucher.inventories.append(inventory) dbsession.add(inventory) def purchase_create_journals(inventories, account_id, dbsession): - other_account = dbsession.query(AccountBase).filter(AccountBase.id == uuid.UUID(account_id)).first() + other_account = ( + dbsession.query(AccountBase) + .filter(AccountBase.id == uuid.UUID(account_id)) + .first() + ) journals = dict() amount = 0 for item in inventories: @@ -65,33 +99,41 @@ def purchase_create_journals(inventories, account_id, dbsession): 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 + 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 + debit=-1, + cost_centre_id=other_account.cost_centre_id, + account_id=other_account.id, + amount=amount, ) return list(journals.values()) 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'] + voucher.date = datetime.datetime.strptime(json["date"], "%d-%b-%Y") + voucher.is_starred = json["isStarred"] + voucher.narration = json["narration"] 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) + 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] + 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'])) + dbsession.add(DbImage(voucher.id, "voucher", value["f"], value["t"])) return voucher @@ -101,24 +143,35 @@ def purchase_update_inventory(voucher, new_inventories, dbsession): 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() + 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') - new_quantity = round(Decimal(i['quantity']), 2) + raise ValidationError("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 ValidationError("Quantity of {0} cannot be zero".format(item.product.name)) - if old_quantity > new_quantity and quantity_remaining < (old_quantity - new_quantity): - raise ValidationError("{0} has been issued, minimum quantity is".format( - old_quantity - quantity_remaining)) - item.batch.quantity_remaining -= (old_quantity - new_quantity) + raise ValidationError( + "Quantity of {0} cannot be zero".format(item.product.name) + ) + if old_quantity > new_quantity and quantity_remaining < ( + old_quantity - new_quantity + ): + raise ValidationError( + "{0} has been issued, minimum quantity is".format( + old_quantity - quantity_remaining + ) + ) + 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) + 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: @@ -135,25 +188,49 @@ def purchase_update_inventory(voucher, new_inventories, dbsession): # 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() + uses = ( + dbsession.query(func.count(Inventory.id)) + .filter(Inventory.batch_id == item.batch.id) + .filter(Inventory.id != item.id) + .scalar() + ) if uses > 0: - raise ValidationError("{0} has been issued, it cannot be deleted".format(item.product.name)) + raise ValidationError( + "{0} has been issued, it cannot be deleted".format( + item.product.name + ) + ) 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) + 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 @@ -163,10 +240,12 @@ def purchase_update_inventory(voucher, new_inventories, dbsession): 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() + 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: @@ -177,10 +256,16 @@ def purchase_update_journals(voucher, journals, dbsession): 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 + 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 + 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] diff --git a/brewman/views/services/voucher/purchase_return.py b/brewman/views/services/voucher/purchase_return.py index 4c4dafc0..5db84e8f 100644 --- a/brewman/views/services/voucher/purchase_return.py +++ b/brewman/views/services/voucher/purchase_return.py @@ -5,53 +5,86 @@ 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 +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') + dt = datetime.datetime.strptime(json["date"], "%d-%b-%Y") voucher = Voucher( - date=dt, narration=json['narration'], - is_starred=json['isStarred'], - user_id=user.id, type=VoucherType.by_name(json['type']) + date=dt, + narration=json["narration"], + is_starred=json["isStarred"], + user_id=user.id, + type=VoucherType.by_name(json["type"]), ) dbsession.add(voucher) - for item in json['inventories']: + 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): + 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'])) + 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']) + 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("Quantity of {0} cannot be zero".format(item.product.name)) + raise ValidationError( + "Quantity of {0} cannot be zero".format(item.product.name) + ) if quantity > batch.quantity_remaining: - raise ValidationError("Quantity available is {0} only".format(batch.quantity_remaining)) + raise ValidationError( + "Quantity available is {0} only".format(batch.quantity_remaining) + ) if batch.name > voucher.date: - raise ValidationError("Batch of {0} was purchased after the issue date".format(batch.product.name)) + raise ValidationError( + "Batch of {0} was purchased after the issue date".format(batch.product.name) + ) 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) + 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() + other_account = ( + dbsession.query(AccountBase) + .filter(AccountBase.id == uuid.UUID(account_id)) + .first() + ) journals = dict() amount = 0 for item in inventories: @@ -62,33 +95,43 @@ def purchase_return_create_journals(inventories, account_id, dbsession): 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) + 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 + 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'] + voucher.date = datetime.datetime.strptime(json["date"], "%d-%b-%Y") + voucher.is_starred = json["isStarred"] + voucher.narration = json["narration"] 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) + 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] + 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'])) + dbsession.add(DbImage(voucher.id, "voucher", value["f"], value["t"])) return voucher @@ -98,23 +141,34 @@ def purchase_return_update_inventory(voucher, new_inventories, date, dbsession): 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() + 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) + 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)) + 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 + 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) + 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 @@ -127,9 +181,12 @@ def purchase_return_update_inventory(voucher, new_inventories, date, 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() + 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: @@ -140,10 +197,16 @@ def purchase_return_update_journals(voucher, journals, dbsession): 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) + 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 + 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] diff --git a/brewman/views/services/voucher/salary_deduction.py b/brewman/views/services/voucher/salary_deduction.py index 1f59fb11..d43199b4 100644 --- a/brewman/views/services/voucher/salary_deduction.py +++ b/brewman/views/services/voucher/salary_deduction.py @@ -9,21 +9,41 @@ from brewman.views.services.session import get_last_day def salary_deduction_create_voucher(json, user, dbsession): - dt = get_last_day(datetime.datetime.strptime(json['date'], '%d-%b-%Y')) + 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, days_in_month, voucher, dbsession) + for item in json["employeeBenefits"]: + item_exp, item_total = add_salary_deduction( + item, days_in_month, voucher, dbsession + ) exp += item_exp total += item_total - account = dbsession.query(AccountBase).filter(AccountBase.id == AccountBase.esi_pf_expense()).first() - journal = Journal(amount=exp, debit=1, account_id=account.id, cost_centre_id=account.cost_centre_id) + account = ( + dbsession.query(AccountBase) + .filter(AccountBase.id == AccountBase.esi_pf_expense()) + .first() + ) + journal = Journal( + amount=exp, + debit=1, + account_id=account.id, + cost_centre_id=account.cost_centre_id, + ) dbsession.add(journal) voucher.journals.append(journal) - account = dbsession.query(AccountBase).filter(AccountBase.id == AccountBase.esi_pf_payable()).first() - journal = Journal(amount=total, debit=-1, account_id=account.id, cost_centre_id=account.cost_centre_id) + account = ( + dbsession.query(AccountBase) + .filter(AccountBase.id == AccountBase.esi_pf_payable()) + .first() + ) + journal = Journal( + amount=total, + debit=-1, + account_id=account.id, + cost_centre_id=account.cost_centre_id, + ) dbsession.add(journal) voucher.journals.append(journal) @@ -32,7 +52,7 @@ def salary_deduction_create_voucher(json, user, dbsession): def salary_deduction_update_voucher(voucher, json, user, dbsession): - dt = get_last_day(datetime.datetime.strptime(json['date'], '%d-%b-%Y')) + 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!") days_in_month = voucher.date.day @@ -40,14 +60,18 @@ def salary_deduction_update_voucher(voucher, json, user, dbsession): voucher.posted = False voucher.last_edit_date = datetime.datetime.utcnow() - new_deductions = json['employeeBenefits'] + 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] found = False for j in range(len(new_deductions), 0, -1): new_item = new_deductions[j - 1] - if 'id' in new_item and new_item['id'] is not None and item.id == uuid.UUID(new_item['id']): + if ( + "id" in new_item + and new_item["id"] is not None + and item.id == uuid.UUID(new_item["id"]) + ): journals.append(item.journal.id) exp += item.esi_er + item.pf_er total += item.esi_ee + item.pf_ee + item.esi_er + item.pf_er @@ -57,14 +81,20 @@ def salary_deduction_update_voucher(voucher, json, user, dbsession): voucher.salary_deductions.remove(item) voucher.journals.remove(item.journal) for new_item in new_deductions: - item_exp, item_total = add_salary_deduction(new_item, days_in_month, voucher, dbsession) + item_exp, item_total = add_salary_deduction( + new_item, days_in_month, voucher, dbsession + ) exp += item_exp total += item_total - journal = [i for i in voucher.journals if i.account_id == AccountBase.esi_pf_expense()] + journal = [ + i for i in voucher.journals if i.account_id == AccountBase.esi_pf_expense() + ] journal = journal[0] journal.amount = exp - journal = [i for i in voucher.journals if i.account_id == AccountBase.esi_pf_payable()] + journal = [ + i for i in voucher.journals if i.account_id == AccountBase.esi_pf_payable() + ] journal = journal[0] journal.amount = total @@ -73,15 +103,31 @@ def salary_deduction_update_voucher(voucher, json, user, dbsession): def add_salary_deduction(item, days_in_month, voucher, dbsession): - account = dbsession.query(Employee).filter(Employee.id == uuid.UUID(item['journal']['account']['id'])).first() - gross_salary = int(item['grossSalary']) - days_worked = int(item['daysWorked']) - esi_ee, esi_er, esi_both = esi_contribution(gross_salary, days_worked, days_in_month) + account = ( + dbsession.query(Employee) + .filter(Employee.id == uuid.UUID(item["journal"]["account"]["id"])) + .first() + ) + gross_salary = int(item["grossSalary"]) + days_worked = int(item["daysWorked"]) + esi_ee, esi_er, esi_both = esi_contribution( + gross_salary, days_worked, days_in_month + ) pf_ee, pf_er, pf_both = pf_contribution(gross_salary, days_worked, days_in_month) - journal = Journal(amount=esi_ee + pf_ee, debit=1, account_id=account.id, cost_centre_id=account.cost_centre_id) + journal = Journal( + amount=esi_ee + pf_ee, + debit=1, + account_id=account.id, + cost_centre_id=account.cost_centre_id, + ) sd = SalaryDeduction( - journal=journal, gross_salary=gross_salary, days_worked=days_worked, - esi_ee=esi_ee, pf_ee=pf_ee, esi_er=esi_er, pf_er=pf_er + journal=journal, + gross_salary=gross_salary, + days_worked=days_worked, + esi_ee=esi_ee, + pf_ee=pf_ee, + esi_er=esi_er, + pf_er=pf_er, ) voucher.journals.append(journal) voucher.salary_deductions.append(sd) @@ -92,17 +138,33 @@ def add_salary_deduction(item, days_in_month, voucher, dbsession): def esi_contribution(gross_salary, days_worked, days_in_month): limit = 21000 - employee_rate = .0175 - employer_rate = .0475 - employee = 0 if gross_salary > limit else ceil(employee_rate * gross_salary * days_worked / days_in_month) - employer = 0 if gross_salary > limit else ceil(employer_rate * gross_salary * days_worked / days_in_month) + employee_rate = 0.0175 + employer_rate = 0.0475 + employee = ( + 0 + if gross_salary > limit + else ceil(employee_rate * gross_salary * days_worked / days_in_month) + ) + employer = ( + 0 + if gross_salary > limit + else ceil(employer_rate * gross_salary * days_worked / days_in_month) + ) return employee, employer, employee + employer def pf_contribution(gross_salary, days_worked, days_in_month): limit = 15000 - employee_rate = .12 - employer_rate = .12 + .011 + .005 + .0001 - employee = 0 if gross_salary > limit else ceil(employee_rate * gross_salary * days_worked / days_in_month) - employer = 0 if gross_salary > limit else ceil(employer_rate * gross_salary * days_worked / days_in_month) + employee_rate = 0.12 + employer_rate = 0.12 + 0.011 + 0.005 + 0.0001 + employee = ( + 0 + if gross_salary > limit + else ceil(employee_rate * gross_salary * days_worked / days_in_month) + ) + employer = ( + 0 + if gross_salary > limit + else ceil(employer_rate * gross_salary * days_worked / days_in_month) + ) return employee, employer, employee + employer diff --git a/brewman/views/services/voucher/savevoucher.py b/brewman/views/services/voucher/savevoucher.py index 6ffe5ba6..b87ac116 100644 --- a/brewman/views/services/voucher/savevoucher.py +++ b/brewman/views/services/voucher/savevoucher.py @@ -10,13 +10,20 @@ from brewman.models.validation_exception import ValidationError from brewman.models.voucher import Voucher from brewman.views import get_lock_info from brewman.views.services.session import session_current_date_set -from . import voucher_info, journal_create_voucher, purchase_create_voucher, issue_create_voucher +from . import ( + voucher_info, + journal_create_voucher, + purchase_create_voucher, + issue_create_voucher, +) from . import service_charge_create_voucher from .purchase_return import purchase_return_create_voucher from .salary_deduction import salary_deduction_create_voucher -@view_defaults(request_method='POST', route_name='api_voucher', renderer='json', trans=True) +@view_defaults( + request_method="POST", route_name="api_voucher", renderer="json", trans=True +) class SaveVoucher(object): def __init__(self, request): def parse_post(req): @@ -24,7 +31,7 @@ class SaveVoucher(object): files = {} model = {} for key in keys: - if key == 'model': + if key == "model": model = loads(req.POST[key], encoding=req.charset) else: index = key[1:] @@ -35,62 +42,88 @@ class SaveVoucher(object): return model, files self.request = request - self.user = request.dbsession.query(User).filter(User.id == uuid.UUID(request.authenticated_userid)).one() + self.user = ( + request.dbsession.query(User) + .filter(User.id == uuid.UUID(request.authenticated_userid)) + .one() + ) self.json, self.files = parse_post(request) self.start, self.finish = get_lock_info(request.dbsession) - self.voucher_date = datetime.datetime.strptime(self.json['date'], '%d-%b-%Y') + self.voucher_date = datetime.datetime.strptime(self.json["date"], "%d-%b-%Y") - @view_config(request_param='t=Journal', permission='Journal') + @view_config(request_param="t=Journal", permission="Journal") def journal(self): return self.save() - @view_config(request_param='t=Payment', permission='Payment') + @view_config(request_param="t=Payment", permission="Payment") def payment(self): return self.save() - @view_config(request_param='t=Receipt', permission='Receipt') + @view_config(request_param="t=Receipt", permission="Receipt") def receipt(self): return self.save() - @view_config(request_param='t=Purchase', permission='Purchase') + @view_config(request_param="t=Purchase", permission="Purchase") def purchase(self): return self.save() - @view_config(request_param='t=Purchase Return', permission='Purchase Return') + @view_config(request_param="t=Purchase Return", permission="Purchase Return") def purchase_return(self): return self.save() - @view_config(request_param='t=Issue', permission='Issue') + @view_config(request_param="t=Issue", permission="Issue") def issue(self): return self.save() - @view_config(request_param='t=Salary Deduction', permission='Salary Deduction') + @view_config(request_param="t=Salary Deduction", permission="Salary Deduction") def salary_deduction(self): return self.save() - @view_config(request_param='t=Service Charge', permission='Service Charge') + @view_config(request_param="t=Service Charge", permission="Service Charge") def salary_deduction(self): return self.save() def save(self): if self.start is not None and self.start > self.voucher_date: - raise ValidationError("Vouchers before {0} have been locked.".format(self.start.strftime('%d-%b-%Y'))) + raise ValidationError( + "Vouchers before {0} have been locked.".format( + self.start.strftime("%d-%b-%Y") + ) + ) elif self.finish is not None and self.finish < self.voucher_date: - raise ValidationError("Vouchers after {0} have been locked.".format(self.finish.strftime('%d-%b-%Y'))) + raise ValidationError( + "Vouchers after {0} have been locked.".format( + self.finish.strftime("%d-%b-%Y") + ) + ) - if self.json['type'] in ['Journal', 'Payment', 'Receipt']: - voucher = journal_create_voucher(self.json, self.files, self.user, self.request.dbsession) - elif self.json['type'] in ['Purchase']: - voucher = purchase_create_voucher(self.json, self.files, self.user, self.request.dbsession) - elif self.json['type'] in ['Purchase Return']: - voucher = purchase_return_create_voucher(self.json, self.files, self.user, self.request.dbsession) - elif self.json['type'] in ['Issue']: + if self.json["type"] in ["Journal", "Payment", "Receipt"]: + voucher = journal_create_voucher( + self.json, self.files, self.user, self.request.dbsession + ) + elif self.json["type"] in ["Purchase"]: + voucher = purchase_create_voucher( + self.json, self.files, self.user, self.request.dbsession + ) + elif self.json["type"] in ["Purchase Return"]: + voucher = purchase_return_create_voucher( + self.json, self.files, self.user, self.request.dbsession + ) + elif self.json["type"] in ["Issue"]: voucher = issue_create_voucher(self.json, self.user, self.request.dbsession) - elif self.json['type'] in ['Salary Deduction']: - voucher = salary_deduction_create_voucher(self.json, self.user, self.request.dbsession) - elif self.json['type'] in ['Service Charge']: - voucher = service_charge_create_voucher(self.json, self.user, self.request.dbsession) + elif self.json["type"] in ["Salary Deduction"]: + voucher = salary_deduction_create_voucher( + self.json, self.user, self.request.dbsession + ) + elif self.json["type"] in ["Service Charge"]: + voucher = service_charge_create_voucher( + self.json, self.user, self.request.dbsession + ) transaction.commit() - session_current_date_set(self.request, self.json['date']) - new_voucher = self.request.dbsession.query(Voucher).filter(Voucher.id == voucher.id).first() + session_current_date_set(self.request, self.json["date"]) + new_voucher = ( + self.request.dbsession.query(Voucher) + .filter(Voucher.id == voucher.id) + .first() + ) return voucher_info(new_voucher, self.request) diff --git a/brewman/views/services/voucher/service_charge.py b/brewman/views/services/voucher/service_charge.py index 4d67a577..730cd07f 100644 --- a/brewman/views/services/voucher/service_charge.py +++ b/brewman/views/services/voucher/service_charge.py @@ -6,39 +6,62 @@ from sqlalchemy import or_, func from brewman.models.master import Employee, AttendanceType, Account from brewman.models.operations import journals_valid -from brewman.models.voucher import Journal, Voucher, VoucherType, Attendance, ServiceCharge +from brewman.models.voucher import ( + Journal, + Voucher, + VoucherType, + Attendance, + ServiceCharge, +) from brewman.views.services.session import get_first_day def service_charge_create_voucher(json, user, dbsession): - date = datetime.datetime.strptime(json['date'], '%d-%b-%Y') + date = datetime.datetime.strptime(json["date"], "%d-%b-%Y") voucher = Voucher(date=date, user_id=user.id, type=VoucherType.by_id(13)) dbsession.add(voucher) - employees = get_employees(get_first_day(date), date + datetime.timedelta(1), json['incentives'], - dbsession=dbsession) - amount = balance(date, dbsession=dbsession) * Decimal(.9) + employees = get_employees( + get_first_day(date), + date + datetime.timedelta(1), + json["incentives"], + dbsession=dbsession, + ) + amount = balance(date, dbsession=dbsession) * Decimal(0.9) total_points = 0 for item in employees: - total_points += item['points'] * item['daysWorked'] + total_points += item["points"] * item["daysWorked"] point_value = round(amount / total_points, 2) total_amount = 0 for item in employees: - item_amount = round(item['points'] * item['daysWorked'] * point_value) - employee = item['employee'] - journal = Journal(amount=item_amount, debit=-1, account_id=employee.id, cost_centre_id=employee.cost_centre_id) - sc = ServiceCharge(journal=journal, days_worked=item['daysWorked'], points=item['points']) + item_amount = round(item["points"] * item["daysWorked"] * point_value) + employee = item["employee"] + journal = Journal( + amount=item_amount, + debit=-1, + account_id=employee.id, + cost_centre_id=employee.cost_centre_id, + ) + sc = ServiceCharge( + journal=journal, days_worked=item["daysWorked"], points=item["points"] + ) voucher.journals.append(journal) voucher.service_charges.append(sc) dbsession.add(journal) dbsession.add(sc) total_amount += item_amount - sc = dbsession.query(Account).filter(Account.id == Account.service_charge_id()).first() - journal = Journal(amount=total_amount, debit=1, account_id=sc.id, cost_centre_id=sc.cost_centre_id) + sc = ( + dbsession.query(Account) + .filter(Account.id == Account.service_charge_id()) + .first() + ) + journal = Journal( + amount=total_amount, debit=1, account_id=sc.id, cost_centre_id=sc.cost_centre_id + ) voucher.journals.append(journal) dbsession.add(journal) journals_valid(voucher) @@ -46,7 +69,7 @@ def service_charge_create_voucher(json, user, dbsession): def service_charge_update_voucher(voucher, json, user, dbsession): - date = datetime.datetime.strptime(json['date'], '%d-%b-%Y') + date = datetime.datetime.strptime(json["date"], "%d-%b-%Y") voucher.date = date voucher.user_id = user.id voucher.posted = False @@ -55,67 +78,79 @@ def service_charge_update_voucher(voucher, json, user, dbsession): employees = get_employees( get_first_day(date), date + datetime.timedelta(1), - json['incentives'], + json["incentives"], voucher.journals, - dbsession=dbsession + dbsession=dbsession, ) - amount = balance(date, voucher.id, dbsession) * Decimal(.9) + amount = balance(date, voucher.id, dbsession) * Decimal(0.9) total_points = 0 for item in employees: - total_points += item['points'] * item['daysWorked'] + total_points += item["points"] * item["daysWorked"] point_value = round(amount / total_points, 2) total_amount = 0 for item in voucher.service_charges: - employee = [e for e in employees if e['employee'].id == item.journal.account_id][0] - item_amount = round(employee['points'] * employee['daysWorked'] * point_value) - item.days_worked = employee['daysWorked'] - item.points = employee['points'] + employee = [ + e for e in employees if e["employee"].id == item.journal.account_id + ][0] + item_amount = round(employee["points"] * employee["daysWorked"] * point_value) + item.days_worked = employee["daysWorked"] + item.points = employee["points"] item.journal.amount = item_amount total_amount += item_amount - journal = [j for j in voucher.journals if j.account_id == Account.service_charge_id()][0] + journal = [ + j for j in voucher.journals if j.account_id == Account.service_charge_id() + ][0] journal.amount = total_amount journals_valid(voucher) return voucher -def get_employees(start_date, finish_date, json, voucher_employees=None, dbsession=None): +def get_employees( + start_date, finish_date, json, voucher_employees=None, dbsession=None +): details = [] - employees = dbsession.query( - Employee - ).filter( - Employee.joining_date <= finish_date - ).filter( - or_(Employee.is_active, Employee.leaving_date >= start_date) - ).order_by(Employee.cost_centre_id).order_by(Employee.designation).order_by(Employee.name).all() + employees = ( + dbsession.query(Employee) + .filter(Employee.joining_date <= finish_date) + .filter(or_(Employee.is_active, Employee.leaving_date >= start_date)) + .order_by(Employee.cost_centre_id) + .order_by(Employee.designation) + .order_by(Employee.name) + .all() + ) check_if_employees_changed(json, employees, voucher_employees) for employee in employees: - att = dbsession.query(Attendance) \ - .filter(Attendance.employee_id == employee.id) \ - .filter(Attendance.date >= start_date) \ - .filter(Attendance.date < finish_date) \ - .filter(Attendance.is_valid == True) \ + att = ( + dbsession.query(Attendance) + .filter(Attendance.employee_id == employee.id) + .filter(Attendance.date >= start_date) + .filter(Attendance.date < finish_date) + .filter(Attendance.is_valid == True) .all() + ) att = sum(map(lambda x: AttendanceType.by_id(x.attendance_type).value, att)) - details.append({'employee': employee, 'daysWorked': round(Decimal(att), 2)}) + details.append({"employee": employee, "daysWorked": round(Decimal(att), 2)}) for item in details: - j = [x for x in json if uuid.UUID(x['id']) == item['employee'].id][0] - item['points'] = round(Decimal(j['points']), 2) + j = [x for x in json if uuid.UUID(x["id"]) == item["employee"].id][0] + item["points"] = round(Decimal(j["points"]), 2) json.remove(j) return details def balance(date, voucher_id=None, dbsession=None): - amount = dbsession.query(func.sum(Journal.amount * Journal.debit)) \ - .join(Journal.voucher) \ - .filter(Voucher.date < date + datetime.timedelta(1)) \ - .filter(Voucher.type != VoucherType.by_name('Issue').id) \ + amount = ( + dbsession.query(func.sum(Journal.amount * Journal.debit)) + .join(Journal.voucher) + .filter(Voucher.date < date + datetime.timedelta(1)) + .filter(Voucher.type != VoucherType.by_name("Issue").id) .filter(Journal.account_id == Account.service_charge_id()) + ) if voucher_id is not None: amount = amount.filter(Voucher.id != voucher_id) amount = amount.scalar() @@ -123,9 +158,19 @@ def balance(date, voucher_id=None, dbsession=None): def check_if_employees_changed(json, db, voucher): - json = set([uuid.UUID(x['id']) for x in json]) + json = set([uuid.UUID(x["id"]) for x in json]) db = set([x.id for x in db]) - voucher = set([x.account_id for x in voucher if x.account_id != Account.service_charge_id()]) if voucher is not None else None + voucher = ( + set( + [ + x.account_id + for x in voucher + if x.account_id != Account.service_charge_id() + ] + ) + if voucher is not None + else None + ) if voucher is None: if len(json ^ db) != 0: raise ValueError("Employee missing in json data") diff --git a/brewman/views/services/voucher/updatevoucher.py b/brewman/views/services/voucher/updatevoucher.py index d0425a97..4a64b300 100644 --- a/brewman/views/services/voucher/updatevoucher.py +++ b/brewman/views/services/voucher/updatevoucher.py @@ -10,13 +10,24 @@ from brewman.models.auth import User from brewman.models.voucher import Voucher from brewman.views import get_lock_info from brewman.views.services.session import session_current_date_set -from . import voucher_info, issue_update_voucher, purchase_update_voucher, journal_update_voucher +from . import ( + voucher_info, + issue_update_voucher, + purchase_update_voucher, + journal_update_voucher, +) from . import service_charge_update_voucher -from brewman.views.services.voucher.purchase_return import purchase_return_update_voucher -from brewman.views.services.voucher.salary_deduction import salary_deduction_update_voucher +from brewman.views.services.voucher.purchase_return import ( + purchase_return_update_voucher, +) +from brewman.views.services.voucher.salary_deduction import ( + salary_deduction_update_voucher, +) -@view_defaults(request_method='POST', route_name='api_voucher_id', renderer='json', trans=True) +@view_defaults( + request_method="POST", route_name="api_voucher_id", renderer="json", trans=True +) class UpdateVoucher(object): def __init__(self, request): def parse_post(request): @@ -24,93 +35,130 @@ class UpdateVoucher(object): files = {} model = {} for key in keys: - if key == 'model': + if key == "model": model = loads(request.POST[key], encoding=request.charset) else: index = key[1:] if index in files: files[index][key[:1]] = bytearray(request.POST[key].file.read()) else: - files[index] = {key[:1]: bytearray(request.POST[key].file.read())} + files[index] = { + key[:1]: bytearray(request.POST[key].file.read()) + } return model, files self.request = request - self.user = request.dbsession.query(User).filter(User.id == uuid.UUID(request.authenticated_userid)).one() - self.voucher = self.request.dbsession.query(Voucher).filter( - Voucher.id == uuid.UUID(request.matchdict['id'])).first() + self.user = ( + request.dbsession.query(User) + .filter(User.id == uuid.UUID(request.authenticated_userid)) + .one() + ) + self.voucher = ( + self.request.dbsession.query(Voucher) + .filter(Voucher.id == uuid.UUID(request.matchdict["id"])) + .first() + ) self.json, self.files = parse_post(request) self.start, self.finish = get_lock_info(request.dbsession) - self.voucher_date = datetime.datetime.strptime(self.json['date'], '%d-%b-%Y') + self.voucher_date = datetime.datetime.strptime(self.json["date"], "%d-%b-%Y") - if self.voucher.posted and not request.has_permission('Edit Posted Vouchers'): + if self.voucher.posted and not request.has_permission("Edit Posted Vouchers"): response = Response("You are not allowed to edit posted vouchers") response.status_int = 403 self.error = response - elif self.voucher.user_id != self.user.id and not request.has_permission("Edit Other User's Vouchers"): + elif self.voucher.user_id != self.user.id and not request.has_permission( + "Edit Other User's Vouchers" + ): response = Response("You are not allowed to edit other user's vouchers") response.status_int = 403 self.error = response - elif self.start is not None and (self.start > self.voucher_date or self.start > self.voucher.date): - response = Response("Vouchers before {0} have been locked.".format(self.start.strftime('%d-%b-%Y'))) + elif self.start is not None and ( + self.start > self.voucher_date or self.start > self.voucher.date + ): + response = Response( + "Vouchers before {0} have been locked.".format( + self.start.strftime("%d-%b-%Y") + ) + ) response.status_int = 403 self.error = response - elif self.finish is not None and (self.finish < self.voucher_date or self.finish < self.voucher.date): - response = Response("Vouchers after {0} have been locked.".format(self.finish.strftime('%d-%b-%Y'))) + elif self.finish is not None and ( + self.finish < self.voucher_date or self.finish < self.voucher.date + ): + response = Response( + "Vouchers after {0} have been locked.".format( + self.finish.strftime("%d-%b-%Y") + ) + ) response.status_int = 403 self.error = response else: self.error = None - @view_config(request_param='t=Journal', permission='Journal') + @view_config(request_param="t=Journal", permission="Journal") def journal(self): return self.update() - @view_config(request_param='t=Payment', permission='Payment') + @view_config(request_param="t=Payment", permission="Payment") def payment(self): return self.update() - @view_config(request_param='t=Receipt', permission='Receipt') + @view_config(request_param="t=Receipt", permission="Receipt") def receipt(self): return self.update() - @view_config(request_param='t=Purchase', permission='Purchase') + @view_config(request_param="t=Purchase", permission="Purchase") def purchase(self): return self.update() - @view_config(request_param='t=Purchase Return', permission='Purchase Return') + @view_config(request_param="t=Purchase Return", permission="Purchase Return") def purchase_return(self): return self.update() - @view_config(request_param='t=Issue', permission='Issue') + @view_config(request_param="t=Issue", permission="Issue") def issue(self): return self.update() - @view_config(request_param='t=Salary Deduction', permission='Salary Deduction') + @view_config(request_param="t=Salary Deduction", permission="Salary Deduction") def salary_deduction(self): return self.update() - @view_config(request_param='t=Service Charge', permission='Service Charge') + @view_config(request_param="t=Service Charge", permission="Service Charge") def service_charge(self): return self.update() def update(self): if self.error is not None: return self.error - if self.json['type'] in ['Journal', 'Payment', 'Receipt']: - voucher = journal_update_voucher(self.voucher, self.json, self.files, self.user, self.request.dbsession) - elif self.json['type'] in ['Purchase']: - voucher = purchase_update_voucher(self.voucher, self.json, self.files, self.user, self.request.dbsession) - elif self.json['type'] in ['Purchase Return']: + if self.json["type"] in ["Journal", "Payment", "Receipt"]: + voucher = journal_update_voucher( + self.voucher, self.json, self.files, self.user, self.request.dbsession + ) + elif self.json["type"] in ["Purchase"]: + voucher = purchase_update_voucher( + self.voucher, self.json, self.files, self.user, self.request.dbsession + ) + elif self.json["type"] in ["Purchase Return"]: voucher = purchase_return_update_voucher( self.voucher, self.json, self.files, self.user, self.request.dbsession ) - elif self.json['type'] in ['Issue']: - voucher = issue_update_voucher(self.voucher, self.json, self.user, self.request.dbsession) - elif self.json['type'] in ['Salary Deduction']: - voucher = salary_deduction_update_voucher(self.voucher, self.json, self.user, self.request.dbsession) - elif self.json['type'] in ['Service Charge']: - voucher = service_charge_update_voucher(self.voucher, self.json, self.user, self.request.dbsession) + elif self.json["type"] in ["Issue"]: + voucher = issue_update_voucher( + self.voucher, self.json, self.user, self.request.dbsession + ) + elif self.json["type"] in ["Salary Deduction"]: + voucher = salary_deduction_update_voucher( + self.voucher, self.json, self.user, self.request.dbsession + ) + elif self.json["type"] in ["Service Charge"]: + voucher = service_charge_update_voucher( + self.voucher, self.json, self.user, self.request.dbsession + ) transaction.commit() - session_current_date_set(self.request, self.json['date']) - new_voucher = self.request.dbsession.query(Voucher).filter(Voucher.id == voucher.id).first() + session_current_date_set(self.request, self.json["date"]) + new_voucher = ( + self.request.dbsession.query(Voucher) + .filter(Voucher.id == voucher.id) + .first() + ) return voucher_info(new_voucher, self.request)