Added salary deductions model / route.

Updated import queries to support deductions.
Added esi_pf expense and payable ledgers to LedgerBase.
This commit is contained in:
Tanshu 2012-11-28 13:28:16 +05:30
parent 517b56431a
commit f60cca97e6
21 changed files with 459 additions and 131 deletions

View File

@ -92,6 +92,8 @@ def main(global_config, **settings):
config.add_route('issue_id', '/Issue/{id}')
config.add_route('issue', '/Issue')
config.add_route('issues_grid', '/Issues/Services/{date}')
config.add_route('salary_deduction_id', '/SalaryDeduction/{id}')
config.add_route('salary_deduction', '/SalaryDeduction')
config.add_route('voucher', '/Voucher/{id}')
config.add_route('voucher_new', '/Voucher')

View File

@ -227,6 +227,14 @@ class LedgerBase(Base):
def salary(cls):
return {'LedgerID': '5c2b54d0-c174-004d-a0d5-92cdaadcefa7', 'Name': 'salary staff'}
@classmethod
def esi_pf_expense(cls):
return uuid.UUID('d2a1a286-e900-764b-a1a5-9f4b00dbb940')
@classmethod
def esi_pf_payable(cls):
return uuid.UUID('42277912-cc18-854b-b134-9f4b00dba419')
class Employee(LedgerBase):
__tablename__ = 'entities_employees'

View File

@ -6,11 +6,49 @@ from brewman.models.guidtype import GUID
from sqlalchemy import Column, Integer, Boolean, Unicode, DateTime, Numeric, ForeignKey, func
from sqlalchemy.orm import relationship, synonym
from sqlalchemy.orm import relationship, synonym, backref
from brewman.models import Base, DBSession
from brewman.models.master import Product
class VoucherType:
def __init__(self, id, name):
self.id = id
self.name = name
@classmethod
def list(cls):
list = []
list.append(VoucherType(1, 'Journal'))
list.append(VoucherType(2, 'Purchase'))
list.append(VoucherType(3, 'Issue'))
list.append(VoucherType(4, 'Payment'))
list.append(VoucherType(5, 'Receipt'))
list.append(VoucherType(6, 'Purchase Return'))
list.append(VoucherType(7, 'Opening Ledgers'))
list.append(VoucherType(8, 'Opening Inventories'))
list.append(VoucherType(9, 'Verification'))
list.append(VoucherType(10, 'Opening Balance'))
list.append(VoucherType(11, 'Closing Balance'))
list.append(VoucherType(12, 'Salary Deductions'))
return list
@classmethod
def by_name(cls, name):
list = cls.list()
for item in list:
if item.name == name:
return item
@classmethod
def by_id(cls, id):
list = cls.list()
for item in list:
if item.id == id:
return item
class Voucher(Base):
__tablename__ = 'entities_vouchers'
@ -30,6 +68,8 @@ class Voucher(Base):
journals = relationship('Journal', backref='voucher', cascade="delete, delete-orphan", cascade_backrefs=False)
inventories = relationship('Inventory', backref='voucher', cascade="delete, delete-orphan", cascade_backrefs=False)
salary_deductions = relationship('SalaryDeduction', backref='voucher', cascade="delete, delete-orphan",
cascade_backrefs=False)
def _get_type(self):
return self._type
@ -50,7 +90,8 @@ class Voucher(Base):
def __name__(self):
return self.name
def __init__(self, date=None, reconcilliation_date=None, narration=None, posted=False, creation_date=None, last_edit_date=None, type=None, user_id=None, poster_id=None):
def __init__(self, date=None, reconcilliation_date=None, narration='', posted=False, creation_date=None,
last_edit_date=None, type=None, user_id=None, poster_id=None):
self.date = date
self.reconcilliation_date = reconcilliation_date
self.narration = narration
@ -113,42 +154,34 @@ class Journal(Base):
return DBSession.query(cls)
class VoucherType:
def __init__(self, id, name):
class SalaryDeduction(Base):
__tablename__ = 'entities_salarydeductions'
id = Column('SalaryDeductionID', GUID(), primary_key=True, default=uuid.uuid4)
voucher_id = Column('VoucherID', GUID(), ForeignKey('entities_vouchers.VoucherID'))
journal_id = Column('JournalID', GUID(), ForeignKey('entities_journals.JournalID'))
gross_salary = Column('GrossSalary', Integer)
days_worked = Column('DaysWorked', Integer)
esi_ee = Column('EsiEmployee', Integer)
pf_ee = Column('PfEmployee', Integer)
esi_er = Column('EsiEmployer', Integer)
pf_er = Column('PfEmployer', Integer)
journal = relationship(Journal, backref=backref('salary_deduction', uselist=False), cascade=None,
cascade_backrefs=False)
def __init__(self, id=None, voucher_id=None, journal_id=None, journal=None, gross_salary=None, days_worked=None,
esi_ee=None, pf_ee=None, esi_er=None, pf_er=None):
self.id = id
self.name = name
@classmethod
def list(cls):
list = []
list.append(VoucherType(1, 'Journal'))
list.append(VoucherType(2, 'Purchase'))
list.append(VoucherType(3, 'Issue'))
list.append(VoucherType(4, 'Payment'))
list.append(VoucherType(5, 'Receipt'))
list.append(VoucherType(6, 'Purchase Return'))
list.append(VoucherType(7, 'Opening Ledgers'))
list.append(VoucherType(8, 'Opening Inventories'))
list.append(VoucherType(9, 'Verification'))
list.append(VoucherType(10, 'Opening Balance'))
list.append(VoucherType(11, 'Closing Balance'))
list.append(VoucherType(12, 'Salary Deductions'))
return list
@classmethod
def by_name(cls, name):
list = cls.list()
for item in list:
if item.name == name:
return item
@classmethod
def by_id(cls, id):
list = cls.list()
for item in list:
if item.id == id:
return item
self.voucher_id = voucher_id
self.journal_id = journal_id
self.gross_salary = gross_salary
self.days_worked = days_worked
self.esi_ee = esi_ee
self.pf_ee = pf_ee
self.esi_er = esi_er
self.pf_er = pf_er
if journal_id is None and journal is not None:
self.journal = journal
class Inventory(Base):

View File

@ -18,15 +18,6 @@
<a class="btn btn-info" ng-href="{{attendanceRecordUrl()}}" target="_self">Download <i class="icon-download-alt icon-white"></i></a>
</div>
</div>
<legend>Credit Esi / Pf</legend>
<div class="control-group">
<label for="txtEsiPfMonth" class="control-label">Month</label>
<div class="controls">
<datepicker id="txtEsiPfMonth" model="esiPfMonth" ng-model="esiPfMonth"></datepicker>
<button class="btn" ng-click="creditEsiPf()">Credit</button>
</div>
</div>
<legend>Upload Fingerprints</legend>
<div class="control-group">
<label for="uploadFingerprints" class="control-label"></label>

View File

@ -1,5 +1,5 @@
<form method="post" autocomplete="off" class="form-horizontal">
<legend>Credit Esi Pf</legend>
<legend>Credit Esi / Pf</legend>
<div class="control-group">
<label for="txtDate" class="control-label">Date</label>
@ -35,14 +35,13 @@
<th>Esi ER</th>
<th>Pf ER</th>
<th>Delete</th>
<th>Delete</th>
</tr>
</thead>
<tbody id="tbodyMain">
<tr ng-repeat="deduction in voucher.SalaryDeductions">
<td>{{deduction.Employee.Name}}</td>
<td>{{deduction.Employee.Designation}}</td>
<td>{{deduction.Employee.Department}}</td>
<td>{{deduction.Journal.Ledger.Name}}</td>
<td>{{deduction.Journal.Ledger.Designation}}</td>
<td>{{deduction.Journal.Ledger.CostCenter.Name}}</td>
<td>{{deduction.GrossSalary}}</td>
<td>{{deduction.DaysWorked}}</td>
<td>{{deduction.EsiEmployee}}</td>
@ -61,14 +60,6 @@
</table>
</div>
</div>
<div class="control-group">
<label for="txtNarration" class="control-label">Narration</label>
<div class="controls">
<textarea rows="2" cols="20" id="txtNarration"
class="non-search-box" ng-model="voucher.Narration"></textarea>
</div>
</div>
<div class="form-actions">
<button class="btn btn-primary" ng-click="save()"
ng-disabled="preventAlteration(voucher)">{{voucher.VoucherID | save_button}}

View File

@ -1,6 +1,6 @@
'use strict';
function EmployeeFunctionsCtrl($scope, $http) {
var EmployeeFunctionsCtrl = ['$scope', '$http', function ($scope, $http) {
$scope.record = {};
$scope.creditSalary = function () {
$http.
@ -12,9 +12,6 @@ function EmployeeFunctionsCtrl($scope, $http) {
$scope.toasts.push({Type:'Error', Message:errorMessage});
});
};
$scope.creditEsiPf = function () {
$scope.toasts.push({Type:'Error', Message:'Not Implemented Yet'});
};
$scope.attendanceRecordUrl = function () {
var url = '/AttendanceReport?StartDate=' + $scope.record.Start + "&FinishDate=" + $scope.record.Finish;
return url;
@ -23,4 +20,162 @@ function EmployeeFunctionsCtrl($scope, $http) {
$scope.toasts.push({Type:'Error', Message:'Not Implemented Yet'});
};
}
}]
var SalaryDeductionCtrl = ['$scope', '$location', 'voucher', function ($scope, $location, voucher) {
$scope.voucher = voucher;
$scope.name = '';
function getOldItem(ledgerID, items) {
for (var i = 0, l = items.length; i < l; i++) {
if (items[i].Journal.Ledger.LedgerID === ledgerID) {
return journals[i];
}
}
}
function daysInMonthFunction(date) {
var months = {
Jan:1,
Feb:2,
Mar:3,
Apr:4,
May:5,
Jun:6,
Jul:7,
Aug:8,
Sep:9,
Oct:10,
Nov:11,
Dev:12
}
if (!date.match(/^\d{2}-[\w]{3}-[\d]{4}$/g)) {
return;
}
var parts = date.split("-");
return new Date(parseInt(parts[2]), months[parts[1]], 0).getDate();
}
function getEsi(grossSalary, daysWorked, daysInMonth) {
var limit = 15000,
employee_rate = .0175,
employer_rate = .0475;
var employee = (grossSalary > limit) ? 0 : Math.ceil(employee_rate * grossSalary * daysWorked / daysInMonth)
var employer = (grossSalary > limit) ? 0 : Math.ceil(employer_rate * grossSalary * daysWorked / daysInMonth)
return {ee:employee, er:employer, both:employee + employer};
}
function getPf(grossSalary, daysWorked, daysInMonth) {
var limit = 6500,
employee_rate = .12,
employer_rate = .12 + .011 + .005 + .0001;
var employee = (grossSalary > limit) ? 0 : Math.ceil(employee_rate * grossSalary * daysWorked / daysInMonth)
var employer = (grossSalary > limit) ? 0 : Math.ceil(employer_rate * grossSalary * daysWorked / daysInMonth)
return {ee:employee, er:employer, both:employee + employer};
}
$scope.add = function () {
var oldJournal = getOldItem($scope.employee.LedgerID, this.voucher.SalaryDeductions),
grossSalary = parseInt($scope.grossSalary),
daysWorked = parseInt($scope.daysWorked),
daysInMonth = daysInMonthFunction($scope.voucher.Date),
esi = getEsi(grossSalary, daysWorked, daysInMonth),
pf = getPf(grossSalary, daysWorked, daysInMonth);
if (typeof oldJournal !== 'undefined') {
$scope.toasts.push({Type:'Error', Message:'Employee has already been added!'});
} else {
this.voucher.SalaryDeductions.push(
{
Journal:{Ledger:$scope.employee},
GrossSalary:grossSalary,
DaysWorked:daysWorked,
EsiEmployee:esi.ee,
PfEmployee:pf.ee,
EsiEmployer:esi.er,
PfEmployer:pf.er
}
)
;
}
delete $scope.employee;
delete $scope.grossSalary;
delete $scope.daysWorked;
$('#txtEmployee').val('');
$('#txtEmployee').focus();
};
$scope.remove = function (deduction) {
var index = this.voucher.SalaryDeductions.indexOf(deduction);
this.voucher.SalaryDeductions.splice(index, 1);
};
$scope.preventAlteration = function (voucher) {
if (typeof $scope.perms === 'undefined') {
return false;
} else if (typeof voucher.VoucherID === 'undefined') {
return !$scope.perms['Salary Deduction'];
} else if (voucher.Posted && !$scope.perms['Edit Posted Vouchers']) {
return true;
} else if (voucher.User.UserID != $scope.auth.UserID && !$scope.perms["Edit Other User's Vouchers"]) {
return true;
} else {
return false;
}
};
$scope.get = function (voucherid) {
$scope.voucher = Voucher.get({VoucherID:voucherid}, function (u, putResponseHeaders) {
$scope.toasts.push({Type:'Success', Message:''});
}, function (data, status) {
$scope.toasts.push({Type:'Error', Message:data.data});
});
};
$scope.save = function () {
$scope.voucher.$save({type:'Salary Deduction'}, function (u, putResponseHeaders) {
$scope.toasts.push({Type:'Success', Message:''});
$location.path('/SalaryDeduction/' + u.VoucherID);
}, function (data, status) {
$scope.toasts.push({Type:'Error', Message:data.data});
});
};
$scope.delete = function () {
$scope.voucher.$delete(function (u, putResponseHeaders) {
$scope.toasts.push({Type:'Success', Message:''});
$location.path('/SalaryDeduction').replace();
}, function (data, status) {
$scope.toasts.push({Type:'Error', Message:data.data});
});
};
$scope.post = function () {
$scope.voucher.$post(function (u, putResponseHeaders) {
$scope.toasts.push({Type:'Success', Message:''});
}, function (data, status) {
$scope.toasts.push({Type:'Error', Message:data.data});
});
};
}]
SalaryDeductionCtrl.resolve = {
voucher:['$q', '$route', 'Voucher', function ($q, $route, Voucher) {
var deferred = $q.defer();
var id = $route.current.params.id;
var successCb = function (result) {
deferred.resolve(result);
};
if (typeof id === 'undefined') {
Voucher.get({type:'Salary Deduction'}, successCb);
} else {
Voucher.get({id:id}, successCb);
}
return deferred.promise;
}]
};

View File

@ -25,6 +25,9 @@ var overlord = angular.module('overlord', ['overlord.directive', 'overlord.filte
when('/Issue', {templateUrl:'/partial/issue.html', controller:IssueCtrl, resolve:IssueCtrl.resolve}).
when('/Issue/:id', {templateUrl:'/partial/issue.html', controller:IssueCtrl, resolve:IssueCtrl.resolve}).
when('/SalaryDeduction', {templateUrl:'/partial/salary-deduction.html', controller:SalaryDeductionCtrl, resolve:SalaryDeductionCtrl.resolve}).
when('/SalaryDeduction/:id', {templateUrl:'/partial/salary-deduction.html', controller:SalaryDeductionCtrl, resolve:SalaryDeductionCtrl.resolve}).
when('/Ledger', {templateUrl:'/partial/ledger.html', controller:LedgerCtrl, resolve:LedgerCtrl.resolve}).
when('/Ledger/:id', {templateUrl:'/partial/ledger.html', controller:LedgerCtrl, resolve:LedgerCtrl.resolve}).

View File

@ -138,6 +138,7 @@
<li><a href="/Attendance">Attendance</a></li>
<li><a href="/EmployeeAttendance">Employee Attendance</a></li>
<li><a href="/EmployeeFunctions">Employee Functions</a></li>
<li><a href="/SalaryDeduction">Credit Esi / Pf</a></li>
<li><a href="/AccountsTesting/Employees/SalarySheet.aspx">Salary Sheet</a></li>
<li><a href="/AccountsTesting/Employees/PaymentSheet.aspx">Employee Payment Sheet</a></li>
<li><a href="/features/elements.html">Display Salary Sheet</a></li>

View File

@ -5,7 +5,7 @@ from pyramid.response import Response
from pyramid.view import view_config
import transaction
from brewman.models.master import CostCenter, Employee
from brewman.models.master import CostCenter, Employee, LedgerBase
from brewman.models.validation_exception import ValidationError
from brewman.views.account import ledger_list
@ -14,7 +14,8 @@ from brewman.views.account import ledger_list
permission='Employees')
@view_config(request_method='GET', route_name='employee', renderer='brewman:templates/angular_base.mako', xhr=False,
permission='Employees')
@view_config(request_method='GET', route_name='employee_functions', renderer='brewman:templates/angular_base.mako', xhr=False,
@view_config(request_method='GET', route_name='employee_functions', renderer='brewman:templates/angular_base.mako',
xhr=False,
permission='Employees')
def html(request):
return {}
@ -98,10 +99,19 @@ def show_list(request):
permission='Authenticated')
def show_term(request):
filter = request.GET.get('term', None)
filter = filter if filter is not None and filter is not '' else None
filter = None if filter == '' else filter
count = request.GET.get('count', None)
count = None if count is None or count == '' else int(count)
return ledger_list(10, filter, count)
list = []
for index, item in enumerate(LedgerBase.list(10, filter)):
list.append({'label': item.name,
'model': {'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):

View File

@ -5,7 +5,7 @@ from pyramid.view import view_config
from brewman.models.voucher import Voucher, Journal, VoucherType
from brewman.views.services.session import session_period_finish, session_period_start
from brewman.views.transactions import get_edit_url
from brewman.views.services.voucher import get_edit_url
@view_config(request_method='GET', route_name='daybook', renderer='brewman:templates/angular_base.mako',
xhr=False, permission='Daybook')

View File

@ -10,7 +10,7 @@ from brewman.models.master import LedgerBase
from brewman.models.voucher import Voucher, Journal, VoucherType
from brewman.views.services.session import session_period_start, session_period_finish
from brewman.views.transactions import get_edit_url
from brewman.views.services.voucher import get_edit_url
@view_config(request_method='GET', route_name='ledger_id', renderer='brewman:templates/angular_base.mako',
xhr=False, permission='Ledger')

View File

@ -10,7 +10,7 @@ from brewman.models.master import Product, CostCenter
from brewman.models.voucher import Voucher, Journal, VoucherType, Inventory
from brewman.views.services.session import session_period_start, session_period_finish
from brewman.views.transactions import get_edit_url
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',
xhr=False, permission='Product Ledger')

View File

@ -8,7 +8,7 @@ from brewman.models.master import CostCenter, LedgerType, LedgerBase
from brewman.models.voucher import Voucher, Journal, VoucherType, Inventory
from brewman.views.services.session import session_period_start, session_period_finish
from brewman.views.transactions import get_edit_url
from brewman.views.services.voucher import get_edit_url
@view_config(request_method='GET', route_name='purchase_entries', renderer='brewman:templates/angular_base.mako',
xhr=False, permission='Purchase Entries')

View File

@ -3,7 +3,7 @@ from sqlalchemy.orm import joinedload_all
from pyramid.view import view_config
from brewman.models.voucher import Voucher, Journal, VoucherType
from brewman.views.transactions import get_edit_url
from brewman.views.services.voucher import get_edit_url
@view_config(request_method='GET', route_name='unposted', renderer='brewman:templates/angular_base.mako',
xhr=False, permission='Post Vouchers')

View File

@ -88,14 +88,3 @@ def check_client(client, otp, client_name, user):
client.name = client_name
transaction.commit()
return True, None
def get_first_day(dt, d_years=0, d_months=0):
# d_years, d_months are "deltas" to apply to dt
y, m = dt.year + d_years, dt.month + d_months
a, m = divmod(m - 1, 12)
return date(y + a, m + 1, 1)
def get_last_day(dt):
return get_first_day(dt, 0, 1) + timedelta(-1)

View File

@ -1,4 +1,5 @@
import uuid
from datetime import date
from pyramid.response import Response
from pyramid.security import authenticated_userid
from pyramid.view import view_config
@ -15,6 +16,37 @@ from brewman.views.services.voucher.purchase import purchase_create_voucher, pur
__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')
def journal_get(request):
return {}
@view_config(request_method='POST', route_name='voucher', request_param='post', renderer='json', xhr=True,
permission='Post Vouchers')
@ -115,6 +147,20 @@ def voucher_info(voucher):
json_voucher['Journals'].append({'JournalID': item.id, 'Debit': item.debit, 'Amount': item.amount,
'Ledger': {'LedgerID': item.ledger.id, 'Name': item.ledger.name},
'CostCenter': {'CostCenterID': item.cost_center_id}})
for item in voucher.salary_deductions:
json_voucher['SalaryDeductions'] = []
json_voucher['SalaryDeductions'].append(
{'GrossSalary': item.gross_salary,
'DaysWorked': item.days_worked,
'EsiEmployee': item.esi_ee,
'PfEmployee': item.pf_ee,
'EsiEmployer': item.esi_er,
'PfEmployer': item.pf_er,
'Journal': {'JournalID': item.journal.id,
'Ledger': {'LedgerID': item.journal.ledger.id, 'Name': item.journal.ledger.name,
'Designation': item.journal.ledger.designation,
'CostCenter': {'CostCenterID': item.journal.ledger.costcenter.id,
'Name': item.journal.ledger.costcenter.name}}}})
for item in voucher.inventories:
json_voucher['Inventories'].append(
{'InventoryID': item.id, 'Quantity': item.quantity, 'Rate': item.rate,
@ -172,6 +218,24 @@ def blank_voucher(type=None, date=None, additionalInfo=None):
'Debit': item['Debit'],
'CostCenter': {'CostCenterID': item['CostCenter']['CostCenterID']}})
elif type == 'Salary Deduction':
json_voucher['SalaryDeductions'] = []
else:
raise ValidationError("Voucher of type \"{0}\" does not exist.".format(type))
return json_voucher
def get_edit_url(request, voucher):
if voucher.type == 1:
return request.route_url('journal_id', id=voucher.id)
elif voucher.type == 2:
return request.route_url('purchase_id', id=voucher.id)
elif voucher.type == 3:
return request.route_url('issue_id', id=voucher.id)
elif voucher.type == 4:
return request.route_url('payment_id', id=voucher.id)
elif voucher.type == 5:
return request.route_url('receipt_id', id=voucher.id)
else:
return '#'

View File

@ -35,6 +35,11 @@ class blank_voucher_view(object):
return self.get_blank()
@view_config(request_param='type=Salary Deduction', permission='Purchase Return')
def purchase_return(self):
return self.get_blank()
@view_config(request_param='type=Issue', permission='Issue')
def issue(self):
voucher_type = self.request.GET.get('type', None)

View File

@ -0,0 +1,109 @@
import datetime
from decimal import Decimal
from math import ceil
import uuid
from brewman.models import DBSession
from brewman.models.master import LedgerBase, Employee
from brewman.models.operations import journals_valid
from brewman.models.validation_exception import ValidationError
from brewman.models.voucher import Journal, Voucher, VoucherType, SalaryDeduction
from brewman.views.services.session import get_last_day
__author__ = 'tanshu'
def salary_deduction_create_voucher(json, user):
dt = get_last_day(datetime.datetime.strptime(json['Date'], '%d-%b-%Y'))
days_in_month = dt.day
voucher = Voucher(date=dt, user_id=user.id, type=VoucherType.by_id(12))
DBSession.add(voucher)
exp, total = 0, 0
for item in json['SalaryDeductions']:
item_exp, item_total = add_salary_deduction(item, days_in_month, voucher)
exp += item_exp
total += item_total
ledger = LedgerBase.by_id(LedgerBase.esi_pf_expense())
journal = Journal(amount=exp, debit=1, ledger_id=ledger.id, cost_center_id=ledger.costcenter_id)
DBSession.add(journal)
voucher.journals.append(journal)
ledger = LedgerBase.by_id(LedgerBase.esi_pf_payable())
journal = Journal(amount=total, debit=-1, ledger_id=ledger.id, cost_center_id=ledger.costcenter_id)
DBSession.add(journal)
voucher.journals.append(journal)
journals_valid(voucher)
return voucher
def salary_deduction_update_voucher(voucher, json, user):
dt = get_last_day(datetime.datetime.strptime(json['Date'], '%d-%b-%Y'))
if dt != voucher.date:
raise ValidationError("Date Cannot be changed for Salary Deduction voucher!")
days_in_month = voucher.date.day
voucher.user_id = user.id
voucher.posted = False
voucher.last_edit_date = datetime.datetime.now()
newDeductions = json['SalaryDeductions']
exp, total, journals = 0, 0, []
for i in range(len(voucher.salary_deductions), 0, -1):
item = voucher.salary_deductions[i - 1]
found = False
for i in range(len(newDeductions), 0, -1):
j = newDeductions[i - 1]
if 'SalaryDeductionID' in j and item.id == uuid.UUID(j['SalaryDeductionID']):
journals.append(item.journal.id)
exp += item.esi_er + item.pf_er
total += item.esi_ee + item.pf_ee + item.esi_er + item.pf_er
newDeductions.remove(j)
break
if not found:
voucher.salary_deductions.remove(item)
voucher.journals.remove(item.journal)
for j in newDeductions:
item_exp, item_total = add_salary_deduction(j, days_in_month, voucher)
exp += item_exp
total += item_total
journal = [i for i in voucher.journals if i.ledger_id == LedgerBase.esi_pf_expense()]
journal = journal[0]
journal.amount = exp
journal = [i for i in voucher.journals if i.ledger_id == LedgerBase.esi_pf_payable()]
journal = journal[0]
journal.amount = total
journals_valid(voucher)
return voucher
def add_salary_deduction(item, days_in_month, voucher):
ledger = Employee.by_id(uuid.UUID(item['Journal']['Ledger']['LedgerID']))
gross_salary = int(item['GrossSalary'])
days_worked = int(item['DaysWorked'])
esi_ee, esi_er, esi_both = esi_contribution(gross_salary, days_worked, days_in_month)
pf_ee, pf_er, pf_both = pf_contribution(gross_salary, days_worked, days_in_month)
journal = Journal(amount=esi_ee + pf_ee, debit=1, ledger_id=ledger.id, cost_center_id=ledger.costcenter_id)
sd = SalaryDeduction(journal=journal, gross_salary=gross_salary, days_worked=days_worked, esi_ee=esi_ee,
pf_ee=pf_ee, esi_er=esi_er, pf_er=pf_er)
voucher.journals.append(journal)
voucher.salary_deductions.append(sd)
DBSession.add(journal)
DBSession.add(sd)
return esi_er + pf_er, esi_both + pf_both
def esi_contribution(gross_salary, days_worked, days_in_month):
limit = 15000
employee_rate = .0175
employer_rate = .0475
employee = 0 if gross_salary > limit else ceil(employee_rate * gross_salary * days_worked / days_in_month)
employer = 0 if gross_salary > limit else ceil(employer_rate * gross_salary * days_worked / days_in_month)
return employee, employer, employee + employer
def pf_contribution(gross_salary, days_worked, days_in_month):
limit = 6500
employee_rate = .12
employer_rate = .12 + .011 + .005 + .0001
employee = 0 if gross_salary > limit else ceil(employee_rate * gross_salary * days_worked / days_in_month)
employer = 0 if gross_salary > limit else ceil(employer_rate * gross_salary * days_worked / days_in_month)
return employee, employer, employee + employer

View File

@ -9,6 +9,7 @@ from brewman.models.voucher import Voucher
from brewman.views.services.session import session_current_date_set
from brewman.views.services.voucher import voucher_info, journal_create_voucher, purchase_create_voucher, issue_create_voucher
from brewman.views.services.voucher.purchase_return import purchase_return_create_voucher
from brewman.views.services.voucher.salary_deduction import salary_deduction_create_voucher
__author__ = 'tanshu'
@ -49,6 +50,10 @@ class save_voucher(object):
def issue(self):
return self.save()
@view_config(request_param='type=Salary Deduction', permission='Salary Deduction')
def salary_deduction(self):
return self.save()
def save(self):
try:
if self.json['Type'] in ['Journal', 'Payment', 'Receipt']:
@ -59,6 +64,8 @@ class save_voucher(object):
voucher = purchase_return_create_voucher(self.json, self.user)
elif self.json['Type'] in ['Issue']:
voucher = issue_create_voucher(self.json, self.user)
elif self.json['Type'] in ['Salary Deduction']:
voucher = salary_deduction_create_voucher(self.json, self.user)
transaction.commit()
session_current_date_set(self.request,self.json['Date'])
return voucher_info(Voucher.by_id(voucher.id))

View File

@ -10,6 +10,7 @@ from brewman.models.voucher import Voucher
from brewman.views.services.session import session_current_date_set
from brewman.views.services.voucher import voucher_info, issue_update_voucher, purchase_update_voucher, journal_update_voucher
from brewman.views.services.voucher.purchase_return import purchase_return_update_voucher
from brewman.views.services.voucher.salary_deduction import salary_deduction_update_voucher
__author__ = 'tanshu'
@ -64,6 +65,10 @@ class update_voucher(object):
def issue(self):
return self.update()
@view_config(request_param='type=Salary Deduction', permission='Salary Deduction')
def salary_deduction(self):
return self.update()
def update(self):
if self.error is not None:
return self.error
@ -76,6 +81,8 @@ class update_voucher(object):
voucher = purchase_return_update_voucher(self.voucher, self.json, self.user)
elif self.json['Type'] in ['Issue']:
voucher = issue_update_voucher(self.voucher, self.json, self.user)
elif self.json['Type'] in ['Salary Deduction']:
voucher = salary_deduction_update_voucher(self.voucher, self.json, self.user)
transaction.commit()
session_current_date_set(self.request,self.json['Date'])
return voucher_info(Voucher.by_id(voucher.id))

View File

@ -1,47 +0,0 @@
from datetime import date
from pyramid.view import view_config
__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')
def journal_get(request):
return {}
def get_edit_url(request, voucher):
if voucher.type == 1:
return request.route_url('journal_id', id = voucher.id)
elif voucher.type == 2:
return request.route_url('purchase_id', id = voucher.id)
elif voucher.type == 3:
return request.route_url('issue_id', id = voucher.id)
elif voucher.type == 4:
return request.route_url('payment_id', id = voucher.id)
elif voucher.type == 5:
return request.route_url('receipt_id', id = voucher.id)
else:
return '#'