diff --git a/src/bpp/admin/wydawnictwo_zwarte.py b/src/bpp/admin/wydawnictwo_zwarte.py
index fd374e538..644643b41 100644
--- a/src/bpp/admin/wydawnictwo_zwarte.py
+++ b/src/bpp/admin/wydawnictwo_zwarte.py
@@ -273,6 +273,9 @@ def _sprawdz_isbn_z_nadrzednym(
wydawca = forms.ModelChoiceField(
required=False,
queryset=Wydawca.objects.all(),
+ help_text="Przy rozdziale (gdy wskazano wydawnictwo nadrzędne) wydawca "
+ "jest dziedziczony po wydawnictwie nadrzędnym, o ile pozostawisz to pole "
+ "puste. Możesz wpisać innego wydawcę ręcznie.",
widget=autocomplete.ModelSelect2(
url="bpp:wydawca-autocomplete", attrs={"class": "bpp-autocomplete-wide"}
),
@@ -345,8 +348,32 @@ def clean(self):
if message:
self._warnings.append(message)
+ self._dziedzicz_wydawce_po_nadrzednym(cleaned_data, wydawnictwo_nadrzedne)
+
return cleaned_data
+ def _dziedzicz_wydawce_po_nadrzednym(self, cleaned_data, wydawnictwo_nadrzedne):
+ """Dziedziczenie wydawcy po wydawnictwie nadrzędnym (rozdziale).
+
+ Freshdesk #385. Jeżeli rekord ma wskazane wydawnictwo nadrzędne
+ (czyli jest rozdziałem), a operator nie podał własnego wydawcy —
+ podstaw wydawcę z wydawnictwa nadrzędnego. Jawnie wpisany wydawca
+ NIE jest nadpisywany. Mutuje ``cleaned_data`` w miejscu.
+ """
+ if not wydawnictwo_nadrzedne:
+ return
+ if cleaned_data.get("wydawca"):
+ return
+ if wydawnictwo_nadrzedne.wydawca_id is None:
+ return
+
+ cleaned_data["wydawca"] = wydawnictwo_nadrzedne.wydawca
+ self._warnings.append(
+ "Wydawca został odziedziczony po wydawnictwie nadrzędnym "
+ f"'{wydawnictwo_nadrzedne.tytul_oryginalny}': "
+ f"{wydawnictwo_nadrzedne.wydawca}."
+ )
+
class Meta:
model = Wydawnictwo_Zwarte
fields = [
@@ -427,6 +454,13 @@ class Meta:
"slowa_kluczowe": TextareaTagWidget(attrs={"rows": 2}),
}
+ class Media:
+ # Freshdesk #385: podświetlenie wymaganego pola "wydawca" przy
+ # rozdziale (rekord z wydawnictwem nadrzędnym). Warstwa wyłącznie
+ # wizualna — dziedziczenie wydawcy realizuje serwer w clean().
+ js = ["/static/bpp/js/wydawnictwo_zwarte_wydawca.js"]
+ css = {"all": ["/static/bpp/css/wydawnictwo_zwarte_wydawca.css"]}
+
class Wydawnictwo_Zwarte_Zewnetrzna_Baza_DanychForm(forms.ModelForm):
class Meta:
diff --git a/src/bpp/static/bpp/css/wydawnictwo_zwarte_wydawca.css b/src/bpp/static/bpp/css/wydawnictwo_zwarte_wydawca.css
new file mode 100644
index 000000000..0effc52fc
--- /dev/null
+++ b/src/bpp/static/bpp/css/wydawnictwo_zwarte_wydawca.css
@@ -0,0 +1,17 @@
+/*
+ * Freshdesk #385 — podświetlenie wymaganego pola "wydawca" przy rozdziale.
+ * Aktywowane klasą .bpp-wydawca-wymagany dodawaną przez
+ * wydawnictwo_zwarte_wydawca.js, gdy wskazano wydawnictwo nadrzędne,
+ * a pole wydawca jest puste.
+ */
+.bpp-wydawca-wymagany {
+ border-left: 4px solid #e6a700;
+ padding-left: 8px;
+ background-color: rgba(230, 167, 0, 0.08);
+}
+
+.bpp-wydawca-required-marker {
+ color: #b35900;
+ font-weight: bold;
+ font-size: 0.85em;
+}
diff --git a/src/bpp/static/bpp/js/wydawnictwo_zwarte_wydawca.js b/src/bpp/static/bpp/js/wydawnictwo_zwarte_wydawca.js
new file mode 100644
index 000000000..e725501bf
--- /dev/null
+++ b/src/bpp/static/bpp/js/wydawnictwo_zwarte_wydawca.js
@@ -0,0 +1,71 @@
+/*
+ * Freshdesk #385 — Rozdział: podświetlanie wymaganego pola "wydawca".
+ *
+ * Gdy rekord wydawnictwa zwartego ma wskazane wydawnictwo nadrzędne
+ * (czyli jest rozdziałem), pole "wydawca" jest istotne i łatwo je
+ * przeoczyć. Ten skrypt podświetla je wizualnie jako wymagane, dopóki
+ * pozostaje puste. Faktyczne dziedziczenie wydawcy po wydawnictwie
+ * nadrzędnym realizuje serwer (Wydawnictwo_ZwarteForm.clean) — to jest
+ * wyłącznie warstwa UI i nie jest wymagana do działania mechanizmu.
+ */
+(function ($) {
+ "use strict";
+
+ function wydawcaInput() {
+ return $("#id_wydawca");
+ }
+
+ function wydawcaRow() {
+ // Wiersz formularza admina opakowujący pole wydawca (div.form-row /
+ // div.field-wydawca w zależności od wersji szablonu).
+ return wydawcaInput().closest(".form-row, .field-wydawca");
+ }
+
+ function nadrzedneWybrane() {
+ var val = $("#id_wydawnictwo_nadrzedne").val();
+ return val !== null && val !== undefined && val !== "";
+ }
+
+ function wydawcaPusty() {
+ var val = wydawcaInput().val();
+ return val === null || val === undefined || val === "";
+ }
+
+ function odswiezPodswietlenie() {
+ var row = wydawcaRow();
+ if (!row.length) {
+ return;
+ }
+ var wymagany = nadrzedneWybrane() && wydawcaPusty();
+ row.toggleClass("bpp-wydawca-wymagany", wymagany);
+
+ var label = row.find("label").first();
+ if (!label.length) {
+ return;
+ }
+ var marker = label.find(".bpp-wydawca-required-marker");
+ if (wymagany) {
+ if (!marker.length) {
+ label.append(
+ ' ' +
+ "❗ wymagane przy rozdziale"
+ );
+ }
+ } else {
+ marker.remove();
+ }
+ }
+
+ $(function () {
+ odswiezPodswietlenie();
+ // django-autocomplete-light (Select2) emituje "change" na ukrytym
+ //