diff --git a/erpnext/buying/doctype/supplier/regional/france.js b/erpnext/buying/doctype/supplier/regional/france.js
index 2ffa764d0b29da7fb9935656a64a130ddf4277d1..72aaf6f6a4d94ed20cdde26ec8c2ffcdd75e23bb 100644
--- a/erpnext/buying/doctype/supplier/regional/france.js
+++ b/erpnext/buying/doctype/supplier/regional/france.js
@@ -1,6 +1,6 @@
frappe.ui.form.on("Supplier", {
- setup: function (frm) {
- frm.set_query("company_search", function(doc) {
+ setup(frm) {
+ frm.set_query("company_search", function (doc) {
return {
query: "erpnext.regional.france.extensions.supplier.company_query"
};
@@ -11,10 +11,11 @@ frappe.ui.form.on("Supplier", {
if (frm.get_field("company_search")._data.length) {
const selection = frm.get_field("company_search")._data.filter(f => f.value == frm.doc.company_search)
- if (selection.length){
- const selected_company = selection[0]
- frm.set_value("supplier_name", selected_company.label)
- frm.set_value("siren_number", selected_company.value)
+ if (selection.length) {
+ const selected_company = selection[0];
+ frm.set_value("supplier_name", selected_company.label);
+ frm.set_value("siren_number", selected_company.value.substring(4));
+ frm.set_value("tax_id", selected_company.value);
}
}
}
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 2a93c3eb9ced3d8092609e88ef97e9837a66fbde..a4867df436667c902ebfdb0f4ecddf2e7852332e 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -387,6 +387,7 @@ erpnext.accounts.doctype.mode_of_payment.patches.migrate_fees_and_cost_center_to
execute:frappe.delete_doc_if_exists("DocType", "Integration References")
execute:frappe.delete_doc_if_exists("DocType", "Social Media Post")
erpnext.patches.dokos.v4_0.update_advance_for_down_payments #2024-05-207
+erpnext.patches.dokos.v4_0.check_enable_pappers
# @dokos
diff --git a/erpnext/patches/dokos/v4_0/check_enable_pappers.py b/erpnext/patches/dokos/v4_0/check_enable_pappers.py
new file mode 100644
index 0000000000000000000000000000000000000000..e8cb4fa60de460b8ca6c91535dc7978153a27bca
--- /dev/null
+++ b/erpnext/patches/dokos/v4_0/check_enable_pappers.py
@@ -0,0 +1,7 @@
+import frappe
+
+
+def execute():
+ global_defauts = frappe.get_single("Global Defaults")
+ if global_defauts.pappers_api_key:
+ frappe.db.set_single_value("Global Defaults", "enable_pappers", 1)
diff --git a/erpnext/public/js/utils/contact_address_quick_entry.js b/erpnext/public/js/utils/contact_address_quick_entry.js
index 6b5254c84c303e23e94b83a719db5609daaadf7c..54dd4155020a11e51e4a7dd1c4db0b4e82827583 100644
--- a/erpnext/public/js/utils/contact_address_quick_entry.js
+++ b/erpnext/public/js/utils/contact_address_quick_entry.js
@@ -35,8 +35,10 @@ frappe.ui.form.ContactAddressQuickEntryForm = class ContactAddressQuickEntryForm
const selected_company = selection[0]
me.dialog.set_values({
customer_name: selected_company.label,
- siren_number: selected_company.value
- })
+ supplier_name: selected_company.label,
+ tax_id: selected_company.value,
+ });
+ me.dialog.refresh();
}
}
}
diff --git a/erpnext/regional/france/extensions/customer.py b/erpnext/regional/france/extensions/customer.py
index 56fe6b5677d164eeafb84ed78ce7e4bcba90c20b..336d39c1e87840e413711f1c74e35f72ce6a363b 100644
--- a/erpnext/regional/france/extensions/customer.py
+++ b/erpnext/regional/france/extensions/customer.py
@@ -1,9 +1,7 @@
from erpnext.regional.france.extensions.supplier import (
- get_info_from_pappers,
- get_siren_from_tax_id,
+ get_pappers_data,
)
def validate(doc, method):
- get_siren_from_tax_id(doc)
- get_info_from_pappers(doc)
+ get_pappers_data(doc)
diff --git a/erpnext/regional/france/extensions/supplier.py b/erpnext/regional/france/extensions/supplier.py
index fc07a925cdba0ac07b13f5afb019a5ee8290e506..b2cb46441aec8a854c51d7fab70367573f802d76 100644
--- a/erpnext/regional/france/extensions/supplier.py
+++ b/erpnext/regional/france/extensions/supplier.py
@@ -1,5 +1,6 @@
import frappe
from frappe import _
+from frappe.contacts.doctype.address.address import get_default_address
from frappe.utils import cint, date_diff, nowdate
from erpnext.regional.france.pappers.entreprise import PappersEntreprise
@@ -7,29 +8,32 @@ from erpnext.regional.france.pappers.recherche import PappersRecherche
def validate(doc, method):
+ get_pappers_data(doc)
+
+def get_pappers_data(doc):
meta = frappe.get_meta(doc.doctype)
if meta.has_field("siren_number"):
- get_siren_from_tax_id(doc)
+ if doc.tax_id and not doc.get("siren_number"):
+ get_siren_from_tax_id(doc.tax_id)
get_info_from_pappers(doc)
-def get_siren_from_tax_id(doc):
- if doc.tax_id and not doc.get("siren_number"):
- doc.siren_number = doc.tax_id[4:]
+def get_siren_from_tax_id(tax_id):
+ return tax_id[4:]
def get_info_from_pappers(doc):
global_defauts = frappe.get_single("Global Defaults")
- if not global_defauts.pappers_api_key:
+ if not global_defauts.enable_pappers or not global_defauts.pappers_api_key:
return
- if not doc.siren_number:
+ if not doc.siren_number or not (doc.tax_id and doc.tax_id.startswith("FR")):
return
if date_diff(nowdate(), doc.last_pappers_update) > cint(global_defauts.pappers_update_interval):
return
- data = PappersEntreprise().get({"siren": doc.siren_number})
+ data = PappersEntreprise().get({"siren": doc.siren_number or get_siren_from_tax_id(doc.tax_id)})
if data and not data.get("statusCode"):
update_tax_id(doc, data.get("numero_tva_intracommunautaire"))
@@ -39,6 +43,8 @@ def get_info_from_pappers(doc):
if meta.has_field(key):
doc.set(key, value)
+ update_billing_address(doc, data)
+
doc.last_pappers_update = nowdate()
@@ -49,16 +55,42 @@ def update_tax_id(doc, vat_number):
elif doc.tax_id != vat_number:
frappe.msgprint(
_(
- "The VAT number registered in this document doesn't match the VAT number available publicly for this company: {}".format(
+ "The VAT number registered in this document doesn't match the VAT number available publicly for this company: {}".format( # noqa: UP032
vat_number
)
)
)
+def update_billing_address(doc, pappers_data):
+ data = frappe._dict(pappers_data.get("siege", {}))
+ if not get_default_address(doc.doctype, doc.name, sort_key="is_primary_address"):
+ if data.get("ville") and frappe.db.exists("Country", data.get("pays")):
+ address = frappe.new_doc("Address")
+ address.update(
+ {
+ "address_title": pappers_data.get("denomination"),
+ "address_type": "Billing",
+ "address_line1": data.get("adresse_ligne_1"),
+ "address_line2": data.get("adresse_ligne_2"),
+ "city": data.get("ville"),
+ "country": data.get("pays"),
+ }
+ )
+ address.append("links", {"link_doctype": doc.doctype, "link_name": doc.name})
+ address.insert()
+
+
@frappe.whitelist()
def company_query(txt):
if txt:
+ if txt.startswith("FR") and len(txt) == 13 and txt[4:].isdigit():
+ if res := get_company_by_siren(get_siren_from_tax_id(txt)):
+ return res
+ if len(txt.replace(" ", "")) == 9 and txt.replace(" ", "").isdigit():
+ if res := get_company_by_siren(txt.replace(" ", "")):
+ return res
+
res = PappersRecherche().get(
{"q": txt, "cibles": "nom_entreprise,siren,siret", "longueur": 100, "api_token": None}
)
@@ -71,10 +103,26 @@ def company_query(txt):
return list(
{
"label": r.get("nom_entreprise"),
- "value": r.get("siren"),
+ "value": r.get("numero_tva_intracommunautaire") or calculated_vat_number(r.get('siren')),
"description": f"SIREN: {r.get('siren_formate')}
{r.get('siege', {}).get('adresse_ligne_1', '')} {r.get('siege', {}).get('code_postal', '')} {r.get('siege', {}).get('ville', '')}",
}
for r in res.get("resultats_nom_entreprise", [])
)
return []
+
+def get_company_by_siren(siren):
+ res = PappersEntreprise().get({"siren": siren})
+ if not res.get("statusCode"):
+ return list([
+ {
+ "label": res.get("nom_entreprise"),
+ "value": res.get("numero_tva_intracommunautaire"),
+ "description": f"SIREN: {res.get('siren_formate')}
{res.get('siege', {}).get('adresse_ligne_1', '')} {res.get('siege', {}).get('code_postal', '')} {res.get('siege', {}).get('ville', '')}",
+ }
+ ])
+
+ return []
+
+def calculated_vat_number(siren):
+ return f"FR{(12+3*int(siren)%97)%97}{siren}"
diff --git a/erpnext/regional/france/pappers/api.py b/erpnext/regional/france/pappers/api.py
index 51486af13c79cf92b8376a71497de358d0574d19..592d187de055fcec4d5f2c5aab27b6831d2f941c 100644
--- a/erpnext/regional/france/pappers/api.py
+++ b/erpnext/regional/france/pappers/api.py
@@ -27,6 +27,8 @@ def setup_pappers(doc, method):
def setup_custom_fields():
+ # _("The search tool uses Pappers API")
+
pappers_fields = [
dict(
fieldname="public_information_tab",
@@ -249,7 +251,7 @@ def setup_custom_fields():
label="Company Search",
fieldtype="Autocomplete",
insert_after="naming_series",
- description="The search tool uses Pappers API.
You are limited to 100 searches per day.",
+ description="The search tool uses Pappers API",
allow_in_quick_entry=True,
),
]
diff --git a/erpnext/regional/france/pappers/entreprise.py b/erpnext/regional/france/pappers/entreprise.py
index 8860e3712f7bf81441fe119fe16c1f2dbffcd99a..ed262fa64305ee682ab31a54e648b97129c0fab3 100644
--- a/erpnext/regional/france/pappers/entreprise.py
+++ b/erpnext/regional/france/pappers/entreprise.py
@@ -3,5 +3,5 @@ from erpnext.regional.france.pappers.api import PappersAPI
class PappersEntreprise(PappersAPI):
def __init__(self):
- super(PappersEntreprise, self).__init__()
+ super().__init__()
self.url = f"{self.base_url.rstrip('/')}/entreprise"
diff --git a/erpnext/selling/doctype/customer/regional/france.js b/erpnext/selling/doctype/customer/regional/france.js
index b1f9686c43bc8599c6e35e56910fafb9b307aa47..7e56e6dea86f8291d5f15e4c0cdd9eaaf89213b5 100644
--- a/erpnext/selling/doctype/customer/regional/france.js
+++ b/erpnext/selling/doctype/customer/regional/france.js
@@ -11,10 +11,11 @@ frappe.ui.form.on("Customer", {
if (frm.get_field("company_search")._data.length) {
const selection = frm.get_field("company_search")._data.filter(f => f.value == frm.doc.company_search)
- if (selection.length){
- const selected_company = selection[0]
- frm.set_value("customer_name", selected_company.label)
- frm.set_value("siren_number", selected_company.value)
+ if (selection.length) {
+ const selected_company = selection[0];
+ frm.set_value("customer_name", selected_company.label);
+ frm.set_value("siren_number", selected_company.value.substring(4));
+ frm.set_value("tax_id", selected_company.value);
}
}
}
diff --git a/erpnext/setup/doctype/global_defaults/global_defaults.json b/erpnext/setup/doctype/global_defaults/global_defaults.json
index 640f666974847a77121795063bab354739a4d94a..7bd158b2cda36c40c5d18a4d7027e9401dfaeab9 100644
--- a/erpnext/setup/doctype/global_defaults/global_defaults.json
+++ b/erpnext/setup/doctype/global_defaults/global_defaults.json
@@ -15,6 +15,8 @@
"disable_in_words",
"pappers_tab",
"pappers_help",
+ "enable_pappers",
+ "section_break_cdgg",
"pappers_api_key",
"pappers_update_interval"
],
@@ -88,15 +90,27 @@
"label": "Pappers Help"
},
{
+ "depends_on": "eval:doc.enable_pappers",
"fieldname": "pappers_api_key",
"fieldtype": "Password",
"label": "API Key"
},
{
"default": "90",
+ "depends_on": "eval:doc.enable_pappers",
"fieldname": "pappers_update_interval",
"fieldtype": "Int",
"label": "Update data every (Days)"
+ },
+ {
+ "default": "0",
+ "fieldname": "enable_pappers",
+ "fieldtype": "Check",
+ "label": "Enable Pappers"
+ },
+ {
+ "fieldname": "section_break_cdgg",
+ "fieldtype": "Section Break"
}
],
"icon": "fa fa-cog",
@@ -104,7 +118,7 @@
"in_create": 1,
"issingle": 1,
"links": [],
- "modified": "2023-09-02 16:42:42.943877",
+ "modified": "2024-12-20 21:19:40.872287",
"modified_by": "Administrator",
"module": "Setup",
"name": "Global Defaults",
@@ -122,4 +136,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"states": []
-}
+}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/global_defaults/global_defaults.py b/erpnext/setup/doctype/global_defaults/global_defaults.py
index 2e7fdd759e58c5565e6ccd6b58b9469f8526c0cb..8c26cf1f859abacb40c3b4fe7777ce7557eaa6c4 100644
--- a/erpnext/setup/doctype/global_defaults/global_defaults.py
+++ b/erpnext/setup/doctype/global_defaults/global_defaults.py
@@ -37,6 +37,7 @@ class GlobalDefaults(Document):
default_distance_unit: DF.Link | None
disable_in_words: DF.Check
disable_rounded_total: DF.Check
+ enable_pappers: DF.Check
hide_currency_symbol: DF.Literal["", "No", "Yes"]
pappers_api_key: DF.Password | None
pappers_update_interval: DF.Int