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
240 lines
10 KiB
Python
240 lines
10 KiB
Python
import datetime
|
|
import uuid
|
|
from pyramid.response import Response
|
|
from pyramid.security import authenticated_userid
|
|
|
|
from pyramid.view import view_config
|
|
from sqlalchemy.orm import joinedload_all
|
|
import transaction
|
|
from brewman import groupfinder
|
|
from brewman.models import DBSession
|
|
|
|
from brewman.models.master import CostCenter, Employee, LedgerBase, Ledger
|
|
from brewman.models.validation_exception import ValidationError, TryCatchFunction
|
|
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')
|
|
def html(request):
|
|
return {}
|
|
|
|
|
|
@view_config(request_method='POST', route_name='api_employee', renderer='json', permission='Employees')
|
|
@TryCatchFunction
|
|
def save(request):
|
|
name = request.json_body.get('Name', '').strip()
|
|
if name == '':
|
|
raise ValidationError('Name cannot be blank')
|
|
|
|
cost_center_id = uuid.UUID(request.json_body['CostCenter']['CostCenterID'])
|
|
designation = request.json_body.get('Designation', '').strip()
|
|
|
|
try:
|
|
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()
|
|
return employee_info(item.id)
|
|
|
|
|
|
@view_config(request_method='POST', route_name='api_employee_id', renderer='json', permission='Employees')
|
|
@TryCatchFunction
|
|
def update(request):
|
|
item = Employee.by_id(uuid.UUID(request.matchdict['id']))
|
|
if item.is_fixture:
|
|
raise ValidationError("{0} is a fixture and cannot be edited or deleted.".format(item.name))
|
|
|
|
item.name = request.json_body.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']
|
|
try:
|
|
if item.is_active:
|
|
item.leaving_date = None
|
|
else:
|
|
item.leaving_date = datetime.datetime.strptime(request.json_body['LeavingDate'], '%d-%b-%Y')
|
|
if item.leaving_date < item.joining_date:
|
|
raise ValidationError("Leaving Date cannot be less than Joining Date")
|
|
except (ValueError, KeyError, TypeError):
|
|
raise ValidationError("Leaving Date is not a valid date")
|
|
|
|
transaction.commit()
|
|
return employee_info(item.id)
|
|
|
|
|
|
@view_config(request_method='DELETE', route_name='api_employee_id', renderer='json', permission='Employees')
|
|
@TryCatchFunction
|
|
def delete(request):
|
|
employee = Employee.by_id(uuid.UUID(request.matchdict['id']))
|
|
can_delete, reason = employee.can_delete('Advanced Delete' in groupfinder(authenticated_userid(request), request))
|
|
if can_delete:
|
|
delete_with_data(employee)
|
|
transaction.commit()
|
|
return employee_info(None)
|
|
else:
|
|
transaction.abort()
|
|
response = Response("Cannot delete account because {0}".format(reason))
|
|
response.status_int = 500
|
|
return response
|
|
|
|
|
|
@view_config(request_method='GET', route_name='api_employee_id', renderer='json', permission='Employees')
|
|
@TryCatchFunction
|
|
def show_id(request):
|
|
id = to_uuid(request.matchdict['id'])
|
|
if id is None:
|
|
raise ValidationError("Invalid Employee")
|
|
return employee_info(id)
|
|
|
|
|
|
@view_config(request_method='GET', route_name='api_employee', renderer='json', permission='Employees')
|
|
def show_blank(request):
|
|
return employee_info(None)
|
|
|
|
|
|
@view_config(request_method='GET', route_name='api_employee', request_param='list', renderer='json',
|
|
permission='Authenticated')
|
|
def show_list(request):
|
|
list = Employee.list()
|
|
ledgers = []
|
|
for item in list:
|
|
ledgers.append(
|
|
{'Code': item.code, 'Name': item.name, 'Designation': item.designation, 'Salary': item.salary,
|
|
'ServicePoints': item.service_points, 'IsActive': item.is_active,
|
|
'CostCenter': item.costcenter.name, 'Url': request.route_url('employee_id', id=item.id),
|
|
'JoiningDate': item.joining_date.strftime('%d-%b-%Y'),
|
|
'LeavingDate': '' if item.is_active else item.leaving_date.strftime('%d-%b-%Y')})
|
|
return ledgers
|
|
|
|
|
|
@view_config(request_method='GET', route_name='api_employee', renderer='json', request_param='term',
|
|
permission='Authenticated')
|
|
def show_term(request):
|
|
filter = request.GET.get('term', None)
|
|
filter = None if filter == '' else filter
|
|
count = request.GET.get('count', None)
|
|
count = None if count is None or count == '' else int(count)
|
|
|
|
list = []
|
|
for index, item in enumerate(LedgerBase.list(10, filter)):
|
|
list.append({'LedgerID': item.id, 'Name': item.name, 'Designation': item.designation,
|
|
'CostCenter': {'CostCenterID': item.costcenter.id, 'Name': item.costcenter.name}})
|
|
if count is not None and index == count - 1:
|
|
break
|
|
return list
|
|
|
|
|
|
def employee_info(id):
|
|
if id is None:
|
|
employee = {'Code': '(Auto)', 'IsActive': True, 'CostCenter': CostCenter.overall()}
|
|
else:
|
|
employee = Employee.by_id(id)
|
|
if employee is None:
|
|
raise ValidationError("Invalid Employee")
|
|
employee = {'LedgerID': employee.id, 'Code': employee.code, 'Name': employee.name,
|
|
'IsActive': employee.is_active, 'Designation': employee.designation, 'Salary': employee.salary,
|
|
'ServicePoints': employee.service_points, 'JoiningDate': employee.joining_date.strftime('%d-%b-%Y'),
|
|
'LeavingDate': None if employee.is_active else employee.leaving_date.strftime('%d-%b-%Y'),
|
|
'CostCenter': {'CostCenterID': employee.costcenter_id, 'Name': employee.costcenter.name}}
|
|
return employee
|
|
|
|
|
|
def delete_with_data(employee):
|
|
suspense_ledger = Ledger.by_id(Ledger.suspense())
|
|
query = Voucher.query().options(joinedload_all(Voucher.journals, Journal.ledger, innerjoin=True)) \
|
|
.filter(Voucher.journals.any(Journal.ledger_id == employee.id)) \
|
|
.all()
|
|
|
|
for voucher in query:
|
|
others, sus_jnl, acc_jnl = False, None, None
|
|
for journal in voucher.journals:
|
|
if journal.ledger_id == employee.id:
|
|
acc_jnl = journal
|
|
elif journal.ledger_id == Ledger.suspense():
|
|
sus_jnl = journal
|
|
else:
|
|
others = True
|
|
if not others:
|
|
DBSession.delete(voucher)
|
|
else:
|
|
if sus_jnl is None:
|
|
acc_jnl.ledger = suspense_ledger
|
|
voucher.narration += '\nSuspense \u20B9 {0:,.2f} is {1}'.format(acc_jnl.amount, employee.name)
|
|
else:
|
|
amount = (sus_jnl.debit * sus_jnl.amount) + (acc_jnl.debit * acc_jnl.amount)
|
|
if acc_jnl.salary_deduction is not None:
|
|
DBSession.delete(acc_jnl.salary_deduction)
|
|
DBSession.delete(acc_jnl)
|
|
if amount == 0:
|
|
DBSession.delete(sus_jnl)
|
|
else:
|
|
sus_jnl.amount = abs(amount)
|
|
sus_jnl.debit = -1 if amount < 0 else 1
|
|
voucher.narration += '\nDeleted \u20B9 {0:,.2f} of {1}'.format(acc_jnl.amount * acc_jnl.debit,
|
|
employee.name)
|
|
if voucher.type in (VoucherType.by_name('Payment').id, VoucherType.by_name('Receipt').id):
|
|
voucher.type = VoucherType.by_name('Journal')
|
|
for fingerprint in employee.fingerprints:
|
|
DBSession.delete(fingerprint)
|
|
for attendance in employee.attendances:
|
|
DBSession.delete(attendance)
|
|
DBSession.delete(employee)
|