[ADD] PAYROLL: Comment section for reimbursement request/leave encashment request views
This commit is contained in:
@@ -11,7 +11,8 @@ from payroll.models.models import (
|
||||
Payslip,
|
||||
WorkRecord,
|
||||
LoanAccount,
|
||||
Reimbursement
|
||||
Reimbursement,
|
||||
ReimbursementrequestComment
|
||||
)
|
||||
from payroll.models.tax_models import (
|
||||
PayrollSettings,
|
||||
@@ -29,3 +30,4 @@ admin.site.register(Payslip)
|
||||
admin.site.register(PayrollSettings)
|
||||
admin.site.register(LoanAccount)
|
||||
admin.site.register(Reimbursement)
|
||||
admin.site.register(ReimbursementrequestComment)
|
||||
@@ -5,7 +5,7 @@ from django import forms
|
||||
from django.forms import widgets
|
||||
from django.utils.translation import gettext_lazy as trans
|
||||
from django.template.loader import render_to_string
|
||||
from payroll.models.models import WorkRecord
|
||||
from payroll.models.models import ReimbursementrequestComment, WorkRecord
|
||||
from payroll.models.models import Contract
|
||||
from base.methods import reload_queryset
|
||||
|
||||
@@ -116,3 +116,17 @@ class WorkRecordForm(ModelForm):
|
||||
|
||||
fields = "__all__"
|
||||
model = WorkRecord
|
||||
|
||||
|
||||
class ReimbursementrequestCommentForm(ModelForm):
|
||||
"""
|
||||
ReimbursementrequestCommentForm form
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
"""
|
||||
Meta class for additional options
|
||||
"""
|
||||
|
||||
model = ReimbursementrequestComment
|
||||
fields = ('comment',)
|
||||
@@ -1557,3 +1557,21 @@ class Reimbursement(models.Model):
|
||||
if self.allowance_id:
|
||||
self.allowance_id.delete()
|
||||
return super().delete(*args, **kwargs)
|
||||
|
||||
|
||||
class ReimbursementrequestComment(models.Model):
|
||||
"""
|
||||
ReimbursementrequestComment Model
|
||||
"""
|
||||
|
||||
request_id = models.ForeignKey(Reimbursement, on_delete=models.CASCADE)
|
||||
employee_id = models.ForeignKey(Employee, on_delete=models.CASCADE)
|
||||
comment = models.TextField(null=True, verbose_name=_("Comment"))
|
||||
created_at = models.DateTimeField(
|
||||
auto_now_add=True,
|
||||
verbose_name=_("Created At"),
|
||||
null=True,
|
||||
)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.comment}"
|
||||
|
||||
56
payroll/templates/payroll/reimbursement/comment_view.html
Normal file
56
payroll/templates/payroll/reimbursement/comment_view.html
Normal file
@@ -0,0 +1,56 @@
|
||||
{% load basefilters %}
|
||||
{% load i18n %}
|
||||
|
||||
{% if no_comments %}
|
||||
|
||||
<div class="oh-timeoff-modal__profile-content">
|
||||
<div class="">
|
||||
<div>
|
||||
<span class="oh-timeoff-title fw-bold" style="display: block;">{% trans "There is no comments to show." %}</span>
|
||||
<img style="display: block;width: 100px;margin: 20px auto ;" src="/static/images/ui/comment.png" class="">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% else %}
|
||||
|
||||
{% for comment in comments %}
|
||||
<div class="oh-timeoff-modal__profile-content">
|
||||
<div class="oh-profile ms-4">
|
||||
<div>
|
||||
<span class="oh-timeoff-modal__stat-title fw-bold">{% trans "Comment" %}
|
||||
<a href='{% url "payroll-request-delete-comment" comment.id %}' title='Delete Comment'>
|
||||
<ion-icon name="close-circle-outline" class="text-danger ms-3 mt-1" aria-label="close outline"></ion-icon></a>
|
||||
</span>
|
||||
<div>
|
||||
<span class="oh-timeoff-title fw-bold">{{comment.comment}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oh-modal__dialog-body">
|
||||
<div class="oh-timeoff-modal__stats-container">
|
||||
<div class="oh-timeoff-modal__stat">
|
||||
<span class="oh-timeoff-modal__stat-title fw-bold">{% trans "By" %}</span>
|
||||
<a style="text-decoration:none;"
|
||||
href ="{% url 'employee-view-individual' comment.employee_id.id %}">
|
||||
<span class="oh-timeoff-modal__stat-count">{{ comment.employee_id }}</span></a>
|
||||
</div>
|
||||
<div class="oh-timeoff-modal__stat" style="margin-left: 20px;">
|
||||
<span class="oh-timeoff-modal__stat-title fw-bold">{% trans "Date & Time" %}</span>
|
||||
<span class="oh-timeoff-modal__stat-count">
|
||||
{% trans "on" %}  <span class="dateformat_changer">{{ comment.created_at|date:"F j, Y" }}</span>  
|
||||
{% trans "at" %}   <span class="timeformat_changer">{{ comment.created_at|time:"g:i A" }}</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<hr>
|
||||
</div>
|
||||
|
||||
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
@@ -10,14 +10,14 @@
|
||||
<ion-icon name="search-outline" class="oh-input-group__icon oh-input-group__icon--left md hydrated" role="img" aria-label="search outline"></ion-icon>
|
||||
<input type="text" id="pipelineSearch" placeholder="Search" style="margin-right:10px" onkeyup="$('.filterButton').click()" name="search" class="oh-input oh-input__icon mr-3" aria-label="Search Input" />
|
||||
</div>
|
||||
<ul class="oh-view-types ml-2" style="margin-bottom: 0;">
|
||||
{% comment %} <ul class="oh-view-types ml-2" style="margin-bottom: 0;">
|
||||
<li class="oh-view-type" data-view="list" onclick="event.stopPropagation()">
|
||||
<a class="oh-btn oh-btn--view" title="List"><ion-icon name="list-outline" role="img" class="md hydrated" aria-label="list outline"></ion-icon></a>
|
||||
</li>
|
||||
<li class="oh-view-type" data-view="card">
|
||||
<a class="oh-btn oh-btn--view oh-btn--view-active" title="Card"><ion-icon name="grid-outline" role="img" class="md hydrated" aria-label="grid outline"></ion-icon></a>
|
||||
</li>
|
||||
</ul>
|
||||
</ul> {% endcomment %}
|
||||
{% include 'payroll/reimbursement/filter.html' %}
|
||||
<div class="oh-main__titlebar-button-container">
|
||||
<div class="oh-main__titlebar-button-container">
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
{% load i18n %}
|
||||
{% if form.errors %}
|
||||
<!-- form errors -->
|
||||
<div class="oh-wrapper">
|
||||
<div class="oh-alert-container">
|
||||
{% for error in form.non_field_errors %}
|
||||
<div class="oh-alert oh-alert--animated oh-alert--danger">
|
||||
{{ error }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<form
|
||||
hx-post="{% url 'payroll-request-add-comment' request_id %}"
|
||||
hx-target="#shiftRequestCommentForm"
|
||||
method="post"
|
||||
hx-encoding="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{form.as_p}}
|
||||
<button
|
||||
type="submit"
|
||||
class="oh-btn oh-btn--secondary mt-2 mr-0 oh-btn--w-100-resp"
|
||||
>
|
||||
{% trans "Save" %}
|
||||
</button>
|
||||
</form>
|
||||
@@ -56,8 +56,17 @@
|
||||
</div>
|
||||
<h3 class="oh-faq-card__title">{{ req.title }}</h3>
|
||||
<p class="oh-faq-card__desc">{{ req.description }}.</p>
|
||||
<span class="oh-card__footer--border-top pt-1" style="display: block;">
|
||||
<i style="color: hsl(0,0%,45%);">{% trans 'Allowance on' %}</i> {{ req.allowance_on }}.
|
||||
<span class="oh-card__footer--border-top pt-1 " style="display: block;">
|
||||
|
||||
<div class="mb-2">
|
||||
<i><a hx-target="#shiftRequestCommentForm" hx-get="{% url 'payroll-request-add-comment' req.id %}" class="text-primary"
|
||||
hx-swap="innerHTML" data-toggle="oh-modal-toggle" data-target="#shiftcommentModal" style='cursor:pointer;'>{% trans 'Add Comments' %}</a>  ,
|
||||
|
||||
<a hx-target="#shiftRequestDetailTarget" hx-get="{% url 'payroll-request-view-comment' req.id %}" class="text-primary"
|
||||
data-toggle='oh-modal-toggle' data-target = '#shiftRequestDetailModal' style='cursor:pointer;'>{% trans 'View Comments' %}</a></i>
|
||||
</div>
|
||||
|
||||
<i style="color: hsl(0,0%,45%);">{% trans 'Allowance on' %}</i> <span class='dateformat_changer'>{{ req.allowance_on }}</span>
|
||||
{% if req.type == 'reimbursement' %}
|
||||
<i><a data-target="#reimbursementAttachementModal" data-toggle="oh-modal-toggle" hx-target="#reimbursementAttachementModalBody" hx-get="{% url "reimbursement-attachments" req.id %}" class="text-danger"
|
||||
title="Attachments" rel="noopener noreferrer">{% trans 'View Attachments' %}</a></i>
|
||||
@@ -145,6 +154,54 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- start of comment modal -->
|
||||
<div
|
||||
class="oh-modal"
|
||||
id="shiftcommentModal"
|
||||
role="dialog"
|
||||
aria-labelledby="emptagModal"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="oh-modal__dialog">
|
||||
<div class="oh-modal__dialog-header">
|
||||
<h2 class="oh-modal__dialog-title" id="createModalTitle">
|
||||
{% trans "Add Comment" %}
|
||||
</h2>
|
||||
<button class="oh-modal__close" aria-label="Close">
|
||||
<ion-icon name="close-outline"></ion-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="oh-modal__dialog-body" id="shiftRequestCommentForm"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end of comment modal -->
|
||||
|
||||
<div
|
||||
class="oh-modal" style="z-index: 60;"
|
||||
id="shiftRequestDetailModal"
|
||||
role="dialog"
|
||||
aria-labelledby="shiftRequestDetailModal"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="oh-modal__dialog">
|
||||
<div class="oh-modal__dialog-header">
|
||||
<h2
|
||||
class="oh-modal__dialog-title"
|
||||
id=""
|
||||
>
|
||||
{% trans "Details" %}
|
||||
</h2>
|
||||
<button class="oh-modal__close" aria-label="Close">
|
||||
<ion-icon name="close-outline"></ion-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="oh-modal__dialog-body oh-modal__dialog-relative"
|
||||
id="shiftRequestDetailTarget"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function reimbursementConfirm(params, target, approve = false) {
|
||||
Swal.fire({
|
||||
|
||||
@@ -126,4 +126,20 @@ urlpatterns = [
|
||||
views.payslip_select_filter,
|
||||
name="payslip-select-filter",
|
||||
),
|
||||
|
||||
path(
|
||||
"payroll-request-add-comment/<int:payroll_id>/",
|
||||
views.create_payrollrequest_comment,
|
||||
name="payroll-request-add-comment",
|
||||
),
|
||||
path(
|
||||
"payroll-request-view-comment/<int:payroll_id>/",
|
||||
views.view_payrollrequest_comment,
|
||||
name="payroll-request-view-comment",
|
||||
),
|
||||
path(
|
||||
"payroll-request-delete-comment/<int:comment_id>/",
|
||||
views.delete_payrollrequest_comment,
|
||||
name="payroll-request-delete-comment",
|
||||
),
|
||||
]
|
||||
|
||||
@@ -19,8 +19,8 @@ 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 Payslip, WorkRecord, Contract
|
||||
from payroll.forms.forms import ContractForm, WorkRecordForm
|
||||
from payroll.models.models import 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
|
||||
@@ -1186,3 +1186,58 @@ def payslip_select_filter(request):
|
||||
context = {"payslip_ids": payslip_ids, "total_count": total_count}
|
||||
|
||||
return JsonResponse(context)
|
||||
|
||||
|
||||
@login_required
|
||||
def create_payrollrequest_comment(request, payroll_id):
|
||||
"""
|
||||
This method renders form and template to create Reimbursement request comments
|
||||
"""
|
||||
payroll = Reimbursement.objects.filter(id=payroll_id).first()
|
||||
emp = request.user.employee_get
|
||||
form = ReimbursementrequestCommentForm(initial={'employee_id':emp.id, 'request_id':payroll_id})
|
||||
|
||||
if request.method == "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})
|
||||
messages.success(request, _("Comment added successfully!"))
|
||||
return HttpResponse("<script>window.location.reload()</script>")
|
||||
return render(
|
||||
request,
|
||||
"payroll/reimbursement/reimbursement_request_comment_form.html",
|
||||
{
|
||||
"form": form, "request_id":payroll_id
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
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')
|
||||
no_comments = False
|
||||
if not comments.exists():
|
||||
no_comments = True
|
||||
|
||||
return render(
|
||||
request,
|
||||
"payroll/reimbursement/comment_view.html",
|
||||
{"comments": comments, 'no_comments': no_comments }
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
def delete_payrollrequest_comment(request, comment_id):
|
||||
"""
|
||||
This method is used to delete Reimbursement request comments
|
||||
"""
|
||||
ReimbursementrequestComment.objects.get(id=comment_id).delete()
|
||||
|
||||
messages.success(request, _("Comment deleted successfully!"))
|
||||
return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))
|
||||
|
||||
Reference in New Issue
Block a user