diff --git a/core/templates/core/email/payslip_email.html b/core/templates/core/email/payslip_email.html
index ad7a262..79e3856 100644
--- a/core/templates/core/email/payslip_email.html
+++ b/core/templates/core/email/payslip_email.html
@@ -29,7 +29,7 @@
@@ -53,6 +53,11 @@
Advance Payment: {{ advance_description }}
R {{ advance_amount|floatformat:2 }}
+ {% elif is_loan %}
+
+ Loan Payment: {{ loan_description }}
+ R {{ loan_amount|floatformat:2 }}
+
{% else %}
diff --git a/core/templates/core/payroll_dashboard.html b/core/templates/core/payroll_dashboard.html
index 2994b8a..0c3b74c 100644
--- a/core/templates/core/payroll_dashboard.html
+++ b/core/templates/core/payroll_dashboard.html
@@ -545,6 +545,22 @@
Description
+
+ {# Pay Immediately — only shown for New Loan type #}
+ {# When checked, the loan is paid to the worker right away and #}
+ {# a payslip is emailed to Spark. When unchecked, the loan sits #}
+ {# in pending payments and gets included in the next pay cycle. #}
+
+ {% elif is_loan %}
+
+ Loan Details
+
+
+
+
+ Date
+ Type
+ Description
+ Amount
+
+
+
+
+ {{ loan_adj.date|date:"M d, Y" }}
+ Loan Payment
+ {{ loan_adj.description|default:"Worker loan" }}
+ R {{ loan_adj.amount|floatformat:2 }}
+
+
+
+
+
+
+
+
+
+
+ Loan Amount:
+ R {{ loan_adj.amount|floatformat:2 }}
+
+
+
+
+
{% else %}
Work Log Details (Attendance)
diff --git a/core/templates/core/pdf/payslip_pdf.html b/core/templates/core/pdf/payslip_pdf.html
index 6d2a5b0..717a32c 100644
--- a/core/templates/core/pdf/payslip_pdf.html
+++ b/core/templates/core/pdf/payslip_pdf.html
@@ -107,7 +107,7 @@
@@ -132,6 +132,12 @@
Advance Payment: {{ advance_description }}
R {{ advance_amount|floatformat:2 }}
+ {% elif is_loan %}
+
+
+ Loan Payment: {{ loan_description }}
+ R {{ loan_amount|floatformat:2 }}
+
{% else %}
diff --git a/core/views.py b/core/views.py
index c85ce56..f6a6848 100644
--- a/core/views.py
+++ b/core/views.py
@@ -1338,18 +1338,27 @@ def _send_payslip_email(request, worker, payroll_record, log_count, logs_amount,
total_amount = payroll_record.amount_paid
- # === DETECT ADVANCE-ONLY PAYMENT ===
- # If the payment has 0 work logs and consists of only an Advance Payment
- # adjustment, use the special advance payslip layout (shows the advance
- # as a positive amount instead of the confusing "0 days + deduction" format).
+ # === DETECT STANDALONE PAYMENT (no work logs, single adjustment) ===
+ # Advance-only or Loan-only payments use a cleaner payslip layout
+ # showing just the amount instead of "0 days worked + adjustment".
advance_adj = None
+ loan_adj = None
if log_count == 0:
adjs_list = list(payroll_record.adjustments.all())
- if len(adjs_list) == 1 and adjs_list[0].type == 'Advance Payment':
- advance_adj = adjs_list[0]
+ if len(adjs_list) == 1:
+ if adjs_list[0].type == 'Advance Payment':
+ advance_adj = adjs_list[0]
+ elif adjs_list[0].type == 'New Loan':
+ loan_adj = adjs_list[0]
is_advance = advance_adj is not None
- subject = f"{'Advance ' if is_advance else ''}Payslip for {worker.name} - {payroll_record.date}"
+ is_loan = loan_adj is not None
+ if is_advance:
+ subject = f"Advance Payslip for {worker.name} - {payroll_record.date}"
+ elif is_loan:
+ subject = f"Loan Payslip for {worker.name} - {payroll_record.date}"
+ else:
+ subject = f"Payslip for {worker.name} - {payroll_record.date}"
# Context for both the HTML email body and the PDF attachment
email_context = {
@@ -1361,6 +1370,9 @@ def _send_payslip_email(request, worker, payroll_record, log_count, logs_amount,
'is_advance': is_advance,
'advance_amount': advance_adj.amount if advance_adj else None,
'advance_description': advance_adj.description if advance_adj else '',
+ 'is_loan': is_loan,
+ 'loan_amount': loan_adj.amount if loan_adj else None,
+ 'loan_description': loan_adj.description if loan_adj else '',
}
# 1. Render HTML email body
@@ -1760,6 +1772,10 @@ def add_adjustment(request):
continue
# === NEW LOAN — create a Loan record (loan_type='loan') ===
+ # If "Pay Immediately" is checked (default), the loan is processed
+ # right away — PayrollRecord is created, payslip emailed to Spark,
+ # and the adjustment is marked as paid. If unchecked, the loan sits
+ # in Pending Payments and is included in the next pay cycle.
if adj_type == 'New Loan':
loan = Loan.objects.create(
worker=worker,
@@ -1770,6 +1786,30 @@ def add_adjustment(request):
reason=description,
)
+ pay_immediately = request.POST.get('pay_immediately') == '1'
+ if pay_immediately:
+ # Create the adjustment and immediately mark it as paid
+ loan_adj = PayrollAdjustment.objects.create(
+ worker=worker,
+ type='New Loan',
+ amount=amount,
+ date=adj_date,
+ description=description,
+ loan=loan,
+ )
+ payroll_record = PayrollRecord.objects.create(
+ worker=worker,
+ amount_paid=amount,
+ date=adj_date,
+ )
+ loan_adj.payroll_record = payroll_record
+ loan_adj.save()
+
+ # Send payslip email to Spark
+ _send_payslip_email(request, worker, payroll_record, 0, Decimal('0.00'))
+ created_count += 1
+ continue # Skip the generic PayrollAdjustment creation below
+
# === ADVANCE PAYMENT — immediate payment + auto-repayment ===
# An advance is a salary prepayment — worker gets money now, and
# the full amount is automatically deducted from their next salary.
@@ -2196,13 +2236,16 @@ def payslip_detail(request, pk):
# Calculate net adjustment amount (additive minus deductive)
adjustments_net = record.amount_paid - base_pay
- # === DETECT ADVANCE-ONLY PAYMENT ===
- # If payment has 0 work logs and a single Advance Payment adjustment,
- # show a cleaner "advance payslip" layout instead of "0 days worked".
+ # === DETECT STANDALONE PAYMENT (no work logs, single adjustment) ===
+ # Advance-only or Loan-only payments use a cleaner layout.
adjs_list = list(adjustments)
advance_adj = None
- if logs.count() == 0 and len(adjs_list) == 1 and adjs_list[0].type == 'Advance Payment':
- advance_adj = adjs_list[0]
+ loan_adj = None
+ if logs.count() == 0 and len(adjs_list) == 1:
+ if adjs_list[0].type == 'Advance Payment':
+ advance_adj = adjs_list[0]
+ elif adjs_list[0].type == 'New Loan':
+ loan_adj = adjs_list[0]
context = {
'record': record,
@@ -2214,6 +2257,8 @@ def payslip_detail(request, pk):
'deductive_types': DEDUCTIVE_TYPES,
'is_advance': advance_adj is not None,
'advance_adj': advance_adj,
+ 'is_loan': loan_adj is not None,
+ 'loan_adj': loan_adj,
}
return render(request, 'core/payslip.html', context)