Feature: The app checks if the database schema is not created and creates it automatially on first run.

Fix: While user login try to catch None password error.
Fix: Rename Yeild to the correct spelling Yield.
Fix: Wrong column type for IsReconciled in Voucher.
Fix: Redirect user on login to last page.
Fix: Validate input in save/update of employee and product
This commit is contained in:
Amritanshu 2014-03-12 22:49:29 +05:30
parent f4551c8b5a
commit 69071182a3
9 changed files with 284 additions and 56 deletions

View File

@ -8,14 +8,118 @@ from sqlalchemy.orm import sessionmaker
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension(), expire_on_commit=False)) DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension(), expire_on_commit=False))
Base = declarative_base() Base = declarative_base()
def initialize_sql(engine): def initialize_sql(engine):
# 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.auth import Client, Group, Role, User, role_group, user_group
# from .master import DbSetting
DBSession.configure(bind=engine) DBSession.configure(bind=engine)
Base.metadata.bind = engine Base.metadata.bind = engine
# Base.metadata.create_all(engine) if not schema_exists(engine):
fixtures(engine)
def schema_exists(engine):
from brewman.models.master import DbSetting
with engine.connect() as connection:
return engine.dialect.has_table(connection, DbSetting.__tablename__)
def fixtures(engine):
import transaction
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.auth import Client, Group, Role, User, role_group, user_group
Base.metadata.create_all(engine)
user = User('Admin', '123456', False, uuid.UUID('8de98592-76d9-c74d-bb3f-d6184d388b5a'))
DBSession.add(user)
groups = [Group('Owner', uuid.UUID('52e08c0c-048a-784f-be10-6e129ad4b5d4')),
Group('Accountant', uuid.UUID('bc4c2d23-437a-984d-abd4-7d5fce677547')),
Group('Accounts Manager', uuid.UUID('cfc44fa7-3392-5b45-b311-5959333f568f'))]
for group in groups:
DBSession.add(group)
user.groups.append(group)
roles = [Role('Attendance', uuid.UUID('09d05434-a09a-fa45-963b-769a2e3fc667')),
Role('Trial Balance', uuid.UUID('3b099fec-ddc5-4243-b30e-afb78d9ca14a')),
Role('Cash Flow', uuid.UUID('c4d3ae29-420b-ea4c-ae90-00a356263fd9')),
Role('Cost Centers', uuid.UUID('6fcc1a20-6aec-e840-b334-1632b34aeab8')),
Role('Users', uuid.UUID('c5b7d9d7-f178-0e45-8ea4-bf4e08ec901b')),
Role('Daybook', uuid.UUID('c3edb554-a057-8942-8030-37b8e926d583')),
Role('Edit Posted Vouchers', uuid.UUID('d6675817-ddf5-bf40-9de6-fa223eb4aaa6')),
Role('Employees', uuid.UUID('e4edd0ac-7f5d-e64d-8611-73fdc4cd8ba2')),
Role('Fingerprints', uuid.UUID('d9c45323-f997-ba46-9407-8a7145f0828b')),
Role('Issue', uuid.UUID('03b602eb-f58a-b94f-af58-8cb47d7849d0')),
Role('Journal', uuid.UUID('7661388f-62ce-1c41-8e0d-0326ee5d4018')),
Role('Accounts', uuid.UUID('f438262f-72dd-2f4e-9186-5abc3af44fba')),
Role('Product Ledger', uuid.UUID('018a2408-e804-1446-90c5-b015829da6ba')),
Role('Backdated Vouchers', uuid.UUID('b67b2062-5ca7-134f-8258-5d284dd92426')),
Role('Payment', uuid.UUID('f85c0b52-c3fd-7141-8957-7a56cdc014a4')),
Role('Post Vouchers', uuid.UUID('36e741da-1a57-b047-a59e-dcd58fcf4338')),
Role('Products', uuid.UUID('74fa6d21-eebb-e14c-8153-bebc57190ab4')),
Role('Product Groups', uuid.UUID('08413a22-cf88-fd43-b2b7-365d2951d99f')),
Role('Profit & Loss', uuid.UUID('0492ebb3-76f3-204e-ab94-bbfe880f0691')),
Role('Purchase', uuid.UUID('12335acb-8630-2d41-a191-1517c8d172de')),
Role('Purchase Entries', uuid.UUID('78a6422b-aa11-174c-9dfa-412a99e87e02')),
Role('Purchase Return', uuid.UUID('ab33196e-d9e4-114c-ac8c-997954363756')),
Role('Receipt', uuid.UUID('1f1ce53e-76ff-a346-974a-65db6f606e5f')),
Role('Closing Stock', uuid.UUID('97515732-24e4-c94d-9585-d4bd7f6c7891')),
Role('Ledger', uuid.UUID('a2120944-243f-3f49-be57-0ad633ce4801')),
Role('Raw Material Cost', uuid.UUID('d462842b-baf1-2343-95e5-ffdba9bbc163')),
Role('Edit Other User\'s Vouchers', uuid.UUID('a8328891-7ce2-a943-8c29-2eabc1ffeea3')),
Role('Clients', uuid.UUID('cfad44f0-f2a9-7045-89d7-9019cf0f371a')),
Role('Salary Deduction', uuid.UUID('92d70e80-1c32-384d-959e-abf84b804696')),
Role('Messages', uuid.UUID('f586d128-b6d9-4090-a913-78fcbdb68e59')),
Role('Lock Date', uuid.UUID('d52de0be-9388-4b0b-a359-7e122ab6e53a')),
Role('Net Transactions', uuid.UUID('2c40f7cf-67fc-4efa-a670-8d16a2e7884d')),
Role('Balance Sheet', uuid.UUID('40deb018-b8f2-460a-88be-8972c9fcdf04')),
Role('Advanced Delete', uuid.UUID('197ebcd2-bc4a-4b65-a138-ce942ece32ea')),
Role('Rebase', uuid.UUID('de204a88-5f9d-4579-a2d6-aa2f25efde42')),
Role('Reset Stock', uuid.UUID('aecaf82f-aa41-4634-b754-0c1308b621b1')),
Role('Reconcile', uuid.UUID('a5cb51cb-e38e-4705-84a7-cc1e9a8b866b')),
Role('Stock Movement', uuid.UUID('20b707ee-2b59-41ad-be87-76d5fe1efca8')),
Role('Purchases', uuid.UUID('cf7019c8-3fd3-45b0-9a42-601029ce5b71')),
Role('Dashboard', uuid.UUID('53eecc09-bd06-4890-b6f5-6885dda762d4'))]
for role in roles:
DBSession.add(role)
groups[0].roles.append(role)
cost_centers = [CostCenter('Overall', uuid.UUID('36f59436-522a-0746-ae94-e0f746bf6c0d'), True),
CostCenter('Purchase', uuid.UUID('7b845f95-dfef-fa4a-897c-f0baf15284a3'), True),
CostCenter('Kitchen', uuid.UUID('b2d398ce-e3cc-c542-9feb-5d7783e899df'), True)]
for cost_center in cost_centers:
DBSession.add(cost_center)
ledgers = [Ledger(1, 'All Purchases', 2, True, False, uuid.UUID('7b845f95-dfef-fa4a-897c-f0baf15284a3'),
uuid.UUID('240dd899-c413-854c-a7eb-67a29d154490'), True),
Ledger(1, 'Local Purchase', 9, True, False, uuid.UUID('36f59436-522a-0746-ae94-e0f746bf6c0d'),
uuid.UUID('d2b75912-505f-2548-9093-466dfff6a0f9'), True),
Ledger(1, 'ESI/PF - Payable', 11, True, False, uuid.UUID('36f59436-522a-0746-ae94-e0f746bf6c0d'),
uuid.UUID('42277912-cc18-854b-b134-9f4b00dba419'), True),
Ledger(2, 'ESI/PF - Expense', 7, True, False, uuid.UUID('36f59436-522a-0746-ae94-e0f746bf6c0d'),
uuid.UUID('d2a1a286-e900-764b-a1a5-9f4b00dbb940'), True),
Ledger(1, 'Cash in Hand', 1, True, False, uuid.UUID('36f59436-522a-0746-ae94-e0f746bf6c0d'),
uuid.UUID('ed2341bb-80b8-9649-90db-f9aaca183bb3'), True),
Ledger(1, 'Staff Salary', 7, True, False, uuid.UUID('36f59436-522a-0746-ae94-e0f746bf6c0d'),
uuid.UUID('5c2b54d0-c174-004d-a0d5-92cdaadcefa7'), True),
Ledger(1, 'Suspense', 4, True, False, uuid.UUID('36f59436-522a-0746-ae94-e0f746bf6c0d'),
uuid.UUID('3854e317-6f3b-5142-ab26-9c44d4cddd08'), True)]
for ledger in ledgers:
DBSession.add(ledger)
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,
uuid.UUID('aa79a643-9ddc-4790-ac7f-a41f9efb4c15'), True)
DBSession.add(product)
transaction.commit()

View File

@ -1,17 +1,17 @@
import random import random
import string import string
import uuid import uuid
from sqlalchemy.schema import ForeignKey, Table
from brewman.models.guidtype import GUID
from hashlib import md5 from hashlib import md5
from sqlalchemy.schema import ForeignKey, Table
from sqlalchemy import Column, Boolean, Unicode, Integer from sqlalchemy import Column, Boolean, Unicode, Integer
from sqlalchemy.orm import synonym, relationship from sqlalchemy.orm import synonym, relationship
from brewman.models.guidtype import GUID
from brewman.models import Base from brewman.models import Base
from brewman.models import DBSession from brewman.models import DBSession
def encrypt(val): def encrypt(val):
return md5(val.encode('utf-8') + "Salt".encode('utf-8')).hexdigest() return md5(val.encode('utf-8') + "Salt".encode('utf-8')).hexdigest()
@ -68,7 +68,6 @@ user_group = Table(
Column('GroupID', GUID(), ForeignKey('auth_groups.GroupID')) Column('GroupID', GUID(), ForeignKey('auth_groups.GroupID'))
) )
role_group = Table( role_group = Table(
'auth_rolegroups', Base.metadata, 'auth_rolegroups', Base.metadata,
Column('RoleGroupID', GUID(), primary_key=True, default=uuid.uuid4), Column('RoleGroupID', GUID(), primary_key=True, default=uuid.uuid4),
@ -101,10 +100,11 @@ class User(Base):
def __name__(self): def __name__(self):
return self.name return self.name
def __init__(self, name=None, password=None, locked_out=None): def __init__(self, name=None, password=None, locked_out=None, id=None):
self.name = name self.name = name
self.password = password self.password = password
self.locked_out = locked_out self.locked_out = locked_out
self.id = id
@classmethod @classmethod
def by_name(cls, name): def by_name(cls, name):
@ -120,6 +120,8 @@ class User(Base):
@classmethod @classmethod
def auth(cls, name, password): def auth(cls, name, password):
if password is None:
return False, None
user = cls.by_name(name) user = cls.by_name(name)
if not user: if not user:
return False, None return False, None
@ -150,8 +152,10 @@ class Group(Base):
id = Column('GroupID', GUID(), primary_key=True, default=uuid.uuid4) id = Column('GroupID', GUID(), primary_key=True, default=uuid.uuid4)
name = Column('Name', Unicode(255), unique=True) name = Column('Name', Unicode(255), unique=True)
def __init__(self, name=None):
def __init__(self, name=None, id=None):
self.name = name self.name = name
self.id = id
@classmethod @classmethod
def by_id(cls, id): def by_id(cls, id):
@ -170,8 +174,9 @@ class Role(Base):
groups = relationship("Group", secondary=role_group, backref="roles") groups = relationship("Group", secondary=role_group, backref="roles")
def __init__(self, name=None): def __init__(self, name=None, id=None):
self.name = name self.name = name
self.id = id
@classmethod @classmethod
def list(cls): def list(cls):

View File

@ -17,7 +17,7 @@ class Product(Base):
units = Column('Units', Unicode(255), nullable=False) units = Column('Units', Unicode(255), nullable=False)
fraction = Column('Fraction', Numeric, nullable=False) fraction = Column('Fraction', Numeric, nullable=False)
fraction_units = Column('FractionUnits', Unicode(255), nullable=False) fraction_units = Column('FractionUnits', Unicode(255), nullable=False)
yeild = Column('Yeild', Numeric, nullable=False) product_yield = Column('ProductYield', Numeric, nullable=False)
show_for_purchase = Column('ShowForPurchase', Boolean, 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('entities_productgroups.ProductGroupID'),
nullable=False) nullable=False)
@ -31,20 +31,21 @@ class Product(Base):
ledger = relationship('Ledger', primaryjoin="Ledger.id==Product.ledger_id", backref='products') 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, 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, show_for_purchase=None, product_group_id=None, ledger_id=None, price=None, discontinued=None,
is_fixture=False): id=None,is_fixture=False):
self.code = code self.code = code
self.name = name self.name = name
self.units = units self.units = units
self.fraction = fraction self.fraction = fraction
self.fraction_units = fraction_units self.fraction_units = fraction_units
self.yeild = yeild self.product_yield = product_yield
self.show_for_purchase = show_for_purchase self.show_for_purchase = show_for_purchase
self.product_group_id = product_group_id self.product_group_id = product_group_id
self.ledger_id = ledger_id self.ledger_id = ledger_id
self.price = price self.price = price
self.discontinued = discontinued self.discontinued = discontinued
self.id = id
self.is_fixture = is_fixture self.is_fixture = is_fixture
@property @property
@ -108,8 +109,9 @@ class ProductGroup(Base):
products = relationship('Product', backref='product_group') products = relationship('Product', backref='product_group')
def __init__(self, name=None, is_fixture=False): def __init__(self, name=None, id=None, is_fixture=False):
self.name = name self.name = name
self.id = id
self.is_fixture = is_fixture self.is_fixture = is_fixture
@classmethod @classmethod
@ -135,8 +137,9 @@ class CostCenter(Base):
def __name__(self): def __name__(self):
return self.name return self.name
def __init__(self, name=None, is_fixture=False): def __init__(self, name=None, id=None, is_fixture=False):
self.name = name self.name = name
self.id = id
self.is_fixture = is_fixture self.is_fixture = is_fixture
@classmethod @classmethod
@ -190,13 +193,14 @@ class LedgerBase(Base):
return LedgerType.by_id(self.type) 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): id=None, is_fixture=False):
self.code = code self.code = code
self.name = name self.name = name
self.type = type self.type = type
self.is_active = is_active self.is_active = is_active
self.is_reconcilable = is_reconcilable self.is_reconcilable = is_reconcilable
self.costcenter_id = costcenter_id self.costcenter_id = costcenter_id
self.id = id
self.is_fixture = is_fixture self.is_fixture = is_fixture
@classmethod @classmethod

View File

@ -54,7 +54,7 @@ class Voucher(Base):
id = Column('VoucherID', GUID(), primary_key=True, default=uuid.uuid4) id = Column('VoucherID', GUID(), primary_key=True, default=uuid.uuid4)
date = Column('Date', DateTime, nullable=False) date = Column('Date', DateTime, nullable=False)
reconcile_date = Column('ReconcileDate', DateTime, nullable=False) reconcile_date = Column('ReconcileDate', DateTime, nullable=False)
is_reconciled = Column('IsReconciled', DateTime, nullable=False) is_reconciled = Column('IsReconciled', Boolean, nullable=False)
narration = Column('Narration', Unicode(1000), nullable=False) narration = Column('Narration', Unicode(1000), nullable=False)
posted = Column('Posted', Boolean, nullable=False) posted = Column('Posted', Boolean, nullable=False)
creation_date = Column('CreationDate', DateTime(timezone=True), nullable=False) creation_date = Column('CreationDate', DateTime(timezone=True), nullable=False)

View File

@ -37,17 +37,17 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="txtFractionUnits" class="col-md-2 control-label">FractionUnits</label> <label for="txtFractionUnits" class="col-md-2 control-label">Fraction Units</label>
<div class="col-md-10"> <div class="col-md-10">
<input type="text" id="txtFractionUnits" class="form-control" ng-model="product.FractionUnits"/> <input type="text" id="txtFractionUnits" class="form-control" ng-model="product.FractionUnits"/>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="txtYeild" class="col-md-2 control-label">Yeild</label> <label for="txtYield" class="col-md-2 control-label">Yield</label>
<div class="col-md-10"> <div class="col-md-10">
<input type="text" id="txtYeild" class="form-control" ng-model="product.Yeild"/> <input type="text" id="txtYield" class="form-control" ng-model="product.ProductYield"/>
</div> </div>
</div> </div>

View File

@ -1,3 +1,4 @@
from decimal import Decimal
from datetime import date, datetime, timedelta, time from datetime import date, datetime, timedelta, time
import uuid import uuid
import re import re
@ -23,7 +24,7 @@ def forbidden(request):
response.status_int = 401 response.status_int = 401
return response return response
else: else:
return HTTPFound(location=request.route_url('login')) return HTTPFound(location=request.route_url('login', _query={'came_from': request.path}))
@view_config(route_name='favicon') @view_config(route_name='favicon')
@ -58,3 +59,20 @@ def get_lock_info():
def to_uuid(value): def to_uuid(value):
p = re.compile('^[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}$') p = re.compile('^[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}$')
return uuid.UUID(value) if p.match(value) else None return uuid.UUID(value) if p.match(value) else None
def to_decimal(value, default=0):
import re
_parser = re.compile(r""" # A numeric string consists of:
(?P<sign>[-+])? # an optional sign, followed by either...
(
(?=\d|\.\d) # ...a number (with at least one digit)
(?P<int>\d*) # having a (possibly empty) integer part
(\.(?P<frac>\d*))? # followed by an optional fractional part
|
(?P<signal>s)? # ...an (optionally signaling)
NaN # NaN
(?P<diag>\d*) # with (possibly empty) diagnostic info.
)
\Z
""", re.VERBOSE | re.IGNORECASE).match
return Decimal(value) if _parser(value.strip()) is not None else default

View File

@ -29,16 +29,45 @@ def html(request):
@view_config(request_method='POST', route_name='api_employee', renderer='json', permission='Employees') @view_config(request_method='POST', route_name='api_employee', renderer='json', permission='Employees')
@TryCatchFunction @TryCatchFunction
def save(request): def save(request):
is_active = request.json_body['IsActive'] name = request.json_body.get('Name', '').strip()
joining_date = datetime.datetime.strptime(request.json_body['JoiningDate'], '%d-%b-%Y') if name == '':
leaving_date = None if is_active else datetime.datetime.strptime(request.json_body['LeavingDate'], raise ValidationError('Name cannot be blank')
'%d-%b-%Y')
item = Employee(0, request.json_body['Name'], is_active, cost_center_id = uuid.UUID(request.json_body['CostCenter']['CostCenterID'])
uuid.UUID(request.json_body['CostCenter']['CostCenterID']), designation = request.json_body.get('Designation', '').strip()
request.json_body['Designation'], int(request.json_body['Salary']),
int(request.json_body['ServicePoints']), try:
joining_date, leaving_date).create() salary = int(request.json_body['Salary'])
if salary < 0:
raise ValidationError("Salary must be an integer >= 0")
except (ValueError, KeyError):
raise ValidationError("Salary must be an integer >= 0")
try:
service_points = int(request.json_body['ServicePoints'])
if service_points < 0:
raise ValidationError("Service Points must be an integer >= 0")
except (ValueError, KeyError):
raise ValidationError("Service Points must be an integer >= 0")
try:
joining_date = datetime.datetime.strptime(request.json_body['JoiningDate'], '%d-%b-%Y')
except (ValueError, KeyError, TypeError):
raise ValidationError("Joining Date is not a valid date")
is_active = request.json_body['IsActive']
try:
if is_active:
leaving_date = None
else:
leaving_date = datetime.datetime.strptime(request.json_body['LeavingDate'], '%d-%b-%Y')
if leaving_date < joining_date:
raise ValidationError("Leaving Date cannot be less than Joining Date")
except (ValueError, KeyError, TypeError):
raise ValidationError("Leaving Date is not a valid date")
item = Employee(0, name, is_active, cost_center_id, designation, salary, service_points, joining_date,
leaving_date).create()
transaction.commit() transaction.commit()
return employee_info(item.id) return employee_info(item.id)
@ -49,15 +78,44 @@ def update(request):
item = Employee.by_id(uuid.UUID(request.matchdict['id'])) item = Employee.by_id(uuid.UUID(request.matchdict['id']))
if item.is_fixture: if item.is_fixture:
raise ValidationError("{0} is a fixture and cannot be edited or deleted.".format(item.name)) raise ValidationError("{0} is a fixture and cannot be edited or deleted.".format(item.name))
item.name = request.json_body['Name']
item.name = request.json_body.get('Name', '').strip()
if item.name == '':
raise ValidationError('Name cannot be blank')
item.cost_center_id = uuid.UUID(request.json_body['CostCenter']['CostCenterID'])
item.designation = request.json_body.get('Designation', '').strip()
try:
item.salary = int(request.json_body['Salary'])
if item.salary < 0:
raise ValidationError("Salary must be an integer >= 0")
except (ValueError, KeyError):
raise ValidationError("Salary must be an integer >= 0")
try:
item.service_points = int(request.json_body['ServicePoints'])
if item.service_points < 0:
raise ValidationError("Service Points must be an integer >= 0")
except (ValueError, KeyError):
raise ValidationError("Service Points must be an integer >= 0")
try:
item.joining_date = datetime.datetime.strptime(request.json_body['JoiningDate'], '%d-%b-%Y')
except (ValueError, KeyError, TypeError):
raise ValidationError("Joining Date is not a valid date")
item.is_active = request.json_body['IsActive'] item.is_active = request.json_body['IsActive']
item.costcenter_id = uuid.UUID(request.json_body['CostCenter']['CostCenterID']) try:
item.designation = request.json_body['Designation'] if item.is_active:
item.salary = int(request.json_body['Salary']) item.leaving_date = None
item.service_points = int(request.json_body['ServicePoints']) else:
item.joining_date = datetime.datetime.strptime(request.json_body['JoiningDate'], '%d-%b-%Y') item.leaving_date = datetime.datetime.strptime(request.json_body['LeavingDate'], '%d-%b-%Y')
item.leaving_date = None if item.is_active else datetime.datetime.strptime(request.json_body['LeavingDate'], if item.leaving_date < item.joining_date:
'%d-%b-%Y') raise ValidationError("Leaving Date cannot be less than Joining Date")
except (ValueError, KeyError, TypeError):
raise ValidationError("Leaving Date is not a valid date")
transaction.commit() transaction.commit()
return employee_info(item.id) return employee_info(item.id)
@ -141,8 +199,8 @@ def employee_info(id):
def delete_with_data(employee): def delete_with_data(employee):
suspense_ledger = Ledger.by_id(Ledger.suspense()) suspense_ledger = Ledger.by_id(Ledger.suspense())
query = Voucher.query().options(joinedload_all(Voucher.journals, Journal.ledger, innerjoin=True))\ query = Voucher.query().options(joinedload_all(Voucher.journals, Journal.ledger, innerjoin=True)) \
.filter(Voucher.journals.any(Journal.ledger_id == employee.id))\ .filter(Voucher.journals.any(Journal.ledger_id == employee.id)) \
.all() .all()
for voucher in query: for voucher in query:

View File

@ -1,4 +1,4 @@
from decimal import Decimal from decimal import Decimal, InvalidOperation
import uuid import uuid
from pyramid.response import Response from pyramid.response import Response
from pyramid.security import authenticated_userid from pyramid.security import authenticated_userid
@ -27,21 +27,42 @@ def html(request):
@TryCatchFunction @TryCatchFunction
def save(request): def save(request):
json = request.json_body json = request.json_body
name = json.get('Name', '').strip() name = json.get('Name', '').strip()
if name == '': if name == '':
raise ValidationError('Name cannot be blank') raise ValidationError('Name cannot be blank')
units = json.get('Units', '').strip() units = json.get('Units', '').strip()
fraction = Decimal(json.get('Fraction', 0))
try:
fraction = Decimal(json.get('Fraction', 0))
if fraction <= 0 or fraction > 1:
raise ValidationError("Fraction must be a decimal > 0 and <= 1")
except (ValueError, InvalidOperation):
raise ValidationError("Fraction must be a decimal > 0 and <= 1")
fraction_units = json.get('FractionUnits', '').strip() fraction_units = json.get('FractionUnits', '').strip()
yeild = Decimal(json.get('Yeild', 1))
try:
product_yield = Decimal(json.get('ProductYield', 1))
if product_yield < 0 or product_yield > 1:
raise ValidationError("Yield must be a decimal >= 0 <= 1")
except (ValueError, InvalidOperation):
raise ValidationError("Yield must be a decimal >= 0 <= 1")
show_for_purchase = json.get('ShowForPurchase', True) show_for_purchase = json.get('ShowForPurchase', True)
product_group = json.get('ProductGroup', None) product_group = json.get('ProductGroup', None)
if product_group is None: if product_group is None:
raise ValidationError('Please choose a product group') raise ValidationError('Please choose a product group')
product_group_id = uuid.UUID(product_group['ProductGroupID']) product_group_id = uuid.UUID(product_group['ProductGroupID'])
price = Decimal(json.get('Price', 0)) try:
price = Decimal(json.get('Price', 0))
if price < 0:
raise ValidationError("Price must be a decimal > 0")
except (ValueError, InvalidOperation):
raise ValidationError("Price must be a decimal > 0")
discontinued = json.get('Discontinued', False) discontinued = json.get('Discontinued', False)
item = Product(0, name, units, fraction, fraction_units, yeild, show_for_purchase, product_group_id, item = Product(0, name, units, fraction, fraction_units, product_yield, show_for_purchase, product_group_id,
Ledger.all_purchases(), price, discontinued).create() Ledger.all_purchases(), price, discontinued).create()
transaction.commit() transaction.commit()
return product_info(item.id) return product_info(item.id)
@ -55,13 +76,30 @@ def update(request):
raise ValidationError("{0} is a fixture and cannot be edited or deleted.".format(item.full_name)) raise ValidationError("{0} is a fixture and cannot be edited or deleted.".format(item.full_name))
item.name = request.json_body['Name'].strip() item.name = request.json_body['Name'].strip()
item.units = request.json_body['Units'].strip() item.units = request.json_body['Units'].strip()
item.fraction = Decimal(request.json_body['Fraction']) 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")
except (ValueError, InvalidOperation):
raise ValidationError("Fraction must be a decimal > 0 and <= 1")
item.fraction_units = request.json_body['FractionUnits'] item.fraction_units = request.json_body['FractionUnits']
item.yeild = Decimal(request.json_body['Yeild'])
try:
item.product_yield = Decimal(request.json_body['ProductYield'])
if item.product_yield < 0 or item.product_yield > 1:
raise ValidationError("Yield must be a decimal >= 0 <= 1")
except (ValueError, InvalidOperation):
raise ValidationError("Yield must be a decimal >= 0 <= 1")
item.show_for_purchase = request.json_body['ShowForPurchase'] item.show_for_purchase = request.json_body['ShowForPurchase']
item.product_group_id = uuid.UUID(request.json_body['ProductGroup']['ProductGroupID']) item.product_group_id = uuid.UUID(request.json_body['ProductGroup']['ProductGroupID'])
item.ledger_id = Ledger.all_purchases() item.ledger_id = Ledger.all_purchases()
item.price = Decimal(request.json_body['Price']) try:
item.price = Decimal(request.json_body['Price'])
if item.price < 0:
raise ValidationError("Price must be a decimal > 0")
except (ValueError, InvalidOperation):
raise ValidationError("Price must be a decimal > 0")
item.discontinued = request.json_body['Discontinued'] item.discontinued = request.json_body['Discontinued']
transaction.commit() transaction.commit()
return product_info(item.id) return product_info(item.id)
@ -131,9 +169,10 @@ def product_info(id):
else: else:
product = Product.by_id(id) product = Product.by_id(id)
product = {'ProductID': product.id, 'Code': product.code, 'Name': product.name, 'Units': product.units, product = {'ProductID': product.id, 'Code': product.code, 'Name': product.name, 'Units': product.units,
'Fraction': product.fraction, 'FractionUnits': product.fraction_units, 'Yeild': product.yeild, 'Fraction': product.fraction, 'FractionUnits': product.fraction_units,
'ShowForPurchase': product.show_for_purchase, 'Discontinued': product.discontinued, 'ProductYield': product.product_yield, 'ShowForPurchase': product.show_for_purchase,
'IsFixture': product.is_fixture, 'ProductGroup': {'ProductGroupID': product.product_group_id}, 'Discontinued': product.discontinued, 'IsFixture': product.is_fixture,
'ProductGroup': {'ProductGroupID': product.product_group_id},
'Ledger': {'LedgerID': product.ledger_id}, 'Price': product.price} 'Ledger': {'LedgerID': product.ledger_id}, 'Price': product.price}
return product return product

View File

@ -6,7 +6,7 @@ from brewman.models.voucher import Batch
@view_config(request_method='GET', route_name='api_batch', renderer='json', permission='Authenticated') @view_config(request_method='GET', route_name='api_batch', renderer='json', permission='Authenticated')
def batch_term(request): def batch_term(request):
filter = request.GET.get('term', None) filter = request.GET.get('term', None)
filter = filter if filter is not None and filter is not '' else None filter = filter if filter is not None and filter.strip() is not '' else None
count = request.GET.get('count', None) count = request.GET.get('count', None)
count = None if count is None or count == '' else int(count) count = None if count is None or count == '' else int(count)
date = request.GET.get('date', None) date = request.GET.get('date', None)