Ver 14.06 Overtime working
This commit is contained in:
parent
bb49956693
commit
f3ada22ab3
Binary file not shown.
Binary file not shown.
19
core/migrations/0015_payrolladjustment_work_log.py
Normal file
19
core/migrations/0015_payrolladjustment_work_log.py
Normal file
@ -0,0 +1,19 @@
|
||||
# Generated by Django 5.2.7 on 2026-02-10 11:11
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0014_remove_worklog_overtime_priced_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='payrolladjustment',
|
||||
name='work_log',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='adjustments', to='core.worklog'),
|
||||
),
|
||||
]
|
||||
Binary file not shown.
@ -145,6 +145,9 @@ class PayrollAdjustment(models.Model):
|
||||
worker = models.ForeignKey(Worker, on_delete=models.CASCADE, related_name='adjustments')
|
||||
payroll_record = models.ForeignKey(PayrollRecord, on_delete=models.SET_NULL, null=True, blank=True, related_name='adjustments')
|
||||
loan = models.ForeignKey(Loan, on_delete=models.SET_NULL, null=True, blank=True, related_name='repayments')
|
||||
# Link back to WorkLog to track Project/Team context for Overtime
|
||||
work_log = models.ForeignKey(WorkLog, on_delete=models.SET_NULL, null=True, blank=True, related_name='adjustments')
|
||||
|
||||
amount = models.DecimalField(max_digits=10, decimal_places=2, help_text="Positive adds to pay, negative subtracts (except for Loan Repayment which is auto-handled)")
|
||||
date = models.DateField(default=timezone.now)
|
||||
description = models.CharField(max_length=255)
|
||||
|
||||
@ -63,10 +63,23 @@ def home(request):
|
||||
|
||||
if user_is_admin:
|
||||
# 1. Outstanding Payments
|
||||
active_workers = Worker.objects.filter(is_active=True)
|
||||
active_workers = Worker.objects.filter(is_active=True).prefetch_related('work_logs', 'adjustments')
|
||||
for worker in active_workers:
|
||||
# Unpaid logs
|
||||
unpaid_logs_count = worker.work_logs.exclude(paid_in__worker=worker).count()
|
||||
outstanding_total += unpaid_logs_count * worker.day_rate
|
||||
log_amount = unpaid_logs_count * worker.day_rate
|
||||
|
||||
# Pending Adjustments
|
||||
pending_adjustments = worker.adjustments.filter(payroll_record__isnull=True)
|
||||
adj_total = Decimal('0.00')
|
||||
for adj in pending_adjustments:
|
||||
if adj.type in ['BONUS', 'OVERTIME', 'LOAN']:
|
||||
adj_total += adj.amount
|
||||
elif adj.type in ['DEDUCTION', 'LOAN_REPAYMENT']:
|
||||
adj_total -= adj.amount
|
||||
|
||||
total_payable = log_amount + adj_total
|
||||
outstanding_total += max(total_payable, Decimal('0.00'))
|
||||
|
||||
# 2. Paid This Month
|
||||
recent_payments_total = PayrollRecord.objects.filter(
|
||||
@ -298,18 +311,18 @@ def work_log_list(request):
|
||||
logs = logs.filter(paid_in__isnull=True)
|
||||
|
||||
# --- 2. Fetch Adjustments ---
|
||||
# Adjustments are shown unless a Project/Team filter is active (as they don't belong to projects/teams),
|
||||
# OR if a specific worker is selected (then we always show their adjustments).
|
||||
show_adjustments = True
|
||||
if (project_id or team_id) and not worker_id:
|
||||
show_adjustments = False
|
||||
adjustments = PayrollAdjustment.objects.all().select_related('worker', 'payroll_record', 'work_log')
|
||||
|
||||
adjustments = PayrollAdjustment.objects.none()
|
||||
if show_adjustments:
|
||||
adjustments = PayrollAdjustment.objects.all().select_related('worker', 'payroll_record')
|
||||
if worker_id:
|
||||
adjustments = adjustments.filter(worker_id=worker_id)
|
||||
|
||||
if project_id:
|
||||
# Include only adjustments linked to this project (via work_log)
|
||||
adjustments = adjustments.filter(work_log__project_id=project_id)
|
||||
|
||||
if team_id:
|
||||
adjustments = adjustments.filter(work_log__team_id=team_id)
|
||||
|
||||
if payment_status == 'paid':
|
||||
adjustments = adjustments.filter(payroll_record__isnull=False)
|
||||
elif payment_status == 'unpaid':
|
||||
@ -338,7 +351,7 @@ def work_log_list(request):
|
||||
end_date = datetime.date(curr_year, curr_month, num_days)
|
||||
|
||||
logs = logs.filter(date__range=(start_date, end_date))
|
||||
if show_adjustments:
|
||||
# No 'show_adjustments' check needed as query is already filtered
|
||||
adjustments = adjustments.filter(date__range=(start_date, end_date))
|
||||
|
||||
# --- 4. Combine and Sort ---
|
||||
@ -376,7 +389,6 @@ def work_log_list(request):
|
||||
combined_records.append(record)
|
||||
|
||||
# Process Adjustments
|
||||
if show_adjustments:
|
||||
for adj in adjustments:
|
||||
# Determine signed amount for display/total
|
||||
amt = adj.amount
|
||||
@ -522,20 +534,23 @@ def export_work_log_csv(request):
|
||||
logs = logs.filter(paid_in__isnull=True)
|
||||
|
||||
# --- 2. Fetch Adjustments ---
|
||||
show_adjustments = True
|
||||
if (project_id or team_id) and not worker_id:
|
||||
show_adjustments = False
|
||||
adjustments = PayrollAdjustment.objects.all().select_related('worker', 'payroll_record', 'work_log')
|
||||
|
||||
adjustments = []
|
||||
if show_adjustments:
|
||||
qs = PayrollAdjustment.objects.all().select_related('worker', 'payroll_record')
|
||||
if worker_id:
|
||||
qs = qs.filter(worker_id=worker_id)
|
||||
adjustments = adjustments.filter(worker_id=worker_id)
|
||||
|
||||
if project_id:
|
||||
adjustments = adjustments.filter(work_log__project_id=project_id)
|
||||
|
||||
if team_id:
|
||||
adjustments = adjustments.filter(work_log__team_id=team_id)
|
||||
|
||||
if payment_status == 'paid':
|
||||
qs = qs.filter(payroll_record__isnull=False)
|
||||
adjustments = adjustments.filter(payroll_record__isnull=False)
|
||||
elif payment_status == 'unpaid':
|
||||
qs = qs.filter(payroll_record__isnull=True)
|
||||
adjustments = list(qs)
|
||||
adjustments = adjustments.filter(payroll_record__isnull=True)
|
||||
|
||||
adjustments = list(adjustments)
|
||||
|
||||
user_is_admin = is_admin(request.user)
|
||||
|
||||
@ -982,7 +997,8 @@ def price_overtime(request):
|
||||
type='OVERTIME',
|
||||
amount=amount,
|
||||
date=worklog.date,
|
||||
description=f"Overtime: {worklog.get_overtime_display()} @ {rate_pct}% - {worklog.date.strftime('%d %b %Y')}"
|
||||
description=f"Overtime: {worklog.get_overtime_display()} @ {rate_pct}% - {worklog.date.strftime('%d %b %Y')}",
|
||||
work_log=worklog
|
||||
)
|
||||
created += 1
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user