|
|
|
@ -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(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 = TimeSheetSerializer(timesheet, many=True).data |
|
|
|
|
response = RecordSheetSerializer(recordsheets, many=True).data |
|
|
|
|
|
|
|
|
|
return Response(response, status=status.HTTP_200_OK) |
|
|
|
|
|
|
|
|
|