mirror of
https://github.com/peter-tanner/money-manager.git
synced 2024-11-30 14:20:17 +08:00
147 lines
4.2 KiB
Python
147 lines
4.2 KiB
Python
from datetime import datetime, timedelta
|
|
from django.db import models
|
|
from django.utils import timezone
|
|
from djmoney.models.fields import MoneyField, Money
|
|
from .deletable_model import DeletableModel
|
|
from util import truncate_string # new line
|
|
from django.db.models import Q
|
|
|
|
# class ExpenseManager(models.Manager):
|
|
# def active(self):
|
|
# return self.filter(deleted=False)
|
|
|
|
# # Soft delete only!
|
|
# def delete_model(self, request, obj):
|
|
# obj.deleted = True
|
|
# obj.save()
|
|
|
|
# def get_actions(self, request):
|
|
# actions = super().get_actions(request)
|
|
# # Remove the default delete action from the actions list
|
|
# del actions["delete_selected"]
|
|
# return actions
|
|
|
|
# def soft_delete_selected(self, request, queryset):
|
|
# # Mark selected entries as deleted (soft delete)
|
|
# queryset.update(deleted=True)
|
|
|
|
# soft_delete_selected.short_description = "Soft delete selected entries"
|
|
|
|
# actions = [soft_delete_selected]
|
|
|
|
|
|
class TimesheetRate(DeletableModel):
|
|
rate = MoneyField(
|
|
decimal_places=3,
|
|
default=0.000,
|
|
default_currency="AUD",
|
|
max_digits=11,
|
|
)
|
|
description = models.TextField(blank=True)
|
|
default_rate = models.BooleanField(default=False)
|
|
|
|
def __str__(self):
|
|
return f"{self.rate} {truncate_string(self.description,8)}"
|
|
|
|
def save(self, *args, **kwargs):
|
|
# Ensure that only one entry can be marked as a favorite
|
|
if self.default_rate:
|
|
TimesheetRate.objects.filter(~Q(pk=self.pk)).update(default_rate=False)
|
|
super().save(*args, **kwargs)
|
|
|
|
|
|
class Timesheet(DeletableModel):
|
|
shift_start = models.DateTimeField(null=True, blank=True)
|
|
shift_end = models.DateTimeField(null=True, blank=True)
|
|
break_start = models.DateTimeField(null=True, blank=True)
|
|
break_end = models.DateTimeField(null=True, blank=True)
|
|
submitted = models.DateTimeField(null=True, blank=True)
|
|
rate = models.ForeignKey(
|
|
TimesheetRate,
|
|
on_delete=models.SET_NULL,
|
|
null=True,
|
|
blank=True,
|
|
related_name="timesheets",
|
|
)
|
|
|
|
@property
|
|
def shift_hours(self) -> timedelta:
|
|
if self.shift_start and self.shift_end:
|
|
return self.shift_end - self.shift_start
|
|
return timedelta(0)
|
|
|
|
@property
|
|
def break_hours(self) -> timedelta:
|
|
if self.break_start and self.break_end:
|
|
return self.break_end - self.break_start
|
|
return timedelta(0)
|
|
|
|
@property
|
|
def worked_hours(self) -> timedelta:
|
|
return self.shift_hours - self.break_hours
|
|
|
|
@property
|
|
def worked_decimal(self) -> str:
|
|
return f"{self.worked_hours.total_seconds() / 60.0 / 60:.4f}"
|
|
|
|
@property
|
|
def total(self) -> Money:
|
|
hours = self.worked_hours.total_seconds() / 60.0 / 60
|
|
return hours * self.rate.rate
|
|
|
|
def _rules(self):
|
|
hours = self.worked_hours.total_seconds() / 60.0 / 60
|
|
return hours > 3 and hours <= 7.5
|
|
|
|
_rules.boolean = True
|
|
rules = property(_rules)
|
|
|
|
def __str__(self):
|
|
return f"{self.shift_start} to {self.shift_end}"
|
|
|
|
|
|
class ExpenseCategory(DeletableModel):
|
|
name = models.TextField(blank=True)
|
|
description = models.TextField(blank=True)
|
|
|
|
def __str__(self):
|
|
return truncate_string(self.name, 48)
|
|
|
|
|
|
class Vendor(DeletableModel):
|
|
name = models.TextField(blank=True)
|
|
description = models.TextField(blank=True)
|
|
|
|
def __str__(self):
|
|
return truncate_string(self.name, 48)
|
|
|
|
|
|
class Expense(DeletableModel):
|
|
price = MoneyField(
|
|
decimal_places=3,
|
|
default=0.000,
|
|
default_currency="AUD",
|
|
max_digits=11,
|
|
)
|
|
date = models.DateField()
|
|
description = models.TextField(blank=True)
|
|
vendor = models.ForeignKey(
|
|
Vendor,
|
|
on_delete=models.SET_NULL,
|
|
null=True,
|
|
blank=True,
|
|
related_name="expenses",
|
|
)
|
|
receipt = models.FileField(upload_to="receipts/", blank=True)
|
|
link = models.URLField(blank=True)
|
|
category = models.ForeignKey(
|
|
ExpenseCategory,
|
|
on_delete=models.SET_NULL,
|
|
null=True,
|
|
blank=True,
|
|
related_name="expenses",
|
|
)
|
|
|
|
def __str__(self):
|
|
return f"{self.date} {self.price} {truncate_string(self.description,32)}"
|