feat(tally): Preprocess and create parties and addresses
This commit is contained in:
parent
0668482f82
commit
f2202cf638
@ -368,6 +368,70 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"translatable": 0,
|
"translatable": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_in_quick_entry": 0,
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"columns": 0,
|
||||||
|
"fieldname": "parties",
|
||||||
|
"fieldtype": "Attach",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
|
"label": "Parties",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"translatable": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_in_quick_entry": 0,
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"columns": 0,
|
||||||
|
"fieldname": "addresses",
|
||||||
|
"fieldtype": "Attach",
|
||||||
|
"hidden": 0,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
|
"label": "Addresses",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"translatable": 0,
|
||||||
|
"unique": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
"has_web_view": 0,
|
||||||
@ -380,7 +444,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2019-03-01 20:58:04.320605",
|
"modified": "2019-03-01 22:44:04.042954",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "ERPNext Integrations",
|
"module": "ERPNext Integrations",
|
||||||
"name": "Tally Migration",
|
"name": "Tally Migration",
|
||||||
|
@ -6,6 +6,7 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
|
import traceback
|
||||||
import zipfile
|
import zipfile
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
@ -17,6 +18,7 @@ PRIMARY_ACCOUNT = "Primary"
|
|||||||
class TallyMigration(Document):
|
class TallyMigration(Document):
|
||||||
def _preprocess(self):
|
def _preprocess(self):
|
||||||
company, chart_of_accounts_tree, customers, suppliers = self._process_master_data()
|
company, chart_of_accounts_tree, customers, suppliers = self._process_master_data()
|
||||||
|
parties, addresses = self._process_parties(customers, suppliers)
|
||||||
self.tally_company = company
|
self.tally_company = company
|
||||||
self.erpnext_company = company
|
self.erpnext_company = company
|
||||||
self.status = "Preprocessed"
|
self.status = "Preprocessed"
|
||||||
@ -29,6 +31,25 @@ class TallyMigration(Document):
|
|||||||
"content": json.dumps(chart_of_accounts_tree)
|
"content": json.dumps(chart_of_accounts_tree)
|
||||||
}).insert()
|
}).insert()
|
||||||
self.chart_of_accounts = coa_file.file_url
|
self.chart_of_accounts = coa_file.file_url
|
||||||
|
|
||||||
|
parties_file = frappe.get_doc({
|
||||||
|
"doctype": "File",
|
||||||
|
"file_name": "Parties.json",
|
||||||
|
"attached_to_doctype": self.doctype,
|
||||||
|
"attached_to_name": self.name,
|
||||||
|
"content": json.dumps(parties)
|
||||||
|
}).insert()
|
||||||
|
self.parties = parties_file.file_url
|
||||||
|
|
||||||
|
addresses_file = frappe.get_doc({
|
||||||
|
"doctype": "File",
|
||||||
|
"file_name": "Addresses.json",
|
||||||
|
"attached_to_doctype": self.doctype,
|
||||||
|
"attached_to_name": self.name,
|
||||||
|
"content": json.dumps(addresses)
|
||||||
|
}).insert()
|
||||||
|
self.addresses = addresses_file.file_url
|
||||||
|
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def _process_master_data(self):
|
def _process_master_data(self):
|
||||||
@ -93,6 +114,7 @@ class TallyMigration(Document):
|
|||||||
for parent, account, is_group in accounts:
|
for parent, account, is_group in accounts:
|
||||||
children.setdefault(parent, set()).add(account)
|
children.setdefault(parent, set()).add(account)
|
||||||
parents.setdefault(account, set()).add(parent)
|
parents.setdefault(account, set()).add(parent)
|
||||||
|
parents[account].update(parents.get(parent, []))
|
||||||
return children, parents
|
return children, parents
|
||||||
|
|
||||||
def remove_parties(parents, children, group_set):
|
def remove_parties(parents, children, group_set):
|
||||||
@ -126,10 +148,63 @@ class TallyMigration(Document):
|
|||||||
|
|
||||||
return company, chart_of_accounts_tree, customer_names, supplier_names
|
return company, chart_of_accounts_tree, customer_names, supplier_names
|
||||||
|
|
||||||
|
def _process_parties(self, customers, suppliers):
|
||||||
|
def get_master_collection(master_data):
|
||||||
|
master_file = frappe.get_doc("File", {"file_url": master_data})
|
||||||
|
|
||||||
|
with zipfile.ZipFile(master_file.get_full_path()) as zf:
|
||||||
|
content = zf.read(zf.namelist()[0]).decode("utf-16")
|
||||||
|
|
||||||
|
master = bs(sanitize(emptify(content)), "xml")
|
||||||
|
collection = master.BODY.IMPORTDATA.REQUESTDATA
|
||||||
|
return collection
|
||||||
|
|
||||||
|
def get_parties_addresses(collection, customers, suppliers):
|
||||||
|
parties, addresses = [], []
|
||||||
|
for account in collection.find_all("LEDGER"):
|
||||||
|
party_type = None
|
||||||
|
if account.NAME.string in customers:
|
||||||
|
party_type = "Customer"
|
||||||
|
parties.append({
|
||||||
|
"doctype": party_type,
|
||||||
|
"customer_name": account.NAME.string,
|
||||||
|
"tax_id": account.INCOMETAXNUMBER.string if account.INCOMETAXNUMBER else None,
|
||||||
|
"customer_group": "All Customer Groups",
|
||||||
|
"territory": "All Territories",
|
||||||
|
"customer_type": "Individual",
|
||||||
|
})
|
||||||
|
elif account.NAME.string in suppliers:
|
||||||
|
party_type = "Supplier"
|
||||||
|
parties.append({
|
||||||
|
"doctype": party_type,
|
||||||
|
"supplier_name": account.NAME.string,
|
||||||
|
"pan": account.INCOMETAXNUMBER.string if account.INCOMETAXNUMBER else None,
|
||||||
|
"supplier_group": "All Supplier Groups",
|
||||||
|
"supplier_type": "Individual",
|
||||||
|
})
|
||||||
|
if party_type:
|
||||||
|
address = "\n".join([a.string for a in account.find_all("ADDRESS")[:2]])
|
||||||
|
addresses.append({
|
||||||
|
"doctype": "Address",
|
||||||
|
"address_line1": address[:140].strip(),
|
||||||
|
"address_line2": address[140:].strip(),
|
||||||
|
"country": account.COUNTRYNAME.string if account.COUNTRYNAME else None,
|
||||||
|
"state": account.STATENAME.string if account.STATENAME else None,
|
||||||
|
"gst_state": account.STATENAME.string if account.STATENAME else None,
|
||||||
|
"pin_code": account.PINCODE.string if account.PINCODE else None,
|
||||||
|
"gstin": account.PARTYGSTIN.string if account.PARTYGSTIN else None,
|
||||||
|
"links": [{"link_doctype": party_type, "link_name": account["NAME"]}],
|
||||||
|
})
|
||||||
|
return parties, addresses
|
||||||
|
|
||||||
|
collection = get_master_collection(self.master_data)
|
||||||
|
parties, addresses = get_parties_addresses(collection, customers, suppliers)
|
||||||
|
return parties, addresses
|
||||||
|
|
||||||
def preprocess(self):
|
def preprocess(self):
|
||||||
frappe.enqueue_doc(self.doctype, self.name, "_preprocess")
|
frappe.enqueue_doc(self.doctype, self.name, "_preprocess")
|
||||||
|
|
||||||
def start_import(self):
|
def _start_import(self):
|
||||||
def create_company_and_coa(coa_file_url):
|
def create_company_and_coa(coa_file_url):
|
||||||
coa_file = frappe.get_doc("File", {"file_url": coa_file_url})
|
coa_file = frappe.get_doc("File", {"file_url": coa_file_url})
|
||||||
frappe.local.flags.ignore_chart_of_accounts = True
|
frappe.local.flags.ignore_chart_of_accounts = True
|
||||||
@ -141,8 +216,30 @@ class TallyMigration(Document):
|
|||||||
frappe.local.flags.ignore_chart_of_accounts = False
|
frappe.local.flags.ignore_chart_of_accounts = False
|
||||||
create_charts(company.name, json.loads(coa_file.get_content()))
|
create_charts(company.name, json.loads(coa_file.get_content()))
|
||||||
|
|
||||||
create_company_and_coa(self.chart_of_accounts)
|
def create_parties_addresses(parties_file_url, addresses_file_url):
|
||||||
|
parties_file = frappe.get_doc("File", {"file_url": parties_file_url})
|
||||||
|
for party in json.loads(parties_file.get_content()):
|
||||||
|
try:
|
||||||
|
frappe.get_doc(party).insert()
|
||||||
|
except:
|
||||||
|
log(party)
|
||||||
|
addresses_file = frappe.get_doc("File", {"file_url": addresses_file_url})
|
||||||
|
for address in json.loads(addresses_file.get_content()):
|
||||||
|
try:
|
||||||
|
frappe.get_doc(address).insert(ignore_mandatory=True)
|
||||||
|
except:
|
||||||
|
log(address)
|
||||||
|
|
||||||
|
create_company_and_coa(self.chart_of_accounts)
|
||||||
|
create_parties_addresses(self.parties, self.addresses)
|
||||||
|
|
||||||
|
def start_import(self):
|
||||||
|
frappe.enqueue_doc(self.doctype, self.name, "_start_import")
|
||||||
|
|
||||||
|
|
||||||
|
def log(data=None):
|
||||||
|
message = json.dumps({"data": data, "exception": traceback.format_exc()}, indent=4)
|
||||||
|
frappe.log_error(title="Tally Migration Error", message=message)
|
||||||
|
|
||||||
def sanitize(string):
|
def sanitize(string):
|
||||||
return re.sub("", "", string)
|
return re.sub("", "", string)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user