diff --git a/brewman/__init__.py b/brewman/__init__.py
index eb2d53d4..70e00b6a 100644
--- a/brewman/__init__.py
+++ b/brewman/__init__.py
@@ -106,6 +106,7 @@ def main(global_config, **settings):
config.add_route('attendance_report', '/AttendanceReport')
config.add_route('api_credit_salary', '/api/CreditSalary')
+ config.add_route('api_credit_service_charge', '/api/CreditServiceCharge')
config.add_route('employee_functions', '/EmployeeFunctions')
config.add_route('api_fingerprint', '/api/Fingerprint')
diff --git a/brewman/models/__init__.py b/brewman/models/__init__.py
index 279eb45e..1e6162e2 100644
--- a/brewman/models/__init__.py
+++ b/brewman/models/__init__.py
@@ -108,6 +108,8 @@ def fixtures(engine):
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(2, 'Service Charges', 11, True, False, uuid.UUID('36f59436-522a-0746-ae94-e0f746bf6c0d'),
+ uuid.UUID('b7eff754-e8ba-e047-ab06-9132c15c7640'), True),
Ledger(1, 'Suspense', 4, True, False, uuid.UUID('36f59436-522a-0746-ae94-e0f746bf6c0d'),
uuid.UUID('3854e317-6f3b-5142-ab26-9c44d4cddd08'), True)]
diff --git a/brewman/models/master.py b/brewman/models/master.py
index 467f4d32..eee8d1c6 100644
--- a/brewman/models/master.py
+++ b/brewman/models/master.py
@@ -347,6 +347,10 @@ class LedgerBase(Base):
def salary(cls):
return {'LedgerID': '5c2b54d0-c174-004d-a0d5-92cdaadcefa7', 'Name': 'Staff Salary'}
+ @classmethod
+ def service_charge(cls):
+ return {'LedgerID': 'b7eff754-e8ba-e047-ab06-9132c15c7640', 'Name': 'Service Charges'}
+
@classmethod
def esi_pf_expense(cls):
return uuid.UUID('d2a1a286-e900-764b-a1a5-9f4b00dbb940')
@@ -367,7 +371,7 @@ class Employee(LedgerBase):
id = Column('LedgerID', GUID(), ForeignKey(LedgerBase.id), primary_key=True)
designation = Column('Designation', Unicode(255))
salary = Column('Salary', Integer)
- service_points = Column('ServicePoints', Integer)
+ service_points = Column('ServicePoints', Numeric(precision=5, scale=2))
joining_date = Column('JoiningDate', DateTime)
leaving_date = Column('LeavingDate', DateTime)
diff --git a/brewman/static/partial/employee-functions.html b/brewman/static/partial/employee-functions.html
index 63e4ae2c..ca4a6b6e 100644
--- a/brewman/static/partial/employee-functions.html
+++ b/brewman/static/partial/employee-functions.html
@@ -19,6 +19,37 @@
+
Credit Service Charge
+
+
Attendance Record
diff --git a/brewman/static/scripts/employee-functions.js b/brewman/static/scripts/employee-functions.js
index 3163568d..ef5e9e40 100644
--- a/brewman/static/scripts/employee-functions.js
+++ b/brewman/static/scripts/employee-functions.js
@@ -17,6 +17,25 @@ var EmployeeFunctionsController = ['$scope', '$http', 'asDateFilter', function (
});
};
+ $scope.creditServiceCharge = function () {
+ if (!angular.isDate($scope.sc.Month)) {
+ return;
+ }
+ var ServiceChargeMonth = asDate($scope.sc.Month);
+ if (!angular.isDate($scope.sc.CreditDate)) {
+ return;
+ }
+ var CreditDate = asDate($scope.sc.CreditDate);
+ return $http.
+ post('/api/CreditServiceCharge', {Month: ServiceChargeMonth, CreditDate: CreditDate}).
+ success(function (data) {
+ $scope.toasts.push({Type: 'Success', Message: data.message});
+ }).
+ error(function (errorMessage) {
+ $scope.toasts.push({Type: 'Danger', Message: errorMessage});
+ });
+ };
+
$scope.attendanceRecordUrl = function () {
if (!$scope.record.StartDate || !$scope.record.FinishDate) {
return;
diff --git a/brewman/views/employee.py b/brewman/views/employee.py
index 1f3830e8..477f6cad 100644
--- a/brewman/views/employee.py
+++ b/brewman/views/employee.py
@@ -1,5 +1,6 @@
import datetime
import uuid
+from decimal import Decimal
import pkg_resources
from pyramid.response import Response, FileResponse
from pyramid.security import authenticated_userid
@@ -44,11 +45,11 @@ def save(request):
raise ValidationError("Salary must be an integer >= 0")
try:
- service_points = int(request.json_body['ServicePoints'])
+ service_points = round(Decimal(request.json_body['ServicePoints']), 2)
if service_points < 0:
- raise ValidationError("Service Points must be an integer >= 0")
+ raise ValidationError("Service Points must be a decimal >= 0 and < 1000")
except (ValueError, KeyError):
- raise ValidationError("Service Points must be an integer >= 0")
+ raise ValidationError("Service Points must be a decimal >= 0 and < 1000")
try:
joining_date = datetime.datetime.strptime(request.json_body['JoiningDate'], '%d-%b-%Y')
@@ -94,11 +95,11 @@ def update(request):
raise ValidationError("Salary must be an integer >= 0")
try:
- item.service_points = int(request.json_body['ServicePoints'])
+ item.service_points = round(Decimal(request.json_body['ServicePoints']), 2)
if item.service_points < 0:
- raise ValidationError("Service Points must be an integer >= 0")
+ raise ValidationError("Service Points must be a decimal >= 0")
except (ValueError, KeyError):
- raise ValidationError("Service Points must be an integer >= 0")
+ raise ValidationError("Service Points must be a decimal >= 0")
try:
item.joining_date = datetime.datetime.strptime(request.json_body['JoiningDate'], '%d-%b-%Y')
diff --git a/brewman/views/services/voucher/credit_service_charge.py b/brewman/views/services/voucher/credit_service_charge.py
new file mode 100644
index 00000000..044d6ddc
--- /dev/null
+++ b/brewman/views/services/voucher/credit_service_charge.py
@@ -0,0 +1,83 @@
+import datetime
+import uuid
+from decimal import Decimal
+from pyramid.security import authenticated_userid
+from pyramid.view import view_config
+from sqlalchemy import or_, func
+import transaction
+from ....models import DBSession
+from ....models.auth import User
+from ....models.master import Employee, AttendanceType, Ledger
+from ....models.validation_exception import TryCatchFunction
+from ....models.voucher import Voucher, VoucherType, Attendance, Journal
+from ..session import get_first_day, get_last_day
+
+__author__ = 'tanshu'
+
+
+@view_config(request_method='POST', route_name='api_credit_service_charge', renderer='json', permission='Attendance')
+@TryCatchFunction
+def credit_sc(request):
+ user = User.by_id(uuid.UUID(authenticated_userid(request)))
+ month = datetime.datetime.strptime(request.json_body['Month'], '%d-%b-%Y')
+ credit_date = datetime.datetime.strptime(request.json_body['CreditDate'], '%d-%b-%Y')
+
+ amount = balance(month)
+ start_date = get_first_day(month)
+ finish_date = get_last_day(month)
+ voucher = Voucher(date=credit_date, narration='Auto Generated Service Charge Entry', user_id=user.id,
+ type=VoucherType.by_name('Journal'), posted=True, poster_id=user.id)
+ DBSession.add(voucher)
+ for item in service_charge_journals(amount, start_date, finish_date):
+ voucher.journals.append(item)
+ DBSession.add(item)
+ transaction.commit()
+ return {'message': 'Salary Entry created'}
+
+
+def service_charge_journals(amount, start_date, finish_date):
+ amount = amount * Decimal(.7) * Decimal(.9)
+ total_points = 0
+ details = []
+ finish_date = finish_date + datetime.timedelta(1)
+ journals = []
+ employees = DBSession().query(Employee) \
+ .filter(Employee.joining_date <= finish_date) \
+ .filter(or_(Employee.is_active, Employee.leaving_date >= start_date)) \
+ .order_by(Employee.costcenter_id).order_by(Employee.designation).order_by(Employee.name).all()
+ for employee in employees:
+ if employee.service_points != 0:
+ att = DBSession.query(Attendance) \
+ .filter(Attendance.employee_id == employee.id) \
+ .filter(Attendance.date >= start_date) \
+ .filter(Attendance.date < finish_date) \
+ .filter(Attendance.is_valid == True) \
+ .all()
+ att = sum(map(lambda x: AttendanceType.by_id(x.attendance_type).value, att))
+ points = Decimal(att) * employee.service_points
+ if points != 0:
+ total_points += points
+ details.append({'Employee': employee, 'Points': points})
+ if total_points == 0:
+ raise ValueError("There is no data to credit service charges")
+ point_value = round(amount / total_points, 2)
+ amount = 0
+ for item in details:
+ ee = item['Employee']
+ employee_amount = round(point_value * item['Points'])
+ journal = Journal(amount=employee_amount, debit=-1, ledger_id=ee.id, cost_center_id=ee.costcenter_id)
+ journals.append(journal)
+ amount += employee_amount
+ sc = Ledger.by_id(uuid.UUID(Ledger.service_charge()['LedgerID']))
+ journals.append(Journal(amount=amount, debit=1, ledger_id=sc.id, cost_center_id=sc.costcenter_id))
+ return journals
+
+
+def balance(date):
+ amount = DBSession.query(func.sum(Journal.amount * Journal.debit)) \
+ .join(Journal.voucher) \
+ .filter(Voucher.date < date + datetime.timedelta(1)) \
+ .filter(Voucher.type != VoucherType.by_name('Issue').id) \
+ .filter(Journal.ledger_id == uuid.UUID(Ledger.service_charge()['LedgerID'])) \
+ .scalar()
+ return 0 if amount is None else amount * -1