Merge pull request #33022 from barredterra/incoterms

feat: Incoterms in buying and selling
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index a5981fd..a03157e 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -69,6 +69,7 @@
   "tax_category",
   "column_break_49",
   "shipping_rule",
+  "incoterm",
   "section_break_51",
   "taxes",
   "totals",
@@ -1534,13 +1535,19 @@
    "oldfieldtype": "Section Break",
    "options": "fa fa-file-text",
    "print_hide": 1
+  },
+  {
+   "fieldname": "incoterm",
+   "fieldtype": "Link",
+   "label": "Incoterm",
+   "options": "Incoterm"
   }
  ],
  "icon": "fa fa-file-text",
  "idx": 204,
  "is_submittable": 1,
  "links": [],
- "modified": "2022-11-22 12:44:29.935567",
+ "modified": "2022-11-25 12:44:29.935567",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Purchase Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index dc2f9a9..18d2b5c 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -64,6 +64,7 @@
   "taxes_and_charges",
   "column_break_38",
   "shipping_rule",
+  "incoterm",
   "column_break_55",
   "tax_category",
   "section_break_40",
@@ -2114,6 +2115,12 @@
    "label": "Repost Required",
    "no_copy": 1,
    "read_only": 1
+  },
+  {
+   "fieldname": "incoterm",
+   "fieldtype": "Link",
+   "label": "Incoterm",
+   "options": "Incoterm"
   }
  ],
  "icon": "fa fa-file-text",
@@ -2126,7 +2133,7 @@
    "link_fieldname": "consolidated_invoice"
   }
  ],
- "modified": "2022-11-15 09:33:47.870616",
+ "modified": "2022-11-17 17:17:10.883487",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Sales Invoice",
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json
index e2a70c2..9349626 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.json
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.json
@@ -67,6 +67,7 @@
   "tax_category",
   "column_break_50",
   "shipping_rule",
+  "incoterm",
   "section_break_52",
   "taxes",
   "totals",
@@ -1249,13 +1250,19 @@
   {
    "fieldname": "column_break_103",
    "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "incoterm",
+   "fieldtype": "Link",
+   "label": "Incoterm",
+   "options": "Incoterm"
   }
  ],
  "icon": "fa fa-file-text",
  "idx": 105,
  "is_submittable": 1,
  "links": [],
- "modified": "2022-11-17 12:34:36.033363",
+ "modified": "2022-11-17 17:28:07.729943",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Purchase Order",
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json
index 083cab7..019d45b 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json
@@ -28,6 +28,7 @@
   "sec_break_email_2",
   "message_for_supplier",
   "terms_section_break",
+  "incoterm",
   "tc_name",
   "terms",
   "printing_settings",
@@ -271,13 +272,19 @@
    "fieldname": "schedule_date",
    "fieldtype": "Date",
    "label": "Required Date"
+  },
+  {
+   "fieldname": "incoterm",
+   "fieldtype": "Link",
+   "label": "Incoterm",
+   "options": "Incoterm"
   }
  ],
  "icon": "fa fa-shopping-cart",
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2022-04-06 17:47:49.909000",
+ "modified": "2022-11-17 17:26:33.770993",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Request for Quotation",
@@ -345,5 +352,6 @@
  "search_fields": "status, transaction_date",
  "show_name_in_global_search": 1,
  "sort_field": "modified",
- "sort_order": "DESC"
-}
+ "sort_order": "DESC",
+ "states": []
+}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
index 1636561..7776ab8 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
@@ -45,6 +45,7 @@
   "tax_category",
   "column_break_36",
   "shipping_rule",
+  "incoterm",
   "section_break_38",
   "taxes",
   "totals",
@@ -823,6 +824,12 @@
   {
    "fieldname": "column_break_85",
    "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "incoterm",
+   "fieldtype": "Link",
+   "label": "Incoterm",
+   "options": "Incoterm"
   }
  ],
  "icon": "fa fa-shopping-cart",
@@ -830,7 +837,7 @@
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2022-09-27 18:20:09.462037",
+ "modified": "2022-11-17 17:27:32.179686",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Supplier Quotation",
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 639809d..166faf9 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -317,3 +317,4 @@
 erpnext.patches.v13_0.update_schedule_type_in_loans
 erpnext.patches.v14_0.create_accounting_dimensions_for_asset_capitalization
 erpnext.patches.v14_0.update_partial_tds_fields
+erpnext.patches.v14_0.create_incoterms_and_migrate_shipment
diff --git a/erpnext/patches/v14_0/create_incoterms_and_migrate_shipment.py b/erpnext/patches/v14_0/create_incoterms_and_migrate_shipment.py
new file mode 100644
index 0000000..6e1e09a
--- /dev/null
+++ b/erpnext/patches/v14_0/create_incoterms_and_migrate_shipment.py
@@ -0,0 +1,31 @@
+import frappe
+
+from erpnext.setup.doctype.incoterm.incoterm import create_incoterms
+
+
+def execute():
+	create_incoterms()
+	migrate_shipments()
+
+
+def migrate_shipments():
+	if not frappe.db.count("Shipment"):
+		return
+
+	OLD_VALUES = [
+		"EXW (Ex Works)",
+		"FCA (Free Carrier)",
+		"FOB (Free On Board)",
+		"FAS (Free Alongside Ship)",
+		"CPT (Carriage Paid To)",
+		"CIP (Carriage and Insurance Paid to)",
+		"CFR (Cost and Freight)",
+		"DPU (Delivered At Place Unloaded)",
+		"DAP (Delivered At Place)",
+		"DDP (Delivered Duty Paid)",
+	]
+	shipment = frappe.qb.DocType("Shipment")
+	for old_value in OLD_VALUES:
+		frappe.qb.update(shipment).set(shipment.incoterm, old_value[:3]).where(
+			shipment.incoterm == old_value
+		).run()
diff --git a/erpnext/selling/doctype/quotation/quotation.json b/erpnext/selling/doctype/quotation/quotation.json
index fa64b16..08918f4 100644
--- a/erpnext/selling/doctype/quotation/quotation.json
+++ b/erpnext/selling/doctype/quotation/quotation.json
@@ -48,6 +48,7 @@
   "tax_category",
   "column_break_34",
   "shipping_rule",
+  "incoterm",
   "section_break_36",
   "taxes",
   "section_break_39",
@@ -1052,13 +1053,19 @@
   {
    "fieldname": "column_break_108",
    "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "incoterm",
+   "fieldtype": "Link",
+   "label": "Incoterm",
+   "options": "Incoterm"
   }
  ],
  "icon": "fa fa-shopping-cart",
  "idx": 82,
  "is_submittable": 1,
  "links": [],
- "modified": "2022-10-11 13:06:33.479650",
+ "modified": "2022-11-17 17:20:54.984348",
  "modified_by": "Administrator",
  "module": "Selling",
  "name": "Quotation",
diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json
index e6ff39d..9ec32cb 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.json
+++ b/erpnext/selling/doctype/sales_order/sales_order.json
@@ -63,6 +63,7 @@
   "tax_category",
   "column_break_49",
   "shipping_rule",
+  "incoterm",
   "section_break_40",
   "taxes",
   "section_break_43",
@@ -1623,13 +1624,19 @@
   {
    "fieldname": "column_break_152",
    "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "incoterm",
+   "fieldtype": "Link",
+   "label": "Incoterm",
+   "options": "Incoterm"
   }
  ],
  "icon": "fa fa-file-text",
  "idx": 105,
  "is_submittable": 1,
  "links": [],
- "modified": "2022-10-11 13:06:10.469796",
+ "modified": "2022-11-17 17:22:00.413878",
  "modified_by": "Administrator",
  "module": "Selling",
  "name": "Sales Order",
diff --git a/erpnext/setup/doctype/incoterm/__init__.py b/erpnext/setup/doctype/incoterm/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/setup/doctype/incoterm/__init__.py
diff --git a/erpnext/setup/doctype/incoterm/incoterm.js b/erpnext/setup/doctype/incoterm/incoterm.js
new file mode 100644
index 0000000..bc65123
--- /dev/null
+++ b/erpnext/setup/doctype/incoterm/incoterm.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+// frappe.ui.form.on("Incoterm", {
+// 	refresh(frm) {
+
+// 	},
+// });
diff --git a/erpnext/setup/doctype/incoterm/incoterm.json b/erpnext/setup/doctype/incoterm/incoterm.json
new file mode 100644
index 0000000..c547b7c
--- /dev/null
+++ b/erpnext/setup/doctype/incoterm/incoterm.json
@@ -0,0 +1,168 @@
+{
+ "actions": [],
+ "allow_rename": 1,
+ "autoname": "field:code",
+ "creation": "2022-11-17 15:17:34.717467",
+ "default_view": "List",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "code",
+  "title",
+  "description"
+ ],
+ "fields": [
+  {
+   "fieldname": "code",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Code",
+   "length": 3,
+   "reqd": 1,
+   "unique": 1
+  },
+  {
+   "fieldname": "title",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Title",
+   "reqd": 1
+  },
+  {
+   "fieldname": "description",
+   "fieldtype": "Long Text",
+   "label": "Description"
+  }
+ ],
+ "links": [
+  {
+   "group": "Selling",
+   "link_doctype": "Quotation",
+   "link_fieldname": "incoterm"
+  },
+  {
+   "group": "Selling",
+   "link_doctype": "Sales Order",
+   "link_fieldname": "incoterm"
+  },
+  {
+   "group": "Buying",
+   "link_doctype": "Request for Quotation",
+   "link_fieldname": "incoterm"
+  },
+  {
+   "group": "Buying",
+   "link_doctype": "Supplier Quotation",
+   "link_fieldname": "incoterm"
+  },
+  {
+   "group": "Buying",
+   "link_doctype": "Purchase Order",
+   "link_fieldname": "incoterm"
+  },
+  {
+   "group": "Stock",
+   "link_doctype": "Delivery Note",
+   "link_fieldname": "incoterm"
+  },
+  {
+   "group": "Stock",
+   "link_doctype": "Purchase Receipt",
+   "link_fieldname": "incoterm"
+  },
+  {
+   "group": "Stock",
+   "link_doctype": "Shipment",
+   "link_fieldname": "incoterm"
+  },
+  {
+   "group": "Accounts",
+   "link_doctype": "Sales Invoice",
+   "link_fieldname": "incoterm"
+  },
+  {
+   "group": "Accounts",
+   "link_doctype": "Purchase Invoice",
+   "link_fieldname": "incoterm"
+  }
+ ],
+ "modified": "2022-11-17 22:35:52.084553",
+ "modified_by": "Administrator",
+ "module": "Setup",
+ "name": "Incoterm",
+ "naming_rule": "By fieldname",
+ "owner": "Administrator",
+ "permissions": [
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Accounts Manager",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Sales Manager",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Purchase Manager",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Stock Manager",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "read": 1,
+   "role": "Purchase User"
+  },
+  {
+   "read": 1,
+   "role": "Sales User"
+  },
+  {
+   "read": 1,
+   "role": "Accounts User"
+  },
+  {
+   "read": 1,
+   "role": "Stock User"
+  }
+ ],
+ "show_title_field_in_link": 1,
+ "sort_field": "name",
+ "sort_order": "ASC",
+ "states": [],
+ "title_field": "title",
+ "translated_doctype": 1
+}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/incoterm/incoterm.py b/erpnext/setup/doctype/incoterm/incoterm.py
new file mode 100644
index 0000000..7e2e622
--- /dev/null
+++ b/erpnext/setup/doctype/incoterm/incoterm.py
@@ -0,0 +1,24 @@
+# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+import frappe
+from frappe.model.document import Document
+
+
+class Incoterm(Document):
+	pass
+
+
+def create_incoterms():
+	"""Create Incoterm records from incoterms.csv."""
+	import os
+	from csv import DictReader
+
+	with open(os.path.join(os.path.dirname(__file__), "incoterms.csv"), "r") as f:
+		for incoterm in DictReader(f):
+			if frappe.db.exists("Incoterm", incoterm["code"]):
+				continue
+
+			doc = frappe.new_doc("Incoterm")
+			doc.update(incoterm)
+			doc.save()
diff --git a/erpnext/setup/doctype/incoterm/incoterms.csv b/erpnext/setup/doctype/incoterm/incoterms.csv
new file mode 100644
index 0000000..af532cf
--- /dev/null
+++ b/erpnext/setup/doctype/incoterm/incoterms.csv
@@ -0,0 +1,12 @@
+code,title
+EXW,Ex Works
+FCA,Free Carrier
+FAS,Free Alongside Ship
+FOB,Free On Board
+CPT,Carriage Paid To
+CIP,Carriage and Insurance Paid to
+CFR,Cost and Freight
+CIF,"Cost, Insurance and Freight"
+DAP,Delivered At Place
+DPU,Delivered At Place Unloaded
+DDP,Delivered Duty Paid
diff --git a/erpnext/setup/doctype/incoterm/test_incoterm.py b/erpnext/setup/doctype/incoterm/test_incoterm.py
new file mode 100644
index 0000000..06b8c3b
--- /dev/null
+++ b/erpnext/setup/doctype/incoterm/test_incoterm.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+
+# import frappe
+from frappe.tests.utils import FrappeTestCase
+
+
+class TestIncoterm(FrappeTestCase):
+	pass
diff --git a/erpnext/setup/install.py b/erpnext/setup/install.py
index 2076dde..d3b47f9 100644
--- a/erpnext/setup/install.py
+++ b/erpnext/setup/install.py
@@ -10,6 +10,7 @@
 
 from erpnext.accounts.doctype.cash_flow_mapper.default_cash_flow_mapper import DEFAULT_MAPPERS
 from erpnext.setup.default_energy_point_rules import get_default_energy_point_rules
+from erpnext.setup.doctype.incoterm.incoterm import create_incoterms
 
 from .default_success_action import get_default_success_action
 
@@ -25,6 +26,7 @@
 	create_default_cash_flow_mapper_templates()
 	create_default_success_action()
 	create_default_energy_point_rules()
+	create_incoterms()
 	add_company_to_session_defaults()
 	add_standard_navbar_items()
 	add_app_name()
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json
index 0ca3e69..80e4bcb 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.json
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.json
@@ -62,6 +62,7 @@
   "tax_category",
   "column_break_39",
   "shipping_rule",
+  "incoterm",
   "section_break_41",
   "taxes",
   "section_break_44",
@@ -1381,13 +1382,19 @@
   {
    "fieldname": "column_break_18",
    "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "incoterm",
+   "fieldtype": "Link",
+   "label": "Incoterm",
+   "options": "Incoterm"
   }
  ],
  "icon": "fa fa-truck",
  "idx": 146,
  "is_submittable": 1,
  "links": [],
- "modified": "2022-10-11 13:06:58.655635",
+ "modified": "2022-11-17 17:22:42.860790",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Delivery Note",
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
index 3141212..ab91d7c 100755
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
@@ -63,6 +63,7 @@
   "tax_category",
   "column_break_53",
   "shipping_rule",
+  "incoterm",
   "taxes_section",
   "taxes",
   "totals",
@@ -1218,13 +1219,19 @@
   {
    "fieldname": "column_break_104",
    "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "incoterm",
+   "fieldtype": "Link",
+   "label": "Incoterm",
+   "options": "Incoterm"
   }
  ],
  "icon": "fa fa-truck",
  "idx": 261,
  "is_submittable": 1,
  "links": [],
- "modified": "2022-10-11 13:02:31.776256",
+ "modified": "2022-11-17 17:29:30.067536",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Purchase Receipt",
diff --git a/erpnext/stock/doctype/shipment/shipment.json b/erpnext/stock/doctype/shipment/shipment.json
index a33cbc2..53b549d 100644
--- a/erpnext/stock/doctype/shipment/shipment.json
+++ b/erpnext/stock/doctype/shipment/shipment.json
@@ -412,9 +412,9 @@
   },
   {
    "fieldname": "incoterm",
-   "fieldtype": "Select",
+   "fieldtype": "Link",
    "label": "Incoterm",
-   "options": "EXW (Ex Works)\nFCA (Free Carrier)\nCPT (Carriage Paid To)\nCIP (Carriage and Insurance Paid to)\nDPU (Delivered At Place Unloaded)\nDAP (Delivered At Place)\nDDP (Delivered Duty Paid)"
+   "options": "Incoterm"
   },
   {
    "fieldname": "shipment_delivery_note",
@@ -433,10 +433,11 @@
  ],
  "is_submittable": 1,
  "links": [],
- "modified": "2021-04-13 17:14:18.181818",
+ "modified": "2022-11-17 17:23:27.025802",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Shipment",
+ "naming_rule": "Expression (old style)",
  "owner": "Administrator",
  "permissions": [
   {
@@ -470,5 +471,6 @@
  ],
  "sort_field": "modified",
  "sort_order": "DESC",
+ "states": [],
  "track_changes": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/translations/de.csv b/erpnext/translations/de.csv
index 0caea25..0fdd3c9 100644
--- a/erpnext/translations/de.csv
+++ b/erpnext/translations/de.csv
@@ -9903,3 +9903,14 @@
 Total Liability,Verbindlichkeiten,
 Total Equity,Eigenkapital,
 Warehouse wise Stock Value,Warenwert nach Lager,
+Ex Works,Ab Werk,
+Free Carrier,Frei Frachtführer,
+Free Alongside Ship,Frei Längsseite Schiff,
+Free on Board,Frei an Bord,
+Carriage Paid To,Frachtfrei,
+Carriage and Insurance Paid to,Frachtfrei versichert,
+Cost and Freight,Kosten und Fracht,
+"Cost, Insurance and Freight","Kosten, Versicherung und Fracht",
+Delivered at Place,Geliefert benannter Ort,
+Delivered at Place Unloaded,Geliefert benannter Ort entladen,
+Delivered Duty Paid,Geliefert verzollt,