logs system

This commit is contained in:
Peter 2023-10-08 18:01:23 +08:00
parent 07c0f40b05
commit 33eb31f86e
10 changed files with 232 additions and 3 deletions

3
.gitignore vendored
View File

@ -1,12 +1,13 @@
# nah i don't think i want you to have my receipts thanks... # nah i don't think i want you to have my receipts thanks...
receipts/ receipts/
receipts/* receipts/*
db_backup/
etc/ etc/
test.py test.py
localhost_config.py localhost_config.py
static/ /static/
# Byte-compiled / optimized / DLL files # Byte-compiled / optimized / DLL files

View File

@ -10,6 +10,7 @@ For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/ https://docs.djangoproject.com/en/4.2/ref/settings/
""" """
import os
from import_export.formats.base_formats import CSV, XLSX from import_export.formats.base_formats import CSV, XLSX
from pathlib import Path from pathlib import Path
@ -135,3 +136,5 @@ STATIC_URL = "static/"
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")

View File

@ -5,7 +5,7 @@ from django.contrib import admin
from util import next_payday, rgb_tuple_to_hex from util import next_payday, rgb_tuple_to_hex
from .admin_base import AdminBase, DeletedListFilter, DeletableAdminForm from .admin_base import AdminBase, DeletedListFilter, DeletableAdminForm
from .models import Expense, ExpenseCategory, Timesheet, TimesheetRate, Vendor from .models import Log, Expense, ExpenseCategory, Timesheet, TimesheetRate, Vendor
from django import forms from django import forms
from django.utils import timezone from django.utils import timezone
from import_export import resources from import_export import resources
@ -13,6 +13,38 @@ from import_export.admin import ImportExportModelAdmin
from admincharts.admin import AdminChartMixin from admincharts.admin import AdminChartMixin
from admincharts.utils import months_between_dates from admincharts.utils import months_between_dates
from djmoney.contrib.exchange.models import convert_money from djmoney.contrib.exchange.models import convert_money
from django.utils.html import format_html
class LogsAdminForm(DeletableAdminForm):
class Meta:
model = Log
fields = "__all__"
@admin.register(Log)
class LogsAdmin(AdminBase):
class Media:
css = {"all": ("/static/logs.css",)}
def truncated_title(self, instance):
return f"{instance.title[:2]}...{instance.title[-1:]}"
list_display = (
"title",
"truncated_title",
"date",
"goodness_value",
)
list_display_links = (
"title",
"truncated_title",
)
search_fields = (
"title",
"date",
)
form = LogsAdminForm
class VendorAdminForm(DeletableAdminForm): class VendorAdminForm(DeletableAdminForm):

View File

@ -0,0 +1,23 @@
# Generated by Django 4.2.5 on 2023-10-04 10:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('expenses', '0004_vendor_remove_expense_merchant_and_more'),
]
operations = [
migrations.AddField(
model_name='expense',
name='cash',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='historicalexpense',
name='cash',
field=models.BooleanField(default=False),
),
]

View File

@ -0,0 +1,52 @@
# Generated by Django 4.2.5 on 2023-10-06 13:43
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import simple_history.models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('expenses', '0005_expense_cash_historicalexpense_cash'),
]
operations = [
migrations.CreateModel(
name='Logs',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('deleted', models.BooleanField(default=False)),
('title', models.TextField(blank=True)),
('date', models.DateTimeField(blank=True, null=True)),
('information', models.TextField(blank=True)),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='HistoricalLogs',
fields=[
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
('deleted', models.BooleanField(default=False)),
('title', models.TextField(blank=True)),
('date', models.DateTimeField(blank=True, null=True)),
('information', models.TextField(blank=True)),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField(db_index=True)),
('history_change_reason', models.CharField(max_length=100, null=True)),
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'historical logs',
'verbose_name_plural': 'historical logss',
'ordering': ('-history_date', '-history_id'),
'get_latest_by': ('history_date', 'history_id'),
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 4.2.5 on 2023-10-06 13:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('expenses', '0006_logs_historicallogs'),
]
operations = [
migrations.AlterField(
model_name='historicallogs',
name='title',
field=models.CharField(blank=True, max_length=256),
),
migrations.AlterField(
model_name='logs',
name='title',
field=models.CharField(blank=True, max_length=256),
),
]

View File

@ -0,0 +1,27 @@
# Generated by Django 4.2.5 on 2023-10-06 13:49
from django.conf import settings
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('expenses', '0007_alter_historicallogs_title_alter_logs_title'),
]
operations = [
migrations.RenameModel(
old_name='HistoricalLogs',
new_name='HistoricalLog',
),
migrations.RenameModel(
old_name='Logs',
new_name='Log',
),
migrations.AlterModelOptions(
name='historicallog',
options={'get_latest_by': ('history_date', 'history_id'), 'ordering': ('-history_date', '-history_id'), 'verbose_name': 'historical log', 'verbose_name_plural': 'historical logs'},
),
]

View File

@ -0,0 +1,28 @@
# Generated by Django 4.2.5 on 2023-10-08 09:55
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('expenses', '0008_rename_historicallogs_historicallog_rename_logs_log_and_more'),
]
operations = [
migrations.AddField(
model_name='historicallog',
name='goodness_value',
field=models.FloatField(default=0.0, validators=[django.core.validators.MinValueValidator(-10.0), django.core.validators.MaxValueValidator(10.0)]),
),
migrations.AddField(
model_name='log',
name='goodness_value',
field=models.FloatField(default=0.0, validators=[django.core.validators.MinValueValidator(-10.0), django.core.validators.MaxValueValidator(10.0)]),
),
migrations.AddConstraint(
model_name='log',
constraint=models.CheckConstraint(check=models.Q(('goodness_value__gte', -10.0), ('goodness_value__lte', 10.0)), name='log_goodness_value_range'),
),
]

View File

@ -4,7 +4,8 @@ from django.utils import timezone
from djmoney.models.fields import MoneyField, Money from djmoney.models.fields import MoneyField, Money
from .deletable_model import DeletableModel from .deletable_model import DeletableModel
from util import truncate_string # new line from util import truncate_string # new line
from django.db.models import Q from django.db.models import Q, CheckConstraint
from django.core.validators import MaxValueValidator, MinValueValidator
# class ExpenseManager(models.Manager): # class ExpenseManager(models.Manager):
# def active(self): # def active(self):
@ -30,6 +31,32 @@ from django.db.models import Q
# actions = [soft_delete_selected] # actions = [soft_delete_selected]
class Log(DeletableModel):
# TODO: Use Markdown formatting!
title = models.CharField(max_length=256, blank=True)
date = models.DateTimeField(null=True, blank=True)
goodness_value = models.FloatField(
default=0.0,
validators=(
MinValueValidator(-10.0),
MaxValueValidator(10.0),
),
)
information = models.TextField(blank=True)
def __str__(self):
return f"{self.date}: {self.title}"
class Meta:
constraints = (
# for checking in the DB
CheckConstraint(
check=Q(goodness_value__gte=-10.0) & Q(goodness_value__lte=10.0),
name="log_goodness_value_range",
),
)
class TimesheetRate(DeletableModel): class TimesheetRate(DeletableModel):
rate = MoneyField( rate = MoneyField(
decimal_places=3, decimal_places=3,
@ -141,6 +168,7 @@ class Expense(DeletableModel):
blank=True, blank=True,
related_name="expenses", related_name="expenses",
) )
cash = models.BooleanField(default=False)
def __str__(self): def __str__(self):
return f"{self.date} {self.price} {truncate_string(self.description,32)}" return f"{self.date} {self.price} {truncate_string(self.description,32)}"

12
expenses/static/logs.css Normal file
View File

@ -0,0 +1,12 @@
/* Hide title of log when mouse is not hovering over it for privacy */
.field-title:not(:hover) > a {
color: transparent;
text-decoration: none;
cursor: pointer;
}
.field-goodness_value:not(:hover) {
color: transparent;
text-decoration: none;
cursor: pointer;
}