Add support for invoices

This commit is contained in:
2025-02-10 00:13:15 +01:00
parent 570c00e34f
commit f246656425
11 changed files with 564 additions and 413 deletions

View File

@@ -4,7 +4,8 @@ from ram.admin import publish, unpublish
from repository.models import (
GenericDocument,
InvoiceDocument,
# BaseBookDocument,
BookDocument,
CatalogDocument,
DecoderDocument,
RollingStockDocument
)
@@ -61,23 +62,32 @@ class InvoiceDocumentAdmin(admin.ModelAdmin):
list_display = (
"__str__",
"description",
"date",
"shop",
"size",
"download",
)
search_fields = (
"rolling_stock__manufacturer__name",
"rolling_stock__item_number",
"book__title",
"catalog__manufacturer__name",
"shop__name",
"description",
"file",
)
autocomplete_fields = ("rolling_stock", "book", "catalog")
autocomplete_fields = ("rolling_stock", "book", "catalog", "shop")
fieldsets = (
(
None,
{
"fields": (
"description",
"rolling_stock",
"book",
"catalog",
"description",
"date",
"shop",
"file",
"size",
)
@@ -100,39 +110,72 @@ class InvoiceDocumentAdmin(admin.ModelAdmin):
)
# @admin.register(BaseBookDocument)
# class BookDocumentAdmin(admin.ModelAdmin):
# readonly_fields = ("size",)
# list_display = (
# "__str__",
# # FIXME
# "book__book",
# "book__catalog",
# "description",
# "private",
# "size",
# "download",
# )
# search_fields = (
# "book__title",
# "description",
# "file",
# )
# fieldsets = (
# (
# None,
# {
# "fields": (
# "private",
# # FIXME
# "description",
# "file",
# "size",
# )
# },
# ),
# )
# actions = [publish, unpublish]
@admin.register(BookDocument)
class BookDocumentAdmin(admin.ModelAdmin):
readonly_fields = ("size",)
list_display = (
"__str__",
"book",
"description",
"private",
"size",
"download",
)
search_fields = (
"book__title",
"description",
"file",
)
autocomplete_fields = ("book",)
fieldsets = (
(
None,
{
"fields": (
"private",
"book",
"description",
"file",
"size",
)
},
),
)
actions = [publish, unpublish]
@admin.register(CatalogDocument)
class CatalogDocumentAdmin(admin.ModelAdmin):
readonly_fields = ("size",)
list_display = (
"__str__",
"catalog",
"description",
"private",
"size",
"download",
)
search_fields = (
"catalog__title",
"description",
"file",
)
autocomplete_fields = ("catalog",)
fieldsets = (
(
None,
{
"fields": (
"private",
"catalog",
"description",
"file",
"size",
)
},
),
)
actions = [publish, unpublish]
@admin.register(DecoderDocument)

View File

@@ -53,15 +53,26 @@ def migrate_rollingstock(apps, schema_editor):
def migrate_book(apps, schema_editor):
book_document = apps.get_model("bookshelf", "BaseBookDocument")
book_document_new = apps.get_model("repository", "BaseBookDocument")
catalog_document_new = apps.get_model("repository", "CatalogDocument")
for d in book_document.objects.all():
book_document_new.objects.create(
book=d.book,
description=d.description,
file=d.file,
private=d.private,
creation_time=d.creation_time,
updated_time=d.updated_time,
)
if hasattr(d.book, "book"):
book_document_new.objects.create(
book=d.book.book,
description=d.description,
file=d.file,
private=d.private,
creation_time=d.creation_time,
updated_time=d.updated_time,
)
else:
catalog_document_new.objects.create(
catalog=d.book.catalog,
description=d.description,
file=d.file,
private=d.private,
creation_time=d.creation_time,
updated_time=d.updated_time,
)
class Migration(migrations.Migration):
@@ -115,6 +126,98 @@ class Migration(migrations.Migration):
"abstract": False,
},
),
migrations.CreateModel(
name="BookDocument",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("description", models.CharField(blank=True, max_length=128)),
(
"file",
models.FileField(
storage=ram.utils.DeduplicatedStorage(), upload_to="files/"
),
),
("creation_time", models.DateTimeField(auto_now_add=True)),
("updated_time", models.DateTimeField(auto_now=True)),
(
"private",
models.BooleanField(
default=False,
help_text="Document will be visible only to logged users",
),
),
(
"book",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="document",
to="bookshelf.book",
),
),
],
options={
"verbose_name_plural": "Book documents",
"constraints": [
models.UniqueConstraint(
fields=("book", "file"), name="unique_book_file"
)
],
},
),
migrations.CreateModel(
name="CatalogDocument",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("description", models.CharField(blank=True, max_length=128)),
(
"file",
models.FileField(
storage=ram.utils.DeduplicatedStorage(), upload_to="files/"
),
),
("creation_time", models.DateTimeField(auto_now_add=True)),
("updated_time", models.DateTimeField(auto_now=True)),
(
"private",
models.BooleanField(
default=False,
help_text="Document will be visible only to logged users",
),
),
(
"catalog",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="document",
to="bookshelf.catalog",
),
),
],
options={
"verbose_name_plural": "Catalog documents",
"constraints": [
models.UniqueConstraint(
fields=("catalog", "file"), name="unique_catalog_file"
)
],
},
),
migrations.CreateModel(
name="GenericDocument",
fields=[

View File

@@ -1,80 +0,0 @@
# Generated by Django 5.1.4 on 2025-02-09 13:48
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("bookshelf", "0023_delete_basebookdocument"),
(
"metadata",
"0024_remove_genericdocument_tags_delete_decoderdocument_and_more",
),
("repository", "0001_initial"),
("roster", "0036_delete_rollingstockdocument"),
]
operations = [
migrations.AlterModelOptions(
name="decoderdocument",
options={},
),
migrations.AlterModelOptions(
name="rollingstockdocument",
options={},
),
migrations.AlterField(
model_name="basebookdocument",
name="book",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="document",
to="bookshelf.basebook",
),
),
migrations.AlterField(
model_name="decoderdocument",
name="decoder",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="document",
to="metadata.decoder",
),
),
migrations.AlterField(
model_name="genericdocument",
name="tags",
field=models.ManyToManyField(
blank=True, related_name="document", to="metadata.tag"
),
),
migrations.AlterField(
model_name="rollingstockdocument",
name="rolling_stock",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="document",
to="roster.rollingstock",
),
),
migrations.AddConstraint(
model_name="basebookdocument",
constraint=models.UniqueConstraint(
fields=("book", "file"), name="unique_book_file"
),
),
migrations.AddConstraint(
model_name="decoderdocument",
constraint=models.UniqueConstraint(
fields=("decoder", "file"), name="unique_decoder_file"
),
),
migrations.AddConstraint(
model_name="rollingstockdocument",
constraint=models.UniqueConstraint(
fields=("rolling_stock", "file"), name="unique_stock_file"
),
),
]

View File

@@ -0,0 +1,157 @@
# Generated by Django 5.1.4 on 2025-02-09 23:10
import django.db.models.deletion
import tinymce.models
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("bookshelf", "0023_delete_basebookdocument"),
(
"metadata",
"0024_remove_genericdocument_tags_delete_decoderdocument_and_more",
),
("repository", "0001_initial"),
("roster", "0036_delete_rollingstockdocument"),
]
operations = [
migrations.CreateModel(
name="InvoiceDocument",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("description", models.CharField(blank=True, max_length=128)),
("creation_time", models.DateTimeField(auto_now_add=True)),
("updated_time", models.DateTimeField(auto_now=True)),
("private", models.BooleanField(default=True, editable=False)),
("date", models.DateField()),
("file", models.FileField(upload_to="files/invoices/")),
("notes", tinymce.models.HTMLField(blank=True)),
],
options={
"abstract": False,
},
),
migrations.RemoveField(
model_name="basebookdocument",
name="book",
),
migrations.AlterModelOptions(
name="decoderdocument",
options={},
),
migrations.AlterModelOptions(
name="genericdocument",
options={"verbose_name_plural": "Generic documents"},
),
migrations.AlterModelOptions(
name="rollingstockdocument",
options={},
),
migrations.AlterField(
model_name="bookdocument",
name="file",
field=models.FileField(upload_to="files/"),
),
migrations.AlterField(
model_name="catalogdocument",
name="file",
field=models.FileField(upload_to="files/"),
),
migrations.AlterField(
model_name="decoderdocument",
name="decoder",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="document",
to="metadata.decoder",
),
),
migrations.AlterField(
model_name="decoderdocument",
name="file",
field=models.FileField(upload_to="files/"),
),
migrations.AlterField(
model_name="genericdocument",
name="file",
field=models.FileField(upload_to="files/"),
),
migrations.AlterField(
model_name="genericdocument",
name="tags",
field=models.ManyToManyField(
blank=True, related_name="document", to="metadata.tag"
),
),
migrations.AlterField(
model_name="rollingstockdocument",
name="file",
field=models.FileField(upload_to="files/"),
),
migrations.AlterField(
model_name="rollingstockdocument",
name="rolling_stock",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="document",
to="roster.rollingstock",
),
),
migrations.AddConstraint(
model_name="decoderdocument",
constraint=models.UniqueConstraint(
fields=("decoder", "file"), name="unique_decoder_file"
),
),
migrations.AddConstraint(
model_name="rollingstockdocument",
constraint=models.UniqueConstraint(
fields=("rolling_stock", "file"), name="unique_stock_file"
),
),
migrations.AddField(
model_name="invoicedocument",
name="book",
field=models.ManyToManyField(
blank=True, related_name="invoice", to="bookshelf.book"
),
),
migrations.AddField(
model_name="invoicedocument",
name="catalog",
field=models.ManyToManyField(
blank=True, related_name="invoice", to="bookshelf.catalog"
),
),
migrations.AddField(
model_name="invoicedocument",
name="rolling_stock",
field=models.ManyToManyField(
blank=True, related_name="invoice", to="roster.rollingstock"
),
),
migrations.AddField(
model_name="invoicedocument",
name="shop",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="metadata.shop",
),
),
migrations.DeleteModel(
name="BaseBookDocument",
),
]

View File

@@ -1,66 +0,0 @@
# Generated by Django 5.1.4 on 2025-02-09 15:16
import ram.utils
import tinymce.models
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("bookshelf", "0023_delete_basebookdocument"),
("repository", "0002_alter_decoderdocument_options_and_more"),
("roster", "0036_delete_rollingstockdocument"),
]
operations = [
migrations.AlterModelOptions(
name="basebookdocument",
options={"verbose_name_plural": "Bookshelf Documents"},
),
migrations.AlterModelOptions(
name="genericdocument",
options={"verbose_name_plural": "Generic documents"},
),
migrations.CreateModel(
name="InvoiceDocument",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("description", models.CharField(blank=True, max_length=128)),
(
"file",
models.FileField(
storage=ram.utils.DeduplicatedStorage(), upload_to="files/"
),
),
("creation_time", models.DateTimeField(auto_now_add=True)),
("updated_time", models.DateTimeField(auto_now=True)),
("private", models.BooleanField(default=True, editable=False)),
("notes", tinymce.models.HTMLField(blank=True)),
(
"book",
models.ManyToManyField(
blank=True, related_name="invoice", to="bookshelf.basebook"
),
),
(
"rolling_stock",
models.ManyToManyField(
blank=True, related_name="invoice", to="roster.rollingstock"
),
),
],
options={
"verbose_name": "Invoice",
"verbose_name_plural": "Invoices",
},
),
]

View File

@@ -1,28 +0,0 @@
# Generated by Django 5.1.4 on 2025-02-09 17:42
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("bookshelf", "0023_delete_basebookdocument"),
("repository", "0003_alter_basebookdocument_options_and_more"),
]
operations = [
migrations.AddField(
model_name="invoicedocument",
name="catalog",
field=models.ManyToManyField(
blank=True, related_name="invoice", to="bookshelf.catalog"
),
),
migrations.AlterField(
model_name="invoicedocument",
name="book",
field=models.ManyToManyField(
blank=True, related_name="invoice", to="bookshelf.book"
),
),
]

View File

@@ -1,11 +1,12 @@
from django.db import models
from django.core.exceptions import ValidationError
from tinymce import models as tinymce
from ram.models import PrivateDocument
from metadata.models import Decoder, Tag
from metadata.models import Decoder, Shop, Tag
from roster.models import RollingStock
from bookshelf.models import Book, Catalog, BaseBook
from bookshelf.models import Book, Catalog
class GenericDocument(PrivateDocument):
@@ -19,23 +20,21 @@ class GenericDocument(PrivateDocument):
class InvoiceDocument(PrivateDocument):
private = models.BooleanField(default=True, editable=False)
rolling_stock = models.ManyToManyField(
RollingStock, related_name="invoice",
blank=True
)
book = models.ManyToManyField(
Book, related_name="invoice",
blank=True
RollingStock, related_name="invoice", blank=True
)
book = models.ManyToManyField(Book, related_name="invoice", blank=True)
catalog = models.ManyToManyField(
Catalog, related_name="invoice",
blank=True
Catalog, related_name="invoice", blank=True
)
date = models.DateField()
shop = models.ForeignKey(
Shop, on_delete=models.SET_NULL, null=True, blank=True
)
file = models.FileField(
upload_to="files/invoices/",
)
notes = tinymce.HTMLField(blank=True)
class Meta:
verbose_name = "Invoice"
verbose_name_plural = "Invoices"
class DecoderDocument(PrivateDocument):
decoder = models.ForeignKey(
@@ -45,23 +44,35 @@ class DecoderDocument(PrivateDocument):
class Meta:
constraints = [
models.UniqueConstraint(
fields=["decoder", "file"],
name="unique_decoder_file"
fields=["decoder", "file"], name="unique_decoder_file"
)
]
class BaseBookDocument(PrivateDocument):
class BookDocument(PrivateDocument):
book = models.ForeignKey(
BaseBook, on_delete=models.CASCADE, related_name="document"
Book, on_delete=models.CASCADE, related_name="document"
)
class Meta:
verbose_name_plural = "Bookshelf Documents"
verbose_name_plural = "Book documents"
constraints = [
models.UniqueConstraint(
fields=["book", "file"],
name="unique_book_file"
fields=["book", "file"], name="unique_book_file"
)
]
class CatalogDocument(PrivateDocument):
catalog = models.ForeignKey(
Catalog, on_delete=models.CASCADE, related_name="document"
)
class Meta:
verbose_name_plural = "Catalog documents"
constraints = [
models.UniqueConstraint(
fields=["catalog", "file"], name="unique_catalog_file"
)
]
@@ -74,7 +85,6 @@ class RollingStockDocument(PrivateDocument):
class Meta:
constraints = [
models.UniqueConstraint(
fields=["rolling_stock", "file"],
name="unique_stock_file"
fields=["rolling_stock", "file"], name="unique_stock_file"
)
]