feat: validate sales invoice for germany
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index 2397b7d..ed1ed43 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -19,6 +19,7 @@
   "is_return",
   "column_break1",
   "company",
+  "company_tax_id",
   "posting_date",
   "posting_time",
   "set_posting_time",
@@ -1940,13 +1941,20 @@
    "hide_seconds": 1,
    "label": "Is Internal Customer",
    "read_only": 1
+  },
+  {
+   "fetch_from": "company.tax_id",
+   "fieldname": "company_tax_id",
+   "fieldtype": "Data",
+   "label": "Company Tax ID",
+   "read_only": 1
   }
  ],
  "icon": "fa fa-file-text",
  "idx": 181,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-08-27 01:56:28.532140",
+ "modified": "2020-09-29 10:00:41.470858",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Sales Invoice",
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 4e05076..d9a639a 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -393,6 +393,9 @@
 	'Italy': {
 		'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.italy.utils.update_itemised_tax_data',
 		'erpnext.controllers.accounts_controller.validate_regional': 'erpnext.regional.italy.utils.sales_invoice_validate',
+	},
+	'Germany': {
+		'erpnext.controllers.accounts_controller.validate_regional': 'erpnext.regional.germany.accounts_controller.validate_regional',
 	}
 }
 user_privacy_documents = [
diff --git a/erpnext/regional/germany/accounts_controller.py b/erpnext/regional/germany/accounts_controller.py
new file mode 100644
index 0000000..193c8e1
--- /dev/null
+++ b/erpnext/regional/germany/accounts_controller.py
@@ -0,0 +1,57 @@
+import frappe
+from frappe import _
+from frappe import msgprint
+
+
+REQUIRED_FIELDS = {
+	"Sales Invoice": [
+		{
+			"field_name": "company_address",
+			"regulation": "§ 14 Abs. 4 Nr. 1 UStG"
+		},
+		{
+			"field_name": "company_tax_id",
+			"regulation": "§ 14 Abs. 4 Nr. 2 UStG"
+		},
+		{
+			"field_name": "taxes",
+			"regulation": "§ 14 Abs. 4 Nr. 8 UStG",
+			"condition": "not exempt_from_sales_tax"
+		},
+		{
+			"field_name": "customer_address",
+			"regulation": "§ 14 Abs. 4 Nr. 1 UStG",
+			"condition": "base_grand_total > 250"
+		}
+	]
+}
+
+
+def validate_regional(doc):
+	"""Check if required fields for this document are present."""
+	required_fields = REQUIRED_FIELDS.get(doc.doctype)
+	if not required_fields:
+		return
+
+	meta = frappe.get_meta(doc.doctype)
+	field_map = {field.fieldname: field.label for field in meta.fields}
+
+	for field in required_fields:
+		condition = field.get("condition")
+		if condition and not frappe.safe_eval(condition, doc.as_dict()):
+			continue
+
+		field_name = field.get("field_name")
+		regulation = field.get("regulation")
+		if field_name and not doc.get(field_name):
+			missing(field_map.get(field_name), regulation)
+
+
+def missing(field_label, regulation):
+	"""Notify the user that a required field is missing."""
+	context = 'Specific for Germany. Example: Remember to set Company Tax ID. It is required by § 14 Abs. 4 Nr. 2 UStG.'
+	msgprint(_('Remember to set {field_label}. It is required by {regulation}.', context=context).format(
+			field_label=frappe.bold(_(field_label)),
+			regulation=regulation
+		)
+	)