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

@@ -8,7 +8,7 @@ from adminsortable2.admin import SortableAdminBase, SortableInlineAdminMixin
from ram.admin import publish, unpublish from ram.admin import publish, unpublish
from ram.utils import generate_csv from ram.utils import generate_csv
from portal.utils import get_site_conf from portal.utils import get_site_conf
from repository.models import BaseBookDocument from repository.models import BookDocument, CatalogDocument
from bookshelf.models import ( from bookshelf.models import (
BaseBookProperty, BaseBookProperty,
BaseBookImage, BaseBookImage,
@@ -28,13 +28,6 @@ class BookImageInline(SortableInlineAdminMixin, admin.TabularInline):
verbose_name = "Image" verbose_name = "Image"
class BookDocInline(admin.TabularInline):
model = BaseBookDocument
min_num = 0
extra = 0
classes = ["collapse"]
class BookPropertyInline(admin.TabularInline): class BookPropertyInline(admin.TabularInline):
model = BaseBookProperty model = BaseBookProperty
min_num = 0 min_num = 0
@@ -44,6 +37,17 @@ class BookPropertyInline(admin.TabularInline):
verbose_name_plural = "Properties" verbose_name_plural = "Properties"
class BookDocInline(admin.TabularInline):
model = BookDocument
min_num = 0
extra = 0
classes = ["collapse"]
class CatalogDocInline(BookDocInline):
model = CatalogDocument
@admin.register(Book) @admin.register(Book)
class BookAdmin(SortableAdminBase, admin.ModelAdmin): class BookAdmin(SortableAdminBase, admin.ModelAdmin):
inlines = ( inlines = (
@@ -64,53 +68,50 @@ class BookAdmin(SortableAdminBase, admin.ModelAdmin):
search_fields = ("title", "publisher__name", "authors__last_name") search_fields = ("title", "publisher__name", "authors__last_name")
list_filter = ("publisher__name", "authors") list_filter = ("publisher__name", "authors")
def get_fieldsets(self, request, obj=None): fieldsets = (
fieldsets = ( (
( None,
None, {
{ "fields": (
"fields": ( "published",
"published", "title",
"title", "authors",
"authors", "publisher",
"publisher", "ISBN",
"ISBN", "language",
"language", "number_of_pages",
"number_of_pages", "publication_year",
"publication_year", "description",
"description", "tags",
"tags", )
) },
}, ),
), (
( "Purchase data",
"Purchase data", {
{ "fields": (
"fields": ( "shop",
"shop", "purchase_date",
"purchase_date", "price",
"price", "invoices",
) )
}, },
), ),
( (
"Notes", "Notes",
{"classes": ("collapse",), "fields": ("notes",)}, {"classes": ("collapse",), "fields": ("notes",)},
), ),
( (
"Audit", "Audit",
{ {
"classes": ("collapse",), "classes": ("collapse",),
"fields": ( "fields": (
"creation_time", "creation_time",
"updated_time", "updated_time",
), ),
}, },
), ),
) )
if obj and obj.invoice.count() > 0:
fieldsets[1][1]["fields"] += ("invoices",)
return fieldsets
def get_form(self, request, obj=None, **kwargs): def get_form(self, request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs) form = super().get_form(request, obj, **kwargs)
@@ -121,10 +122,13 @@ class BookAdmin(SortableAdminBase, admin.ModelAdmin):
@admin.display(description="Invoices") @admin.display(description="Invoices")
def invoices(self, obj): def invoices(self, obj):
html = "<br>".join( if obj.invoice.exists():
"<a href=\"{}\" target=\"_blank\">{}</a>".format( html = "<br>".join(
i.file.url, i "<a href=\"{}\" target=\"_blank\">{}</a>".format(
) for i in obj.invoice.all()) i.file.url, i
) for i in obj.invoice.all())
else:
html = "-"
return format_html(html) return format_html(html)
@admin.display(description="Publisher") @admin.display(description="Publisher")
@@ -212,7 +216,7 @@ class CatalogAdmin(SortableAdminBase, admin.ModelAdmin):
inlines = ( inlines = (
BookPropertyInline, BookPropertyInline,
BookImageInline, BookImageInline,
BookDocInline, CatalogDocInline,
) )
list_display = ( list_display = (
"__str__", "__str__",
@@ -222,56 +226,54 @@ class CatalogAdmin(SortableAdminBase, admin.ModelAdmin):
"published", "published",
) )
autocomplete_fields = ("manufacturer",) autocomplete_fields = ("manufacturer",)
readonly_fields = ("creation_time", "updated_time") readonly_fields = ("invoices", "creation_time", "updated_time")
search_fields = ("manufacturer__name", "years", "scales__scale") search_fields = ("manufacturer__name", "years", "scales__scale")
list_filter = ("manufacturer__name", "publication_year", "scales__scale") list_filter = ("manufacturer__name", "publication_year", "scales__scale")
def get_fieldsets(self, request, obj=None): fieldsets = (
fieldsets = ( (
( None,
None, {
{ "fields": (
"fields": ( "published",
"published", "manufacturer",
"manufacturer", "years",
"years", "scales",
"scales", "ISBN",
"ISBN", "language",
"language", "number_of_pages",
"number_of_pages", "publication_year",
"publication_year", "description",
"description", "tags",
"tags", )
) },
}, ),
), (
( "Purchase data",
"Purchase data", {
{ "fields": (
"fields": ( "shop",
"purchase_date", "purchase_date",
"price", "price",
) "invoices",
}, )
), },
( ),
"Notes", (
{"classes": ("collapse",), "fields": ("notes",)}, "Notes",
), {"classes": ("collapse",), "fields": ("notes",)},
( ),
"Audit", (
{ "Audit",
"classes": ("collapse",), {
"fields": ( "classes": ("collapse",),
"creation_time", "fields": (
"updated_time", "creation_time",
), "updated_time",
}, ),
), },
) ),
if obj and obj.invoice.count() > 0: )
fieldsets[1][1]["fields"] += ("invoices",)
return fieldsets
def get_form(self, request, obj=None, **kwargs): def get_form(self, request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs) form = super().get_form(request, obj, **kwargs)
@@ -280,6 +282,17 @@ class CatalogAdmin(SortableAdminBase, admin.ModelAdmin):
) )
return form return form
@admin.display(description="Invoices")
def invoices(self, obj):
if obj.invoice.exists():
html = "<br>".join(
"<a href=\"{}\" target=\"_blank\">{}</a>".format(
i.file.url, i
) for i in obj.invoice.all())
else:
html = "-"
return format_html(html)
def download_csv(modeladmin, request, queryset): def download_csv(modeladmin, request, queryset):
header = [ header = [
"Catalog", "Catalog",

View File

@@ -1,4 +1,4 @@
from ram.utils import git_suffix from ram.utils import git_suffix
__version__ = "0.16.9" __version__ = "0.17.0"
__version__ += git_suffix(__file__) __version__ += git_suffix(__file__)

View File

@@ -27,7 +27,6 @@ class Document(models.Model):
description = models.CharField(max_length=128, blank=True) description = models.CharField(max_length=128, blank=True)
file = models.FileField( file = models.FileField(
upload_to="files/", upload_to="files/",
storage=DeduplicatedStorage(),
) )
creation_time = models.DateTimeField(auto_now_add=True) creation_time = models.DateTimeField(auto_now_add=True)
updated_time = models.DateTimeField(auto_now=True) updated_time = models.DateTimeField(auto_now=True)

View File

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

View File

@@ -53,15 +53,26 @@ def migrate_rollingstock(apps, schema_editor):
def migrate_book(apps, schema_editor): def migrate_book(apps, schema_editor):
book_document = apps.get_model("bookshelf", "BaseBookDocument") book_document = apps.get_model("bookshelf", "BaseBookDocument")
book_document_new = apps.get_model("repository", "BaseBookDocument") book_document_new = apps.get_model("repository", "BaseBookDocument")
catalog_document_new = apps.get_model("repository", "CatalogDocument")
for d in book_document.objects.all(): for d in book_document.objects.all():
book_document_new.objects.create( if hasattr(d.book, "book"):
book=d.book, book_document_new.objects.create(
description=d.description, book=d.book.book,
file=d.file, description=d.description,
private=d.private, file=d.file,
creation_time=d.creation_time, private=d.private,
updated_time=d.updated_time, 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): class Migration(migrations.Migration):
@@ -115,6 +126,98 @@ class Migration(migrations.Migration):
"abstract": False, "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( migrations.CreateModel(
name="GenericDocument", name="GenericDocument",
fields=[ 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.db import models
from django.core.exceptions import ValidationError
from tinymce import models as tinymce from tinymce import models as tinymce
from ram.models import PrivateDocument from ram.models import PrivateDocument
from metadata.models import Decoder, Tag from metadata.models import Decoder, Shop, Tag
from roster.models import RollingStock from roster.models import RollingStock
from bookshelf.models import Book, Catalog, BaseBook from bookshelf.models import Book, Catalog
class GenericDocument(PrivateDocument): class GenericDocument(PrivateDocument):
@@ -19,23 +20,21 @@ class GenericDocument(PrivateDocument):
class InvoiceDocument(PrivateDocument): class InvoiceDocument(PrivateDocument):
private = models.BooleanField(default=True, editable=False) private = models.BooleanField(default=True, editable=False)
rolling_stock = models.ManyToManyField( rolling_stock = models.ManyToManyField(
RollingStock, related_name="invoice", RollingStock, related_name="invoice", blank=True
blank=True
)
book = models.ManyToManyField(
Book, related_name="invoice",
blank=True
) )
book = models.ManyToManyField(Book, related_name="invoice", blank=True)
catalog = models.ManyToManyField( catalog = models.ManyToManyField(
Catalog, related_name="invoice", Catalog, related_name="invoice", blank=True
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) notes = tinymce.HTMLField(blank=True)
class Meta:
verbose_name = "Invoice"
verbose_name_plural = "Invoices"
class DecoderDocument(PrivateDocument): class DecoderDocument(PrivateDocument):
decoder = models.ForeignKey( decoder = models.ForeignKey(
@@ -45,23 +44,35 @@ class DecoderDocument(PrivateDocument):
class Meta: class Meta:
constraints = [ constraints = [
models.UniqueConstraint( models.UniqueConstraint(
fields=["decoder", "file"], fields=["decoder", "file"], name="unique_decoder_file"
name="unique_decoder_file"
) )
] ]
class BaseBookDocument(PrivateDocument): class BookDocument(PrivateDocument):
book = models.ForeignKey( book = models.ForeignKey(
BaseBook, on_delete=models.CASCADE, related_name="document" Book, on_delete=models.CASCADE, related_name="document"
) )
class Meta: class Meta:
verbose_name_plural = "Bookshelf Documents" verbose_name_plural = "Book documents"
constraints = [ constraints = [
models.UniqueConstraint( models.UniqueConstraint(
fields=["book", "file"], fields=["book", "file"], name="unique_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: class Meta:
constraints = [ constraints = [
models.UniqueConstraint( models.UniqueConstraint(
fields=["rolling_stock", "file"], fields=["rolling_stock", "file"], name="unique_stock_file"
name="unique_stock_file"
) )
] ]

View File

@@ -152,65 +152,62 @@ class RollingStockAdmin(SortableAdminBase, admin.ModelAdmin):
'<img src="{}" /> {}'.format(obj.country.flag, obj.country) '<img src="{}" /> {}'.format(obj.country.flag, obj.country)
) )
def get_fieldsets(self, request, obj=None): fieldsets = (
fieldsets = ( (
( None,
None, {
{ "fields": (
"fields": ( "preview",
"preview", "published",
"published", "rolling_class",
"rolling_class", "road_number",
"road_number", "scale",
"scale", "manufacturer",
"manufacturer", "item_number",
"item_number", "set",
"set", "era",
"era", "description",
"description", "production_year",
"production_year", "tags",
"tags", )
) },
}, ),
), (
( "DCC",
"DCC", {
{ "fields": (
"fields": ( "decoder_interface",
"decoder_interface", "decoder",
"decoder", "address",
"address", )
) },
}, ),
), (
( "Purchase data",
"Purchase data", {
{ "fields": (
"fields": ( "shop",
"shop", "purchase_date",
"purchase_date", "price",
"price", "invoices",
) )
}, },
), ),
( (
"Notes", "Notes",
{"classes": ("collapse",), "fields": ("notes",)}, {"classes": ("collapse",), "fields": ("notes",)},
), ),
( (
"Audit", "Audit",
{ {
"classes": ("collapse",), "classes": ("collapse",),
"fields": ( "fields": (
"creation_time", "creation_time",
"updated_time", "updated_time",
), ),
}, },
), ),
) )
if obj and obj.invoice.count() > 0:
fieldsets[2][1]["fields"] += ("invoices",)
return fieldsets
def get_form(self, request, obj=None, **kwargs): def get_form(self, request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs) form = super().get_form(request, obj, **kwargs)
@@ -221,10 +218,13 @@ class RollingStockAdmin(SortableAdminBase, admin.ModelAdmin):
@admin.display(description="Invoices") @admin.display(description="Invoices")
def invoices(self, obj): def invoices(self, obj):
html = "<br>".join( if obj.invoice.exists():
"<a href=\"{}\" target=\"_blank\">{}</a>".format( html = "<br>".join(
i.file.url, i "<a href=\"{}\" target=\"_blank\">{}</a>".format(
) for i in obj.invoice.all()) i.file.url, i
) for i in obj.invoice.all())
else:
html = "-"
return format_html(html) return format_html(html)
def download_csv(modeladmin, request, queryset): def download_csv(modeladmin, request, queryset):