diff --git a/MANIFEST.in b/MANIFEST.in index a4ea8b96..90ae255a 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,2 @@ include *.txt *.ini *.cfg *.rst -recursive-include brewman *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml *.map *.eot *.svg *.ttf *.woff +recursive-include brewman *.ico *.png *.css *.gif *.jpg *.txt *.js *.html *.map *.eot *.svg *.ttf *.woff diff --git a/README.txt b/README.txt index 18bdcea5..3ddc3a44 100644 --- a/README.txt +++ b/README.txt @@ -1 +1,41 @@ -brewman README +# Installation on Ubuntu 14.04 +## Prepare the system +1. Install system-wide pip +**Currently the ensurepip is broken in Python 3.4 / Ubuntu 14.04, therefore we need to install system-wide pip** +```bash +sudo apt-get install python3-pip +``` + +2. Install postgresql +```bash +sudo apt-get install postgresql postgresql-client pgadmin3 +``` +[Full Guide](https://help.ubuntu.com/community/PostgreSQL) + +3. Configure the server and set password +```bash +sudo -u postgresql psql postgres +\password postgres +``` + +4. Install components to build psycopg2 +```bash +sudo apt-get install libpq-dev python3-dev +``` + +## Setup the virutal environment +1. Create the virtual environment +**Currently the ensurepip is broken in Python 3.4 / Ubuntu 14.04, therefore --without-pip is needed.** +```bash +pyvenv-3.4 env --without-pip --system-site-packages +``` + +2. Activate the virtual environment +```bash +source env/bin/activate +``` + +3. Install pyramid, sqlachemy, psycopg2 and other dependencies: +```bash +python3 -m pip install pyramid waitress sqlalchemy zope.sqlalchemy psycopg2 +``` diff --git a/brewman/__init__.py b/brewman/__init__.py index e9423209..41581b8e 100644 --- a/brewman/__init__.py +++ b/brewman/__init__.py @@ -67,6 +67,7 @@ def main(global_config, **settings): 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}') diff --git a/brewman/factories.py b/brewman/factories.py index 2d1ec9c4..f462e779 100644 --- a/brewman/factories.py +++ b/brewman/factories.py @@ -18,11 +18,24 @@ class RootFactory(object): pass +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' + else: + return word + 's' + return word + + 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', url + 's') + config.add_route(name + '_list', pluralize(url)) config.add_route('api_' + name + '_' + variable, '/api' + url + '/{' + variable + '}') config.add_route('api_' + name, '/api' + url) diff --git a/brewman/models/__init__.py b/brewman/models/__init__.py index 5e8306a9..9f5cd16f 100644 --- a/brewman/models/__init__.py +++ b/brewman/models/__init__.py @@ -27,7 +27,7 @@ def fixtures(engine): import uuid from brewman.models.messaging import Tag, Thread, Subscriber, thread_tag, Post from brewman.models.voucher import Attendance, Batch, Fingerprint, Inventory, Journal, Product, SalaryDeduction, Voucher, VoucherType - from brewman.models.master import Product, AttendanceType, CostCenter, Employee, Ledger, LedgerBase, LedgerType, ProductGroup + from brewman.models.master import Product, AttendanceType, CostCenter, Employee, Ledger, LedgerBase, LedgerType, ProductGroup, MenuItem, Recipe, RecipeItem from brewman.models.auth import Client, Group, Role, User, role_group, user_group Base.metadata.create_all(engine) @@ -66,6 +66,7 @@ def fixtures(engine): 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')), @@ -116,8 +117,11 @@ def fixtures(engine): product_group = ProductGroup('Suspense', uuid.UUID('ae59a20c-87bb-444a-8abb-915ad5e58b83'), True) DBSession.add(product_group) - product = Product(1, 'Suspense', '', 1, '', 1, False, uuid.UUID('ae59a20c-87bb-444a-8abb-915ad5e58b83'), - uuid.UUID('240dd899-c413-854c-a7eb-67a29d154490'), 0, 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, False, uuid.UUID('aa79a643-9ddc-4790-ac7f-a41f9efb4c15'), True) DBSession.add(product) diff --git a/brewman/models/master.py b/brewman/models/master.py index d57ff6af..aad4f794 100644 --- a/brewman/models/master.py +++ b/brewman/models/master.py @@ -1,15 +1,19 @@ import uuid -from sqlalchemy import UniqueConstraint, Column, Integer, Unicode, Numeric, Boolean, ForeignKey, func, DateTime, desc, PickleType + +from sqlalchemy import UniqueConstraint, Column, Integer, Unicode, Numeric, Boolean, ForeignKey, func, DateTime, desc, \ + PickleType from sqlalchemy.orm import relationship + from brewman.models import Base, DBSession from brewman.models.guidtype import GUID + __author__ = 'tanshu' -class Product(Base): - __tablename__ = 'entities_products' - __tableagrs__ = (UniqueConstraint('Name', 'Units')) +class ProductBase(Base): + __tablename__ = 'products' + __table_args__ = (UniqueConstraint('Name', 'Units'), ) id = Column('ProductID', GUID(), primary_key=True, default=uuid.uuid4) code = Column('Code', Integer, unique=True) @@ -18,33 +22,32 @@ class Product(Base): fraction = Column('Fraction', Numeric, nullable=False) fraction_units = Column('FractionUnits', Unicode(255), nullable=False) product_yield = Column('ProductYield', Numeric, nullable=False) - show_for_purchase = Column('ShowForPurchase', Boolean, nullable=False) - product_group_id = Column('ProductGroupID', GUID(), ForeignKey('entities_productgroups.ProductGroupID'), + product_group_id = Column('ProductGroupID', GUID(), ForeignKey('product_groups.ProductGroupID'), nullable=False) - ledger_id = Column('LedgerID', GUID(), ForeignKey('entities_ledgers.LedgerID'), nullable=False) + ledger_id = Column('LedgerID', GUID(), ForeignKey('ledgers.LedgerID'), nullable=False) price = Column('Price', Numeric, nullable=False) - discontinued = Column('Discontinued', Boolean, nullable=False) + is_active = Column('IsActive', Boolean, nullable=False) is_fixture = Column('IsFixture', Boolean, nullable=False) + product_type = Column('product_type', Unicode(50), nullable=False) + __mapper_args__ = {'polymorphic_on': product_type} batches = relationship('Batch', backref='product') inventories = relationship('Inventory', backref='product') 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, product_yield=None, - show_for_purchase=None, product_group_id=None, ledger_id=None, price=None, discontinued=None, - id=None,is_fixture=False): + product_group_id=None, ledger_id=None, price=None, is_active=None, id=None, is_fixture=False): self.code = code self.name = name self.units = units self.fraction = fraction self.fraction_units = fraction_units self.product_yield = product_yield - self.show_for_purchase = show_for_purchase self.product_group_id = product_group_id self.ledger_id = ledger_id self.price = price - self.discontinued = discontinued + self.is_active = is_active self.id = id self.is_fixture = is_fixture @@ -56,7 +59,7 @@ class Product(Base): def list(cls, name, active): query = DBSession.query(cls) if active is not None: - query = query.filter(cls.discontinued != active) + query = query.filter(cls.is_active == active) for item in name.split(): query = query.filter(cls.name.ilike('%' + item + '%')) return query.order_by(cls.name) @@ -78,7 +81,7 @@ class Product(Base): return DBSession.query(cls) def create(self): - code = DBSession.query(func.max(Product.code)).one()[0] + code = DBSession.query(func.max(ProductBase.code)).one()[0] if code is None: self.code = 1 else: @@ -89,7 +92,7 @@ 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) - if not self.discontinued: + if self.is_active: return False, 'Product is active' if len(self.inventories) > 0 and not advanced_delete: return False, 'Product has entries' @@ -100,8 +103,71 @@ class Product(Base): return uuid.UUID('aa79a643-9ddc-4790-ac7f-a41f9efb4c15') +class Product(ProductBase): + __mapper_args__ = {'polymorphic_identity': ''} + + +class MenuItem(ProductBase): + __tablename__ = 'menu_items' + __mapper_args__ = {'polymorphic_identity': 'menu_items'} + + id = Column('ProductID', GUID(), ForeignKey(ProductBase.id), primary_key=True) + is_semi = Column('is_semi', Boolean, nullable=False) + + recipes = relationship('Recipe', backref='product') + + def __init__(self, code=None, name=None, units=None, is_semi=None, fraction=None, fraction_units=None, + product_group_id=None, ledger_id=None, price=None, is_active=None, id=None): + self.is_semi = is_semi + super().__init__(code=code, name=name, units=units, fraction=fraction, fraction_units=fraction_units, + product_yield=1, product_group_id=product_group_id, ledger_id=ledger_id, price=price, + is_active=is_active, id=id, is_fixture=False) + + +class Recipe(Base): + __tablename__ = 'recipes' + __table_args__ = (UniqueConstraint('date', 'product_id'), ) + + id = Column('recipe_id', GUID(), primary_key=True, default=uuid.uuid4) + date = Column('date', DateTime, nullable=False) + product_id = Column('product_id', GUID(), ForeignKey(MenuItem.id), nullable=False) + quantity = Column('quantity', Numeric, nullable=False) + sale_price = Column('sale_price', Numeric, nullable=True) + notes = Column('notes', Unicode(255)) + + recipe_items = relationship('RecipeItem', backref='recipe') + + def __init__(self, date=None, product_id=None, quantity=None, sale_price=None, notes=None, id=None): + self.date = date + self.product_id = product_id + self.quantity = quantity + self.sale_price = sale_price + self.notes = notes + self.id = id + + +class RecipeItem(Base): + __tablename__ = 'recipe_items' + __table_args__ = (UniqueConstraint('recipe_id', 'ingredient_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) + ingredient_id = Column('ingredient_id', GUID(), ForeignKey('products.ProductID'), nullable=False) + quantity = Column('quantity', Integer, nullable=False) + price = Column('price', Integer, nullable=False) + + product = relationship('ProductBase') + + def __init__(self, recipe_id=None, ingredient_id=None, quantity=None, price=None, id=None): + self.recipe_id = recipe_id + self.ingredient_id = ingredient_id + self.quantity = quantity + self.price = price + self.id = id + + class ProductGroup(Base): - __tablename__ = 'entities_productgroups' + __tablename__ = 'product_groups' id = Column('ProductGroupID', GUID(), primary_key=True, default=uuid.uuid4) name = Column('Name', Unicode(255), unique=True) @@ -122,9 +188,17 @@ class ProductGroup(Base): def by_id(cls, id): return DBSession.query(cls).filter(cls.id == id).first() + @classmethod + def menu_item(cls): + return uuid.UUID('dad46805-f577-4e5b-8073-9b788e0173fc') + + @classmethod + def semi(cls): + return uuid.UUID('e6bf81b9-1e9b-499f-81d5-ab5662e9d9b1') + class CostCenter(Base): - __tablename__ = 'entities_costcenters' + __tablename__ = 'cost_centers' id = Column('CostCenterID', GUID(), primary_key=True, default=uuid.uuid4) name = Column('Name', Unicode(255), unique=True) @@ -168,7 +242,7 @@ class CostCenter(Base): class LedgerBase(Base): - __tablename__ = 'entities_ledgers' + __tablename__ = 'ledgers' id = Column('LedgerID', GUID(), primary_key=True, default=uuid.uuid4) code = Column('Code', Integer) @@ -177,7 +251,7 @@ class LedgerBase(Base): ledger_type = Column('ledger_type', Unicode(50), nullable=False) is_active = Column('IsActive', Boolean) is_reconcilable = Column('IsReconcilable', Boolean) - costcenter_id = Column('CostCenterID', GUID(), ForeignKey('entities_costcenters.CostCenterID')) + costcenter_id = Column('CostCenterID', GUID(), ForeignKey('cost_centers.CostCenterID')) is_fixture = Column('IsFixture', Boolean, nullable=False) __mapper_args__ = {'polymorphic_on': ledger_type} @@ -287,7 +361,7 @@ class LedgerBase(Base): class Employee(LedgerBase): - __tablename__ = 'entities_employees' + __tablename__ = 'employees' __mapper_args__ = {'polymorphic_identity': 'employees'} id = Column('LedgerID', GUID(), ForeignKey(LedgerBase.id), primary_key=True) diff --git a/brewman/models/voucher.py b/brewman/models/voucher.py index b559b704..7ec52b07 100644 --- a/brewman/models/voucher.py +++ b/brewman/models/voucher.py @@ -2,7 +2,7 @@ from datetime import datetime import uuid from sqlalchemy.ext.hybrid import hybrid_property -from sqlalchemy import Column, Integer, Boolean, Unicode, DateTime, Numeric, ForeignKey +from sqlalchemy import Column, Integer, Boolean, Unicode, DateTime, Numeric, ForeignKey, UniqueConstraint from sqlalchemy.orm import relationship, synonym, backref from brewman.models.guidtype import GUID @@ -49,7 +49,7 @@ class VoucherType: class Voucher(Base): - __tablename__ = 'entities_vouchers' + __tablename__ = 'vouchers' id = Column('VoucherID', GUID(), primary_key=True, default=uuid.uuid4) date = Column('Date', DateTime, nullable=False) @@ -117,14 +117,14 @@ class Voucher(Base): class Journal(Base): - __tablename__ = 'entities_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('entities_vouchers.VoucherID'), nullable=False) - ledger_id = Column('LedgerID', GUID(), ForeignKey('entities_ledgers.LedgerID'), nullable=False) - cost_center_id = Column('CostCenterID', GUID(), ForeignKey('entities_costcenters.CostCenterID'), nullable=False) + voucher_id = Column('VoucherID', GUID(), ForeignKey('vouchers.VoucherID'), nullable=False) + ledger_id = Column('LedgerID', GUID(), ForeignKey('ledgers.LedgerID'), nullable=False) + cost_center_id = Column('CostCenterID', GUID(), ForeignKey('cost_centers.CostCenterID'), nullable=False) @hybrid_property def signed_amount(self): @@ -156,10 +156,10 @@ class Journal(Base): class SalaryDeduction(Base): - __tablename__ = 'entities_salarydeductions' + __tablename__ = 'salary_deductions' id = Column('SalaryDeductionID', GUID(), primary_key=True, default=uuid.uuid4) - voucher_id = Column('VoucherID', GUID(), ForeignKey('entities_vouchers.VoucherID'), nullable=False) - journal_id = Column('JournalID', GUID(), ForeignKey('entities_journals.JournalID'), nullable=False) + 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) @@ -186,12 +186,12 @@ class SalaryDeduction(Base): class Inventory(Base): - __tablename__ = 'entities_inventories' - # __tableagrs__ = (UniqueConstraint('VoucherID', 'ProductID')) + __tablename__ = 'inventories' + __table_args__ = (UniqueConstraint('VoucherID', 'BatchID'), ) id = Column('InventoryID', GUID(), primary_key=True, default=uuid.uuid4) - voucher_id = Column('VoucherID', GUID(), ForeignKey('entities_vouchers.VoucherID'), nullable=False) - product_id = Column('ProductID', GUID(), ForeignKey('entities_products.ProductID'), nullable=False) - batch_id = Column('BatchID', GUID(), ForeignKey('entities_batches.BatchID'), nullable=False) + voucher_id = Column('VoucherID', GUID(), ForeignKey('vouchers.VoucherID'), nullable=False) + 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) @@ -216,11 +216,11 @@ class Inventory(Base): class Batch(Base): - __tablename__ = 'entities_batches' + __tablename__ = 'batches' id = Column('BatchID', GUID(), primary_key=True, default=uuid.uuid4) name = Column('Name', DateTime) - product_id = Column('ProductID', GUID(), ForeignKey('entities_products.ProductID'), nullable=False) + product_id = Column('ProductID', GUID(), ForeignKey('products.ProductID'), nullable=False) quantity_remaining = Column('QuantityRemaining', Numeric) rate = Column('Rate', Numeric) tax = Column('Tax', Numeric) @@ -262,10 +262,10 @@ class Batch(Base): class Attendance(Base): - __tablename__ = 'entities_attendances' + __tablename__ = 'attendances' id = Column('AttendanceID', GUID(), primary_key=True, default=uuid.uuid4) - employee_id = Column('EmployeeID', GUID(), ForeignKey('entities_employees.LedgerID')) + employee_id = Column('EmployeeID', GUID(), ForeignKey('employees.LedgerID')) date = Column('Date', DateTime) attendance_type = Column('AttendanceType', Integer) amount = Column('Amount', Numeric) @@ -305,10 +305,10 @@ class Attendance(Base): class Fingerprint(Base): - __tablename__ = 'entities_fingerprints' + __tablename__ = 'fingerprints' id = Column('FingerprintID', GUID(), primary_key=True, default=uuid.uuid4) - employee_id = Column('EmployeeID', GUID(), ForeignKey('entities_employees.LedgerID')) + employee_id = Column('EmployeeID', GUID(), ForeignKey('employees.LedgerID')) date = Column('Date', DateTime) def __init__(self, id=None, employee_id=None, date=None): diff --git a/brewman/templates/angular_base.mako b/brewman/static/base.html similarity index 96% rename from brewman/templates/angular_base.mako rename to brewman/static/base.html index 161a206c..4a5f7c32 100644 --- a/brewman/templates/angular_base.mako +++ b/brewman/static/base.html @@ -8,11 +8,11 @@ - ## + - ## + @@ -25,7 +25,7 @@ } -## + @@ -69,6 +69,7 @@ + @@ -183,6 +184,7 @@
  • Accounts
  • Cost Centers
  • Products
  • +
  • Recipes
  • Product Groups
  • diff --git a/brewman/static/partial/product-detail.html b/brewman/static/partial/product-detail.html index 6a9f0825..4b543cf4 100644 --- a/brewman/static/partial/product-detail.html +++ b/brewman/static/partial/product-detail.html @@ -54,10 +54,7 @@
    -
    diff --git a/brewman/static/partial/product-list.html b/brewman/static/partial/product-list.html index 43d5dbf7..687a136e 100644 --- a/brewman/static/partial/product-list.html +++ b/brewman/static/partial/product-list.html @@ -16,7 +16,7 @@ Name Price Type - Discontinued + Is Active? @@ -25,7 +25,7 @@ {{item.Name}} ({{item.Units}}) ₹ {{item.Price}} {{item.ProductGroup}} - {{item.Discontinued}} + {{item.IsActive}} diff --git a/brewman/static/partial/recipe-detail.html b/brewman/static/partial/recipe-detail.html new file mode 100644 index 00000000..7c488e20 --- /dev/null +++ b/brewman/static/partial/recipe-detail.html @@ -0,0 +1,109 @@ +
    +

    Recipe Detail

    + +
    + + +
    + +
    +
    + +
    +
    +
    + + + + +
    +
    +
    +

    {{cost_price | currency}} / {{cost_price * 100 / recipe.SalePrice | number:2 }}%

    +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    + + +
    +
    +
    + +
    +
    +
    + + +
    + +
    +
    +
    + + {{product.FractionUnits}} +
    +
    +
    +
    + + + /{{product.Units}} + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    IngredientUnitQuantityRateAmount
    {{item.Product.Name}}{{item.Product.FractionUnits}}{{item.Quantity | number:2}}{{item.Price / (item.Product.Fraction * item.Product.ProductYield) | currency}}{{item.Quantity * (item.Price / (item.Product.Fraction * item.Product.ProductYield)) | currency}} + +
    +
    +
    + + +
    +
    + diff --git a/brewman/static/partial/recipe-list.html b/brewman/static/partial/recipe-list.html new file mode 100644 index 00000000..7a304793 --- /dev/null +++ b/brewman/static/partial/recipe-list.html @@ -0,0 +1,81 @@ +
    +

    Recipes +
    +
    + +
    +
    + Add +
    +
    +

    +
    + +
    + +
    +
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameDateSale PriceOriginal CostCurrent CostOriginal CostingCurrent Costing
    {{item.Name}} ({{item.Units}}){{item.Date}}{{item.IsSemi ? '' : (item.SalePrice | currency)}}{{item.CostPrice | currency}}{{item.CurrentCostPrice | currency}}{{item.IsSemi ? '' : (item.Costing | percent)}}{{item.IsSemi ? '' : (item.CurrentCosting | percent)}}
    + + + + + + + + + + + + + + + + + +
    IngredientQuantityRateAmount
    {{sub_item.Name}}{{sub_item.Quantity | number:2}} {{sub_item.FractionUnits}}{{sub_item.Price | currency}}{{sub_item.Quantity * sub_item.Price | currency}}
    +
    +
    \ No newline at end of file diff --git a/brewman/static/scripts/angular_directive.js b/brewman/static/scripts/angular_directive.js index 02d40e52..1662f615 100644 --- a/brewman/static/scripts/angular_directive.js +++ b/brewman/static/scripts/angular_directive.js @@ -130,6 +130,10 @@ overlord_directive.directive('keypress', [function () { }); })(k); } + element.on('$destroy', function() { + $interval.cancel(timeoutId); + }); + }; }]); diff --git a/brewman/static/scripts/angular_service.js b/brewman/static/scripts/angular_service.js index c0ac6619..6041f02a 100644 --- a/brewman/static/scripts/angular_service.js +++ b/brewman/static/scripts/angular_service.js @@ -21,6 +21,13 @@ overlord_service.factory('Account', ['$resource', function ($resource) { }); }]); +overlord_service.factory('Recipe', ['$resource', function ($resource) { + return $resource('/api/Recipe/:id', + {id: '@RecipeID'}, { + query: {method: 'GET', params: {list: true}, isArray: true} + }); +}]); + overlord_service.factory('Employee', ['$resource', function ($resource) { return $resource('/api/Employee/:id', {id: '@LedgerID'}, { diff --git a/brewman/static/scripts/overlord.js b/brewman/static/scripts/overlord.js index 2a25f022..a28f7b02 100644 --- a/brewman/static/scripts/overlord.js +++ b/brewman/static/scripts/overlord.js @@ -83,6 +83,10 @@ var overlord = angular.module('overlord', ['overlord.directive', 'overlord.filte when('/Product', {templateUrl: '/partial/product-detail.html', controller: ProductCtrl, resolve: ProductCtrl.resolve}). when('/Product/:id', {templateUrl: '/partial/product-detail.html', controller: ProductCtrl, resolve: ProductCtrl.resolve}). + when('/Recipes', {templateUrl: '/partial/recipe-list.html', controller: RecipeListCtrl, resolve: RecipeListCtrl.resolve, reloadOnSearch:false}). + when('/Recipe', {templateUrl: '/partial/recipe-detail.html', controller: RecipeCtrl, resolve: RecipeCtrl.resolve}). + when('/Recipe/:id', {templateUrl: '/partial/recipe-detail.html', controller: RecipeCtrl, resolve: RecipeCtrl.resolve}). + when('/ProductGroups', {templateUrl: '/partial/product-group-list.html', controller: ProductGroupListCtrl, resolve: ProductGroupListCtrl.resolve}). when('/ProductGroup', {templateUrl: '/partial/product-group-detail.html', controller: ProductGroupCtrl, resolve: ProductGroupCtrl.resolve}). when('/ProductGroup/:id', {templateUrl: '/partial/product-group-detail.html', controller: ProductGroupCtrl, resolve: ProductGroupCtrl.resolve}). diff --git a/brewman/static/scripts/product.js b/brewman/static/scripts/product.js index e28d9a9a..f385bab2 100644 --- a/brewman/static/scripts/product.js +++ b/brewman/static/scripts/product.js @@ -45,7 +45,7 @@ var ProductListCtrl = ['$scope', '$location', '$routeParams', 'products', functi if (value.indexOf("'") === 0 || value.indexOf('"') === 0) { value = value.substring(1, value.length - 2); } - if (key !== '' && value !== '' && _.any(['w', 'u', 'g'], function (item) { + if (key !== '' && value !== '' && _.any(['a', 'u', 'g'], function (item) { return item === key; })) { matches.push({'key': key, 'value': value}); @@ -60,8 +60,8 @@ var ProductListCtrl = ['$scope', '$location', '$routeParams', 'products', functi if (item.Name.toLowerCase().indexOf(match.value) === -1) { return false; } - } else if (match.key === 'w') { - if (item.Discontinued === $scope.isTrue(match.value)) { + } else if (match.key === 'a') { + if (item.IsActive === $scope.isTrue(match.value)) { return false; } } else if (match.key === 'u') { @@ -85,14 +85,14 @@ ProductListCtrl.resolve = { }] }; -var ProductCtrl = ['$scope', '$location', '$modal', 'product', 'product_groups', function ($scope, $location, $modal, product, product_groups) { +var ProductCtrl = ['$scope', '$location', '$window', '$modal', 'product', 'product_groups', function ($scope, $location, $window, $modal, product, product_groups) { $scope.product = product; $scope.product_groups = product_groups; $scope.save = function () { $scope.product.$save(function (u, putResponseHeaders) { $scope.toasts.push({Type: 'Success', Message: u.Code}); - $location.path('/Products'); + $window.history.back(); }, function (data, status) { $scope.toasts.push({Type: 'Danger', Message: data.data}); }); @@ -101,7 +101,7 @@ var ProductCtrl = ['$scope', '$location', '$modal', 'product', 'product_groups', $scope.delete = function () { $scope.product.$delete(function (u, putResponseHeaders) { $scope.toasts.push({Type: 'Success', Message: ''}); - $location.path('/Products'); + $window.history.back(); }, function (data, status) { $scope.toasts.push({Type: 'Danger', Message: data.data}); }); diff --git a/brewman/static/scripts/recipe.js b/brewman/static/scripts/recipe.js new file mode 100644 index 00000000..63e7563a --- /dev/null +++ b/brewman/static/scripts/recipe.js @@ -0,0 +1,177 @@ +'use strict'; + +var RecipeListCtrl = ['$scope', 'recipes', function ($scope, recipes) { + $scope.info = recipes; + $scope.display = $scope.info; + $scope.product_type_selected = 'all'; + $scope.show_latest = 'latest'; + $scope.show_summary = 'no'; + + $scope.$watch('product_type_selected', function (value) { + $scope.display = $scope.doFilter(); + }, true); + $scope.$watch('show_latest', function (value) { + $scope.display = $scope.doFilter(); + }, true); + + $scope.doFilter = function (q) { + return _.filter($scope.info, function (item) { + if ($scope.product_type_selected === 'menu') { + if (item.IsSemi) { + return false; + } + } else if ($scope.product_type_selected === 'semi') { + if (!item.IsSemi) { + return false; + } + } + if ($scope.show_latest === 'latest' && !item.IsLatest) { + return false; + } + return true; + }); + }; +}]; + +RecipeListCtrl.resolve = { + recipes: ['Recipe', function (Recipe) { + return Recipe.query({}).$promise; + }] +}; + +var RecipeCtrl = ['$scope', '$location', '$window', '$modal', 'dateFilter', 'Product', 'recipe', 'product_groups', function ($scope, $location, $window, $modal, dateFilter, Product, recipe, product_groups) { + $scope.recipe = recipe; + $scope.original = {}; + angular.copy($scope.recipe, $scope.original); + $scope.product_groups = product_groups; + $scope.cost_price = 0; + function getOld(productID, recipe_items) { + return _.find(recipe_items, function (recipe_item) { + return recipe_item.Product.ProductID === productID; + }); + } + + $scope.add = function () { + if (!$scope.product || !$scope.product.ProductID || !$scope.quantity || Number(!$scope.quantity)) { + return; + } + var oldItem = getOld($scope.product.ProductID, this.recipe.RecipeItems); + if (typeof oldItem === 'undefined') { + var quantity = Number($scope.quantity); + var price = Number($scope.product.Price); + this.recipe.RecipeItems.push({ + Product: $scope.product, + Quantity: quantity, + Price: price + }); + } else { + $scope.toasts.push({Type: 'Danger', Message: 'Ingredient already in the list'}); + } + delete $scope.quantity; + delete $scope.product; + $('#txtProduct').focus(); + }; + + $scope.removeItem = function (item) { + var index = this.recipe.RecipeItems.indexOf(item); + this.recipe.RecipeItems.splice(index, 1); + }; + + $scope.$watch('recipe.RecipeItems', function (recipe_items, oldValue) { + if (!angular.isArray(recipe_items)) { + return; + } + $scope.cost_price = recipe_items.reduce(function (sum, item, index, array) { + var rate = item.Price / (item.Product.Fraction * item.Product.ProductYield) + return sum + (item.Quantity * rate); + }, 0); + }, true); + + $scope.save = function () { + if (angular.isDate($scope.recipe.Date)) { + $scope.recipe.Date = dateFilter($scope.recipe.Date, 'dd-MMM-yyyy'); + } + if (angular.isUndefined($scope.recipe.Date) || $scope.recipe.Date === '') { + $scope.toasts.push({Type: 'Danger', Message: 'Please Choose a date'}); + return; + } + if ($scope.recipe.Date === $scope.original.Date) { + var modalInstance = $modal.open({ + backdrop: true, + templateUrl: '/template/modal/confirm.html', + controller: ['$scope', '$modalInstance', function ($scope, $modalInstance) { + $scope.title = "Update Recipe?"; + $scope.body = "Are you sure? This will overwrite the original recipe."; + $scope.isDelete = false; + $scope.ok = function () { + $modalInstance.close(); + }; + $scope.cancel = function () { + $modalInstance.dismiss('cancel'); + }; + }] + }); + modalInstance.result.then(function () { + $scope.doSave(); + }); + } else { + $scope.doSave(); + } + }; + + $scope.doSave = function () { + $scope.recipe.$save(function (u, putResponseHeaders) { + $scope.toasts.push({Type: 'Success', Message: ''}); + $window.history.back(); + }, function (data, status) { + $scope.toasts.push({Type: 'Danger', Message: data.data}); + }); + }; + + $scope.delete = function () { + $scope.recipe.$delete(function (u, putResponseHeaders) { + $scope.toasts.push({Type: 'Success', Message: ''}); + $window.history.back(); + }, function (data, status) { + $scope.toasts.push({Type: 'Danger', Message: data.data}); + }); + }; + + $scope.confirm = function () { + var modalInstance = $modal.open({ + backdrop: true, + templateUrl: '/template/modal/confirm.html', + controller: ['$scope', '$modalInstance', function ($scope, $modalInstance) { + $scope.title = "Delete Recipe"; + $scope.body = "Are you sure? This cannot be undone."; + $scope.isDelete = true; + $scope.ok = function () { + $modalInstance.close(); + }; + $scope.cancel = function () { + $modalInstance.dismiss('cancel'); + }; + }] + }); + modalInstance.result.then(function () { + $scope.delete(); + }); + }; + $('#txtName').focus(); + + $scope.products = function ($viewValue) { + return Product.autocomplete({term: $viewValue, count: 20, a: true, e: true, t: 'S'}).$promise; + }; + +}]; + +RecipeCtrl.resolve = { + recipe: ['$route', 'Recipe', function ($route, Recipe) { + var id = $route.current.params.id; + + return Recipe.get({id: id}).$promise; + }], + product_groups: ['ProductGroup', function (ProductGroup) { + return ProductGroup.query({}).$promise; + }] +}; diff --git a/brewman/views/Management/settings.py b/brewman/views/Management/settings.py index f0a35a3d..a391ffab 100644 --- a/brewman/views/Management/settings.py +++ b/brewman/views/Management/settings.py @@ -1,4 +1,6 @@ import datetime +import pkg_resources +from pyramid.response import FileResponse from pyramid.view import view_config import transaction @@ -8,9 +10,11 @@ from brewman.models.master import DbSetting from brewman.models.validation_exception import TryCatchFunction -@view_config(route_name='settings', renderer='brewman:templates/angular_base.mako', permission='Authenticated') +@view_config(route_name='settings', permission='Authenticated') def html(request): - return {} + package, resource = 'brewman:static/base.html'.split(':', 1) + file = pkg_resources.resource_filename(package, resource) + return FileResponse(file, request=request) @view_config(request_method='POST', route_name='api_lock_info', renderer='json', permission='Lock Date') diff --git a/brewman/views/__init__.py b/brewman/views/__init__.py index 3631b150..cb46c1a6 100644 --- a/brewman/views/__init__.py +++ b/brewman/views/__init__.py @@ -11,13 +11,15 @@ from pyramid.view import view_config from brewman.models.master import DbSetting -@view_config(route_name='home', renderer='brewman:templates/angular_base.mako') -@view_config(request_method='GET', route_name='login', renderer='brewman:templates/angular_base.mako') +@view_config(route_name='home') +@view_config(request_method='GET', route_name='login') def home(request): - return {} + package, resource = 'brewman:static/base.html'.split(':', 1) + file = pkg_resources.resource_filename(package, resource) + return FileResponse(file, request=request) -@view_config(context=HTTPForbidden, renderer='brewman:templates/angular_base.mako') +@view_config(context=HTTPForbidden) def forbidden(request): if 'X-Requested-With' in request.headers and request.headers['X-Requested-With'] == 'XMLHttpRequest': response = Response("Forbidden") diff --git a/brewman/views/account.py b/brewman/views/account.py index 7713c494..23e12904 100644 --- a/brewman/views/account.py +++ b/brewman/views/account.py @@ -1,5 +1,6 @@ import uuid -from pyramid.response import Response +import pkg_resources +from pyramid.response import Response, FileResponse from pyramid.security import authenticated_userid from pyramid.view import view_config @@ -13,13 +14,13 @@ from brewman.models.validation_exception import ValidationError, TryCatchFunctio from brewman.models.voucher import Voucher, Journal, VoucherType -@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') -@view_config(request_method='GET', route_name='account', renderer='brewman:templates/angular_base.mako', - 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): - return {} + package, resource = 'brewman:static/base.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') diff --git a/brewman/views/attendance.py b/brewman/views/attendance.py index 583eee54..511ac46d 100644 --- a/brewman/views/attendance.py +++ b/brewman/views/attendance.py @@ -1,5 +1,7 @@ import datetime import uuid +import pkg_resources +from pyramid.response import FileResponse from pyramid.security import authenticated_userid from pyramid.view import view_config from sqlalchemy import or_ @@ -13,16 +15,14 @@ from brewman.views.services.session import session_period_start, session_period_ __author__ = 'tanshu' -@view_config(request_method='GET', route_name='attendance_date', renderer='brewman:templates/angular_base.mako', - permission='Attendance') -@view_config(request_method='GET', route_name='attendance', renderer='brewman:templates/angular_base.mako', - permission='Attendance') -@view_config(request_method='GET', route_name='employee_attendance_id', renderer='brewman:templates/angular_base.mako', - permission='Attendance') -@view_config(request_method='GET', route_name='employee_attendance', renderer='brewman:templates/angular_base.mako', - 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): - return {} + package, resource = 'brewman:static/base.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') diff --git a/brewman/views/auth/client.py b/brewman/views/auth/client.py index f8d4eb94..5e128380 100644 --- a/brewman/views/auth/client.py +++ b/brewman/views/auth/client.py @@ -1,5 +1,6 @@ import uuid -from pyramid.response import Response +import pkg_resources +from pyramid.response import Response, FileResponse from pyramid.view import view_config import transaction @@ -9,12 +10,12 @@ from brewman.models.auth import Client from brewman.models.validation_exception import TryCatchFunction -@view_config(request_method='GET', route_name='client_list', renderer='brewman:templates/angular_base.mako', - permission='Clients') -@view_config(request_method='GET', route_name='client_id', renderer='brewman:templates/angular_base.mako', - 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): - return {} + package, resource = 'brewman:static/base.html'.split(':', 1) + file = pkg_resources.resource_filename(package, resource) + return FileResponse(file, request=request) @view_config(request_method='POST', route_name='api_client_id', renderer='json', permission='Clients') diff --git a/brewman/views/auth/group.py b/brewman/views/auth/group.py index f37844db..5b4a7c9a 100644 --- a/brewman/views/auth/group.py +++ b/brewman/views/auth/group.py @@ -1,19 +1,20 @@ import uuid +import pkg_resources -from pyramid.response import Response +from pyramid.response import Response, FileResponse from pyramid.view import view_config import transaction from brewman.models import DBSession from brewman.models.auth import Group, Role from brewman.models.validation_exception import ValidationError, TryCatchFunction -@view_config(route_name='group_list', renderer='brewman:templates/angular_base.mako', permission='Users') -@view_config(request_method='GET', route_name='group_id', renderer='brewman:templates/angular_base.mako', - permission='Users') -@view_config(request_method='GET', route_name='group', renderer='brewman:templates/angular_base.mako', - 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): - return {} + package, resource = 'brewman:static/base.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') diff --git a/brewman/views/auth/user.py b/brewman/views/auth/user.py index 2ee58605..fabf5881 100644 --- a/brewman/views/auth/user.py +++ b/brewman/views/auth/user.py @@ -1,6 +1,7 @@ import re import uuid -from pyramid.response import Response +import pkg_resources +from pyramid.response import Response, FileResponse from pyramid.security import authenticated_userid from pyramid.view import view_config @@ -22,13 +23,13 @@ class UserView(object): self.user = User.by_id(self.user) self.has_permission = 'Users' in groupfinder(self.user.id, request) - @view_config(route_name='user_list', renderer='brewman:templates/angular_base.mako', permission='Users') - @view_config(request_method='GET', route_name='user_id', renderer='brewman:templates/angular_base.mako', - permission='Authenticated') - @view_config(request_method='GET', route_name='user', renderer='brewman:templates/angular_base.mako', - 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): - return {} + package, resource = 'brewman:static/base.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') diff --git a/brewman/views/cost_center.py b/brewman/views/cost_center.py index 5e56ef9e..4cc8ffb6 100644 --- a/brewman/views/cost_center.py +++ b/brewman/views/cost_center.py @@ -1,5 +1,6 @@ import uuid -from pyramid.response import Response +import pkg_resources +from pyramid.response import Response, FileResponse from pyramid.view import view_config import transaction @@ -9,13 +10,13 @@ from brewman.models.master import CostCenter from brewman.models.validation_exception import ValidationError, TryCatchFunction -@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') -@view_config(request_method='GET', route_name='cost_center', renderer='brewman:templates/angular_base.mako', - permission='Cost Centers') +@view_config(route_name='cost_center_list', permission='Authenticated') +@view_config(request_method='GET', route_name='cost_center_id', permission='Cost Centers') +@view_config(request_method='GET', route_name='cost_center', permission='Cost Centers') def html(request): - return {} + package, resource = 'brewman:static/base.html'.split(':', 1) + file = pkg_resources.resource_filename(package, resource) + return FileResponse(file, request=request) @view_config(request_method='POST', route_name='api_cost_center', renderer='json', permission='Cost Centers') diff --git a/brewman/views/dashboard.py b/brewman/views/dashboard.py index 8048515d..9c2ccc92 100644 --- a/brewman/views/dashboard.py +++ b/brewman/views/dashboard.py @@ -1,3 +1,5 @@ +import pkg_resources +from pyramid.response import FileResponse from pyramid.security import authenticated_userid from pyramid.view import view_config from sqlalchemy import func @@ -10,9 +12,11 @@ from brewman.models.voucher import Voucher, Journal, VoucherType from brewman.views.services.session import session_period_finish, session_period_start, session_current_date -@view_config(route_name='dashboard', renderer='brewman:templates/angular_base.mako', permission='Authenticated') +@view_config(route_name='dashboard', permission='Authenticated') def html(request): - return {} + package, resource = 'brewman:static/base.html'.split(':', 1) + file = pkg_resources.resource_filename(package, resource) + return FileResponse(file, request=request) @view_config(route_name='api_dashboard', renderer='json') diff --git a/brewman/views/employee.py b/brewman/views/employee.py index d3c2e0c6..f0a0478d 100644 --- a/brewman/views/employee.py +++ b/brewman/views/employee.py @@ -1,6 +1,7 @@ import datetime import uuid -from pyramid.response import Response +import pkg_resources +from pyramid.response import Response, FileResponse from pyramid.security import authenticated_userid from pyramid.view import view_config @@ -15,15 +16,14 @@ from brewman.models.voucher import Voucher, Journal, VoucherType from brewman.views import to_uuid -@view_config(route_name='employee_list', renderer='brewman:templates/angular_base.mako', permission='Authenticated') -@view_config(request_method='GET', route_name='employee_id', renderer='brewman:templates/angular_base.mako', - permission='Employees') -@view_config(request_method='GET', route_name='employee', renderer='brewman:templates/angular_base.mako', - permission='Employees') -@view_config(request_method='GET', route_name='employee_functions', renderer='brewman:templates/angular_base.mako', - 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): - return {} + package, resource = 'brewman:static/base.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') diff --git a/brewman/views/messaging.py b/brewman/views/messaging.py index 5019b398..05ba205a 100644 --- a/brewman/views/messaging.py +++ b/brewman/views/messaging.py @@ -1,5 +1,7 @@ import datetime import uuid +import pkg_resources +from pyramid.response import FileResponse from pyramid.security import authenticated_userid from pyramid.view import view_config @@ -14,10 +16,12 @@ from brewman.models.tzinfoutc import get_age from brewman.models.validation_exception import TryCatchFunction, ValidationError -@view_config(request_method='GET', route_name='message_id', renderer='brewman:templates/angular_base.mako') -@view_config(request_method='GET', route_name='message', renderer='brewman:templates/angular_base.mako') +@view_config(request_method='GET', route_name='message_id') +@view_config(request_method='GET', route_name='message') def html(request): - return {} + package, resource = 'brewman:static/base.html'.split(':', 1) + file = pkg_resources.resource_filename(package, resource) + return FileResponse(file, request=request) @view_config(request_method='POST', route_name='api_message', renderer='json', permission='Authenticated') diff --git a/brewman/views/product.py b/brewman/views/product.py index cafddaaf..968a60be 100644 --- a/brewman/views/product.py +++ b/brewman/views/product.py @@ -1,26 +1,28 @@ from decimal import Decimal, InvalidOperation import uuid -from pyramid.response import Response -from pyramid.security import authenticated_userid +import pkg_resources +from pyramid.response import Response, FileResponse +from pyramid.security import authenticated_userid from pyramid.view import view_config +from sqlalchemy import desc from sqlalchemy.orm import joinedload_all import transaction + from brewman import groupfinder from brewman.models import DBSession - -from brewman.models.master import Product, CostCenter, LedgerType, Ledger +from brewman.models.master import Product, Ledger, MenuItem from brewman.models.validation_exception import TryCatchFunction, ValidationError from brewman.models.voucher import Voucher, Batch, Inventory, VoucherType -@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') -@view_config(request_method='GET', route_name='product', renderer='brewman:templates/angular_base.mako', - 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): - return {} + package, resource = 'brewman:static/base.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') @@ -36,10 +38,10 @@ def save(request): try: fraction = Decimal(json.get('Fraction', 0)) - if fraction <= 0 or fraction > 1: - raise ValidationError("Fraction must be a decimal > 0 and <= 1") + if fraction <= 0: + raise ValidationError("Fraction must be a decimal > 0") except (ValueError, InvalidOperation): - raise ValidationError("Fraction must be a decimal > 0 and <= 1") + raise ValidationError("Fraction must be a decimal > 0") fraction_units = json.get('FractionUnits', '').strip() @@ -50,7 +52,6 @@ def save(request): except (ValueError, InvalidOperation): raise ValidationError("Yield must be a decimal >= 0 <= 1") - show_for_purchase = json.get('ShowForPurchase', True) product_group = json.get('ProductGroup', None) if product_group is None: raise ValidationError('Please choose a product group') @@ -58,12 +59,12 @@ def save(request): try: price = Decimal(json.get('Price', 0)) if price < 0: - raise ValidationError("Price must be a decimal > 0") + raise ValidationError("Price must be a decimal >= 0") except (ValueError, InvalidOperation): - raise ValidationError("Price must be a decimal > 0") - discontinued = json.get('Discontinued', False) - item = Product(0, name, units, fraction, fraction_units, product_yield, show_for_purchase, product_group_id, - Ledger.all_purchases(), price, discontinued).create() + raise ValidationError("Price must be a decimal >= 0") + is_active = json.get('IsActive', True) + item = Product(0, name, units, fraction, fraction_units, product_yield, product_group_id, Ledger.all_purchases(), + price, is_active).create() transaction.commit() return product_info(item.id) @@ -78,10 +79,10 @@ def update(request): item.units = request.json_body['Units'].strip() try: item.fraction = Decimal(request.json_body['Fraction']) - if item.fraction <= 0 or item.fraction > 1: - raise ValidationError("Fraction must be a decimal > 0 and <= 1") + if item.fraction <= 0: + raise ValidationError("Fraction must be a decimal > 0") except (ValueError, InvalidOperation): - raise ValidationError("Fraction must be a decimal > 0 and <= 1") + raise ValidationError("Fraction must be a decimal > 0") item.fraction_units = request.json_body['FractionUnits'] try: @@ -91,16 +92,15 @@ def update(request): except (ValueError, InvalidOperation): raise ValidationError("Yield must be a decimal >= 0 <= 1") - item.show_for_purchase = request.json_body['ShowForPurchase'] item.product_group_id = uuid.UUID(request.json_body['ProductGroup']['ProductGroupID']) item.ledger_id = Ledger.all_purchases() try: item.price = Decimal(request.json_body['Price']) if item.price < 0: - raise ValidationError("Price must be a decimal > 0") + raise ValidationError("Price must be a decimal >= 0") except (ValueError, InvalidOperation): - raise ValidationError("Price must be a decimal > 0") - item.discontinued = request.json_body['Discontinued'] + raise ValidationError("Price must be a decimal >= 0") + item.is_active = request.json_body['IsActive'] transaction.commit() return product_info(item.id) @@ -135,12 +135,12 @@ def show_blank(request): @view_config(request_method='GET', route_name='api_product', request_param='list', renderer='json', permission='Authenticated') def show_list(request): - list = Product.query().order_by(Product.discontinued).order_by(Product.product_group_id).order_by( + list = Product.query().order_by(desc(Product.is_active)).order_by(Product.product_group_id).order_by( Product.name).all() products = [] 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, + 'ProductGroup': item.product_group.name, 'IsActive': item.is_active, 'IsFixture': item.is_fixture, 'Url': request.route_url('product_id', id=item.id)}) return products @@ -149,30 +149,63 @@ def show_list(request): permission='Authenticated') def show_term(request): term = request.GET.get('term', None) - term = term if term is not None and term is not '' else 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('count', None) count = None if count is None or count == '' else int(count) - list = [] - for index, item in enumerate(Product.list(term, active)): - list.append({'ProductID': item.id, 'Name': item.full_name, 'Price': item.price}) - if count is not None and index == count - 1: - break - return list + extended = request.GET.get('e', False) + products_type = request.GET.get('t', 'P') # P = Products / S = + Semi / M = + Menu Items + + if products_type not in ('P', 'S', 'M'): + products_type = 'P' + + def add_list(query): + local_results = [] + for index, item in enumerate(query): + if extended: + product = {'ProductID': item.id, 'Name': item.full_name, 'Price': item.price, 'Units': item.units, + 'Fraction': item.fraction, 'FractionUnits': item.fraction_units, + 'ProductYield': item.product_yield} + else: + product = {'ProductID': item.id, 'Name': item.full_name, 'Price': item.price} + local_results.append(product) + if count is not None and index == count - 1: + break + return local_results + + result_list = [] + if products_type == 'S' or products_type == 'M': + query = DBSession.query(MenuItem) + if active is not None: + query = query.filter(MenuItem.is_active == active) + if products_type == 'S': + query = query.filter(MenuItem.is_semi == True) + for item in term.split(): + if item.strip() != '': + query = query.filter(MenuItem.name.ilike('%' + item + '%')) + result_list += add_list(query) + + query = DBSession.query(Product) + if active is not None: + query = query.filter(Product.is_active == active) + for item in term.split(): + if item.strip() != '': + query = query.filter(Product.name.ilike('%' + item + '%')) + result_list += add_list(query) + + return sorted(result_list, key=lambda k: k['Name']) def product_info(id): if id is None: - product = {'Code': '(Auto)', 'Type': LedgerType.by_name('Creditors').id, 'IsActive': True, - 'CostCenter': CostCenter.overall(), 'ShowForPurchase': True, 'Discontinued': False} + product = {'Code': '(Auto)', 'IsActive': True} else: product = Product.by_id(id) product = {'ProductID': product.id, 'Code': product.code, 'Name': product.name, 'Units': product.units, 'Fraction': product.fraction, 'FractionUnits': product.fraction_units, - 'ProductYield': product.product_yield, 'ShowForPurchase': product.show_for_purchase, - 'Discontinued': product.discontinued, 'IsFixture': product.is_fixture, - 'ProductGroup': {'ProductGroupID': product.product_group_id}, + 'ProductYield': product.product_yield, 'IsActive': product.is_active, + 'IsFixture': product.is_fixture, 'ProductGroup': {'ProductGroupID': product.product_group_id}, 'Ledger': {'LedgerID': product.ledger_id}, 'Price': product.price} return product diff --git a/brewman/views/product_group.py b/brewman/views/product_group.py index aed0da69..b086402d 100644 --- a/brewman/views/product_group.py +++ b/brewman/views/product_group.py @@ -1,5 +1,6 @@ import uuid -from pyramid.response import Response +import pkg_resources +from pyramid.response import Response, FileResponse from pyramid.view import view_config import transaction @@ -9,14 +10,13 @@ from brewman.models.master import ProductGroup from brewman.models.validation_exception import ValidationError, TryCatchFunction -@view_config(route_name='product_group_list', renderer='brewman:templates/angular_base.mako', - permission='Authenticated') -@view_config(request_method='GET', route_name='product_group_id', renderer='brewman:templates/angular_base.mako', - permission='Product Groups') -@view_config(request_method='GET', route_name='product_group', renderer='brewman:templates/angular_base.mako', - 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): - return {} + package, resource = 'brewman:static/base.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') diff --git a/brewman/views/recipe.py b/brewman/views/recipe.py new file mode 100644 index 00000000..15153d04 --- /dev/null +++ b/brewman/views/recipe.py @@ -0,0 +1,240 @@ +import uuid +import datetime +from decimal import Decimal, InvalidOperation + +import pkg_resources +from pyramid.response import FileResponse +from pyramid.view import view_config +from sqlalchemy import desc +import transaction + +from brewman.models import DBSession +from brewman.models.master import Ledger, Recipe, ProductGroup, MenuItem, ProductBase, RecipeItem +from brewman.models.validation_exception import TryCatchFunction, ValidationError + + +@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/base.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') +@TryCatchFunction +def save(request): + json = request.json_body + name = json.get('Name', '').strip() + if name == '': + raise ValidationError('Name cannot be blank') + + try: + quantity = Decimal(json.get('Quantity', 0)) + if quantity < 0: + raise ValidationError("Quantity must be a decimal >= 0") + except (ValueError, InvalidOperation): + raise ValidationError("Quantity must be a decimal >= 0") + + try: + date = datetime.datetime.strptime(request.json_body['Date'], '%d-%b-%Y') + except (ValueError, KeyError, TypeError): + raise ValidationError("Date is not a valid date") + + is_semi = json.get('IsSemi', False) + + if not is_semi: + try: + 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") + 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['ProductGroupID']) + units = 'Portion' + fraction = 1 + fraction_units = 'Portion' + else: + sale_price = 0 + product_group_id = ProductGroup.semi() + units = json.get('Units', '').strip() + try: + 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() + + recipe_cost = 0 + if len(json['RecipeItems']) == 0: + raise ValidationError("Recipe has no ingredients") + recipe_items = [] + for item in json['RecipeItems']: + product = ProductBase.by_id(uuid.UUID(item['Product']['ProductID'])) + quantity = round(Decimal(item['Quantity']), 2) + ingredient_price = round(Decimal(item['Price']), 2) + rate = ingredient_price / (product.fraction * product.product_yield) + recipe_cost += rate * quantity + recipe_items.append(RecipeItem(None, product.id, quantity, ingredient_price)) + + menu_item = MenuItem(0, name, units=units, is_semi=is_semi, fraction=fraction, fraction_units=fraction_units, + product_group_id=product_group_id, ledger_id=Ledger.all_purchases(), + price=recipe_cost, is_active=True).create() + + recipe = Recipe(date=date, product_id=menu_item.id, quantity=quantity, sale_price=sale_price, notes='') + recipe.product = menu_item + DBSession.add(recipe) + for item in recipe_items: + item.recipe_id = recipe.id + recipe.recipe_items.append(item) + DBSession.add(item) + transaction.commit() + return recipe_info(recipe.id) + + +@view_config(request_method='POST', route_name='api_recipe_id', renderer='json', permission='Recipes') +@TryCatchFunction +def update(request): + json = request.json_body + recipe = DBSession.query(Recipe).filter(Recipe.id == uuid.UUID(request.matchdict['id'])).first() + name = json.get('Name', '').strip() + if name == '': + raise ValidationError('Name cannot be blank') + if recipe.product.name != name and recipe.product.is_fixture: + raise ValidationError("{0} is a fixture and cannot be edited or deleted.".format(recipe.product.name)) + try: + date = datetime.datetime.strptime(json['Date'], '%d-%b-%Y') + except (ValueError, KeyError, TypeError): + raise ValidationError("Date is not a valid date") + if len(json['RecipeItems']) == 0: + raise ValidationError("Recipe has no ingredients") + if date == recipe.date: + recipe.date = date + recipe_cost = 0 + try: + recipe.sale_price = Decimal(json.get('SalePrice', 0)) + if recipe.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_items = [] + for item in json['RecipeItems']: + product = ProductBase.by_id(uuid.UUID(item['Product']['ProductID'])) + quantity = round(Decimal(item['Quantity']), 2) + ingredient_price = round(Decimal(item['Price']), 2) + rate = ingredient_price / (product.fraction * product.product_yield) + recipe_cost += rate * quantity + recipe_items.append(RecipeItem(None, product.id, quantity, ingredient_price)) + recipe.product.price = recipe_cost + recipe.recipe_items = [] + for recipe_item in recipe_items: + recipe_item.recipe_id = recipe.id + recipe.recipe_items.append(recipe_item) + DBSession.add(recipe_item) + else: + recipe_cost = 0 + try: + 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_items = [] + for item in json['RecipeItems']: + product = ProductBase.by_id(uuid.UUID(item['Product']['ProductID'])) + quantity = round(Decimal(item['Quantity']), 2) + ingredient_price = round(Decimal(item['Price']), 2) + rate = ingredient_price / (product.fraction * product.product_yield) + recipe_cost += rate * quantity + recipe_items.append(RecipeItem(None, product.id, quantity, ingredient_price)) + + menu_item = recipe.product + print(menu_item.id) + recipe = Recipe(date=date, product_id=menu_item.id, quantity=1, sale_price=sale_price, notes='') + recipe.product = menu_item + DBSession.add(recipe) + for item in recipe_items: + item.recipe_id = recipe.id + recipe.recipe_items.append(item) + DBSession.add(item) + print('One') + transaction.commit() + return recipe_info(recipe.id) + + +@view_config(request_method='DELETE', route_name='api_recipe_id', renderer='json', permission='Recipes') +def delete(request): + recipe = DBSession.query(Recipe).filter(Recipe.id == uuid.UUID(request.matchdict['id'])).first() + if len(recipe.product.recipes) > 1: + DBSession.delete(recipe) + else: + DBSession.delete(recipe) + DBSession.delete(recipe.product) + transaction.commit() + return recipe_info(None) + + +@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'])) + + +@view_config(request_method='GET', route_name='api_recipe', renderer='json', permission='Recipes') +def show_blank(request): + return recipe_info(None) + + +@view_config(request_method='GET', route_name='api_recipe', renderer='json', request_param='list', + permission='Authenticated') +def show_list(request): + list = DBSession.query(Recipe).order_by(Recipe.product_id).order_by(desc(Recipe.date)).all() + recipes = [] + previous_product_id = None + for item in list: + cost_price = 0 + current_cost_price = 0 + recipe_items = [] + for recipe_item in item.recipe_items: + product = recipe_item.product + cost_rate = (recipe_item.price / product.product_yield) / product.fraction + cost_price += recipe_item.quantity * cost_rate + current_cost_price += (product.price / product.product_yield) * recipe_item.quantity / product.fraction + recipe_items.append({'Name': recipe_item.product.name, 'FractionUnits': recipe_item.product.fraction_units, + 'Price': cost_rate, 'Quantity': recipe_item.quantity}) + costing = 0 if item.sale_price == 0 else cost_price / item.sale_price + current_costing = 0 if item.sale_price == 0 else current_cost_price / item.sale_price + recipe = {'Name': item.product.name, 'Date': item.date.strftime('%d-%b-%Y'), 'SalePrice': item.sale_price, + 'CostPrice': cost_price, 'CurrentCostPrice': current_cost_price, 'Costing': costing, + 'CurrentCosting': current_costing, 'IsSemi': item.product.is_semi, 'RecipeItems': recipe_items, + 'IsLatest': previous_product_id != item.product.id, 'Url': request.route_url('recipe_id', id=item.id)} + recipes.append(recipe) + previous_product_id = item.product.id + return recipes + + +def recipe_info(id): + if id is None: + info = {'Quantity': 1, 'IsSemi': False, 'Units': 'Portion', 'Fraction': 1, 'FractionUnits': 'Portion', + 'RecipeItems': []} + else: + recipe = DBSession.query(Recipe).filter(Recipe.id == id).first() + info = {'RecipeID': recipe.id, 'Name': recipe.product.name, 'Quantity': recipe.quantity, + 'Date': recipe.date.strftime('%d-%b-%Y'), 'IsSemi': recipe.product.is_semi, + 'Units': recipe.product.units, 'Fraction': recipe.product.fraction, + 'FractionUnits': recipe.product.fraction_units, 'SalePrice': recipe.sale_price, + 'ProductGroup': {'ProductGroupID': recipe.product.product_group_id}, + 'RecipeItems': []} + for item in recipe.recipe_items: + info['RecipeItems'].append({ + 'Product': {'ProductID': item.product.id, 'Name': item.product.name, + 'FractionUnits': item.product.fraction_units, 'Fraction': item.product.fraction, + 'ProductYield': item.product.product_yield}, + 'Quantity': item.quantity, 'Price': item.price}) + pass + return info diff --git a/brewman/views/reports/balance_sheet.py b/brewman/views/reports/balance_sheet.py index 700342cd..40f93672 100644 --- a/brewman/views/reports/balance_sheet.py +++ b/brewman/views/reports/balance_sheet.py @@ -1,4 +1,6 @@ import datetime +import pkg_resources +from pyramid.response import FileResponse from sqlalchemy.sql.expression import func, desc from pyramid.view import view_config @@ -12,12 +14,12 @@ 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', renderer='brewman:templates/angular_base.mako', - permission='Balance Sheet') -@view_config(request_method='GET', route_name='balance_sheet_date', renderer='brewman:templates/angular_base.mako', - 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): - return {} + package, resource = 'brewman:static/base.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') diff --git a/brewman/views/reports/cash_flow.py b/brewman/views/reports/cash_flow.py index a508b924..bc05db3f 100644 --- a/brewman/views/reports/cash_flow.py +++ b/brewman/views/reports/cash_flow.py @@ -1,4 +1,6 @@ import datetime +import pkg_resources +from pyramid.response import FileResponse from sqlalchemy.orm.util import aliased from sqlalchemy.sql.expression import func, desc @@ -10,12 +12,12 @@ from brewman.models.master import LedgerBase, LedgerType from brewman.models.voucher import Voucher, Journal from brewman.views.services.session import session_period_start, session_period_finish -@view_config(request_method='GET', route_name='cash_flow', renderer='brewman:templates/angular_base.mako', - permission='Cash Flow') -@view_config(request_method='GET', route_name='cash_flow_id', renderer='brewman:templates/angular_base.mako', - 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): - return {} + package, resource = 'brewman:static/base.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') diff --git a/brewman/views/reports/closing_stock.py b/brewman/views/reports/closing_stock.py index 7038daf8..be847690 100644 --- a/brewman/views/reports/closing_stock.py +++ b/brewman/views/reports/closing_stock.py @@ -1,4 +1,6 @@ import datetime +import pkg_resources +from pyramid.response import FileResponse from sqlalchemy.sql.expression import func from pyramid.view import view_config @@ -10,12 +12,12 @@ 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', renderer='brewman:templates/angular_base.mako', - permission='Closing Stock') -@view_config(request_method='GET', route_name='closing_stock_date', renderer='brewman:templates/angular_base.mako', - 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): - return {} + package, resource = 'brewman:static/base.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') diff --git a/brewman/views/reports/daybook.py b/brewman/views/reports/daybook.py index a1a64de8..ccdc2ebb 100644 --- a/brewman/views/reports/daybook.py +++ b/brewman/views/reports/daybook.py @@ -1,4 +1,6 @@ import datetime +import pkg_resources +from pyramid.response import FileResponse from sqlalchemy.orm import joinedload_all from pyramid.view import view_config @@ -8,10 +10,11 @@ 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', renderer='brewman:templates/angular_base.mako', - permission='Daybook') +@view_config(request_method='GET', route_name='daybook', permission='Daybook') def daybook_get(request): - return {} + package, resource = 'brewman:static/base.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') diff --git a/brewman/views/reports/ledger.py b/brewman/views/reports/ledger.py index 9f4a83ac..dbb01c40 100644 --- a/brewman/views/reports/ledger.py +++ b/brewman/views/reports/ledger.py @@ -1,4 +1,6 @@ import datetime +import pkg_resources +from pyramid.response import FileResponse from sqlalchemy.orm import joinedload_all from sqlalchemy.sql.expression import func import uuid @@ -14,12 +16,12 @@ 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', renderer='brewman:templates/angular_base.mako', - permission='Ledger') -@view_config(request_method='GET', route_name='ledger', renderer='brewman:templates/angular_base.mako', - 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): - return {} + package, resource = 'brewman:static/base.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') diff --git a/brewman/views/reports/net_transactions.py b/brewman/views/reports/net_transactions.py index baa99215..726bbb19 100644 --- a/brewman/views/reports/net_transactions.py +++ b/brewman/views/reports/net_transactions.py @@ -1,4 +1,6 @@ import datetime +import pkg_resources +from pyramid.response import FileResponse from sqlalchemy.sql.expression import func, desc from pyramid.view import view_config @@ -10,10 +12,11 @@ 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', renderer='brewman:templates/angular_base.mako', - permission='Net Transactions') +@view_config(request_method='GET', route_name='net_transactions', permission='Net Transactions') def html(request): - return {} + package, resource = 'brewman:static/base.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') diff --git a/brewman/views/reports/product_ledger.py b/brewman/views/reports/product_ledger.py index 0568d48f..ce4c13a6 100644 --- a/brewman/views/reports/product_ledger.py +++ b/brewman/views/reports/product_ledger.py @@ -1,4 +1,6 @@ import datetime +import pkg_resources +from pyramid.response import FileResponse from sqlalchemy.orm import joinedload from sqlalchemy.sql.expression import func import uuid @@ -15,12 +17,12 @@ 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', renderer='brewman:templates/angular_base.mako', - permission='Product Ledger') -@view_config(request_method='GET', route_name='product_ledger', renderer='brewman:templates/angular_base.mako', - 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): - return {} + package, resource = 'brewman:static/base.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') diff --git a/brewman/views/reports/profit_loss.py b/brewman/views/reports/profit_loss.py index a421283c..85f19ffd 100644 --- a/brewman/views/reports/profit_loss.py +++ b/brewman/views/reports/profit_loss.py @@ -1,4 +1,6 @@ import datetime +import pkg_resources +from pyramid.response import FileResponse from sqlalchemy.sql.expression import func, desc from pyramid.view import view_config @@ -11,10 +13,11 @@ 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', renderer='brewman:templates/angular_base.mako', - permission='Profit & Loss') +@view_config(request_method='GET', route_name='profit_loss', permission='Profit & Loss') def html(request): - return {} + package, resource = 'brewman:static/base.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') diff --git a/brewman/views/reports/purchase_entries.py b/brewman/views/reports/purchase_entries.py index 5dd21bdf..b3b4f6cf 100644 --- a/brewman/views/reports/purchase_entries.py +++ b/brewman/views/reports/purchase_entries.py @@ -1,4 +1,6 @@ import datetime +import pkg_resources +from pyramid.response import FileResponse from sqlalchemy.sql.expression import func, desc from pyramid.view import view_config @@ -10,10 +12,11 @@ from brewman.models.voucher import Voucher, Journal, VoucherType, Inventory from brewman.views.services.session import session_period_start, session_period_finish from brewman.views.services.voucher import get_edit_url -@view_config(request_method='GET', route_name='purchase_entries', renderer='brewman:templates/angular_base.mako', - permission='Purchase Entries') +@view_config(request_method='GET', route_name='purchase_entries', permission='Purchase Entries') def html(request): - return {} + package, resource = 'brewman:static/base.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') diff --git a/brewman/views/reports/purchases.py b/brewman/views/reports/purchases.py index 41a6f22e..7bbbbcdc 100644 --- a/brewman/views/reports/purchases.py +++ b/brewman/views/reports/purchases.py @@ -1,4 +1,6 @@ import datetime +import pkg_resources +from pyramid.response import FileResponse from sqlalchemy.sql.expression import func, desc from pyramid.view import view_config @@ -10,10 +12,11 @@ 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', renderer='brewman:templates/angular_base.mako', - permission='Purchases') +@view_config(request_method='GET', route_name='purchases', permission='Purchases') def html(request): - return {} + package, resource = 'brewman:static/base.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') diff --git a/brewman/views/reports/raw_material_cost.py b/brewman/views/reports/raw_material_cost.py index 8ec7896c..521c947a 100644 --- a/brewman/views/reports/raw_material_cost.py +++ b/brewman/views/reports/raw_material_cost.py @@ -1,5 +1,7 @@ import datetime import uuid +import pkg_resources +from pyramid.response import FileResponse from sqlalchemy.sql.expression import func, case from pyramid.view import view_config @@ -11,12 +13,12 @@ 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', renderer='brewman:templates/angular_base.mako', - permission='Raw Material Cost') -@view_config(request_method='GET', route_name='raw_material_cost_id', renderer='brewman:templates/angular_base.mako', - 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): - return {} + package, resource = 'brewman:static/base.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') diff --git a/brewman/views/reports/reconcile.py b/brewman/views/reports/reconcile.py index 6b4a9928..b177fed1 100644 --- a/brewman/views/reports/reconcile.py +++ b/brewman/views/reports/reconcile.py @@ -1,4 +1,6 @@ import datetime +import pkg_resources +from pyramid.response import FileResponse from sqlalchemy.orm import joinedload_all from sqlalchemy.sql.expression import func import uuid @@ -15,12 +17,12 @@ 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', renderer='brewman:templates/angular_base.mako', - permission='Reconcile') -@view_config(request_method='GET', route_name='reconcile', renderer='brewman:templates/angular_base.mako', - 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): - return {} + package, resource = 'brewman:static/base.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') diff --git a/brewman/views/reports/stock_movement.py b/brewman/views/reports/stock_movement.py index 0e2ed106..dd3b8b0e 100644 --- a/brewman/views/reports/stock_movement.py +++ b/brewman/views/reports/stock_movement.py @@ -1,4 +1,6 @@ import datetime +import pkg_resources +from pyramid.response import FileResponse from sqlalchemy.sql.expression import func from pyramid.view import view_config @@ -10,10 +12,11 @@ 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', renderer='brewman:templates/angular_base.mako', - permission='Stock Movement') +@view_config(request_method='GET', route_name='stock_movement', permission='Stock Movement') def html(request): - return {} + package, resource = 'brewman:static/base.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') diff --git a/brewman/views/reports/trial_balance.py b/brewman/views/reports/trial_balance.py index ae767c1c..535bb53b 100644 --- a/brewman/views/reports/trial_balance.py +++ b/brewman/views/reports/trial_balance.py @@ -1,4 +1,6 @@ import datetime +import pkg_resources +from pyramid.response import FileResponse from sqlalchemy.sql.expression import func from pyramid.view import view_config @@ -9,12 +11,12 @@ from brewman.models.master import LedgerBase 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', renderer='brewman:templates/angular_base.mako', - permission='Trial Balance') -@view_config(request_method='GET', route_name='trial_balance_date', renderer='brewman:templates/angular_base.mako', - 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): - return {} + package, resource = 'brewman:static/base.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') def report_blank(request): diff --git a/brewman/views/reports/unposted.py b/brewman/views/reports/unposted.py index c59dab30..5b8215f6 100644 --- a/brewman/views/reports/unposted.py +++ b/brewman/views/reports/unposted.py @@ -1,3 +1,5 @@ +import pkg_resources +from pyramid.response import FileResponse from sqlalchemy.orm import joinedload_all from pyramid.view import view_config @@ -5,10 +7,11 @@ from pyramid.view import view_config 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', renderer='brewman:templates/angular_base.mako', - permission='Post Vouchers') +@view_config(request_method='GET', route_name='unposted', permission='Post Vouchers') def html(request): - return {} + package, resource = 'brewman:static/base.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') diff --git a/brewman/views/services/voucher/__init__.py b/brewman/views/services/voucher/__init__.py index cd74d7e2..21b09ed2 100644 --- a/brewman/views/services/voucher/__init__.py +++ b/brewman/views/services/voucher/__init__.py @@ -1,5 +1,6 @@ import uuid -from pyramid.response import Response +import pkg_resources +from pyramid.response import Response, FileResponse from pyramid.security import authenticated_userid from pyramid.view import view_config from sqlalchemy import func @@ -18,36 +19,24 @@ from .purchase import purchase_create_voucher, purchase_update_voucher __author__ = 'tanshu' -@view_config(request_method='GET', route_name='journal_id', renderer='brewman:templates/angular_base.mako', - permission='Journal') -@view_config(request_method='GET', route_name='journal', renderer='brewman:templates/angular_base.mako', - permission='Journal') -@view_config(request_method='GET', route_name='payment_id', renderer='brewman:templates/angular_base.mako', - permission='Payment') -@view_config(request_method='GET', route_name='payment', renderer='brewman:templates/angular_base.mako', - permission='Payment') -@view_config(request_method='GET', route_name='receipt_id', renderer='brewman:templates/angular_base.mako', - permission='Receipt') -@view_config(request_method='GET', route_name='receipt', renderer='brewman:templates/angular_base.mako', - permission='Receipt') -@view_config(request_method='GET', route_name='purchase_id', renderer='brewman:templates/angular_base.mako', - permission='Purchase') -@view_config(request_method='GET', route_name='purchase', renderer='brewman:templates/angular_base.mako', - permission='Purchase') -@view_config(request_method='GET', route_name='purchase_return_id', renderer='brewman:templates/angular_base.mako', - permission='Purchase Return') -@view_config(request_method='GET', route_name='purchase_return', renderer='brewman:templates/angular_base.mako', - permission='Purchase Return') -@view_config(request_method='GET', route_name='issue_id', renderer='brewman:templates/angular_base.mako', - permission='Issue') -@view_config(request_method='GET', route_name='issue', renderer='brewman:templates/angular_base.mako', - permission='Issue') -@view_config(request_method='GET', route_name='salary_deduction_id', renderer='brewman:templates/angular_base.mako', - permission='Issue') -@view_config(request_method='GET', route_name='salary_deduction', renderer='brewman:templates/angular_base.mako', - permission='Issue') +@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='salary_deduction_id', permission='Issue') +@view_config(request_method='GET', route_name='salary_deduction', permission='Issue') def journal_get(request): - return {} + package, resource = 'brewman:static/base.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='post', renderer='json', diff --git a/setup.py b/setup.py index cdd2704a..af8c919b 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,6 @@ CHANGES = open(os.path.join(here, 'CHANGES.txt')).read() requires = [ 'pyramid', - 'pyramid_debugtoolbar', 'waitress', 'transaction', 'zope.sqlalchemy',