Redirect / -> /admin/, better random color function

This commit is contained in:
Peter 2023-10-03 21:59:00 +08:00
parent 33c3e42864
commit 0a5c93a3c4
7 changed files with 143 additions and 30 deletions

5
.gitignore vendored
View File

@ -1,3 +1,8 @@
# nah i don't think i want you to have my receipts thanks...
receipts/
receipts/*
etc/
test.py
localhost_config.py

View File

@ -17,11 +17,12 @@ Including another URLconf
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import include, path
from django.urls import include, path, reverse_lazy
from expenses.models import Expense, Timesheet
from django.views.generic.base import RedirectView
urlpatterns = [
path("", RedirectView.as_view(url=reverse_lazy("admin:index"))),
path("admin/expenses/", include("expenses.admin_urls")),
path("admin/summary/", include("summary.urls")),
path("admin/", admin.site.urls),

View File

@ -1,21 +1,13 @@
from datetime import datetime, timedelta
import random
from typing import Any, Dict
from datetime import datetime
import distinctipy
from django.contrib import admin
from django.contrib.admin.options import ModelAdmin
from django.core.handlers.wsgi import WSGIRequest
from django.db.models.base import Model
from django.db.models.fields import Field
from django.forms import DecimalField, TextInput, NumberInput
from django.db import models
from util import next_payday
from util import next_payday, rgb_tuple_to_hex
from .admin_base import AdminBase, DeletedListFilter, DeletableAdminForm
from .models import Expense, ExpenseCategory, Timesheet, TimesheetRate
from .models import Expense, ExpenseCategory, Timesheet, TimesheetRate, Vendor
from django import forms
from django.utils import timezone
from django.contrib.admin.widgets import AdminDateWidget, AdminSplitDateTime
from import_export import resources
from import_export.admin import ImportExportModelAdmin
from admincharts.admin import AdminChartMixin
@ -23,6 +15,22 @@ from admincharts.utils import months_between_dates
from djmoney.contrib.exchange.models import convert_money
class VendorAdminForm(DeletableAdminForm):
class Meta:
model = Vendor
fields = "__all__"
@admin.register(Vendor)
class VendorAdmin(AdminBase):
list_display = (
"name",
"description",
)
search_fields = ("name",)
form = VendorAdminForm
class TimesheetRateAdminForm(DeletableAdminForm):
class Meta:
model = TimesheetRate
@ -169,8 +177,9 @@ class ExpenseAdminForm(DeletableAdminForm):
class ExpenseAdmin(AdminBase, AdminChartMixin, ImportExportModelAdmin):
form = ExpenseAdminForm
list_display = ("date", "price", "description", "category")
list_filter = ("date", ("deleted", DeletedListFilter), "category")
autocomplete_fields = ("vendor", "category")
list_display = ("date", "price", "description", "category", "vendor")
list_filter = ("date", ("deleted", DeletedListFilter), "category", "vendor")
ordering = ("-date", "-deleted")
readonly_fields = ("deleted",)
@ -197,14 +206,22 @@ class ExpenseAdmin(AdminBase, AdminChartMixin, ImportExportModelAdmin):
labels = []
totals = []
expenses_total = []
expenses = {
k: {
"label": k,
"data": [],
"backgroundColor": f"#{random.Random(x=1).randrange(0x1000000):06x}",
}
for k in set([x.category.name for x in queryset])
}
expense_types = set([x.category.name for x in queryset])
colors = distinctipy.get_colors(len(expense_types), pastel_factor=0.2, rng=69)
expenses = {}
i = 0
for k in expense_types:
expenses.update(
{
k: {
"label": k,
"data": [],
"backgroundColor": rgb_tuple_to_hex(colors[i]),
}
}
)
i += 1
for b in months_between_dates(earliest, timezone.now().date()):
labels.append(b.strftime("%b %Y"))
totals.append(
@ -213,7 +230,7 @@ class ExpenseAdmin(AdminBase, AdminChartMixin, ImportExportModelAdmin):
convert_money(x.total, "AUD").amount
for x in timesheets
if x.shift_start.year == b.year
and x.shift_start.month == b.month
and x.shift_start.month == b.month # noqa
]
)
)
@ -241,10 +258,10 @@ class ExpenseAdmin(AdminBase, AdminChartMixin, ImportExportModelAdmin):
"backgroundColor": "#865137",
},
]
+ list(expenses.values()),
+ list(expenses.values()), # noqa
}
@admin.register(ExpenseCategory)
class ExpenseCategoryAdmin(AdminBase):
pass
search_fields = ("name",)

View File

@ -0,0 +1,68 @@
# Generated by Django 4.2.5 on 2023-09-21 04:31
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', '0003_remove_expensecategory_default_rate_and_more'),
]
operations = [
migrations.CreateModel(
name='Vendor',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('deleted', models.BooleanField(default=False)),
('name', models.TextField(blank=True)),
('description', models.TextField(blank=True)),
],
options={
'abstract': False,
},
),
migrations.RemoveField(
model_name='expense',
name='merchant',
),
migrations.RemoveField(
model_name='historicalexpense',
name='merchant',
),
migrations.CreateModel(
name='HistoricalVendor',
fields=[
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
('deleted', models.BooleanField(default=False)),
('name', models.TextField(blank=True)),
('description', 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 vendor',
'verbose_name_plural': 'historical vendors',
'ordering': ('-history_date', '-history_id'),
'get_latest_by': ('history_date', 'history_id'),
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
migrations.AddField(
model_name='expense',
name='vendor',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='expenses', to='expenses.vendor'),
),
migrations.AddField(
model_name='historicalexpense',
name='vendor',
field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='expenses.vendor'),
),
]

View File

@ -108,6 +108,14 @@ class ExpenseCategory(DeletableModel):
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,
@ -117,7 +125,13 @@ class Expense(DeletableModel):
)
date = models.DateField()
description = models.TextField(blank=True)
merchant = models.CharField(max_length=255, 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(

View File

@ -3,15 +3,15 @@ Babel==2.12.1
backports.zoneinfo==0.2.1
defusedxml==0.7.1
diff-match-patch==20230430
distinctipy==1.2.3
Django==4.2.5
django-admincharts==0.4.1
django-computedfields==0.2.3
django-fast-update==0.2.3
django-import-export==3.3.1
django-money==3.2.0
django-simple-history==3.4.0
et-xmlfile==1.1.0
MarkupPy==1.14
numpy==1.24.4
odfpy==1.4.1
openpyxl==3.1.2
pip-autoremove==0.10.0

View File

@ -33,3 +33,11 @@ def next_payday(day=datetime.now()) -> datetime:
next_payday -= timedelta(days=1)
return next_payday
def rgb_tuple_to_hex(rgb_tuple):
# Ensure the values are within the valid range
color = [min(max(0, x), 1) for x in rgb_tuple]
color = [format(int(x * 255), "02x") for x in color]
rgb_hex = f"#{color[0]}{color[1]}{color[2]}"
return rgb_hex