diff --git a/ram/bookshelf/admin.py b/ram/bookshelf/admin.py
index 9d0bcd1..0e8a88b 100644
--- a/ram/bookshelf/admin.py
+++ b/ram/bookshelf/admin.py
@@ -8,7 +8,7 @@ from adminsortable2.admin import SortableAdminBase, SortableInlineAdminMixin
from ram.admin import publish, unpublish
from ram.utils import generate_csv
from portal.utils import get_site_conf
-from repository.models import BaseBookDocument
+from repository.models import BookDocument, CatalogDocument
from bookshelf.models import (
BaseBookProperty,
BaseBookImage,
@@ -28,13 +28,6 @@ class BookImageInline(SortableInlineAdminMixin, admin.TabularInline):
verbose_name = "Image"
-class BookDocInline(admin.TabularInline):
- model = BaseBookDocument
- min_num = 0
- extra = 0
- classes = ["collapse"]
-
-
class BookPropertyInline(admin.TabularInline):
model = BaseBookProperty
min_num = 0
@@ -44,6 +37,17 @@ class BookPropertyInline(admin.TabularInline):
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)
class BookAdmin(SortableAdminBase, admin.ModelAdmin):
inlines = (
@@ -64,53 +68,50 @@ class BookAdmin(SortableAdminBase, admin.ModelAdmin):
search_fields = ("title", "publisher__name", "authors__last_name")
list_filter = ("publisher__name", "authors")
- def get_fieldsets(self, request, obj=None):
- fieldsets = (
- (
- None,
- {
- "fields": (
- "published",
- "title",
- "authors",
- "publisher",
- "ISBN",
- "language",
- "number_of_pages",
- "publication_year",
- "description",
- "tags",
- )
- },
- ),
- (
- "Purchase data",
- {
- "fields": (
- "shop",
- "purchase_date",
- "price",
- )
- },
- ),
- (
- "Notes",
- {"classes": ("collapse",), "fields": ("notes",)},
- ),
- (
- "Audit",
- {
- "classes": ("collapse",),
- "fields": (
- "creation_time",
- "updated_time",
- ),
- },
- ),
- )
- if obj and obj.invoice.count() > 0:
- fieldsets[1][1]["fields"] += ("invoices",)
- return fieldsets
+ fieldsets = (
+ (
+ None,
+ {
+ "fields": (
+ "published",
+ "title",
+ "authors",
+ "publisher",
+ "ISBN",
+ "language",
+ "number_of_pages",
+ "publication_year",
+ "description",
+ "tags",
+ )
+ },
+ ),
+ (
+ "Purchase data",
+ {
+ "fields": (
+ "shop",
+ "purchase_date",
+ "price",
+ "invoices",
+ )
+ },
+ ),
+ (
+ "Notes",
+ {"classes": ("collapse",), "fields": ("notes",)},
+ ),
+ (
+ "Audit",
+ {
+ "classes": ("collapse",),
+ "fields": (
+ "creation_time",
+ "updated_time",
+ ),
+ },
+ ),
+ )
def get_form(self, request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs)
@@ -121,10 +122,13 @@ class BookAdmin(SortableAdminBase, admin.ModelAdmin):
@admin.display(description="Invoices")
def invoices(self, obj):
- html = "
".join(
- "{}".format(
- i.file.url, i
- ) for i in obj.invoice.all())
+ if obj.invoice.exists():
+ html = "
".join(
+ "{}".format(
+ i.file.url, i
+ ) for i in obj.invoice.all())
+ else:
+ html = "-"
return format_html(html)
@admin.display(description="Publisher")
@@ -212,7 +216,7 @@ class CatalogAdmin(SortableAdminBase, admin.ModelAdmin):
inlines = (
BookPropertyInline,
BookImageInline,
- BookDocInline,
+ CatalogDocInline,
)
list_display = (
"__str__",
@@ -222,56 +226,54 @@ class CatalogAdmin(SortableAdminBase, admin.ModelAdmin):
"published",
)
autocomplete_fields = ("manufacturer",)
- readonly_fields = ("creation_time", "updated_time")
+ readonly_fields = ("invoices", "creation_time", "updated_time")
search_fields = ("manufacturer__name", "years", "scales__scale")
list_filter = ("manufacturer__name", "publication_year", "scales__scale")
- def get_fieldsets(self, request, obj=None):
- fieldsets = (
- (
- None,
- {
- "fields": (
- "published",
- "manufacturer",
- "years",
- "scales",
- "ISBN",
- "language",
- "number_of_pages",
- "publication_year",
- "description",
- "tags",
- )
- },
- ),
- (
- "Purchase data",
- {
- "fields": (
- "purchase_date",
- "price",
- )
- },
- ),
- (
- "Notes",
- {"classes": ("collapse",), "fields": ("notes",)},
- ),
- (
- "Audit",
- {
- "classes": ("collapse",),
- "fields": (
- "creation_time",
- "updated_time",
- ),
- },
- ),
- )
- if obj and obj.invoice.count() > 0:
- fieldsets[1][1]["fields"] += ("invoices",)
- return fieldsets
+ fieldsets = (
+ (
+ None,
+ {
+ "fields": (
+ "published",
+ "manufacturer",
+ "years",
+ "scales",
+ "ISBN",
+ "language",
+ "number_of_pages",
+ "publication_year",
+ "description",
+ "tags",
+ )
+ },
+ ),
+ (
+ "Purchase data",
+ {
+ "fields": (
+ "shop",
+ "purchase_date",
+ "price",
+ "invoices",
+ )
+ },
+ ),
+ (
+ "Notes",
+ {"classes": ("collapse",), "fields": ("notes",)},
+ ),
+ (
+ "Audit",
+ {
+ "classes": ("collapse",),
+ "fields": (
+ "creation_time",
+ "updated_time",
+ ),
+ },
+ ),
+ )
def get_form(self, request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs)
@@ -280,6 +282,17 @@ class CatalogAdmin(SortableAdminBase, admin.ModelAdmin):
)
return form
+ @admin.display(description="Invoices")
+ def invoices(self, obj):
+ if obj.invoice.exists():
+ html = "
".join(
+ "{}".format(
+ i.file.url, i
+ ) for i in obj.invoice.all())
+ else:
+ html = "-"
+ return format_html(html)
+
def download_csv(modeladmin, request, queryset):
header = [
"Catalog",
diff --git a/ram/ram/__init__.py b/ram/ram/__init__.py
index ec8f297..909b501 100644
--- a/ram/ram/__init__.py
+++ b/ram/ram/__init__.py
@@ -1,4 +1,4 @@
from ram.utils import git_suffix
-__version__ = "0.16.9"
+__version__ = "0.17.0"
__version__ += git_suffix(__file__)
diff --git a/ram/ram/models.py b/ram/ram/models.py
index f389de3..ed71aac 100644
--- a/ram/ram/models.py
+++ b/ram/ram/models.py
@@ -27,7 +27,6 @@ class Document(models.Model):
description = models.CharField(max_length=128, blank=True)
file = models.FileField(
upload_to="files/",
- storage=DeduplicatedStorage(),
)
creation_time = models.DateTimeField(auto_now_add=True)
updated_time = models.DateTimeField(auto_now=True)
diff --git a/ram/repository/admin.py b/ram/repository/admin.py
index c65bb54..546e311 100644
--- a/ram/repository/admin.py
+++ b/ram/repository/admin.py
@@ -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)
diff --git a/ram/repository/migrations/0001_initial.py b/ram/repository/migrations/0001_initial.py
index 0aff19b..06c5e9a 100644
--- a/ram/repository/migrations/0001_initial.py
+++ b/ram/repository/migrations/0001_initial.py
@@ -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=[
diff --git a/ram/repository/migrations/0002_alter_decoderdocument_options_and_more.py b/ram/repository/migrations/0002_alter_decoderdocument_options_and_more.py
deleted file mode 100644
index 4b65285..0000000
--- a/ram/repository/migrations/0002_alter_decoderdocument_options_and_more.py
+++ /dev/null
@@ -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"
- ),
- ),
- ]
diff --git a/ram/repository/migrations/0002_invoicedocument_remove_basebookdocument_book_and_more.py b/ram/repository/migrations/0002_invoicedocument_remove_basebookdocument_book_and_more.py
new file mode 100644
index 0000000..1716fa4
--- /dev/null
+++ b/ram/repository/migrations/0002_invoicedocument_remove_basebookdocument_book_and_more.py
@@ -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",
+ ),
+ ]
diff --git a/ram/repository/migrations/0003_alter_basebookdocument_options_and_more.py b/ram/repository/migrations/0003_alter_basebookdocument_options_and_more.py
deleted file mode 100644
index bd32b29..0000000
--- a/ram/repository/migrations/0003_alter_basebookdocument_options_and_more.py
+++ /dev/null
@@ -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",
- },
- ),
- ]
diff --git a/ram/repository/migrations/0004_invoicedocument_catalog_alter_invoicedocument_book.py b/ram/repository/migrations/0004_invoicedocument_catalog_alter_invoicedocument_book.py
deleted file mode 100644
index 74e83a1..0000000
--- a/ram/repository/migrations/0004_invoicedocument_catalog_alter_invoicedocument_book.py
+++ /dev/null
@@ -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"
- ),
- ),
- ]
diff --git a/ram/repository/models.py b/ram/repository/models.py
index b753e7d..00f8a0b 100644
--- a/ram/repository/models.py
+++ b/ram/repository/models.py
@@ -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"
)
]
diff --git a/ram/roster/admin.py b/ram/roster/admin.py
index 8f94842..f1962aa 100644
--- a/ram/roster/admin.py
+++ b/ram/roster/admin.py
@@ -152,65 +152,62 @@ class RollingStockAdmin(SortableAdminBase, admin.ModelAdmin):
'
{}'.format(obj.country.flag, obj.country)
)
- def get_fieldsets(self, request, obj=None):
- fieldsets = (
- (
- None,
- {
- "fields": (
- "preview",
- "published",
- "rolling_class",
- "road_number",
- "scale",
- "manufacturer",
- "item_number",
- "set",
- "era",
- "description",
- "production_year",
- "tags",
- )
- },
- ),
- (
- "DCC",
- {
- "fields": (
- "decoder_interface",
- "decoder",
- "address",
- )
- },
- ),
- (
- "Purchase data",
- {
- "fields": (
- "shop",
- "purchase_date",
- "price",
- )
- },
- ),
- (
- "Notes",
- {"classes": ("collapse",), "fields": ("notes",)},
- ),
- (
- "Audit",
- {
- "classes": ("collapse",),
- "fields": (
- "creation_time",
- "updated_time",
- ),
- },
- ),
- )
- if obj and obj.invoice.count() > 0:
- fieldsets[2][1]["fields"] += ("invoices",)
- return fieldsets
+ fieldsets = (
+ (
+ None,
+ {
+ "fields": (
+ "preview",
+ "published",
+ "rolling_class",
+ "road_number",
+ "scale",
+ "manufacturer",
+ "item_number",
+ "set",
+ "era",
+ "description",
+ "production_year",
+ "tags",
+ )
+ },
+ ),
+ (
+ "DCC",
+ {
+ "fields": (
+ "decoder_interface",
+ "decoder",
+ "address",
+ )
+ },
+ ),
+ (
+ "Purchase data",
+ {
+ "fields": (
+ "shop",
+ "purchase_date",
+ "price",
+ "invoices",
+ )
+ },
+ ),
+ (
+ "Notes",
+ {"classes": ("collapse",), "fields": ("notes",)},
+ ),
+ (
+ "Audit",
+ {
+ "classes": ("collapse",),
+ "fields": (
+ "creation_time",
+ "updated_time",
+ ),
+ },
+ ),
+ )
def get_form(self, request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs)
@@ -221,10 +218,13 @@ class RollingStockAdmin(SortableAdminBase, admin.ModelAdmin):
@admin.display(description="Invoices")
def invoices(self, obj):
- html = "
".join(
- "{}".format(
- i.file.url, i
- ) for i in obj.invoice.all())
+ if obj.invoice.exists():
+ html = "
".join(
+ "{}".format(
+ i.file.url, i
+ ) for i in obj.invoice.all())
+ else:
+ html = "-"
return format_html(html)
def download_csv(modeladmin, request, queryset):