diff --git a/brewman/brewman/models/master.py b/brewman/brewman/models/master.py index 8979dbbb..31575fc6 100644 --- a/brewman/brewman/models/master.py +++ b/brewman/brewman/models/master.py @@ -13,16 +13,18 @@ class Product(Base): id = Column('ProductID', GUID(), primary_key=True, default=uuid.uuid4) code = Column('Code', Integer, unique=True) - name = Column('Name', Unicode(255)) - units = Column('Units', Unicode(255)) - fraction = Column('Fraction', Numeric) - fraction_units = Column('FractionUnits', Unicode(255)) - yeild = Column('Yeild', Numeric) - show_for_purchase = Column('ShowForPurchase', Boolean) - product_group_id = Column('ProductGroupID', GUID(), ForeignKey('entities_productgroups.ProductGroupID')) - ledger_id = Column('LedgerID', GUID(), ForeignKey('entities_ledgers.LedgerID')) - price = Column('Price', Numeric) - discontinued = Column('Discontinued', Boolean) + 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) + yeild = Column('Yeild', Numeric, nullable=False) + show_for_purchase = Column('ShowForPurchase', Boolean, nullable=False) + product_group_id = Column('ProductGroupID', GUID(), ForeignKey('entities_productgroups.ProductGroupID'), + nullable=False) + ledger_id = Column('LedgerID', GUID(), ForeignKey('entities_ledgers.LedgerID'), nullable=False) + price = Column('Price', Numeric, nullable=False) + discontinued = Column('Discontinued', Boolean, nullable=False) + is_fixture = Column('IsFixture', Boolean, nullable=False) batches = relationship('Batch', backref='product') inventories = relationship('Inventory', backref='product') @@ -30,7 +32,8 @@ class Product(Base): ledger = relationship('Ledger', primaryjoin="Ledger.id==Product.ledger_id", backref='products') def __init__(self, code=None, name=None, units=None, fraction=None, fraction_units=None, yeild=None, - show_for_purchase=None, product_group_id=None, ledger_id=None, price=None, discontinued=None): + show_for_purchase=None, product_group_id=None, ledger_id=None, price=None, discontinued=None, + is_fixture=False): self.code = code self.name = name self.units = units @@ -42,6 +45,7 @@ class Product(Base): self.ledger_id = ledger_id self.price = price self.discontinued = discontinued + self.is_fixture = is_fixture @property def full_name(self): @@ -85,11 +89,13 @@ class ProductGroup(Base): 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') - def __init__(self, name=None): + def __init__(self, name=None, is_fixture=False): self.name = name + self.is_fixture = is_fixture @classmethod def list(cls): @@ -105,6 +111,7 @@ class CostCenter(Base): id = Column('CostCenterID', GUID(), primary_key=True, default=uuid.uuid4) name = Column('Name', Unicode(255), unique=True) + is_fixture = Column('IsFixture', Boolean, nullable=False) ledgers = relationship('LedgerBase', backref='costcenter') journals = relationship('Journal', backref='costcenter') @@ -113,8 +120,9 @@ class CostCenter(Base): def __name__(self): return self.name - def __init__(self, name=None): + def __init__(self, name=None, is_fixture=False): self.name = name + self.is_fixture = is_fixture @classmethod def by_id(cls, id): @@ -152,6 +160,7 @@ class LedgerBase(Base): is_active = Column('IsActive', Boolean) is_reconcilable = Column('IsReconcilable', Boolean) costcenter_id = Column('CostCenterID', GUID(), ForeignKey('entities_costcenters.CostCenterID')) + is_fixture = Column('IsFixture', Boolean, nullable=False) __mapper_args__ = {'polymorphic_on': ledger_type} @@ -165,13 +174,14 @@ class LedgerBase(Base): def type_object(self): return LedgerType.by_id(self.type) - def __init__(self, code=None, name=None, type=None, is_active=None, is_reconcilable=False, costcenter_id=None): + def __init__(self, code=None, name=None, type=None, is_active=None, is_reconcilable=False, costcenter_id=None, is_fixture=False): self.code = code self.name = name self.type = type self.is_active = is_active self.is_reconcilable = is_reconcilable self.costcenter_id = costcenter_id + self.is_fixture = is_fixture @classmethod def by_id(cls, id): @@ -207,6 +217,8 @@ class LedgerBase(Base): return self def can_delete(self): + if self.is_fixture: + return False, "{0} is a fixture and cannot be edited or deleted.".format(self.name) if self.is_active: return False, 'Account is active' if len(self.journals) > 0: @@ -231,11 +243,11 @@ class LedgerBase(Base): @classmethod def local_purchase(cls): - return {'LedgerID': 'd2b75912-505f-2548-9093-466dfff6a0f9', 'Name': 'local purchase'} + return {'LedgerID': 'd2b75912-505f-2548-9093-466dfff6a0f9', 'Name': 'Local Purchase'} @classmethod def salary(cls): - return {'LedgerID': '5c2b54d0-c174-004d-a0d5-92cdaadcefa7', 'Name': 'salary staff'} + return {'LedgerID': '5c2b54d0-c174-004d-a0d5-92cdaadcefa7', 'Name': 'Staff Salary'} @classmethod def esi_pf_expense(cls): diff --git a/brewman/brewman/models/operations.py b/brewman/brewman/models/operations.py index f8b135cc..74b754ab 100644 --- a/brewman/brewman/models/operations.py +++ b/brewman/brewman/models/operations.py @@ -1,5 +1,3 @@ -from datetime import datetime -from brewman.models import DBSession from brewman.models.master import CostCenter from brewman.models.validation_exception import ValidationError diff --git a/brewman/brewman/views/account.py b/brewman/brewman/views/account.py index 89b4469e..bfa5600b 100644 --- a/brewman/brewman/views/account.py +++ b/brewman/brewman/views/account.py @@ -8,11 +8,12 @@ from brewman.models import DBSession from brewman.models.master import CostCenter, Ledger, LedgerType, LedgerBase from brewman.models.validation_exception import ValidationError, TryCatchFunction + @view_config(route_name='account_list', renderer='brewman:templates/angular_base.mako', permission='Accounts') @view_config(request_method='GET', route_name='account_id', renderer='brewman:templates/angular_base.mako', - permission='Accounts') + permission='Accounts') @view_config(request_method='GET', route_name='account', renderer='brewman:templates/angular_base.mako', - permission='Accounts') + permission='Accounts') def html(request): return {} @@ -21,8 +22,8 @@ def html(request): @TryCatchFunction def save(request): item = Ledger(code=0, name=request.json_body['Name'], type=int(request.json_body['Type']), - is_active=request.json_body['IsActive'], is_reconcilable=request.json_body['IsReconcilable'], - costcenter_id=uuid.UUID(request.json_body['CostCenter']['CostCenterID'])).create() + is_active=request.json_body['IsActive'], is_reconcilable=request.json_body['IsReconcilable'], + costcenter_id=uuid.UUID(request.json_body['CostCenter']['CostCenterID'])).create() transaction.commit() return account_info(item.id) @@ -31,6 +32,8 @@ def save(request): @TryCatchFunction def update(request): item = Ledger.by_id(uuid.UUID(request.matchdict['id'])) + 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']) if not item.type == new_type: item.code = Ledger.get_code(new_type) @@ -69,19 +72,19 @@ def show_blank(request): @view_config(request_method='GET', route_name='api_account', renderer='json', request_param='list', - permission='Authenticated') + permission='Authenticated') def show_list(request): list = Ledger.list() ledgers = [] for item in list: ledgers.append({'Name': item.name, 'Type': item.type_object.name, 'IsActive': 'Yes' if item.is_active else 'No', 'IsReconcilable': 'Yes' if item.is_reconcilable else '', 'CostCenter': item.costcenter.name, - 'Url': request.route_url('account_id', id=item.id)}) + 'IsFixture': item.is_fixture, 'Url': request.route_url('account_id', id=item.id)}) return ledgers @view_config(request_method='GET', route_name='api_account', renderer='json', request_param='term', - permission='Authenticated') + permission='Authenticated') def show_term(request): type = request.GET.get('type', None) type = int(type) if type is not None else None @@ -117,6 +120,7 @@ def account_info(id): account = Ledger.by_id(id) account = {'LedgerID': account.id, 'Code': account.code, 'Name': account.name, 'Type': account.type, 'IsActive': account.is_active, 'IsReconcilable': account.is_reconcilable, + 'IsFixture': account.is_fixture, 'CostCenter': {'CostCenterID': account.costcenter_id, 'Name': account.costcenter.name}} return account diff --git a/brewman/brewman/views/cost_center.py b/brewman/brewman/views/cost_center.py index 56d2323f..5e56ef9e 100644 --- a/brewman/brewman/views/cost_center.py +++ b/brewman/brewman/views/cost_center.py @@ -11,9 +11,9 @@ from brewman.models.validation_exception import ValidationError, TryCatchFunctio @view_config(route_name='cost_center_list', renderer='brewman:templates/angular_base.mako', permission='Authenticated') @view_config(request_method='GET', route_name='cost_center_id', renderer='brewman:templates/angular_base.mako', - permission='Cost Centers') + permission='Cost Centers') @view_config(request_method='GET', route_name='cost_center', renderer='brewman:templates/angular_base.mako', - permission='Cost Centers') + permission='Cost Centers') def html(request): return {} @@ -31,6 +31,8 @@ def save(request): @TryCatchFunction def update(request): item = CostCenter.by_id(uuid.UUID(request.matchdict['id'])) + 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'] transaction.commit() return cost_center_info(item.id) @@ -38,11 +40,15 @@ def update(request): @view_config(request_method='DELETE', route_name='api_cost_center_id', renderer='json', permission='Cost Centers') def delete(request): - id = request.matchdict.get('id', None) - if id is None: - response = Response("Cost Center is Null") + item = request.matchdict.get('id', None) + item = None if item is None else CostCenter.by_id(uuid.UUID(item)) + + if item is None: + response = Response("Cost Center 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)) else: response = Response("Cost Center deletion not implemented") response.status_int = 500 @@ -60,13 +66,13 @@ def show_blank(request): @view_config(request_method='GET', route_name='api_cost_center', request_param='list', renderer='json', - permission='Authenticated') + permission='Authenticated') def show_list(request): list = CostCenter.list() cost_centers = [] for item in list: - cost_centers.append( - {'CostCenterID': item.id, 'Name': item.name, 'Url': request.route_url('cost_center_id', id=item.id)}) + cost_centers.append({'CostCenterID': item.id, 'Name': item.name, 'IsFixture': item.is_fixture, + 'Url': request.route_url('cost_center_id', id=item.id)}) return cost_centers @@ -75,6 +81,6 @@ def cost_center_info(id): return {} else: cost_center = CostCenter.by_id(id) - return {'CostCenterID': cost_center.id, 'Name': cost_center.name} + return {'CostCenterID': cost_center.id, 'Name': cost_center.name, 'IsFixture': cost_center.is_fixture} diff --git a/brewman/brewman/views/employee.py b/brewman/brewman/views/employee.py index 66b478f5..0f478bed 100644 --- a/brewman/brewman/views/employee.py +++ b/brewman/brewman/views/employee.py @@ -4,6 +4,7 @@ from pyramid.response import Response from pyramid.view import view_config import transaction +from brewman.models import DBSession from brewman.models.master import CostCenter, Employee, LedgerBase from brewman.models.validation_exception import ValidationError, TryCatchFunction @@ -40,6 +41,8 @@ def save(request): @TryCatchFunction def update(request): item = Employee.by_id(uuid.UUID(request.matchdict['id'])) + 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'] item.is_active = request.json_body['IsActive'] item.costcenter_id = uuid.UUID(request.json_body['CostCenter']['CostCenterID']) @@ -55,13 +58,15 @@ def update(request): @view_config(request_method='DELETE', route_name='api_employee_id', renderer='json', permission='Employees') def delete(request): - id = request.matchdict.get('id', None) - if id is None: - response = Response("Employee is Null") - response.status_int = 500 - return response + employee = Employee.by_id(uuid.UUID(request.matchdict['id'])) + can_delete, reason = employee.can_delete() + if can_delete: + DBSession.delete(employee) + transaction.commit() + return employee_info(None) else: - response = Response("Employee deletion not implemented") + transaction.abort() + response = Response("Cannot delete account because {0}".format(reason)) response.status_int = 500 return response diff --git a/brewman/brewman/views/product.py b/brewman/brewman/views/product.py index 4b22cbd6..24de4f03 100644 --- a/brewman/brewman/views/product.py +++ b/brewman/brewman/views/product.py @@ -6,13 +6,14 @@ from pyramid.view import view_config import transaction from brewman.models.master import Product, CostCenter, LedgerType, Ledger -from brewman.models.validation_exception import TryCatchFunction +from brewman.models.validation_exception import TryCatchFunction, ValidationError + @view_config(route_name='product_list', renderer='brewman:templates/angular_base.mako', permission='Authenticated') @view_config(request_method='GET', route_name='product_id', renderer='brewman:templates/angular_base.mako', - permission='Products') + permission='Products') @view_config(request_method='GET', route_name='product', renderer='brewman:templates/angular_base.mako', - permission='Products') + permission='Products') def html(request): return {} @@ -21,10 +22,10 @@ def html(request): @TryCatchFunction def save(request): item = Product(0, request.json_body['Name'], request.json_body['Units'], - Decimal(request.json_body['Fraction']), request.json_body['FractionUnits'], - Decimal(request.json_body['Yeild']), request.json_body['ShowForPurchase'], - uuid.UUID(request.json_body['ProductGroup']['ProductGroupID']), Ledger.all_purchases(), - Decimal(request.json_body['Price']), request.json_body['Discontinued']).create() + Decimal(request.json_body['Fraction']), request.json_body['FractionUnits'], + Decimal(request.json_body['Yeild']), request.json_body['ShowForPurchase'], + uuid.UUID(request.json_body['ProductGroup']['ProductGroupID']), Ledger.all_purchases(), + Decimal(request.json_body['Price']), request.json_body['Discontinued']).create() transaction.commit() return product_info(item.id) @@ -33,6 +34,8 @@ def save(request): @TryCatchFunction def update(request): item = Product.by_id(uuid.UUID(request.matchdict['id'])) + 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'] item.units = request.json_body['Units'] item.fraction = Decimal(request.json_body['Fraction']) @@ -49,11 +52,15 @@ def update(request): @view_config(request_method='DELETE', route_name='api_product_id', renderer='json', permission='Products') def delete(request): - id = request.matchdict.get('id', None) - if id is None: - response = Response("Product is Null") + item = request.matchdict.get('id', None) + item = None if item is None else Product.by_id(uuid.UUID(item)) + + if item is None: + response = Response("Product 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.full_name)) else: response = Response("Product deletion not implemented") response.status_int = 500 @@ -71,7 +78,7 @@ def show_blank(request): @view_config(request_method='GET', route_name='api_product', request_param='list', renderer='json', - permission='Authenticated') + permission='Authenticated') def show_list(request): list = Product.query().order_by(Product.discontinued).order_by(Product.product_group_id).order_by( Product.name).all() @@ -79,19 +86,19 @@ def show_list(request): for item in list: products.append({'Code': item.code, 'Name': item.name, 'Units': item.units, 'Price': item.price, 'ProductGroup': item.product_group.name, 'Discontinued': item.discontinued, - 'Url': request.route_url('product_id', id=item.id)}) + 'IsFixture': item.is_fixture, 'Url': request.route_url('product_id', id=item.id)}) return products @view_config(request_method='GET', route_name='api_product', renderer='json', request_param='term', - permission='Authenticated') + permission='Authenticated') def show_term(request): - filter = request.GET.get('term', None) - filter = filter if filter is not None and filter is not '' else None + term = request.GET.get('term', None) + term = term if term is not None and term is not '' else None count = request.GET.get('count', None) count = None if count is None or count == '' else int(count) list = [] - for index, item in enumerate(Product.list(filter)): + for index, item in enumerate(Product.list(term)): list.append({'ProductID': item.id, 'Name': item.full_name, 'Price': item.price}) if count is not None and index == count - 1: break @@ -107,6 +114,6 @@ def product_info(id): product = {'ProductID': product.id, 'Code': product.code, 'Name': product.name, 'Units': product.units, 'Fraction': product.fraction, 'FractionUnits': product.fraction_units, 'Yeild': product.yeild, 'ShowForPurchase': product.show_for_purchase, 'Discontinued': product.discontinued, - 'ProductGroup': {'ProductGroupID': product.product_group_id}, + 'IsFixture':product.is_fixture, 'ProductGroup': {'ProductGroupID': product.product_group_id}, 'Ledger': {'LedgerID': product.ledger_id}, 'Price': product.price} return product diff --git a/brewman/brewman/views/product_group.py b/brewman/brewman/views/product_group.py index 46e8adcc..aed0da69 100644 --- a/brewman/brewman/views/product_group.py +++ b/brewman/brewman/views/product_group.py @@ -10,11 +10,11 @@ from brewman.models.validation_exception import ValidationError, TryCatchFunctio @view_config(route_name='product_group_list', renderer='brewman:templates/angular_base.mako', - permission='Authenticated') + permission='Authenticated') @view_config(request_method='GET', route_name='product_group_id', renderer='brewman:templates/angular_base.mako', - permission='Product Groups') + permission='Product Groups') @view_config(request_method='GET', route_name='product_group', renderer='brewman:templates/angular_base.mako', - permission='Product Groups') + permission='Product Groups') def html(request): return {} @@ -32,6 +32,8 @@ def save(request): @TryCatchFunction def update(request): item = ProductGroup.by_id(uuid.UUID(request.matchdict['id'])) + 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'] transaction.commit() return product_group_info(item.id) @@ -39,11 +41,15 @@ def update(request): @view_config(request_method='DELETE', route_name='api_product_group_id', renderer='json', permission='Product Groups') def delete(request): - id = request.matchdict.get('id', None) - if id is None: - response = Response("Product Group is Null") + item = request.matchdict.get('id', None) + item = None if item is None else ProductGroup.by_id(uuid.UUID(item)) + + 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)) else: response = Response("Product Group deletion not implemented") response.status_int = 500 @@ -61,13 +67,13 @@ def show_blank(request): @view_config(request_method='GET', route_name='api_product_group', request_param='list', renderer='json', - permission='Authenticated') + permission='Authenticated') def show_list(request): list = ProductGroup.list() product_groups = [] for item in list: - product_groups.append( - {'ProductGroupID': item.id, 'Name': item.name, 'Url': request.route_url('product_group_id', id=item.id)}) + product_groups.append({'ProductGroupID': item.id, 'Name': item.name, 'IsFixture': item.is_fixture, + 'Url': request.route_url('product_group_id', id=item.id)}) return product_groups @@ -76,6 +82,6 @@ def product_group_info(id): return {} else: product_group = ProductGroup.by_id(id) - return {'ProductGroupID': product_group.id, 'Name': product_group.name} + return {'ProductGroupID': product_group.id, 'Name': product_group.name, 'IsFixture': product_group.is_fixture}