diff --git a/README.md b/README.md
index ce30106..c62f6c9 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,11 @@ App to hold regional code for Germany, built on top of ERPNext.

-- Allow deletion of the most recent sales transaction only
+- Restrict deletion of attachments to submitted transactions (**ERPNext Germany Settings**)
+
+ Applies to **Quotation**, **Sales Order**, **Delivery Note**, **Sales Invoice**, **Request for Quotation**, **Supplier Quotation**, **Purchase Order**, **Purchase Receipt**, **Purchase Invoice**, **Journal Entry**, **Payment Entry** and **Asset**.
+
+- Allow deletion of the most recent sales transaction only (**ERPNext Germany Settings**)
This ensures consecutive numbering of transactions. Applies to **Quotation**, **Sales Order**, **Sales Invoice**.
diff --git a/erpnext_germany/boot.py b/erpnext_germany/boot.py
new file mode 100644
index 0000000..97bcffc
--- /dev/null
+++ b/erpnext_germany/boot.py
@@ -0,0 +1,7 @@
+import frappe
+
+
+def boot_session(bootinfo):
+ bootinfo.sysdefaults.prevent_attachment_deletion = frappe.db.get_single_value(
+ "ERPNext Germany Settings", "prevent_attachment_deletion"
+ )
diff --git a/erpnext_germany/custom/file.py b/erpnext_germany/custom/file.py
new file mode 100644
index 0000000..40a734d
--- /dev/null
+++ b/erpnext_germany/custom/file.py
@@ -0,0 +1,48 @@
+from typing import TYPE_CHECKING
+
+import frappe
+from frappe import _
+
+if TYPE_CHECKING:
+ from frappe.core.doctype.file import File
+
+APPLICABLE_DOCTYPES = (
+ "Quotation",
+ "Sales Order",
+ "Delivery Note",
+ "Sales Invoice",
+ "Request for Quotation",
+ "Supplier Quotation",
+ "Purchase Order",
+ "Purchase Receipt",
+ "Purchase Invoice",
+ "Journal Entry",
+ "Payment Entry",
+ "Asset",
+)
+
+
+def on_trash(doc: "File", method: str):
+ if doc.attached_to_doctype not in APPLICABLE_DOCTYPES:
+ # Not applicable
+ return
+
+ docstatus = frappe.db.get_value(
+ doc.attached_to_doctype, doc.attached_to_name, "docstatus"
+ )
+ if docstatus != 1:
+ # Not submitted
+ return
+
+ prevent_attachment_deletion = frappe.db.get_single_value(
+ "ERPNext Germany Settings", "prevent_attachment_deletion"
+ )
+ if prevent_attachment_deletion:
+ msg = _(
+ "Attachments to the submitted record {0} of type {1} cannot be deleted."
+ ).format(doc.attached_to_name, _(doc.attached_to_doctype))
+
+ if "System Manager" in frappe.get_roles():
+ msg += " " + _("You can allow deletion via ERPNext Germany Settings.")
+
+ frappe.throw(msg, title=_("Attachment Deletion Restricted"))
diff --git a/erpnext_germany/erpnext_germany/doctype/erpnext_germany_settings/erpnext_germany_settings.json b/erpnext_germany/erpnext_germany/doctype/erpnext_germany_settings/erpnext_germany_settings.json
index 3ef876a..95382bd 100644
--- a/erpnext_germany/erpnext_germany/doctype/erpnext_germany_settings/erpnext_germany_settings.json
+++ b/erpnext_germany/erpnext_germany/doctype/erpnext_germany_settings/erpnext_germany_settings.json
@@ -5,21 +5,29 @@
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
- "prevent_gaps_in_transaction_naming"
+ "prevent_gaps_in_transaction_naming",
+ "prevent_attachment_deletion"
],
"fields": [
{
"default": "1",
- "description": "Allow deletion of the most recent record only. Applies to Quotation, Sales Order and Sales Invoice.",
+ "description": "If enabled, allows deletion of the most recent record only. Applies to Quotation, Sales Order and Sales Invoice.",
"fieldname": "prevent_gaps_in_transaction_naming",
"fieldtype": "Check",
"label": "Prevent Gaps In Transaction Naming"
+ },
+ {
+ "default": "0",
+ "description": "If enabled, disallows deletion of files attached to a submitted transaction.",
+ "fieldname": "prevent_attachment_deletion",
+ "fieldtype": "Check",
+ "label": "Prevent Attachment Deletion"
}
],
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2025-02-23 17:38:08.351007",
+ "modified": "2025-02-26 00:02:15.955896",
"modified_by": "Administrator",
"module": "ERPNext Germany",
"name": "ERPNext Germany Settings",
diff --git a/erpnext_germany/hooks.py b/erpnext_germany/hooks.py
index 22ec975..9d95ed5 100644
--- a/erpnext_germany/hooks.py
+++ b/erpnext_germany/hooks.py
@@ -118,6 +118,9 @@
"Sales Invoice": {
"on_trash": "erpnext_germany.custom.sales.on_trash",
},
+ "File": {
+ "on_trash": "erpnext_germany.custom.file.on_trash",
+ },
}
# doc_events = {}
@@ -196,6 +199,8 @@
# "erpnext_germany.auth.validate"
# ]
+boot_session = "erpnext_germany.boot.boot_session"
+
germany_property_setters = {
"Employee": [
("salary_currency", "default", "EUR", "Small Text"),
diff --git a/erpnext_germany/locale/de.po b/erpnext_germany/locale/de.po
index 339aac3..90f253d 100644
--- a/erpnext_germany/locale/de.po
+++ b/erpnext_germany/locale/de.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ERPNext Germany VERSION\n"
"Report-Msgid-Bugs-To: hallo@alyf.de\n"
-"POT-Creation-Date: 2025-02-20 17:53+0053\n"
+"POT-Creation-Date: 2025-02-26 00:02+0053\n"
"PO-Revision-Date: 2025-02-20 11:46+0100\n"
"Last-Translator: hallo@alyf.de\n"
"Language: de\n"
@@ -96,6 +96,14 @@ msgstr "April"
msgid "Arrival or Departure"
msgstr "Ankunft oder Abreise"
+#: erpnext_germany/custom/file.py:48
+msgid "Attachment Deletion Restricted"
+msgstr "Löschen von Anhängen eingeschränkt"
+
+#: erpnext_germany/custom/file.py:41
+msgid "Attachments to the submitted record {0} of type {1} cannot be deleted."
+msgstr "Anhänge zu der gebuchten Transaktion {0} vom Typ {1} können nicht gelöscht werden."
+
#: erpnext_germany/erpnext_germany/report/summen__und_saldenliste/summen__und_saldenliste.js:36
msgid "August"
msgstr "August"
@@ -168,7 +176,7 @@ msgstr "Dienstreise-Region"
msgid "Business Trip Settings"
msgstr "Dienstreise-Einstellungen"
-#: erpnext_germany/custom/sales.py:15
+#: erpnext_germany/custom/sales.py:18
msgid "Cannot delete this transaction"
msgstr "Diese Transaktion kann nicht gelöscht werden"
@@ -316,6 +324,13 @@ msgstr "Entfernung"
msgid "ERPNext Germany"
msgstr "ERPNext-Deutschland"
+#. Name of a DocType
+#. Label of a Link in the Germany Workspace
+#: erpnext_germany/erpnext_germany/doctype/erpnext_germany_settings/erpnext_germany_settings.json
+#: erpnext_germany/erpnext_germany/workspace/germany/germany.json
+msgid "ERPNext Germany Settings"
+msgstr "ERPNext-Deutschland-Einstellungen"
+
#. Label of a Data field in DocType 'Business Letter'
#: erpnext_germany/erpnext_germany/doctype/business_letter/business_letter.json
msgid "Email"
@@ -421,6 +436,18 @@ msgstr "Hat Nebenbeschäftigungen"
msgid "Highest School Qualification"
msgstr "Höchster Schulabschluss"
+#. Description of the 'Prevent Gaps In Transaction Naming' (Check) field in
+#. DocType 'ERPNext Germany Settings'
+#: erpnext_germany/erpnext_germany/doctype/erpnext_germany_settings/erpnext_germany_settings.json
+msgid "If enabled, allows deletion of the most recent record only. Applies to Quotation, Sales Order and Sales Invoice."
+msgstr "Falls aktiviert, ist nur die neueste Transaktion vom Typ Angebot, Auftrag und Ausgangsrechnung löschbar."
+
+#. Description of the 'Prevent Attachment Deletion' (Check) field in DocType
+#. 'ERPNext Germany Settings'
+#: erpnext_germany/erpnext_germany/doctype/erpnext_germany_settings/erpnext_germany_settings.json
+msgid "If enabled, disallows deletion of files attached to a submitted transaction."
+msgstr "Falls aktiviert, können Anhängen einer gebuchten Transaktion nicht gelöscht werden."
+
#: erpnext_germany/erpnext_germany/doctype/vat_id_check/vat_id_check_list.js:8
msgid "Invalid"
msgstr "Ungültig"
@@ -521,7 +548,7 @@ msgstr "November"
msgid "October"
msgstr "Oktober"
-#: erpnext_germany/custom/sales.py:12
+#: erpnext_germany/custom/sales.py:15
msgid "Only the most recent {0} can be deleted in order to avoid gaps in numbering."
msgstr "Nur die neueste Transaktion vom Typ {0} kann gelöscht werden, um Lücken in der Nummerierung zu vermeiden."
@@ -566,6 +593,16 @@ msgstr "Geplant"
msgid "Please enter a start and end date of the trip!"
msgstr "Bitte geben Sie das Start- und Enddatum Ihrer Reise ein!"
+#. Label of a Check field in DocType 'ERPNext Germany Settings'
+#: erpnext_germany/erpnext_germany/doctype/erpnext_germany_settings/erpnext_germany_settings.json
+msgid "Prevent Attachment Deletion"
+msgstr "Löschen von Anhängen verhindern"
+
+#. Label of a Check field in DocType 'ERPNext Germany Settings'
+#: erpnext_germany/erpnext_germany/doctype/erpnext_germany_settings/erpnext_germany_settings.json
+msgid "Prevent Gaps In Transaction Naming"
+msgstr "Lücken in Nummernkreisen verhindern"
+
#. Label of a Tab Break field in DocType 'Business Letter'
#: erpnext_germany/erpnext_germany/doctype/business_letter/business_letter.json
msgid "Preview"
@@ -740,6 +777,7 @@ msgstr ""
#: erpnext_germany/erpnext_germany/doctype/business_trip/business_trip.json
#: erpnext_germany/erpnext_germany/doctype/business_trip_region/business_trip_region.json
#: erpnext_germany/erpnext_germany/doctype/business_trip_settings/business_trip_settings.json
+#: erpnext_germany/erpnext_germany/doctype/erpnext_germany_settings/erpnext_germany_settings.json
#: erpnext_germany/erpnext_germany/doctype/religious_denomination/religious_denomination.json
#: erpnext_germany/erpnext_germany/doctype/vat_id_check/vat_id_check.json
msgid "System Manager"
@@ -900,6 +938,10 @@ msgstr "Ganztägig"
msgid "Working Hours Per Week"
msgstr "Arbeitsstunden pro Woche"
+#: erpnext_germany/custom/file.py:46
+msgid "You can allow deletion via ERPNext Germany Settings."
+msgstr "Sie können das Löschen von Anhängen in den ERPNext Deutschland Einstellungen erlauben."
+
#: erpnext_germany/public/js/erpnext_germany/business_letter.js:7
msgid "You can use {0} in the Subject and Content fields for dynamic values.
All address details are available under the address
object (e.g., {{ address.city }}
), contact details under the contact
object (e.g., {{ contact.first_name }}
), and any specific information related to the dynamically linked document under the reference
object (e.g., {{ reference.some_field }}
).
"
msgstr "Sie können in den Betreff- und Inhalt-Feldern {0} für dynamische Werte verwenden.
Alle Adressdetails sind unter dem address
-Objekt verfügbar (z.B., {{ address.city }}
), Kontaktdetails unter dem contact
-Objekt (z.B., {{ contact.first_name }}
), und jegliche spezifischen Informationen, die mit dem dynamisch verlinkten Dokument zusammenhängen, unter dem reference
-Objekt (z.B., {{ reference.some_field }}
).
"
@@ -927,3 +969,4 @@ msgstr "{} Ungültig"
#: erpnext_germany/erpnext_germany/workspace/germany/germany.json
msgid "{} Open"
msgstr "{} Offen"
+
diff --git a/erpnext_germany/locale/main.pot b/erpnext_germany/locale/main.pot
index 88fda0e..b32447d 100644
--- a/erpnext_germany/locale/main.pot
+++ b/erpnext_germany/locale/main.pot
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: ERPNext Germany VERSION\n"
"Report-Msgid-Bugs-To: hallo@alyf.de\n"
-"POT-Creation-Date: 2025-02-20 17:53+0053\n"
-"PO-Revision-Date: 2025-02-20 17:53+0053\n"
+"POT-Creation-Date: 2025-02-26 00:02+0053\n"
+"PO-Revision-Date: 2025-02-26 00:02+0053\n"
"Last-Translator: hallo@alyf.de\n"
"Language-Team: hallo@alyf.de\n"
"MIME-Version: 1.0\n"
@@ -94,6 +94,14 @@ msgstr ""
msgid "Arrival or Departure"
msgstr ""
+#: erpnext_germany/custom/file.py:48
+msgid "Attachment Deletion Restricted"
+msgstr ""
+
+#: erpnext_germany/custom/file.py:41
+msgid "Attachments to the submitted record {0} of type {1} cannot be deleted."
+msgstr ""
+
#: erpnext_germany/erpnext_germany/report/summen__und_saldenliste/summen__und_saldenliste.js:36
msgid "August"
msgstr ""
@@ -166,7 +174,7 @@ msgstr ""
msgid "Business Trip Settings"
msgstr ""
-#: erpnext_germany/custom/sales.py:15
+#: erpnext_germany/custom/sales.py:18
msgid "Cannot delete this transaction"
msgstr ""
@@ -314,6 +322,13 @@ msgstr ""
msgid "ERPNext Germany"
msgstr ""
+#. Name of a DocType
+#. Label of a Link in the Germany Workspace
+#: erpnext_germany/erpnext_germany/doctype/erpnext_germany_settings/erpnext_germany_settings.json
+#: erpnext_germany/erpnext_germany/workspace/germany/germany.json
+msgid "ERPNext Germany Settings"
+msgstr ""
+
#. Label of a Data field in DocType 'Business Letter'
#: erpnext_germany/erpnext_germany/doctype/business_letter/business_letter.json
msgid "Email"
@@ -419,6 +434,18 @@ msgstr ""
msgid "Highest School Qualification"
msgstr ""
+#. Description of the 'Prevent Gaps In Transaction Naming' (Check) field in
+#. DocType 'ERPNext Germany Settings'
+#: erpnext_germany/erpnext_germany/doctype/erpnext_germany_settings/erpnext_germany_settings.json
+msgid "If enabled, allows deletion of the most recent record only. Applies to Quotation, Sales Order and Sales Invoice."
+msgstr ""
+
+#. Description of the 'Prevent Attachment Deletion' (Check) field in DocType
+#. 'ERPNext Germany Settings'
+#: erpnext_germany/erpnext_germany/doctype/erpnext_germany_settings/erpnext_germany_settings.json
+msgid "If enabled, disallows deletion of files attached to a submitted transaction."
+msgstr ""
+
#: erpnext_germany/erpnext_germany/doctype/vat_id_check/vat_id_check_list.js:8
msgid "Invalid"
msgstr ""
@@ -519,7 +546,7 @@ msgstr ""
msgid "October"
msgstr ""
-#: erpnext_germany/custom/sales.py:12
+#: erpnext_germany/custom/sales.py:15
msgid "Only the most recent {0} can be deleted in order to avoid gaps in numbering."
msgstr ""
@@ -564,6 +591,16 @@ msgstr ""
msgid "Please enter a start and end date of the trip!"
msgstr ""
+#. Label of a Check field in DocType 'ERPNext Germany Settings'
+#: erpnext_germany/erpnext_germany/doctype/erpnext_germany_settings/erpnext_germany_settings.json
+msgid "Prevent Attachment Deletion"
+msgstr ""
+
+#. Label of a Check field in DocType 'ERPNext Germany Settings'
+#: erpnext_germany/erpnext_germany/doctype/erpnext_germany_settings/erpnext_germany_settings.json
+msgid "Prevent Gaps In Transaction Naming"
+msgstr ""
+
#. Label of a Tab Break field in DocType 'Business Letter'
#: erpnext_germany/erpnext_germany/doctype/business_letter/business_letter.json
msgid "Preview"
@@ -738,6 +775,7 @@ msgstr ""
#: erpnext_germany/erpnext_germany/doctype/business_trip/business_trip.json
#: erpnext_germany/erpnext_germany/doctype/business_trip_region/business_trip_region.json
#: erpnext_germany/erpnext_germany/doctype/business_trip_settings/business_trip_settings.json
+#: erpnext_germany/erpnext_germany/doctype/erpnext_germany_settings/erpnext_germany_settings.json
#: erpnext_germany/erpnext_germany/doctype/religious_denomination/religious_denomination.json
#: erpnext_germany/erpnext_germany/doctype/vat_id_check/vat_id_check.json
msgid "System Manager"
@@ -898,6 +936,10 @@ msgstr ""
msgid "Working Hours Per Week"
msgstr ""
+#: erpnext_germany/custom/file.py:46
+msgid "You can allow deletion via ERPNext Germany Settings."
+msgstr ""
+
#: erpnext_germany/public/js/erpnext_germany/business_letter.js:7
msgid "You can use {0} in the Subject and Content fields for dynamic values.
All address details are available under the address
object (e.g., {{ address.city }}
), contact details under the contact
object (e.g., {{ contact.first_name }}
), and any specific information related to the dynamically linked document under the reference
object (e.g., {{ reference.some_field }}
).
"
msgstr ""
diff --git a/erpnext_germany/public/js/erpnext_germany.bundle.js b/erpnext_germany/public/js/erpnext_germany.bundle.js
index 5c9977a..205783e 100644
--- a/erpnext_germany/public/js/erpnext_germany.bundle.js
+++ b/erpnext_germany/public/js/erpnext_germany.bundle.js
@@ -1 +1,2 @@
import "./erpnext_germany/business_letter.js";
+import "./erpnext_germany/prevent_attachment_deletion.js";
diff --git a/erpnext_germany/public/js/erpnext_germany/prevent_attachment_deletion.js b/erpnext_germany/public/js/erpnext_germany/prevent_attachment_deletion.js
new file mode 100644
index 0000000..4dc4c42
--- /dev/null
+++ b/erpnext_germany/public/js/erpnext_germany/prevent_attachment_deletion.js
@@ -0,0 +1,30 @@
+$(document).ready(function () {
+ $(document).on("form-load", function (event, frm) {
+ if (!frappe.boot.sysdefaults.prevent_attachment_deletion || frappe.user.has_role("System Manager")) {
+ return;
+ }
+
+ if (![
+ "Quotation",
+ "Sales Order",
+ "Delivery Note",
+ "Sales Invoice",
+ "Request for Quotation",
+ "Supplier Quotation",
+ "Purchase Order",
+ "Purchase Receipt",
+ "Purchase Invoice",
+ "Journal Entry",
+ "Payment Entry",
+ "Asset",
+ ].includes(frm.doctype)) {
+ return;
+ }
+
+ frappe.ui.form.on(frm.doctype, {
+ refresh: () => {
+ $(".attachment-row .remove-btn").hide();
+ },
+ });
+ });
+});