[UPDT] PAYROLL: Add contribution report
This commit is contained in:
@@ -3,7 +3,9 @@ context_processor.py
|
||||
|
||||
This module is used to register context processor`
|
||||
"""
|
||||
from employee.models import Employee
|
||||
from payroll.models import tax_models as models
|
||||
from payroll.models.models import Deduction
|
||||
|
||||
|
||||
def default_currency(request):
|
||||
@@ -24,3 +26,21 @@ def host(request):
|
||||
"""
|
||||
protocol = "https" if request.is_secure() else "http"
|
||||
return {"host": request.get_host(), "protocol": protocol}
|
||||
|
||||
|
||||
def get_deductions(request):
|
||||
"""
|
||||
This method used to return the deduction
|
||||
"""
|
||||
deductions = Deduction.objects.filter(
|
||||
only_show_under_employee=False, employer_rate__gt=0
|
||||
)
|
||||
return {"get_deductions": deductions}
|
||||
|
||||
|
||||
def get_active_employees(request):
|
||||
"""
|
||||
This method used to return the deduction
|
||||
"""
|
||||
employees = Employee.objects.filter(is_active=True)
|
||||
return {"get_active_employees": employees}
|
||||
|
||||
@@ -204,6 +204,9 @@ class PayslipForm(ModelForm):
|
||||
for contract in active_contracts
|
||||
if contract.employee_id.is_active
|
||||
]
|
||||
if self.instance.pk is None:
|
||||
self.initial["start_date"] = datetime.date.today().replace(day=1)
|
||||
self.initial["end_date"] = datetime.date.today()
|
||||
|
||||
class Meta:
|
||||
"""
|
||||
@@ -281,6 +284,8 @@ class GeneratePayslipForm(HorillaForm):
|
||||
self.fields["start_date"].widget.attrs.update({"class": "oh-input w-100"})
|
||||
self.fields["group_name"].widget.attrs.update({"class": "oh-input w-100"})
|
||||
self.fields["end_date"].widget.attrs.update({"class": "oh-input w-100"})
|
||||
self.initial["start_date"] = datetime.date.today().replace(day=1)
|
||||
self.initial["end_date"] = datetime.date.today()
|
||||
|
||||
class Meta:
|
||||
"""
|
||||
@@ -420,7 +425,9 @@ class PayslipDeductionForm(ModelForm):
|
||||
"""
|
||||
Bonus Creating Form
|
||||
"""
|
||||
|
||||
verbose_name = _("Deduction")
|
||||
|
||||
class Meta:
|
||||
model = Deduction
|
||||
fields = [
|
||||
@@ -450,7 +457,7 @@ class PayslipDeductionForm(ModelForm):
|
||||
context = {"form": self}
|
||||
table_html = render_to_string("one_time_deduction.html", context)
|
||||
return table_html
|
||||
|
||||
|
||||
|
||||
class LoanAccountForm(ModelForm):
|
||||
"""
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""
|
||||
forms.py
|
||||
"""
|
||||
|
||||
from django import forms
|
||||
from django.forms import widgets
|
||||
from django.utils.translation import gettext_lazy as trans
|
||||
@@ -65,7 +66,7 @@ class ContractForm(ModelForm):
|
||||
|
||||
verbose_name = trans("Contract")
|
||||
contract_start_date = forms.DateField()
|
||||
contract_end_date = forms.DateField()
|
||||
contract_end_date = forms.DateField(required=False)
|
||||
|
||||
class Meta:
|
||||
"""
|
||||
@@ -97,6 +98,20 @@ class ContractForm(ModelForm):
|
||||
"placeholder": "Select a date",
|
||||
}
|
||||
)
|
||||
self.fields["contract_status"].widget.attrs.update(
|
||||
{
|
||||
"class": "oh-select",
|
||||
}
|
||||
)
|
||||
if self.instance and self.instance.pk:
|
||||
dynamic_url = self.get_dynamic_hx_post_url(self.instance)
|
||||
self.fields["contract_status"].widget.attrs.update(
|
||||
{
|
||||
"hx-target": "#contractFormTarget",
|
||||
"hx-post": dynamic_url,
|
||||
"hx-swap": "outerHTML",
|
||||
}
|
||||
)
|
||||
first = PayrollGeneralSetting.objects.first()
|
||||
if first and self.instance.pk is None:
|
||||
self.initial["notice_period_in_month"] = first.notice_period
|
||||
@@ -109,6 +124,9 @@ class ContractForm(ModelForm):
|
||||
table_html = render_to_string("contract_form.html", context)
|
||||
return table_html
|
||||
|
||||
def get_dynamic_hx_post_url(self, instance):
|
||||
return f"/payroll/update-contract-status/{instance.pk}"
|
||||
|
||||
|
||||
class WorkRecordForm(ModelForm):
|
||||
"""
|
||||
|
||||
@@ -9,6 +9,12 @@ from horilla.settings import TEMPLATES
|
||||
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
|
||||
"payroll.context_processors.default_currency",
|
||||
)
|
||||
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
|
||||
"payroll.context_processors.get_deductions",
|
||||
)
|
||||
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
|
||||
"payroll.context_processors.get_active_employees",
|
||||
)
|
||||
TEMPLATES[0]["OPTIONS"]["context_processors"].append(
|
||||
"payroll.context_processors.host",
|
||||
)
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
{{ form.verbose_name }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-payslip__header-right">
|
||||
{{ form.contract_status }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-profile-section__card">
|
||||
<div class="row">
|
||||
@@ -16,6 +19,7 @@
|
||||
</div>
|
||||
|
||||
{% for field in form.visible_fields %}
|
||||
{% if field.name != 'contract_status' %}
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="oh-label__info" for="id_{{ field.name }}">
|
||||
<label class="oh-label" for="id_{{ field.name }}">{% trans field.label %}</label>
|
||||
@@ -31,6 +35,7 @@
|
||||
{% else %} {{ field|add_class:"form-control" }} {% endif %}
|
||||
{{field.errors}}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,99 +1,99 @@
|
||||
{% extends 'index.html' %} {% block content %} {% load static %}
|
||||
<div id="contractFormTarget">
|
||||
<div class="oh-wrapper d-flex justify-content-center mt-4 mb-4">
|
||||
<form action="" hx-swap="none" class="oh-onboarding-card" method="post">
|
||||
{% csrf_token %} {{form.as_p}}
|
||||
</form>
|
||||
</div>
|
||||
<script>
|
||||
function toggleFunction() {
|
||||
if ($("#id_calculate_daily_leave_amount").is(":checked")) {
|
||||
$(
|
||||
"#id_deduction_for_one_leave_amount,[for=id_deduction_for_one_leave_amount]"
|
||||
).hide();
|
||||
} else {
|
||||
$(
|
||||
"#id_deduction_for_one_leave_amount,[for=id_deduction_for_one_leave_amount]"
|
||||
).show();
|
||||
}
|
||||
if ($("#id_calculate_daily_leave_amount").is(":checked")) {
|
||||
$("#id_deduction_for_one_leave_amount").parent().hide();
|
||||
} else {
|
||||
$("#id_deduction_for_one_leave_amount").parent().show();
|
||||
}
|
||||
}
|
||||
function contractInitial(element) {
|
||||
var employee_id = $(element).val();
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: "{% url 'contract-info-initial' %}",
|
||||
data: { employee_id: employee_id },
|
||||
success: function (response) {
|
||||
var data;
|
||||
data = response;
|
||||
const change = new Event('change');
|
||||
$("#id_department").val(data.department);
|
||||
document.getElementById("id_department").dispatchEvent(change)
|
||||
$("#id_job_position").val(data.job_position);
|
||||
document.getElementById("id_job_position").dispatchEvent(change)
|
||||
$("#id_job_role").val(data.job_role);
|
||||
document.getElementById("id_job_role").dispatchEvent(change)
|
||||
$("#id_shift").val(data.shift);
|
||||
document.getElementById("id_shift").dispatchEvent(change)
|
||||
$("#id_work_type").val(data.work_type);
|
||||
document.getElementById("id_work_type").dispatchEvent(change)
|
||||
$("#id_wage").val(data.wage);
|
||||
document.getElementById("id_wage").dispatchEvent(change)
|
||||
$("#id_contract_start_date").val(data.contract_start_date);
|
||||
document.getElementById("id_contract_start_date").dispatchEvent(change)
|
||||
$("#id_contract_end_date").val(data.contract_end_date);
|
||||
document.getElementById("id_contract_end_date").dispatchEvent(change)
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
<div class="oh-wrapper d-flex justify-content-center mt-4 mb-4">
|
||||
<form action="" hx-swap="none" class="oh-onboarding-card" method="post">
|
||||
{% csrf_token %} {{form.as_p}}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toggleFunction() {
|
||||
if ($("#id_calculate_daily_leave_amount").is(":checked")) {
|
||||
$(
|
||||
"#id_deduction_for_one_leave_amount,[for=id_deduction_for_one_leave_amount]"
|
||||
).hide();
|
||||
} else {
|
||||
$(
|
||||
"#id_deduction_for_one_leave_amount,[for=id_deduction_for_one_leave_amount]"
|
||||
).show();
|
||||
}
|
||||
if ($("#id_calculate_daily_leave_amount").is(":checked")) {
|
||||
$("#id_deduction_for_one_leave_amount").parent().hide();
|
||||
} else {
|
||||
$("#id_deduction_for_one_leave_amount").parent().show();
|
||||
}
|
||||
}
|
||||
function contractInitial(element) {
|
||||
var employee_id = $(element).val();
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: "{% url 'contract-info-initial' %}",
|
||||
data: { employee_id: employee_id },
|
||||
success: function (response) {
|
||||
var data;
|
||||
data = response;
|
||||
const change = new Event('change');
|
||||
$("#id_department").val(data.department);
|
||||
document.getElementById("id_department").dispatchEvent(change)
|
||||
$("#id_job_position").val(data.job_position);
|
||||
document.getElementById("id_job_position").dispatchEvent(change)
|
||||
$("#id_job_role").val(data.job_role);
|
||||
document.getElementById("id_job_role").dispatchEvent(change)
|
||||
$("#id_shift").val(data.shift);
|
||||
document.getElementById("id_shift").dispatchEvent(change)
|
||||
$("#id_work_type").val(data.work_type);
|
||||
document.getElementById("id_work_type").dispatchEvent(change)
|
||||
$("#id_wage").val(data.wage);
|
||||
document.getElementById("id_wage").dispatchEvent(change)
|
||||
$("#id_contract_start_date").val(data.contract_start_date);
|
||||
document.getElementById("id_contract_start_date").dispatchEvent(change)
|
||||
$("#id_contract_end_date").val(data.contract_end_date);
|
||||
document.getElementById("id_contract_end_date").dispatchEvent(change)
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
$("[type=checkbox]").change(function (e) {
|
||||
e.preventDefault();
|
||||
$(document).ready(function () {
|
||||
$("[type=checkbox]").change(function (e) {
|
||||
e.preventDefault();
|
||||
toggleFunction();
|
||||
});
|
||||
});
|
||||
toggleFunction();
|
||||
});
|
||||
});
|
||||
toggleFunction();
|
||||
{% if form.instance.pk %}
|
||||
{% if form.instance.pk %}
|
||||
|
||||
{% for condition in form.instance.other_conditions.all %}
|
||||
conditionSet = $(
|
||||
`
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-4 condition-highlight">
|
||||
${$("[for=id_field]").clone().attr("class", "style-widget form-control oh-label__info").prop("outerHTML")}
|
||||
${$("#id_field").clone().attr("data-initial-value", "{{condition.field}}").attr("name", "other_fields").attr("class", "style-widget form-control").prop("outerHTML")}
|
||||
</div>
|
||||
<div class="col-12 col-md-4 condition-highlight">
|
||||
${$("[for=id_condition]").clone().attr("class", "style-widget form-control oh-label__info").prop("outerHTML")}
|
||||
${$("#id_condition").clone().attr("data-initial-value", "{{condition.condition}}").attr("class", "style-widget form-control").attr("name", "other_conditions").attr("class", "style-widget form-control").prop("outerHTML")}
|
||||
</div>
|
||||
<div class="col-12 col-md-4 condition-highlight">
|
||||
<div class="d-flex">
|
||||
${$("[for=id_value]").clone().attr("class", "style-widget form-control oh-label__info").prop("outerHTML")}
|
||||
<div class="m-1 p-1" onclick="$(this).closest('.row').remove()" align="center" style="border-radius:15px; width:25px;border:solid 1px red;cursor:pointer;display:inline;">
|
||||
-
|
||||
{% for condition in form.instance.other_conditions.all %}
|
||||
conditionSet = $(
|
||||
`
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-4 condition-highlight">
|
||||
${$("[for=id_field]").clone().attr("class", "style-widget form-control oh-label__info").prop("outerHTML")}
|
||||
${$("#id_field").clone().attr("data-initial-value", "{{condition.field}}").attr("name", "other_fields").attr("class", "style-widget form-control").prop("outerHTML")}
|
||||
</div>
|
||||
<div class="col-12 col-md-4 condition-highlight">
|
||||
${$("[for=id_condition]").clone().attr("class", "style-widget form-control oh-label__info").prop("outerHTML")}
|
||||
${$("#id_condition").clone().attr("data-initial-value", "{{condition.condition}}").attr("class", "style-widget form-control").attr("name", "other_conditions").attr("class", "style-widget form-control").prop("outerHTML")}
|
||||
</div>
|
||||
<div class="col-12 col-md-4 condition-highlight">
|
||||
<div class="d-flex">
|
||||
${$("[for=id_value]").clone().attr("class", "style-widget form-control oh-label__info").prop("outerHTML")}
|
||||
<div class="m-1 p-1" onclick="$(this).closest('.row').remove()" align="center" style="border-radius:15px; width:25px;border:solid 1px red;cursor:pointer;display:inline;">
|
||||
-
|
||||
</div>
|
||||
</div>
|
||||
${$("#id_value").clone().attr("data-initial-value", "{{condition.value}}").attr("name", "other_values").attr("value", "{{condition.value}}").change().attr("class", "style-widget form-control").prop("outerHTML")}
|
||||
</div>
|
||||
</div>
|
||||
${$("#id_value").clone().attr("data-initial-value", "{{condition.value}}").attr("name", "other_values").attr("value", "{{condition.value}}").change().attr("class", "style-widget form-control").prop("outerHTML")}
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
);
|
||||
$("#conditionContainer").prepend(conditionSet)
|
||||
{% endfor %}
|
||||
function initialData () {
|
||||
$.each($("[name=other_fields],[name=other_conditions]"), function (indexInArray, valueOfElement) {
|
||||
$(valueOfElement).val($(valueOfElement).attr("data-initial-value")).change()
|
||||
});
|
||||
}
|
||||
initialData()
|
||||
{% endif %}
|
||||
</script>
|
||||
{% endblock content %}
|
||||
`
|
||||
);
|
||||
$("#conditionContainer").prepend(conditionSet)
|
||||
{% endfor %}
|
||||
function initialData () {
|
||||
$.each($("[name=other_fields],[name=other_conditions]"), function (indexInArray, valueOfElement) {
|
||||
$(valueOfElement).val($(valueOfElement).attr("data-initial-value")).change()
|
||||
});
|
||||
}
|
||||
initialData()
|
||||
{% endif %}
|
||||
</script>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
@@ -171,6 +171,40 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6 oh-card-dashboard--moveable mb-4">
|
||||
<form hx-get="{% url 'get-contribution-report' %}" hx-trigger="load, submit" hx-target="#contributionReportContainer" class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent" >
|
||||
<div class="d-flex justify-content-between oh-card-dashboard__header oh-card-dashboard__header--divider" style = "cursor: default;">
|
||||
{% comment %} <span class="oh-card-dashboard__title" id="employee-previous" style = "cursor: pointer;"><ion-icon name="caret-back-outline"></ion-icon></span> {% endcomment %}
|
||||
<span class="oh-card-dashboard__title">{% trans "Employer Contributions" %}</span>
|
||||
<div>
|
||||
<span class="oh-card-dashboard__title">
|
||||
<select name="employee_id" class="oh-select" onchange="$(this).closest('form').find('[type=submit]').click()" id="deduction">
|
||||
{% for employee in get_active_employees %}
|
||||
{% if request.user == employee.employee_user_id %}
|
||||
<option value="{{employee.id}}" selected>{{employee.get_full_name}}</option>
|
||||
{% else %}
|
||||
<option value="{{employee.id}}">{{employee.get_full_name}}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</span>
|
||||
{% comment %} <span class="oh-card-dashboard__title">
|
||||
<select name="deduction_id" class="oh-select" onchange="$(this).closest('form').find('[type=submit]').click()" id="deduction">
|
||||
<option value="">{% trans "All" %}</option>
|
||||
{% for deduction in get_deductions %}
|
||||
<option value="{{deduction.id}}">{{deduction.title}}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</span> {% endcomment %}
|
||||
</div>
|
||||
{% comment %} <span class="oh-card-dashboard__title float-end" id="payroll-employee-next" style = "cursor: pointer;"><ion-icon name="caret-forward"></ion-icon></span> {% endcomment %}
|
||||
|
||||
</div>
|
||||
<div class="oh-card-dashboard__body" id="contributionReportContainer" >
|
||||
</div>
|
||||
<button type="submit" hidden>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-12 col-sm-12 col-md-12 col-lg-6 oh-card-dashboard--moveable">
|
||||
<div class="oh-card-dashboard oh-card-dashboard--no-scale oh-card-dashboard--transparent" style = "cursor: default;">
|
||||
<h4 class="ms-4 m-2 fw-bold text-danger">{% trans "Contracts ending " %} <b><span class=""></span></b></h4>
|
||||
|
||||
39
payroll/templates/payroll/dashboard/contribution.html
Normal file
39
payroll/templates/payroll/dashboard/contribution.html
Normal file
@@ -0,0 +1,39 @@
|
||||
{% load i18n static %}
|
||||
<div class="oh-sticky-table" style="height: 250px;">
|
||||
<div class="oh-sticky-table__table oh-table--sortable">
|
||||
<div class="oh-sticky-table__thead">
|
||||
<div class="oh-sticky-table__tr">
|
||||
<div class="oh-sticky-table__th">
|
||||
{% trans 'Deduction' %}
|
||||
</div>
|
||||
<div class="oh-sticky-table__th">
|
||||
{% trans 'Employee Contribution' %}
|
||||
</div>
|
||||
<div class="oh-sticky-table__th">
|
||||
{% trans 'Employer Contribution' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__tbody">
|
||||
{% for deduction in contribution_deductions %}
|
||||
<div class="oh-sticky-table__tr" draggable="true">
|
||||
<div class="oh-sticky-table__sd">
|
||||
<div class="oh-profile oh-profile--md">
|
||||
<div class="oh-profile__avatar mr-1">
|
||||
<img src="https://ui-avatars.com/api/?name={{ deduction.title }}&background=random" class="oh-profile__image" />
|
||||
</div>
|
||||
<span class="oh-profile__name oh-text--dark">{{ deduction.title }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-sticky-table__td">{{ currency }} {{ deduction.employee_contribution }}</div>
|
||||
<div class="oh-sticky-table__td">{{ currency }} {{ deduction.employer_contribution }}</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if not contribution_deductions %}
|
||||
<div align="center" style="width: 720px">
|
||||
<img width="100px" class="mt-5" src="{% static 'images/ui/joiningchart.png' %}" alt="" srcset="" />
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -127,4 +127,5 @@ urlpatterns = [
|
||||
component_views.delete_attachments,
|
||||
name="delete-attachments",
|
||||
),
|
||||
path("get-contribution-report",component_views.get_contribution_report,name="get-contribution-report")
|
||||
]
|
||||
|
||||
@@ -3,6 +3,7 @@ urls.py
|
||||
|
||||
This module is used to map url pattern or request path with view functions
|
||||
"""
|
||||
|
||||
from django.urls import path, include
|
||||
from payroll.views import views
|
||||
from payroll.models.models import Contract, Payslip
|
||||
@@ -18,6 +19,11 @@ urlpatterns = [
|
||||
name="update-contract",
|
||||
kwargs={"model": Contract},
|
||||
),
|
||||
path(
|
||||
"update-contract-status/<int:contract_id>",
|
||||
views.contract_status_update,
|
||||
name="update-contract-status",
|
||||
),
|
||||
path(
|
||||
"delete-contract/<int:contract_id>",
|
||||
views.contract_delete,
|
||||
@@ -126,7 +132,6 @@ urlpatterns = [
|
||||
views.payslip_select_filter,
|
||||
name="payslip-select-filter",
|
||||
),
|
||||
|
||||
path(
|
||||
"payroll-request-add-comment/<int:payroll_id>/",
|
||||
views.create_payrollrequest_comment,
|
||||
@@ -142,5 +147,9 @@ urlpatterns = [
|
||||
views.delete_payrollrequest_comment,
|
||||
name="payroll-request-delete-comment",
|
||||
),
|
||||
path("initial-notice-period",views.initial_notice_period,name="initial-notice-period")
|
||||
path(
|
||||
"initial-notice-period",
|
||||
views.initial_notice_period,
|
||||
name="initial-notice-period",
|
||||
),
|
||||
]
|
||||
|
||||
@@ -4,6 +4,7 @@ component_views.py
|
||||
This module is used to write methods to the component_urls patterns respectively
|
||||
"""
|
||||
from collections import defaultdict
|
||||
from itertools import groupby
|
||||
import json
|
||||
import operator
|
||||
from datetime import date, datetime
|
||||
@@ -930,7 +931,6 @@ def add_deduction(request):
|
||||
initial={"employee_id": employee_id, "one_time_date": instance.start_date},
|
||||
)
|
||||
if form.is_valid():
|
||||
|
||||
# Save the form to create the Deduction instance
|
||||
deduction_instance = form.save(commit=False)
|
||||
deduction_instance.only_show_under_employee = True
|
||||
@@ -940,7 +940,7 @@ def add_deduction(request):
|
||||
deduction_instance.specific_employees.set([employee_id])
|
||||
deduction_instance.include_active_employees = False
|
||||
deduction_instance.save()
|
||||
|
||||
|
||||
# Now create new payslip by deleting existing payslip
|
||||
new_post_data = QueryDict(mutable=True)
|
||||
new_post_data.update(
|
||||
@@ -1269,3 +1269,66 @@ def delete_attachments(request, _reimbursement_id):
|
||||
ReimbursementMultipleAttachment.objects.filter(id__in=ids).delete()
|
||||
messages.success(request, "Attachment deleted")
|
||||
return redirect(view_reimbursement)
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("payroll.view_payslip")
|
||||
def get_contribution_report(request):
|
||||
"""
|
||||
This method is used to get the contribution report
|
||||
"""
|
||||
employee_id = request.GET["employee_id"]
|
||||
deudction_id = request.GET.get("deduction_id")
|
||||
pay_heads = Payslip.objects.filter(employee_id__id=employee_id).values_list(
|
||||
"pay_head_data", flat=True
|
||||
)
|
||||
contribution_deductions = []
|
||||
deductions = []
|
||||
for head in pay_heads:
|
||||
for deduction in head["gross_pay_deductions"]:
|
||||
if deduction.get("deduction_id"):
|
||||
deductions.append(deduction)
|
||||
for deduction in head["basic_pay_deductions"]:
|
||||
if deduction.get("deduction_id"):
|
||||
deductions.append(deduction)
|
||||
for deduction in head["pretax_deductions"]:
|
||||
if deduction.get("deduction_id"):
|
||||
deductions.append(deduction)
|
||||
for deduction in head["post_tax_deductions"]:
|
||||
if deduction.get("deduction_id"):
|
||||
deductions.append(deduction)
|
||||
for deduction in head["tax_deductions"]:
|
||||
if deduction.get("deduction_id"):
|
||||
deductions.append(deduction)
|
||||
for deduction in head["net_deductions"]:
|
||||
deductions.append(deduction)
|
||||
|
||||
deductions.sort(key=lambda x: x["deduction_id"])
|
||||
grouped_deductions = {
|
||||
key: list(group)
|
||||
for key, group in groupby(deductions, key=lambda x: x["deduction_id"])
|
||||
}
|
||||
|
||||
for deduction_id, group in grouped_deductions.items():
|
||||
title = group[0]["title"]
|
||||
employee_contribution = sum(item["amount"] for item in group)
|
||||
employer_contribution = sum(
|
||||
item["employer_contribution_amount"] for item in group
|
||||
)
|
||||
total_contribution = employee_contribution + employer_contribution
|
||||
|
||||
contribution_deductions.append(
|
||||
{
|
||||
"deduction_id": deduction_id,
|
||||
"title": title,
|
||||
"employee_contribution": employee_contribution,
|
||||
"employer_contribution": employer_contribution,
|
||||
"total_contribution": total_contribution,
|
||||
}
|
||||
)
|
||||
|
||||
return render(
|
||||
request,
|
||||
"payroll/dashboard/contribution.html",
|
||||
{"contribution_deductions": contribution_deductions},
|
||||
)
|
||||
|
||||
@@ -3,6 +3,7 @@ views.py
|
||||
|
||||
This module is used to define the method for the path in the urls
|
||||
"""
|
||||
|
||||
from collections import defaultdict
|
||||
from urllib.parse import parse_qs
|
||||
import pandas as pd
|
||||
@@ -20,8 +21,19 @@ from base.methods import export_data, generate_colors, get_key_instances
|
||||
from employee.models import Employee, EmployeeWorkInformation
|
||||
from base.methods import closest_numbers
|
||||
from base.methods import generate_pdf
|
||||
from payroll.models.models import PayrollGeneralSetting, Payslip, Reimbursement, ReimbursementrequestComment, WorkRecord, Contract
|
||||
from payroll.forms.forms import ContractForm, ReimbursementrequestCommentForm, WorkRecordForm
|
||||
from payroll.models.models import (
|
||||
PayrollGeneralSetting,
|
||||
Payslip,
|
||||
Reimbursement,
|
||||
ReimbursementrequestComment,
|
||||
WorkRecord,
|
||||
Contract,
|
||||
)
|
||||
from payroll.forms.forms import (
|
||||
ContractForm,
|
||||
ReimbursementrequestCommentForm,
|
||||
WorkRecordForm,
|
||||
)
|
||||
from payroll.models.tax_models import PayrollSettings
|
||||
from payroll.forms.component_forms import ContractExportFieldForm, PayrollSettingsForm
|
||||
from payroll.methods.methods import save_payslip
|
||||
@@ -94,6 +106,20 @@ def contract_update(request, contract_id, **kwargs):
|
||||
)
|
||||
|
||||
|
||||
def contract_status_update(request, contract_id):
|
||||
if request.method == "POST":
|
||||
contract = Contract.objects.get(id=contract_id)
|
||||
contract_form = ContractForm(request.POST, request.FILES, instance=contract)
|
||||
if contract_form.is_valid():
|
||||
contract_form.save()
|
||||
messages.success(request, _("Contract status updated"))
|
||||
else:
|
||||
for errors in contract_form.errors.values():
|
||||
for error in errors:
|
||||
messages.error(request, error)
|
||||
return HttpResponse("<script>window.location.reload()</script>")
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("payroll.delete_contract")
|
||||
def contract_delete(request, contract_id):
|
||||
@@ -424,24 +450,26 @@ def contract_info_initial(request):
|
||||
employee_id = request.GET["employee_id"]
|
||||
work_info = EmployeeWorkInformation.objects.filter(employee_id=employee_id).first()
|
||||
response_data = {
|
||||
"department": work_info.department_id.id
|
||||
if work_info.department_id is not None
|
||||
else "",
|
||||
"job_position": work_info.job_position_id.id
|
||||
if work_info.job_position_id is not None
|
||||
else "",
|
||||
"job_role": work_info.job_role_id.id
|
||||
if work_info.job_role_id is not None
|
||||
else "",
|
||||
"department": (
|
||||
work_info.department_id.id if work_info.department_id is not None else ""
|
||||
),
|
||||
"job_position": (
|
||||
work_info.job_position_id.id
|
||||
if work_info.job_position_id is not None
|
||||
else ""
|
||||
),
|
||||
"job_role": (
|
||||
work_info.job_role_id.id if work_info.job_role_id is not None else ""
|
||||
),
|
||||
"shift": work_info.shift_id.id if work_info.shift_id is not None else "",
|
||||
"work_type": work_info.work_type_id.id
|
||||
if work_info.work_type_id is not None
|
||||
else "",
|
||||
"work_type": (
|
||||
work_info.work_type_id.id if work_info.work_type_id is not None else ""
|
||||
),
|
||||
"wage": work_info.basic_salary,
|
||||
"contract_start_date": work_info.date_joining if work_info.date_joining else "",
|
||||
"contract_end_date": work_info.contract_end_date
|
||||
if work_info.contract_end_date
|
||||
else "",
|
||||
"contract_end_date": (
|
||||
work_info.contract_end_date if work_info.contract_end_date else ""
|
||||
),
|
||||
}
|
||||
return JsonResponse(response_data)
|
||||
|
||||
@@ -641,15 +669,19 @@ def contract_ending(request):
|
||||
date = request.GET.get("period")
|
||||
month = date.split("-")[1]
|
||||
year = date.split("-")[0]
|
||||
|
||||
if request.GET.get("initialLoad") == 'true':
|
||||
if month == '12':
|
||||
month =0
|
||||
|
||||
if request.GET.get("initialLoad") == "true":
|
||||
if month == "12":
|
||||
month = 0
|
||||
year = int(year) + 1
|
||||
|
||||
contract_end = Contract.objects.filter(contract_end_date__month=int(month)+1,contract_end_date__year=int(year))
|
||||
contract_end = Contract.objects.filter(
|
||||
contract_end_date__month=int(month) + 1, contract_end_date__year=int(year)
|
||||
)
|
||||
else:
|
||||
contract_end = Contract.objects.filter(contract_end_date__month=int(month),contract_end_date__year=int(year))
|
||||
contract_end = Contract.objects.filter(
|
||||
contract_end_date__month=int(month), contract_end_date__year=int(year)
|
||||
)
|
||||
|
||||
ending_contract = []
|
||||
for contract in contract_end:
|
||||
@@ -851,9 +883,11 @@ def payslip_export(request):
|
||||
|
||||
df_table3 = df_table3.rename(
|
||||
columns={
|
||||
"contract_ending": f"Contract Ending {start_date} to {end_date}"
|
||||
if start_date and end_date
|
||||
else f"Contract Ending",
|
||||
"contract_ending": (
|
||||
f"Contract Ending {start_date} to {end_date}"
|
||||
if start_date and end_date
|
||||
else f"Contract Ending"
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -918,9 +952,11 @@ def payslip_export(request):
|
||||
0,
|
||||
0,
|
||||
max_columns - 1,
|
||||
f"Payroll details {start_date} to {end_date}"
|
||||
if start_date and end_date
|
||||
else f"Payroll details",
|
||||
(
|
||||
f"Payroll details {start_date} to {end_date}"
|
||||
if start_date and end_date
|
||||
else f"Payroll details"
|
||||
),
|
||||
heading_format,
|
||||
)
|
||||
|
||||
@@ -1202,19 +1238,25 @@ def create_payrollrequest_comment(request, payroll_id):
|
||||
"""
|
||||
payroll = Reimbursement.objects.filter(id=payroll_id).first()
|
||||
emp = request.user.employee_get
|
||||
form = ReimbursementrequestCommentForm(initial={'employee_id':emp.id, 'request_id':payroll_id})
|
||||
form = ReimbursementrequestCommentForm(
|
||||
initial={"employee_id": emp.id, "request_id": payroll_id}
|
||||
)
|
||||
|
||||
if request.method == "POST":
|
||||
form = ReimbursementrequestCommentForm(request.POST )
|
||||
form = ReimbursementrequestCommentForm(request.POST)
|
||||
if form.is_valid():
|
||||
form.instance.employee_id = emp
|
||||
form.instance.request_id = payroll
|
||||
form.save()
|
||||
form = ReimbursementrequestCommentForm(initial={'employee_id':emp.id, 'request_id':payroll_id})
|
||||
form = ReimbursementrequestCommentForm(
|
||||
initial={"employee_id": emp.id, "request_id": payroll_id}
|
||||
)
|
||||
messages.success(request, _("Comment added successfully!"))
|
||||
|
||||
|
||||
if request.user.employee_get.id == payroll.employee_id.id:
|
||||
rec = payroll.employee_id.employee_work_info.reporting_manager_id.employee_user_id
|
||||
rec = (
|
||||
payroll.employee_id.employee_work_info.reporting_manager_id.employee_user_id
|
||||
)
|
||||
notify.send(
|
||||
request.user.employee_get,
|
||||
recipient=rec,
|
||||
@@ -1226,7 +1268,10 @@ def create_payrollrequest_comment(request, payroll_id):
|
||||
redirect="/payroll/view-reimbursement",
|
||||
icon="chatbox-ellipses",
|
||||
)
|
||||
elif request.user.employee_get.id == payroll.employee_id.employee_work_info.reporting_manager_id.id:
|
||||
elif (
|
||||
request.user.employee_get.id
|
||||
== payroll.employee_id.employee_work_info.reporting_manager_id.id
|
||||
):
|
||||
rec = payroll.employee_id.employee_user_id
|
||||
notify.send(
|
||||
request.user.employee_get,
|
||||
@@ -1240,7 +1285,10 @@ def create_payrollrequest_comment(request, payroll_id):
|
||||
icon="chatbox-ellipses",
|
||||
)
|
||||
else:
|
||||
rec = [payroll.employee_id.employee_user_id, payroll.employee_id.employee_work_info.reporting_manager_id.employee_user_id]
|
||||
rec = [
|
||||
payroll.employee_id.employee_user_id,
|
||||
payroll.employee_id.employee_work_info.reporting_manager_id.employee_user_id,
|
||||
]
|
||||
notify.send(
|
||||
request.user.employee_get,
|
||||
recipient=rec,
|
||||
@@ -1252,14 +1300,12 @@ def create_payrollrequest_comment(request, payroll_id):
|
||||
redirect="/payroll/view-reimbursement",
|
||||
icon="chatbox-ellipses",
|
||||
)
|
||||
|
||||
|
||||
return HttpResponse("<script>window.location.reload()</script>")
|
||||
return render(
|
||||
request,
|
||||
"payroll/reimbursement/reimbursement_request_comment_form.html",
|
||||
{
|
||||
"form": form, "request_id":payroll_id
|
||||
},
|
||||
{"form": form, "request_id": payroll_id},
|
||||
)
|
||||
|
||||
|
||||
@@ -1268,7 +1314,9 @@ def view_payrollrequest_comment(request, payroll_id):
|
||||
"""
|
||||
This method is used to show Reimbursement request comments
|
||||
"""
|
||||
comments = ReimbursementrequestComment.objects.filter(request_id=payroll_id).order_by('-created_at')
|
||||
comments = ReimbursementrequestComment.objects.filter(
|
||||
request_id=payroll_id
|
||||
).order_by("-created_at")
|
||||
no_comments = False
|
||||
if not comments.exists():
|
||||
no_comments = True
|
||||
@@ -1276,7 +1324,7 @@ def view_payrollrequest_comment(request, payroll_id):
|
||||
return render(
|
||||
request,
|
||||
"payroll/reimbursement/comment_view.html",
|
||||
{"comments": comments, 'no_comments': no_comments }
|
||||
{"comments": comments, "no_comments": no_comments},
|
||||
)
|
||||
|
||||
|
||||
@@ -1300,7 +1348,7 @@ def initial_notice_period(request):
|
||||
notice_period = eval(request.GET["notice_period"])
|
||||
settings = PayrollGeneralSetting.objects.first()
|
||||
settings = settings if settings else PayrollGeneralSetting()
|
||||
settings.notice_period = max(notice_period,0)
|
||||
settings.notice_period = max(notice_period, 0)
|
||||
settings.save()
|
||||
messages.success(request,"Initial notice period updated")
|
||||
messages.success(request, "Initial notice period updated")
|
||||
return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))
|
||||
|
||||
Reference in New Issue
Block a user