Add employee earnings record generation API route

This commit is contained in:
Tanner Collin 2017-07-01 22:24:51 +00:00
parent 4469db2602
commit 80cc811049
3 changed files with 256 additions and 6 deletions

View File

@ -45,7 +45,7 @@ class Manage(models.Model):
deleted = models.BooleanField(default=False)
def __str__(self):
return self.client.user.username + ' manages ' + self.provider.user.username
return self.client.user.first_name + ' manages ' + self.provider.user.first_name
class Price(models.Model):
uuid = models.UUIDField(default=uuid.uuid4, editable=False)

View File

@ -276,9 +276,36 @@ class TimeSheetSerializer(serializers.Serializer):
amount = serializers.DecimalField(max_digits=8, decimal_places=2)
work = serializers.CharField()
management = serializers.CharField()
client = serializers.CharField()
provider = serializers.CharField()
payday = serializers.DateField()
paystart = serializers.DateField()
payend = serializers.DateField()
shifts = ShiftSerializer(many=True)
class RecordSheetSerializer(serializers.Serializer):
class RecordSerializer(serializers.Serializer):
payday = serializers.DateField()
reg_pay = serializers.DecimalField(max_digits=10, decimal_places=2)
vac_pay = serializers.DecimalField(max_digits=10, decimal_places=2)
earnings = serializers.DecimalField(max_digits=10, decimal_places=2)
cpp_ytd = serializers.DecimalField(max_digits=10, decimal_places=2)
cpp = serializers.DecimalField(max_digits=10, decimal_places=2)
ei_ytd = serializers.DecimalField(max_digits=10, decimal_places=2)
ei = serializers.DecimalField(max_digits=10, decimal_places=2)
taxable_income = serializers.DecimalField(max_digits=10, decimal_places=2)
fed_tax = serializers.DecimalField(max_digits=10, decimal_places=2)
fed_tax_payable = serializers.DecimalField(max_digits=10, decimal_places=2)
prov_tax = serializers.DecimalField(max_digits=10, decimal_places=2)
prov_tax_deduction = serializers.DecimalField(max_digits=10, decimal_places=2)
income_tax = serializers.DecimalField(max_digits=10, decimal_places=2)
total_deductions = serializers.DecimalField(max_digits=10, decimal_places=2)
net_pay = serializers.DecimalField(max_digits=10, decimal_places=2)
management = serializers.CharField()
client = serializers.CharField()
provider = serializers.CharField()
phone_number = serializers.CharField()
sin = serializers.CharField()
record = RecordSerializer(many=True)

View File

@ -12,7 +12,7 @@ from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.renderers import StaticHTMLRenderer
from caremyway.api.serializers import UserSerializer, UserInfoSerializer, ClientSerializer, ProviderSerializer, WorkTypeSerializer, EmployeeSerializer, EmployerSerializer, PriceSerializer, CShiftSerializer, PShiftSerializer, TimeSheetSerializer
from caremyway.api.serializers import UserSerializer, UserInfoSerializer, ClientSerializer, ProviderSerializer, WorkTypeSerializer, EmployeeSerializer, EmployerSerializer, PriceSerializer, CShiftSerializer, PShiftSerializer, TimeSheetSerializer, RecordSheetSerializer
class UserViewSet(viewsets.ModelViewSet):
lookup_field = 'username'
@ -158,9 +158,10 @@ def get_paystart(payday):
def get_payend(payday):
return payday - timedelta(days=4)
def get_timesheet(user, payday, manage=None):
def gen_timesheets(user, payday, manage=None):
paystart = get_paystart(payday)
payend = get_payend(payday)
timesheets = []
shifts = Shift.objects.filter(deleted=False) \
.exclude(actual_end__isnull=True) \
@ -175,9 +176,9 @@ def get_timesheet(user, payday, manage=None):
manage_shifts = groupby(shifts, lambda x: x.price.management)
timesheets = []
for management, shifts in manage_shifts:
timesheet = {}
timesheet['management'] = management
timesheet['client'] = management.client
timesheet['provider'] = management.provider
timesheet['payday'] = payday
@ -200,6 +201,220 @@ def get_timesheet(user, payday, manage=None):
return timesheets
def get_paydays_todate(payday):
# Assumes payday is a valided date obj
year = payday.year
paydays = []
if payday.day == 15:
paydays.append(payday)
elif payday.day == calendar.monthrange(payday.year, payday.month)[1]:
paydays.append(payday)
paydays.append(datetime.date(year, payday.month, 15))
else:
raise serializers.ValidationError("Date is not a valid payday.")
for month in reversed(range(1, payday.month)):
end_of_month = calendar.monthrange(year, month)[1]
paydays.append(datetime.date(year, month, end_of_month))
paydays.append(datetime.date(year, month, 15))
return list(reversed(paydays))
def get_cpp(cpp_ytd, earnings):
D = cpp_ytd
PI = earnings
P = 24
C_i = Decimal(2564.10) - D
C_ii = Decimal(0.0495) * (PI - Decimal(3500 / P))
C = min(C_i, C_ii)
if C < 0:
C = 0
return C
def get_ei(ei_ytd, earnings):
D1 = ei_ytd
IE = earnings
EI_i = Decimal(836.19) - D1
EI_ii = Decimal(0.0163) * IE
EI = min(EI_i, EI_ii)
if EI < 0:
EI = 0
return EI
def get_taxable_income(earnings):
P = 24
I = earnings
F = 0
F2 = 0
U1 = 0
HD = 0
F1 = 0
A = (P * (I - F - F2 - U1)) - HD - F1
return A
def get_fed_tax(taxable_income, cpp, ei, cpp_ytd, ei_ytd):
table = [(0, 0.150, 0),
(45916, 0.205, 2525),
(91831, 0.260, 7576),
(142352, 0.290, 11847),
(202800, 0.330, 19959)]
A = taxable_income
R = Decimal([row for row in table if row[0] < A][-1][1])
K = [row for row in table if row[0] < A][-1][2]
TC = 11635
K1 = Decimal(0.15 * TC)
P = 24
if cpp_ytd + cpp >= 2564.10:
PxC = Decimal(2564.10)
else:
C = cpp
PxC = P * C
if ei_ytd + ei >= 836.19:
PxEI = Decimal(836.19)
else:
EI = ei
PxEI = P * EI
K2 = (Decimal(0.15) * PxC) + (Decimal(0.15) * PxEI)
K3 = 0
K4_i = Decimal(0.15) * A
K4_ii = Decimal(0.15 * 1178)
K4 = min(K4_i, K4_ii)
T3 = (R * A) - K - K1 - K2 - K3 - K4
if T3 < 0:
T3 = 0
return T3
def get_fed_tax_payable(fed_tax):
T3 = fed_tax
LCF = 0
T1 = T3 - LCF
if T1 < 0:
T1 = 0
return T1
def get_prov_tax(taxable_income, cpp, ei, cpp_ytd, ei_ytd):
table = [(0, 0.10, 0),
(126625, 0.12, 2533),
(151950, 0.13, 4052),
(202600, 0.14, 6078),
(303900, 0.15, 9117)]
A = taxable_income
V = Decimal([row for row in table if row[0] < A][-1][1])
KP = [row for row in table if row[0] < A][-1][2]
TCP = 18690
K1P = Decimal(0.1 * TCP)
P = 24
if cpp_ytd + cpp >= 2564.10:
PxC = Decimal(2564.10)
else:
C = cpp
PxC = P * C
if ei_ytd + ei >= 836.19:
PxEI = Decimal(836.19)
else:
EI = ei
PxEI = P * EI
K2P = (Decimal(0.10) * PxC) + (Decimal(0.10) * PxEI)
K3P = 0
T4 = (V * A) - KP - K1P - K2P - K3P
if T4 < 0:
T4 = 0
return T4
def get_prov_tax_deduction(prov_tax):
T4 = prov_tax
V1 = 0
S = 0
LCP = 0
T2 = T4 - V1 - S - LCP
if T2 < 0:
T2 = 0
return T2
def get_income_tax(fed_tax_payable, prov_tax_deduction):
T1 = fed_tax_payable
T2 = prov_tax_deduction
P = 24
L = 0
T = Decimal((T1 + T2) / P) + L
return T
def gen_recordsheets(user, payday, manage):
paydays = get_paydays_todate(payday)
recordsheets = []
flat_records = []
for payday in paydays:
timesheets = gen_timesheets(user, payday, manage)
for timesheet in timesheets:
record = {}
record['payday'] = payday
record['management'] = timesheet['management']
record['reg_pay'] = sum(shift['amount'] for shift in timesheet['shifts'])
record['vac_pay'] = record['reg_pay'] * Decimal(0.04)
record['earnings'] = record['reg_pay'] + record['vac_pay']
record['cpp_ytd'] = sum(r['cpp'] for r in flat_records if r['management'] == timesheet['management'])
record['cpp'] = get_cpp(record['cpp_ytd'], record['earnings'])
record['ei_ytd'] = sum(r['ei'] for r in flat_records if r['management'] == timesheet['management'])
record['ei'] = get_ei(record['ei_ytd'], record['earnings'])
record['taxable_income'] = get_taxable_income(record['earnings'])
record['fed_tax'] = get_fed_tax(record['taxable_income'], record['cpp'], record['ei'], record['cpp_ytd'], record['ei_ytd'])
record['fed_tax_payable'] = get_fed_tax_payable(record['fed_tax'])
record['prov_tax'] = get_prov_tax(record['taxable_income'], record['cpp'], record['ei'], record['cpp_ytd'], record['ei_ytd'])
record['prov_tax_deduction'] = get_prov_tax_deduction(record['prov_tax'])
record['income_tax'] = get_income_tax(record['fed_tax_payable'], record['prov_tax_deduction'])
record['total_deductions'] = record['income_tax'] + record['cpp'] + record['ei']
record['net_pay'] = record['earnings'] - record['total_deductions']
flat_records.append(record)
flat_records = sorted(flat_records, key=lambda x: x['management'].uuid)
grouped_records = groupby(flat_records, lambda x: x['management'])
for management, record in grouped_records:
recordsheet = {}
recordsheet['management'] = management
recordsheet['client'] = management.client
recordsheet['provider'] = management.provider
recordsheet['phone_number'] = management.provider.user.userinfo.phone_number
recordsheet['sin'] = management.provider.sin
recordsheet['record'] = list(record)
recordsheets.append(recordsheet)
return list(recordsheets)
class ReportView(APIView):
def get(self, request, *args, **kwargs):
response = []
@ -211,9 +426,17 @@ class ReportView(APIView):
payday = validate_param(qp.get('payday'), serializers.DateField())
manage = validate_param(qp.get('manage'), serializers.UUIDField(allow_null=True))
timesheet = get_timesheet(request.user, payday, manage)
timesheets = gen_timesheets(request.user, payday, manage)
response = TimeSheetSerializer(timesheet, many=True).data
response = TimeSheetSerializer(timesheets, many=True).data
elif report_type == 'record':
payday = validate_param(qp.get('payday'), serializers.DateField())
manage = validate_param(qp.get('manage'), serializers.UUIDField(allow_null=True))
recordsheets = gen_recordsheets(request.user, payday, manage)
response = RecordSheetSerializer(recordsheets, many=True).data
return Response(response, status=status.HTTP_200_OK)