[UPDT] HORILLA_API: Payslip download api view

This commit is contained in:
Horilla
2025-09-26 11:22:25 +05:30
parent 76595fc367
commit 90683a438d
3 changed files with 172 additions and 1 deletions

View File

@@ -13,7 +13,7 @@ urlpatterns = [
),
path("payslip/", PayslipView.as_view(), name=""),
path("payslip/<int:id>", PayslipView.as_view(), name=""),
path("payslip-download/<int:id>", PayslipDownloadView.as_view(), name=""),
path("payslip-download/<int:id>", PayslipPDFAPIView.as_view(), name=""),
path("payslip-send-mail/", PayslipSendMailView.as_view(), name=""),
path("loan-account/", LoanAccountView.as_view(), name=""),
path("loan-account/<int:pk>", LoanAccountView.as_view(), name=""),

View File

@@ -89,6 +89,7 @@ class ClockInAPIView(APIView):
if request.__dict__.get("date"):
date_today = request.date
attendance_date = date_today
day = date_today.strftime("%A").lower()
day = EmployeeShiftDay.objects.get(day=day)
now = datetime.now().strftime("%H:%M")

View File

@@ -377,3 +377,173 @@ class TaxBracketView(APIView):
tax_bracket = TaxBracket.objects.get(id=pk)
tax_bracket.delete()
return Response(status=200)
from datetime import datetime
from django.http import Http404, HttpResponse
from django.shortcuts import get_object_or_404
from django.template.loader import render_to_string
from rest_framework import status
from rest_framework.authentication import SessionAuthentication
# DRF / Simple JWT imports
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_simplejwt.authentication import JWTAuthentication
from horilla.horilla_settings import HORILLA_DATE_FORMATS
# Your models / helpers
from payroll.models.models import Company, EmployeeWorkInformation, Payslip
from payroll.models.tax_models import PayrollSettings
from payroll.views.component_views import filter_payslip
from payroll.views.views import equalize_lists_length
try:
import pdfkit
HAVE_PDFKIT = True
except Exception:
HAVE_PDFKIT = False
class PayslipPDFAPIView(APIView):
"""
GET /api/payslip/<payslip_id>/?format=pdf
Auth:
- Accepts SimpleJWT Bearer token (Authorization: Bearer <token>)
- Also accepts session auth (browser) when available
"""
authentication_classes = (JWTAuthentication, SessionAuthentication)
permission_classes = (IsAuthenticated,)
def get(self, request, id, format=None):
# get payslip or 404
payslip = get_object_or_404(Payslip, id=id)
# authorization: same logic as your view
user = request.user
if not (
user.has_perm("payroll.view_payslip")
or payslip.employee_id.employee_user_id == user
):
return Response(
{"detail": "You do not have permission to view this payslip."},
status=status.HTTP_403_FORBIDDEN,
)
# employee & company date format resolution
employee = user.employee_get # keep same accessor you used
info = EmployeeWorkInformation.objects.filter(employee_id=employee)
if info.exists():
# take the last one (mirrors your loop behavior)
employee_company = info.last().company_id
emp_company = Company.objects.filter(company=employee_company).first()
date_format = (
emp_company.date_format
if emp_company and emp_company.date_format
else "MMM. D, YYYY"
)
else:
date_format = "MMM. D, YYYY"
# compose data from payslip (same as original)
data = (
payslip.pay_head_data.copy()
if isinstance(payslip.pay_head_data, dict)
else {}
)
start_date_str = data.get("start_date")
end_date_str = data.get("end_date")
if not start_date_str or not end_date_str:
return Response(
{"detail": "Payslip missing start_date or end_date"},
status=status.HTTP_400_BAD_REQUEST,
)
# parse dates
start_date = datetime.strptime(start_date_str, "%Y-%m-%d").date()
end_date = datetime.strptime(end_date_str, "%Y-%m-%d").date()
month_start_name = start_date.strftime("%B %d, %Y")
month_end_name = end_date.strftime("%B %d, %Y")
# formatted date for chosen company format (safe default if not found)
formatted_start_date = start_date.strftime(
HORILLA_DATE_FORMATS.get(date_format, "%b. %d, %Y")
)
formatted_end_date = end_date.strftime(
HORILLA_DATE_FORMATS.get(date_format, "%b. %d, %Y")
)
# fill template context like original view
data["month_start_name"] = month_start_name
data["month_end_name"] = month_end_name
data["formatted_start_date"] = formatted_start_date
data["formatted_end_date"] = formatted_end_date
data["employee"] = payslip.employee_id
data["payslip"] = payslip
data["json_data"] = data.copy()
data["json_data"]["employee"] = payslip.employee_id.id
data["json_data"]["payslip"] = payslip.id
data["instance"] = payslip
data["currency"] = (
PayrollSettings.objects.first().currency_symbol
if PayrollSettings.objects.exists()
else ""
)
data["all_deductions"] = []
for deduction_list in [
data.get("basic_pay_deductions", []),
data.get("gross_pay_deductions", []),
data.get("pretax_deductions", []),
data.get("post_tax_deductions", []),
data.get("tax_deductions", []),
data.get("net_deductions", []),
]:
data["all_deductions"].extend(deduction_list)
data["all_allowances"] = data.get("allowances", []).copy()
# equalize lengths (your helper)
equalize_lists_length(data.setdefault("allowances", []), data["all_deductions"])
data["zipped_data"] = zip(data["allowances"], data["all_deductions"])
data["host"] = request.get_host()
data["protocol"] = "https" if request.is_secure() else "http"
data["company"] = Company.objects.filter(hq=True).first()
# render HTML string using template
html = render_to_string(
"payroll/payslip/payslip_pdf.html", context=data, request=request
)
# If client asked for PDF and pdfkit is available -> return PDF
requested_format = request.GET.get("format", "").lower()
if requested_format == "pdf":
if not HAVE_PDFKIT:
return Response(
{
"detail": "PDF generation not available on server. Install pdfkit/wkhtmltopdf."
},
status=status.HTTP_503_SERVICE_UNAVAILABLE,
)
try:
# optional: configure pdfkit with path if needed
pdf_options = {
"enable-local-file-access": None, # if your template references local CSS
}
pdf_bytes = pdfkit.from_string(html, False, options=pdf_options)
response = HttpResponse(pdf_bytes, content_type="application/pdf")
response["Content-Disposition"] = f'inline; filename="payslip-{id}.pdf"'
return response
except Exception as e:
return Response(
{"detail": f"PDF generation failed: {str(e)}"},
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
)
# default: return rendered HTML (use HttpResponse so browser sees it nicely)
return HttpResponse(html)