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. ![Validate EU VAT ID](docs/vat_check.png) -- 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(); + }, + }); + }); +});