mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-29 06:38:24 +00:00
Merge branch 'version-13-hotfix' into email-digest
This commit is contained in:
@@ -90,12 +90,6 @@ frappe.ui.form.on("Company", {
|
||||
frm.toggle_enable("default_currency", (frm.doc.__onload &&
|
||||
!frm.doc.__onload.transactions_exist));
|
||||
|
||||
if (frm.has_perm('write')) {
|
||||
frm.add_custom_button(__('Create Tax Template'), function() {
|
||||
frm.trigger("make_default_tax_template");
|
||||
});
|
||||
}
|
||||
|
||||
if (frappe.perm.has_perm("Cost Center", 0, 'read')) {
|
||||
frm.add_custom_button(__('Cost Centers'), function() {
|
||||
frappe.set_route('Tree', 'Cost Center', {'company': frm.doc.name});
|
||||
@@ -121,17 +115,21 @@ frappe.ui.form.on("Company", {
|
||||
}
|
||||
|
||||
if (frm.has_perm('write')) {
|
||||
frm.add_custom_button(__('Default Tax Template'), function() {
|
||||
frm.add_custom_button(__('Create Tax Template'), function() {
|
||||
frm.trigger("make_default_tax_template");
|
||||
}, __('Create'));
|
||||
}, __('Manage'));
|
||||
}
|
||||
|
||||
if (frappe.user.has_role('System Manager')) {
|
||||
if (frm.has_perm('write')) {
|
||||
frm.add_custom_button(__('Delete Transactions'), function() {
|
||||
frm.trigger("delete_company_transactions");
|
||||
}, __('Manage'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
erpnext.company.set_chart_of_accounts_options(frm.doc);
|
||||
|
||||
if (!frappe.user.has_role('System Manager')) {
|
||||
frm.get_field("delete_company_transactions").hide();
|
||||
}
|
||||
},
|
||||
|
||||
make_default_tax_template: function(frm) {
|
||||
@@ -145,11 +143,6 @@ frappe.ui.form.on("Company", {
|
||||
})
|
||||
},
|
||||
|
||||
onload_post_render: function(frm) {
|
||||
if(frm.get_field("delete_company_transactions").$input)
|
||||
frm.get_field("delete_company_transactions").$input.addClass("btn-danger");
|
||||
},
|
||||
|
||||
country: function(frm) {
|
||||
erpnext.company.set_chart_of_accounts_options(frm.doc);
|
||||
},
|
||||
@@ -169,9 +162,9 @@ frappe.ui.form.on("Company", {
|
||||
return;
|
||||
}
|
||||
frappe.call({
|
||||
method: "erpnext.setup.doctype.company.delete_company_transactions.delete_company_transactions",
|
||||
method: "erpnext.setup.doctype.company.company.create_transaction_deletion_request",
|
||||
args: {
|
||||
company_name: data.company_name
|
||||
company: data.company_name
|
||||
},
|
||||
freeze: true,
|
||||
callback: function(r, rt) {
|
||||
@@ -276,7 +269,7 @@ erpnext.company.setup_queries = function(frm) {
|
||||
["expenses_included_in_asset_valuation", {"account_type": "Expenses Included In Asset Valuation"}],
|
||||
["capital_work_in_progress_account", {"account_type": "Capital Work in Progress"}],
|
||||
["asset_received_but_not_billed", {"account_type": "Asset Received But Not Billed"}],
|
||||
["unrealized_profit_loss_account", {"root_type": "Liability"},]
|
||||
["unrealized_profit_loss_account", {"root_type": ["in", ["Liability", "Asset"]]}]
|
||||
], function(i, v) {
|
||||
erpnext.company.set_custom_query(frm, v);
|
||||
});
|
||||
|
||||
@@ -99,7 +99,6 @@
|
||||
"company_description",
|
||||
"registration_info",
|
||||
"registration_details",
|
||||
"delete_company_transactions",
|
||||
"lft",
|
||||
"rgt",
|
||||
"old_parent"
|
||||
@@ -666,11 +665,6 @@
|
||||
"oldfieldname": "registration_details",
|
||||
"oldfieldtype": "Code"
|
||||
},
|
||||
{
|
||||
"fieldname": "delete_company_transactions",
|
||||
"fieldtype": "Button",
|
||||
"label": "Delete Company Transactions"
|
||||
},
|
||||
{
|
||||
"fieldname": "lft",
|
||||
"fieldtype": "Int",
|
||||
@@ -747,7 +741,7 @@
|
||||
"image_field": "company_logo",
|
||||
"is_tree": 1,
|
||||
"links": [],
|
||||
"modified": "2021-02-16 15:53:37.167589",
|
||||
"modified": "2021-05-07 03:11:28.189740",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Company",
|
||||
|
||||
@@ -17,6 +17,7 @@ from frappe.utils.nestedset import NestedSet
|
||||
from past.builtins import cmp
|
||||
import functools
|
||||
from erpnext.accounts.doctype.account.account import get_account_currency
|
||||
from erpnext.setup.setup_wizard.operations.taxes_setup import setup_taxes_and_charges
|
||||
|
||||
class Company(NestedSet):
|
||||
nsm_parent_field = 'parent_company'
|
||||
@@ -53,7 +54,7 @@ class Company(NestedSet):
|
||||
|
||||
def validate_abbr(self):
|
||||
if not self.abbr:
|
||||
self.abbr = ''.join([c[0] for c in self.company_name.split()]).upper()
|
||||
self.abbr = ''.join(c[0] for c in self.company_name.split()).upper()
|
||||
|
||||
self.abbr = self.abbr.strip()
|
||||
|
||||
@@ -68,11 +69,7 @@ class Company(NestedSet):
|
||||
|
||||
@frappe.whitelist()
|
||||
def create_default_tax_template(self):
|
||||
from erpnext.setup.setup_wizard.operations.taxes_setup import create_sales_tax
|
||||
create_sales_tax({
|
||||
'country': self.country,
|
||||
'company_name': self.name
|
||||
})
|
||||
setup_taxes_and_charges(self.name, self.country)
|
||||
|
||||
def validate_default_accounts(self):
|
||||
accounts = [
|
||||
@@ -113,7 +110,7 @@ class Company(NestedSet):
|
||||
self.create_default_warehouses()
|
||||
|
||||
if frappe.flags.country_change:
|
||||
install_country_fixtures(self.name)
|
||||
install_country_fixtures(self.name, self.country)
|
||||
self.create_default_tax_template()
|
||||
|
||||
if not frappe.db.get_value("Department", {"company": self.name}):
|
||||
@@ -294,7 +291,7 @@ class Company(NestedSet):
|
||||
cash = frappe.db.get_value('Mode of Payment', {'type': 'Cash'}, 'name')
|
||||
if cash and self.default_cash_account \
|
||||
and not frappe.db.get_value('Mode of Payment Account', {'company': self.name, 'parent': cash}):
|
||||
mode_of_payment = frappe.get_doc('Mode of Payment', cash)
|
||||
mode_of_payment = frappe.get_doc('Mode of Payment', cash, for_update=True)
|
||||
mode_of_payment.append('accounts', {
|
||||
'company': self.name,
|
||||
'default_account': self.default_cash_account
|
||||
@@ -338,7 +335,7 @@ class Company(NestedSet):
|
||||
clear_defaults_cache()
|
||||
|
||||
def abbreviate(self):
|
||||
self.abbr = ''.join([c[0].upper() for c in self.company_name.split()])
|
||||
self.abbr = ''.join(c[0].upper() for c in self.company_name.split())
|
||||
|
||||
def on_trash(self):
|
||||
"""
|
||||
@@ -398,7 +395,7 @@ class Company(NestedSet):
|
||||
|
||||
@frappe.whitelist()
|
||||
def enqueue_replace_abbr(company, old, new):
|
||||
kwargs = dict(company=company, old=old, new=new)
|
||||
kwargs = dict(queue="long", company=company, old=old, new=new)
|
||||
frappe.enqueue('erpnext.setup.doctype.company.company.replace_abbr', **kwargs)
|
||||
|
||||
|
||||
@@ -410,8 +407,6 @@ def replace_abbr(company, old, new):
|
||||
|
||||
frappe.only_for("System Manager")
|
||||
|
||||
frappe.db.set_value("Company", company, "abbr", new)
|
||||
|
||||
def _rename_record(doc):
|
||||
parts = doc[0].rsplit(" - ", 1)
|
||||
if len(parts) == 1 or parts[1].lower() == old.lower():
|
||||
@@ -422,11 +417,18 @@ def replace_abbr(company, old, new):
|
||||
doc = (d for d in frappe.db.sql("select name from `tab%s` where company=%s" % (dt, '%s'), company))
|
||||
for d in doc:
|
||||
_rename_record(d)
|
||||
try:
|
||||
frappe.db.auto_commit_on_many_writes = 1
|
||||
frappe.db.set_value("Company", company, "abbr", new)
|
||||
for dt in ["Warehouse", "Account", "Cost Center", "Department",
|
||||
"Sales Taxes and Charges Template", "Purchase Taxes and Charges Template"]:
|
||||
_rename_records(dt)
|
||||
frappe.db.commit()
|
||||
|
||||
for dt in ["Warehouse", "Account", "Cost Center", "Department",
|
||||
"Sales Taxes and Charges Template", "Purchase Taxes and Charges Template"]:
|
||||
_rename_records(dt)
|
||||
frappe.db.commit()
|
||||
except Exception:
|
||||
frappe.log_error(title=_('Abbreviation Rename Error'))
|
||||
finally:
|
||||
frappe.db.auto_commit_on_many_writes = 0
|
||||
|
||||
|
||||
def get_name_with_abbr(name, company):
|
||||
@@ -438,16 +440,15 @@ def get_name_with_abbr(name, company):
|
||||
|
||||
return " - ".join(parts)
|
||||
|
||||
def install_country_fixtures(company):
|
||||
company_doc = frappe.get_doc("Company", company)
|
||||
path = frappe.get_app_path('erpnext', 'regional', frappe.scrub(company_doc.country))
|
||||
def install_country_fixtures(company, country):
|
||||
path = frappe.get_app_path('erpnext', 'regional', frappe.scrub(country))
|
||||
if os.path.exists(path.encode("utf-8")):
|
||||
try:
|
||||
module_name = "erpnext.regional.{0}.setup.setup".format(frappe.scrub(company_doc.country))
|
||||
frappe.get_attr(module_name)(company_doc, False)
|
||||
module_name = "erpnext.regional.{0}.setup.setup".format(frappe.scrub(country))
|
||||
frappe.get_attr(module_name)(company, False)
|
||||
except Exception as e:
|
||||
frappe.log_error()
|
||||
frappe.throw(_("Failed to setup defaults for country {0}. Please contact support@erpnext.com").format(frappe.bold(company_doc.country)))
|
||||
frappe.throw(_("Failed to setup defaults for country {0}. Please contact support@erpnext.com").format(frappe.bold(country)))
|
||||
|
||||
|
||||
def update_company_current_month_sales(company):
|
||||
@@ -616,4 +617,13 @@ def get_default_company_address(name, sort_key='is_primary_address', existing_ad
|
||||
if out:
|
||||
return sorted(out, key = functools.cmp_to_key(lambda x,y: cmp(y[1], x[1])))[0][0]
|
||||
else:
|
||||
return None
|
||||
return None
|
||||
|
||||
@frappe.whitelist()
|
||||
def create_transaction_deletion_request(company):
|
||||
tdr = frappe.get_doc({
|
||||
'doctype': 'Transaction Deletion Record',
|
||||
'company': company
|
||||
})
|
||||
tdr.insert()
|
||||
tdr.submit()
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
from frappe.utils import cint
|
||||
from frappe import _
|
||||
from frappe.desk.notifications import clear_notifications
|
||||
|
||||
import functools
|
||||
|
||||
@frappe.whitelist()
|
||||
def delete_company_transactions(company_name):
|
||||
frappe.only_for("System Manager")
|
||||
doc = frappe.get_doc("Company", company_name)
|
||||
|
||||
if frappe.session.user != doc.owner:
|
||||
frappe.throw(_("Transactions can only be deleted by the creator of the Company"),
|
||||
frappe.PermissionError)
|
||||
|
||||
delete_bins(company_name)
|
||||
delete_lead_addresses(company_name)
|
||||
|
||||
for doctype in frappe.db.sql_list("""select parent from
|
||||
tabDocField where fieldtype='Link' and options='Company'"""):
|
||||
if doctype not in ("Account", "Cost Center", "Warehouse", "Budget",
|
||||
"Party Account", "Employee", "Sales Taxes and Charges Template",
|
||||
"Purchase Taxes and Charges Template", "POS Profile", "BOM",
|
||||
"Company", "Bank Account", "Item Tax Template", "Mode Of Payment",
|
||||
"Item Default", "Customer", "Supplier", "GST Account"):
|
||||
delete_for_doctype(doctype, company_name)
|
||||
|
||||
# reset company values
|
||||
doc.total_monthly_sales = 0
|
||||
doc.sales_monthly_history = None
|
||||
doc.save()
|
||||
# Clear notification counts
|
||||
clear_notifications()
|
||||
|
||||
def delete_for_doctype(doctype, company_name):
|
||||
meta = frappe.get_meta(doctype)
|
||||
company_fieldname = meta.get("fields", {"fieldtype": "Link",
|
||||
"options": "Company"})[0].fieldname
|
||||
|
||||
if not meta.issingle:
|
||||
if not meta.istable:
|
||||
# delete communication
|
||||
delete_communications(doctype, company_name, company_fieldname)
|
||||
|
||||
# delete children
|
||||
for df in meta.get_table_fields():
|
||||
frappe.db.sql("""delete from `tab{0}` where parent in
|
||||
(select name from `tab{1}` where `{2}`=%s)""".format(df.options,
|
||||
doctype, company_fieldname), company_name)
|
||||
|
||||
#delete version log
|
||||
frappe.db.sql("""delete from `tabVersion` where ref_doctype=%s and docname in
|
||||
(select name from `tab{0}` where `{1}`=%s)""".format(doctype,
|
||||
company_fieldname), (doctype, company_name))
|
||||
|
||||
# delete parent
|
||||
frappe.db.sql("""delete from `tab{0}`
|
||||
where {1}= %s """.format(doctype, company_fieldname), company_name)
|
||||
|
||||
# reset series
|
||||
naming_series = meta.get_field("naming_series")
|
||||
if naming_series and naming_series.options:
|
||||
prefixes = sorted(naming_series.options.split("\n"),
|
||||
key=functools.cmp_to_key(lambda a, b: len(b) - len(a)))
|
||||
|
||||
for prefix in prefixes:
|
||||
if prefix:
|
||||
last = frappe.db.sql("""select max(name) from `tab{0}`
|
||||
where name like %s""".format(doctype), prefix + "%")
|
||||
if last and last[0][0]:
|
||||
last = cint(last[0][0].replace(prefix, ""))
|
||||
else:
|
||||
last = 0
|
||||
|
||||
frappe.db.sql("""update tabSeries set current = %s
|
||||
where name=%s""", (last, prefix))
|
||||
|
||||
def delete_bins(company_name):
|
||||
frappe.db.sql("""delete from tabBin where warehouse in
|
||||
(select name from tabWarehouse where company=%s)""", company_name)
|
||||
|
||||
def delete_lead_addresses(company_name):
|
||||
"""Delete addresses to which leads are linked"""
|
||||
leads = frappe.get_all("Lead", filters={"company": company_name})
|
||||
leads = [ "'%s'"%row.get("name") for row in leads ]
|
||||
addresses = []
|
||||
if leads:
|
||||
addresses = frappe.db.sql_list("""select parent from `tabDynamic Link` where link_name
|
||||
in ({leads})""".format(leads=",".join(leads)))
|
||||
|
||||
if addresses:
|
||||
addresses = ["%s" % frappe.db.escape(addr) for addr in addresses]
|
||||
|
||||
frappe.db.sql("""delete from tabAddress where name in ({addresses}) and
|
||||
name not in (select distinct dl1.parent from `tabDynamic Link` dl1
|
||||
inner join `tabDynamic Link` dl2 on dl1.parent=dl2.parent
|
||||
and dl1.link_doctype<>dl2.link_doctype)""".format(addresses=",".join(addresses)))
|
||||
|
||||
frappe.db.sql("""delete from `tabDynamic Link` where link_doctype='Lead'
|
||||
and parenttype='Address' and link_name in ({leads})""".format(leads=",".join(leads)))
|
||||
|
||||
frappe.db.sql("""update tabCustomer set lead_name=NULL where lead_name in ({leads})""".format(leads=",".join(leads)))
|
||||
|
||||
def delete_communications(doctype, company_name, company_fieldname):
|
||||
reference_docs = frappe.get_all(doctype, filters={company_fieldname:company_name})
|
||||
reference_doc_names = [r.name for r in reference_docs]
|
||||
|
||||
communications = frappe.get_all("Communication", filters={"reference_doctype":doctype,"reference_name":["in", reference_doc_names]})
|
||||
communication_names = [c.name for c in communications]
|
||||
|
||||
frappe.delete_doc("Communication", communication_names, ignore_permissions=True)
|
||||
@@ -86,15 +86,6 @@ class TestCompany(unittest.TestCase):
|
||||
self.delete_mode_of_payment(template)
|
||||
frappe.delete_doc("Company", template)
|
||||
|
||||
def test_delete_communication(self):
|
||||
from erpnext.setup.doctype.company.delete_company_transactions import delete_communications
|
||||
company = create_child_company()
|
||||
lead = create_test_lead_in_company(company)
|
||||
communication = create_company_communication("Lead", lead)
|
||||
delete_communications("Lead", "Test Company", "company")
|
||||
self.assertFalse(frappe.db.exists("Communcation", communication))
|
||||
self.assertFalse(frappe.db.exists({"doctype":"Comunication Link", "link_name": communication}))
|
||||
|
||||
def delete_mode_of_payment(self, company):
|
||||
frappe.db.sql(""" delete from `tabMode of Payment Account`
|
||||
where company =%s """, (company))
|
||||
|
||||
@@ -60,6 +60,9 @@ class EmailDigest(Document):
|
||||
reference_name = self.name,
|
||||
unsubscribe_message = _("Unsubscribe from this Email Digest"))
|
||||
|
||||
frappe.set_user(original_user)
|
||||
frappe.set_user_lang(original_user)
|
||||
|
||||
def get_msg_html(self):
|
||||
"""Build email digest content"""
|
||||
frappe.flags.ignore_account_permission = True
|
||||
@@ -240,7 +243,7 @@ class EmailDigest(Document):
|
||||
card = cache.get(cache_key)
|
||||
|
||||
if card:
|
||||
card = eval(card)
|
||||
card = frappe.safe_eval(card)
|
||||
|
||||
else:
|
||||
card = frappe._dict(getattr(self, "get_" + key)())
|
||||
@@ -799,7 +802,6 @@ def get_incomes_expenses_for_period(account, from_date, to_date):
|
||||
val = balance_on_to_date - balance_before_from_date
|
||||
else:
|
||||
last_year_closing_balance = get_balance_on(account, date=fy_start_date - timedelta(days=1))
|
||||
print(fy_start_date - timedelta(days=1), last_year_closing_balance)
|
||||
val = balance_on_to_date + (last_year_closing_balance - balance_before_from_date)
|
||||
|
||||
return val
|
||||
@@ -828,4 +830,4 @@ def get_future_date_for_calendaer_event(frequency):
|
||||
elif frequency == "Monthly":
|
||||
to_date = add_to_date(from_date, months=1)
|
||||
|
||||
return from_date, to_date
|
||||
return from_date, to_date
|
||||
|
||||
@@ -59,12 +59,14 @@ class GlobalDefaults(Document):
|
||||
|
||||
# Make property setters to hide rounded total fields
|
||||
for doctype in ("Quotation", "Sales Order", "Sales Invoice", "Delivery Note",
|
||||
"Supplier Quotation", "Purchase Order", "Purchase Invoice"):
|
||||
make_property_setter(doctype, "base_rounded_total", "hidden", self.disable_rounded_total, "Check")
|
||||
make_property_setter(doctype, "base_rounded_total", "print_hide", 1, "Check")
|
||||
"Supplier Quotation", "Purchase Order", "Purchase Invoice", "Purchase Receipt"):
|
||||
make_property_setter(doctype, "base_rounded_total", "hidden", self.disable_rounded_total, "Check", validate_fields_for_doctype=False)
|
||||
make_property_setter(doctype, "base_rounded_total", "print_hide", 1, "Check", validate_fields_for_doctype=False)
|
||||
|
||||
make_property_setter(doctype, "rounded_total", "hidden", self.disable_rounded_total, "Check")
|
||||
make_property_setter(doctype, "rounded_total", "print_hide", self.disable_rounded_total, "Check")
|
||||
make_property_setter(doctype, "rounded_total", "hidden", self.disable_rounded_total, "Check", validate_fields_for_doctype=False)
|
||||
make_property_setter(doctype, "rounded_total", "print_hide", self.disable_rounded_total, "Check", validate_fields_for_doctype=False)
|
||||
|
||||
make_property_setter(doctype, "disable_rounded_total", "default", cint(self.disable_rounded_total), "Text", validate_fields_for_doctype=False)
|
||||
|
||||
def toggle_in_words(self):
|
||||
self.disable_in_words = cint(self.disable_in_words)
|
||||
@@ -72,5 +74,5 @@ class GlobalDefaults(Document):
|
||||
# Make property setters to hide in words fields
|
||||
for doctype in ("Quotation", "Sales Order", "Sales Invoice", "Delivery Note",
|
||||
"Supplier Quotation", "Purchase Order", "Purchase Invoice", "Purchase Receipt"):
|
||||
make_property_setter(doctype, "in_words", "hidden", self.disable_in_words, "Check")
|
||||
make_property_setter(doctype, "in_words", "print_hide", self.disable_in_words, "Check")
|
||||
make_property_setter(doctype, "in_words", "hidden", self.disable_in_words, "Check", validate_fields_for_doctype=False)
|
||||
make_property_setter(doctype, "in_words", "print_hide", self.disable_in_words, "Check", validate_fields_for_doctype=False)
|
||||
|
||||
@@ -61,7 +61,7 @@ frappe.ui.form.on("Item Group", {
|
||||
frappe.set_route("List", "Item", {"item_group": frm.doc.name});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
frappe.model.with_doctype('Item', () => {
|
||||
const item_meta = frappe.get_meta('Item');
|
||||
|
||||
@@ -69,10 +69,12 @@ frappe.ui.form.on("Item Group", {
|
||||
df => ['Link', 'Table MultiSelect'].includes(df.fieldtype) && !df.hidden
|
||||
).map(df => ({ label: df.label, value: df.fieldname }));
|
||||
|
||||
const field = frappe.meta.get_docfield("Website Filter Field", "fieldname", frm.docname);
|
||||
field.fieldtype = 'Select';
|
||||
field.options = valid_fields;
|
||||
frm.fields_dict.filter_fields.grid.refresh();
|
||||
frm.fields_dict.filter_fields.grid.update_docfield_property(
|
||||
'fieldname', 'fieldtype', 'Select'
|
||||
);
|
||||
frm.fields_dict.filter_fields.grid.update_docfield_property(
|
||||
'fieldname', 'options', valid_fields
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -87,11 +87,11 @@ class ItemGroup(NestedSet, WebsiteGenerator):
|
||||
if not field_filters:
|
||||
field_filters = {}
|
||||
|
||||
# Ensure the query remains within current item group
|
||||
field_filters['item_group'] = self.name
|
||||
# Ensure the query remains within current item group & sub group
|
||||
field_filters['item_group'] = [ig[0] for ig in get_child_groups(self.name)]
|
||||
|
||||
engine = ProductQuery()
|
||||
context.items = engine.query(attribute_filters, field_filters, search, start)
|
||||
context.items = engine.query(attribute_filters, field_filters, search, start, item_group=self.name)
|
||||
|
||||
filter_engine = ProductFiltersBuilder(self.name)
|
||||
|
||||
@@ -139,7 +139,7 @@ def get_product_list_for_group(product_group=None, start=0, limit=10, search=Non
|
||||
# return child item groups if the type is of "Is Group"
|
||||
return get_child_groups_for_list_in_html(item_group, start, limit, search)
|
||||
|
||||
child_groups = ", ".join([frappe.db.escape(i[0]) for i in get_child_groups(product_group)])
|
||||
child_groups = ", ".join(frappe.db.escape(i[0]) for i in get_child_groups(product_group))
|
||||
|
||||
# base query
|
||||
query = """select I.name, I.item_name, I.item_code, I.route, I.image, I.website_image, I.thumbnail, I.item_group,
|
||||
@@ -239,7 +239,7 @@ def get_item_for_list_in_html(context):
|
||||
return frappe.get_template(products_template).render(context)
|
||||
|
||||
def get_group_item_count(item_group):
|
||||
child_groups = ", ".join(['"' + i[0] + '"' for i in get_child_groups(item_group)])
|
||||
child_groups = ", ".join('"' + i[0] + '"' for i in get_child_groups(item_group))
|
||||
return frappe.db.sql("""select count(*) from `tabItem`
|
||||
where docstatus = 0 and show_in_website = 1
|
||||
and (item_group in (%s)
|
||||
|
||||
@@ -159,6 +159,7 @@ class NamingSeries(Document):
|
||||
if frappe.db.get_value('Series', series, 'name', order_by="name") == None:
|
||||
frappe.db.sql("insert into tabSeries (name, current) values (%s, 0)", (series))
|
||||
|
||||
@frappe.whitelist()
|
||||
def update_series_start(self):
|
||||
if self.prefix:
|
||||
prefix = self.parse_naming_series()
|
||||
@@ -182,8 +183,8 @@ class NamingSeries(Document):
|
||||
def set_by_naming_series(doctype, fieldname, naming_series, hide_name_field=True):
|
||||
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
|
||||
if naming_series:
|
||||
make_property_setter(doctype, "naming_series", "hidden", 0, "Check")
|
||||
make_property_setter(doctype, "naming_series", "reqd", 1, "Check")
|
||||
make_property_setter(doctype, "naming_series", "hidden", 0, "Check", validate_fields_for_doctype=False)
|
||||
make_property_setter(doctype, "naming_series", "reqd", 1, "Check", validate_fields_for_doctype=False)
|
||||
|
||||
# set values for mandatory
|
||||
try:
|
||||
@@ -194,15 +195,15 @@ def set_by_naming_series(doctype, fieldname, naming_series, hide_name_field=True
|
||||
pass
|
||||
|
||||
if hide_name_field:
|
||||
make_property_setter(doctype, fieldname, "reqd", 0, "Check")
|
||||
make_property_setter(doctype, fieldname, "hidden", 1, "Check")
|
||||
make_property_setter(doctype, fieldname, "reqd", 0, "Check", validate_fields_for_doctype=False)
|
||||
make_property_setter(doctype, fieldname, "hidden", 1, "Check", validate_fields_for_doctype=False)
|
||||
else:
|
||||
make_property_setter(doctype, "naming_series", "reqd", 0, "Check")
|
||||
make_property_setter(doctype, "naming_series", "hidden", 1, "Check")
|
||||
make_property_setter(doctype, "naming_series", "reqd", 0, "Check", validate_fields_for_doctype=False)
|
||||
make_property_setter(doctype, "naming_series", "hidden", 1, "Check", validate_fields_for_doctype=False)
|
||||
|
||||
if hide_name_field:
|
||||
make_property_setter(doctype, fieldname, "hidden", 0, "Check")
|
||||
make_property_setter(doctype, fieldname, "reqd", 1, "Check")
|
||||
make_property_setter(doctype, fieldname, "hidden", 0, "Check", validate_fields_for_doctype=False)
|
||||
make_property_setter(doctype, fieldname, "reqd", 1, "Check", validate_fields_for_doctype=False)
|
||||
|
||||
# set values for mandatory
|
||||
frappe.db.sql("""update `tab{doctype}` set `{fieldname}`=`name` where
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
|
||||
class TestTransactionDeletionRecord(unittest.TestCase):
|
||||
def setUp(self):
|
||||
create_company('Dunder Mifflin Paper Co')
|
||||
|
||||
def tearDown(self):
|
||||
frappe.db.rollback()
|
||||
|
||||
def test_doctypes_contain_company_field(self):
|
||||
tdr = create_transaction_deletion_request('Dunder Mifflin Paper Co')
|
||||
for doctype in tdr.doctypes:
|
||||
contains_company = False
|
||||
doctype_fields = frappe.get_meta(doctype.doctype_name).as_dict()['fields']
|
||||
for doctype_field in doctype_fields:
|
||||
if doctype_field['fieldtype'] == 'Link' and doctype_field['options'] == 'Company':
|
||||
contains_company = True
|
||||
break
|
||||
self.assertTrue(contains_company)
|
||||
|
||||
def test_no_of_docs_is_correct(self):
|
||||
for i in range(5):
|
||||
create_task('Dunder Mifflin Paper Co')
|
||||
tdr = create_transaction_deletion_request('Dunder Mifflin Paper Co')
|
||||
for doctype in tdr.doctypes:
|
||||
if doctype.doctype_name == 'Task':
|
||||
self.assertEqual(doctype.no_of_docs, 5)
|
||||
|
||||
def test_deletion_is_successful(self):
|
||||
create_task('Dunder Mifflin Paper Co')
|
||||
create_transaction_deletion_request('Dunder Mifflin Paper Co')
|
||||
tasks_containing_company = frappe.get_all('Task',
|
||||
filters = {
|
||||
'company' : 'Dunder Mifflin Paper Co'
|
||||
})
|
||||
self.assertEqual(tasks_containing_company, [])
|
||||
|
||||
def create_company(company_name):
|
||||
company = frappe.get_doc({
|
||||
'doctype': 'Company',
|
||||
'company_name': company_name,
|
||||
'default_currency': 'INR'
|
||||
})
|
||||
company.insert(ignore_if_duplicate = True)
|
||||
|
||||
def create_transaction_deletion_request(company):
|
||||
tdr = frappe.get_doc({
|
||||
'doctype': 'Transaction Deletion Record',
|
||||
'company': company
|
||||
})
|
||||
tdr.insert()
|
||||
tdr.submit()
|
||||
return tdr
|
||||
|
||||
|
||||
def create_task(company):
|
||||
task = frappe.get_doc({
|
||||
'doctype': 'Task',
|
||||
'company': company,
|
||||
'subject': 'Delete'
|
||||
})
|
||||
task.insert()
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Transaction Deletion Record', {
|
||||
onload: function(frm) {
|
||||
if (frm.doc.docstatus == 0) {
|
||||
let doctypes_to_be_ignored_array;
|
||||
frappe.call({
|
||||
method: 'erpnext.setup.doctype.transaction_deletion_record.transaction_deletion_record.get_doctypes_to_be_ignored',
|
||||
callback: function(r) {
|
||||
doctypes_to_be_ignored_array = r.message;
|
||||
populate_doctypes_to_be_ignored(doctypes_to_be_ignored_array, frm);
|
||||
frm.fields_dict['doctypes_to_be_ignored'].grid.set_column_disp('no_of_docs', false);
|
||||
frm.refresh_field('doctypes_to_be_ignored');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
frm.get_field('doctypes_to_be_ignored').grid.cannot_add_rows = true;
|
||||
frm.fields_dict['doctypes_to_be_ignored'].grid.set_column_disp('no_of_docs', false);
|
||||
frm.refresh_field('doctypes_to_be_ignored');
|
||||
},
|
||||
|
||||
refresh: function(frm) {
|
||||
frm.fields_dict['doctypes_to_be_ignored'].grid.set_column_disp('no_of_docs', false);
|
||||
frm.refresh_field('doctypes_to_be_ignored');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function populate_doctypes_to_be_ignored(doctypes_to_be_ignored_array, frm) {
|
||||
if (!(frm.doc.doctypes_to_be_ignored)) {
|
||||
var i;
|
||||
for (i = 0; i < doctypes_to_be_ignored_array.length; i++) {
|
||||
frm.add_child('doctypes_to_be_ignored', {
|
||||
doctype_name: doctypes_to_be_ignored_array[i]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "TDL.####",
|
||||
"creation": "2021-04-06 20:17:18.404716",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"company",
|
||||
"doctypes",
|
||||
"doctypes_to_be_ignored",
|
||||
"amended_from",
|
||||
"status"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Company",
|
||||
"options": "Company",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "doctypes",
|
||||
"fieldtype": "Table",
|
||||
"label": "Summary",
|
||||
"options": "Transaction Deletion Record Item",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "doctypes_to_be_ignored",
|
||||
"fieldtype": "Table",
|
||||
"label": "Excluded DocTypes",
|
||||
"options": "Transaction Deletion Record Item"
|
||||
},
|
||||
{
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"label": "Amended From",
|
||||
"no_copy": 1,
|
||||
"options": "Transaction Deletion Record",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 1,
|
||||
"label": "Status",
|
||||
"options": "Draft\nCompleted"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-05-08 23:13:48.049879",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Transaction Deletion Record",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from frappe.utils import cint
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from frappe import _
|
||||
from frappe.desk.notifications import clear_notifications
|
||||
|
||||
class TransactionDeletionRecord(Document):
|
||||
def validate(self):
|
||||
frappe.only_for('System Manager')
|
||||
self.validate_doctypes_to_be_ignored()
|
||||
|
||||
def validate_doctypes_to_be_ignored(self):
|
||||
doctypes_to_be_ignored_list = get_doctypes_to_be_ignored()
|
||||
for doctype in self.doctypes_to_be_ignored:
|
||||
if doctype.doctype_name not in doctypes_to_be_ignored_list:
|
||||
frappe.throw(_("DocTypes should not be added manually to the 'Excluded DocTypes' table. You are only allowed to remove entries from it."),
|
||||
title=_("Not Allowed"))
|
||||
|
||||
def before_submit(self):
|
||||
if not self.doctypes_to_be_ignored:
|
||||
self.populate_doctypes_to_be_ignored_table()
|
||||
|
||||
self.delete_bins()
|
||||
self.delete_lead_addresses()
|
||||
self.reset_company_values()
|
||||
clear_notifications()
|
||||
self.delete_company_transactions()
|
||||
|
||||
def populate_doctypes_to_be_ignored_table(self):
|
||||
doctypes_to_be_ignored_list = get_doctypes_to_be_ignored()
|
||||
for doctype in doctypes_to_be_ignored_list:
|
||||
self.append('doctypes_to_be_ignored', {
|
||||
'doctype_name' : doctype
|
||||
})
|
||||
|
||||
def delete_bins(self):
|
||||
frappe.db.sql("""delete from tabBin where warehouse in
|
||||
(select name from tabWarehouse where company=%s)""", self.company)
|
||||
|
||||
def delete_lead_addresses(self):
|
||||
"""Delete addresses to which leads are linked"""
|
||||
leads = frappe.get_all('Lead', filters={'company': self.company})
|
||||
leads = ["'%s'" % row.get("name") for row in leads]
|
||||
addresses = []
|
||||
if leads:
|
||||
addresses = frappe.db.sql_list("""select parent from `tabDynamic Link` where link_name
|
||||
in ({leads})""".format(leads=",".join(leads)))
|
||||
|
||||
if addresses:
|
||||
addresses = ["%s" % frappe.db.escape(addr) for addr in addresses]
|
||||
|
||||
frappe.db.sql("""delete from tabAddress where name in ({addresses}) and
|
||||
name not in (select distinct dl1.parent from `tabDynamic Link` dl1
|
||||
inner join `tabDynamic Link` dl2 on dl1.parent=dl2.parent
|
||||
and dl1.link_doctype<>dl2.link_doctype)""".format(addresses=",".join(addresses)))
|
||||
|
||||
frappe.db.sql("""delete from `tabDynamic Link` where link_doctype='Lead'
|
||||
and parenttype='Address' and link_name in ({leads})""".format(leads=",".join(leads)))
|
||||
|
||||
frappe.db.sql("""update tabCustomer set lead_name=NULL where lead_name in ({leads})""".format(leads=",".join(leads)))
|
||||
|
||||
def reset_company_values(self):
|
||||
company_obj = frappe.get_doc('Company', self.company)
|
||||
company_obj.total_monthly_sales = 0
|
||||
company_obj.sales_monthly_history = None
|
||||
company_obj.save()
|
||||
|
||||
def delete_company_transactions(self):
|
||||
doctypes_to_be_ignored_list = self.get_doctypes_to_be_ignored_list()
|
||||
docfields = self.get_doctypes_with_company_field(doctypes_to_be_ignored_list)
|
||||
|
||||
tables = self.get_all_child_doctypes()
|
||||
for docfield in docfields:
|
||||
if docfield['parent'] != self.doctype:
|
||||
no_of_docs = self.get_number_of_docs_linked_with_specified_company(docfield['parent'], docfield['fieldname'])
|
||||
|
||||
if no_of_docs > 0:
|
||||
self.delete_version_log(docfield['parent'], docfield['fieldname'])
|
||||
self.delete_communications(docfield['parent'], docfield['fieldname'])
|
||||
self.populate_doctypes_table(tables, docfield['parent'], no_of_docs)
|
||||
|
||||
self.delete_child_tables(docfield['parent'], docfield['fieldname'])
|
||||
self.delete_docs_linked_with_specified_company(docfield['parent'], docfield['fieldname'])
|
||||
|
||||
naming_series = frappe.db.get_value('DocType', docfield['parent'], 'autoname')
|
||||
if naming_series:
|
||||
if '#' in naming_series:
|
||||
self.update_naming_series(naming_series, docfield['parent'])
|
||||
|
||||
def get_doctypes_to_be_ignored_list(self):
|
||||
singles = frappe.get_all('DocType', filters = {'issingle': 1}, pluck = 'name')
|
||||
doctypes_to_be_ignored_list = singles
|
||||
for doctype in self.doctypes_to_be_ignored:
|
||||
doctypes_to_be_ignored_list.append(doctype.doctype_name)
|
||||
|
||||
return doctypes_to_be_ignored_list
|
||||
|
||||
def get_doctypes_with_company_field(self, doctypes_to_be_ignored_list):
|
||||
docfields = frappe.get_all('DocField',
|
||||
filters = {
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Company',
|
||||
'parent': ['not in', doctypes_to_be_ignored_list]},
|
||||
fields=['parent', 'fieldname'])
|
||||
|
||||
return docfields
|
||||
|
||||
def get_all_child_doctypes(self):
|
||||
return frappe.get_all('DocType', filters = {'istable': 1}, pluck = 'name')
|
||||
|
||||
def get_number_of_docs_linked_with_specified_company(self, doctype, company_fieldname):
|
||||
return frappe.db.count(doctype, {company_fieldname : self.company})
|
||||
|
||||
def populate_doctypes_table(self, tables, doctype, no_of_docs):
|
||||
if doctype not in tables:
|
||||
self.append('doctypes', {
|
||||
'doctype_name' : doctype,
|
||||
'no_of_docs' : no_of_docs
|
||||
})
|
||||
|
||||
def delete_child_tables(self, doctype, company_fieldname):
|
||||
parent_docs_to_be_deleted = frappe.get_all(doctype, {
|
||||
company_fieldname : self.company
|
||||
}, pluck = 'name')
|
||||
|
||||
child_tables = frappe.get_all('DocField', filters = {
|
||||
'fieldtype': 'Table',
|
||||
'parent': doctype
|
||||
}, pluck = 'options')
|
||||
|
||||
for table in child_tables:
|
||||
frappe.db.delete(table, {
|
||||
'parent': ['in', parent_docs_to_be_deleted]
|
||||
})
|
||||
|
||||
def delete_docs_linked_with_specified_company(self, doctype, company_fieldname):
|
||||
frappe.db.delete(doctype, {
|
||||
company_fieldname : self.company
|
||||
})
|
||||
|
||||
def update_naming_series(self, naming_series, doctype_name):
|
||||
if '.' in naming_series:
|
||||
prefix, hashes = naming_series.rsplit('.', 1)
|
||||
else:
|
||||
prefix, hashes = naming_series.rsplit('{', 1)
|
||||
last = frappe.db.sql("""select max(name) from `tab{0}`
|
||||
where name like %s""".format(doctype_name), prefix + '%')
|
||||
if last and last[0][0]:
|
||||
last = cint(last[0][0].replace(prefix, ''))
|
||||
else:
|
||||
last = 0
|
||||
|
||||
frappe.db.sql("""update tabSeries set current = %s where name=%s""", (last, prefix))
|
||||
|
||||
def delete_version_log(self, doctype, company_fieldname):
|
||||
frappe.db.sql("""delete from `tabVersion` where ref_doctype=%s and docname in
|
||||
(select name from `tab{0}` where `{1}`=%s)""".format(doctype,
|
||||
company_fieldname), (doctype, self.company))
|
||||
|
||||
def delete_communications(self, doctype, company_fieldname):
|
||||
reference_docs = frappe.get_all(doctype, filters={company_fieldname:self.company})
|
||||
reference_doc_names = [r.name for r in reference_docs]
|
||||
|
||||
communications = frappe.get_all('Communication', filters={'reference_doctype':doctype,'reference_name':['in', reference_doc_names]})
|
||||
communication_names = [c.name for c in communications]
|
||||
|
||||
frappe.delete_doc('Communication', communication_names, ignore_permissions=True)
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_doctypes_to_be_ignored():
|
||||
doctypes_to_be_ignored_list = ['Account', 'Cost Center', 'Warehouse', 'Budget',
|
||||
'Party Account', 'Employee', 'Sales Taxes and Charges Template',
|
||||
'Purchase Taxes and Charges Template', 'POS Profile', 'BOM',
|
||||
'Company', 'Bank Account', 'Item Tax Template', 'Mode of Payment',
|
||||
'Item Default', 'Customer', 'Supplier', 'GST Account']
|
||||
return doctypes_to_be_ignored_list
|
||||
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// License: GNU General Public License v3. See license.txt
|
||||
|
||||
frappe.listview_settings['Transaction Deletion Record'] = {
|
||||
get_indicator: function(doc) {
|
||||
if (doc.docstatus == 0) {
|
||||
return [__("Draft"), "red"];
|
||||
} else {
|
||||
return [__("Completed"), "green"];
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2021-04-07 07:34:00.124124",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"doctype_name",
|
||||
"no_of_docs"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "doctype_name",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "DocType",
|
||||
"options": "DocType",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "no_of_docs",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Number of Docs"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2021-05-08 23:10:46.166744",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Transaction Deletion Record Item",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class TransactionDeletionRecordItem(Document):
|
||||
pass
|
||||
@@ -8,9 +8,11 @@ from erpnext.accounts.doctype.cash_flow_mapper.default_cash_flow_mapper import D
|
||||
from .default_success_action import get_default_success_action
|
||||
from frappe import _
|
||||
from frappe.utils import cint
|
||||
from frappe.installer import update_site_config
|
||||
from frappe.desk.page.setup_wizard.setup_wizard import add_all_roles_to
|
||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
|
||||
from erpnext.setup.default_energy_point_rules import get_default_energy_point_rules
|
||||
from six import iteritems
|
||||
|
||||
default_mail_footer = """<div style="padding: 7px; text-align: right; color: #888"><small>Sent via
|
||||
<a style="color: #888" href="http://erpnext.org">ERPNext</a></div>"""
|
||||
@@ -29,6 +31,7 @@ def after_install():
|
||||
add_company_to_session_defaults()
|
||||
add_standard_navbar_items()
|
||||
add_app_name()
|
||||
add_non_standard_user_types()
|
||||
frappe.db.commit()
|
||||
|
||||
|
||||
@@ -36,7 +39,7 @@ def check_setup_wizard_not_completed():
|
||||
if cint(frappe.db.get_single_value('System Settings', 'setup_complete') or 0):
|
||||
message = """ERPNext can only be installed on a fresh site where the setup wizard is not completed.
|
||||
You can reinstall this site (after saving your data) using: bench --site [sitename] reinstall"""
|
||||
frappe.throw(message)
|
||||
frappe.throw(message) # nosemgrep
|
||||
|
||||
|
||||
def set_single_defaults():
|
||||
@@ -164,3 +167,81 @@ def add_standard_navbar_items():
|
||||
|
||||
def add_app_name():
|
||||
frappe.db.set_value('System Settings', None, 'app_name', 'ERPNext')
|
||||
|
||||
def add_non_standard_user_types():
|
||||
user_types = get_user_types_data()
|
||||
|
||||
user_type_limit = {}
|
||||
for user_type, data in iteritems(user_types):
|
||||
user_type_limit.setdefault(frappe.scrub(user_type), 10)
|
||||
|
||||
update_site_config('user_type_doctype_limit', user_type_limit)
|
||||
|
||||
for user_type, data in iteritems(user_types):
|
||||
create_custom_role(data)
|
||||
create_user_type(user_type, data)
|
||||
|
||||
def get_user_types_data():
|
||||
return {
|
||||
'Employee Self Service': {
|
||||
'role': 'Employee Self Service',
|
||||
'apply_user_permission_on': 'Employee',
|
||||
'user_id_field': 'user_id',
|
||||
'doctypes': {
|
||||
'Salary Slip': ['read'],
|
||||
'Employee': ['read', 'write'],
|
||||
'Expense Claim': ['read', 'write', 'create', 'delete'],
|
||||
'Leave Application': ['read', 'write', 'create', 'delete'],
|
||||
'Attendance Request': ['read', 'write', 'create', 'delete'],
|
||||
'Compensatory Leave Request': ['read', 'write', 'create', 'delete'],
|
||||
'Employee Tax Exemption Declaration': ['read', 'write', 'create', 'delete'],
|
||||
'Employee Tax Exemption Proof Submission': ['read', 'write', 'create', 'delete'],
|
||||
'Timesheet': ['read', 'write', 'create', 'delete', 'submit', 'cancel', 'amend']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def create_custom_role(data):
|
||||
if data.get('role') and not frappe.db.exists('Role', data.get('role')):
|
||||
frappe.get_doc({
|
||||
'doctype': 'Role',
|
||||
'role_name': data.get('role'),
|
||||
'desk_access': 1,
|
||||
'is_custom': 1
|
||||
}).insert(ignore_permissions=True)
|
||||
|
||||
def create_user_type(user_type, data):
|
||||
if frappe.db.exists('User Type', user_type):
|
||||
doc = frappe.get_cached_doc('User Type', user_type)
|
||||
doc.user_doctypes = []
|
||||
else:
|
||||
doc = frappe.new_doc('User Type')
|
||||
doc.update({
|
||||
'name': user_type,
|
||||
'role': data.get('role'),
|
||||
'user_id_field': data.get('user_id_field'),
|
||||
'apply_user_permission_on': data.get('apply_user_permission_on')
|
||||
})
|
||||
|
||||
create_role_permissions_for_doctype(doc, data)
|
||||
doc.save(ignore_permissions=True)
|
||||
|
||||
def create_role_permissions_for_doctype(doc, data):
|
||||
for doctype, perms in iteritems(data.get('doctypes')):
|
||||
args = {'document_type': doctype}
|
||||
for perm in perms:
|
||||
args[perm] = 1
|
||||
|
||||
doc.append('user_doctypes', args)
|
||||
|
||||
def update_select_perm_after_install():
|
||||
if not frappe.flags.update_select_perm_after_migrate:
|
||||
return
|
||||
|
||||
frappe.flags.ignore_select_perm = False
|
||||
for row in frappe.get_all('User Type', filters= {'is_standard': 0}):
|
||||
print('Updating user type :- ', row.name)
|
||||
doc = frappe.get_doc('User Type', row.name)
|
||||
doc.save()
|
||||
|
||||
frappe.flags.update_select_perm_after_migrate = False
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -42,29 +42,6 @@ def enable_shopping_cart(args):
|
||||
'quotation_series': "QTN-",
|
||||
}).insert()
|
||||
|
||||
def create_bank_account(args):
|
||||
if args.get("bank_account"):
|
||||
company_name = args.get('company_name')
|
||||
bank_account_group = frappe.db.get_value("Account",
|
||||
{"account_type": "Bank", "is_group": 1, "root_type": "Asset",
|
||||
"company": company_name})
|
||||
if bank_account_group:
|
||||
bank_account = frappe.get_doc({
|
||||
"doctype": "Account",
|
||||
'account_name': args.get("bank_account"),
|
||||
'parent_account': bank_account_group,
|
||||
'is_group':0,
|
||||
'company': company_name,
|
||||
"account_type": "Bank",
|
||||
})
|
||||
try:
|
||||
return bank_account.insert()
|
||||
except RootNotEditable:
|
||||
frappe.throw(_("Bank account cannot be named as {0}").format(args.get("bank_account")))
|
||||
except frappe.DuplicateEntryError:
|
||||
# bank account same as a CoA entry
|
||||
pass
|
||||
|
||||
def create_email_digest():
|
||||
from frappe.utils.user import get_system_managers
|
||||
system_managers = get_system_managers(only_name=True)
|
||||
|
||||
@@ -12,6 +12,7 @@ from frappe.desk.doctype.global_search_settings.global_search_settings import up
|
||||
|
||||
from erpnext.accounts.doctype.account.account import RootNotEditable
|
||||
from erpnext.regional.address_template.setup import set_up_address_templates
|
||||
from frappe.utils.nestedset import rebuild_tree
|
||||
|
||||
default_lead_sources = ["Existing Customer", "Reference", "Advertisement",
|
||||
"Cold Calling", "Exhibition", "Supplier Reference", "Mass Mailing",
|
||||
@@ -280,13 +281,15 @@ def install(country=None):
|
||||
set_more_defaults()
|
||||
update_global_search_doctypes()
|
||||
|
||||
# path = frappe.get_app_path('erpnext', 'regional', frappe.scrub(country))
|
||||
# if os.path.exists(path.encode("utf-8")):
|
||||
# frappe.get_attr("erpnext.regional.{0}.setup.setup_company_independent_fixtures".format(frappe.scrub(country)))()
|
||||
|
||||
|
||||
def set_more_defaults():
|
||||
# Do more setup stuff that can be done here with no dependencies
|
||||
update_selling_defaults()
|
||||
update_buying_defaults()
|
||||
update_hr_defaults()
|
||||
add_uom_data()
|
||||
update_item_variant_settings()
|
||||
|
||||
def update_selling_defaults():
|
||||
selling_settings = frappe.get_doc("Selling Settings")
|
||||
selling_settings.set_default_customer_group_and_territory()
|
||||
selling_settings.cust_master_name = "Customer Name"
|
||||
@@ -296,13 +299,7 @@ def set_more_defaults():
|
||||
selling_settings.sales_update_frequency = "Each Transaction"
|
||||
selling_settings.save()
|
||||
|
||||
add_uom_data()
|
||||
|
||||
# set no copy fields of an item doctype to item variant settings
|
||||
doc = frappe.get_doc('Item Variant Settings')
|
||||
doc.set_default_fields()
|
||||
doc.save()
|
||||
|
||||
def update_buying_defaults():
|
||||
buying_settings = frappe.get_doc("Buying Settings")
|
||||
buying_settings.supp_master_name = "Supplier Name"
|
||||
buying_settings.po_required = "No"
|
||||
@@ -311,12 +308,19 @@ def set_more_defaults():
|
||||
buying_settings.allow_multiple_items = 1
|
||||
buying_settings.save()
|
||||
|
||||
def update_hr_defaults():
|
||||
hr_settings = frappe.get_doc("HR Settings")
|
||||
hr_settings.emp_created_by = "Naming Series"
|
||||
hr_settings.leave_approval_notification_template = _("Leave Approval Notification")
|
||||
hr_settings.leave_status_notification_template = _("Leave Status Notification")
|
||||
hr_settings.save()
|
||||
|
||||
def update_item_variant_settings():
|
||||
# set no copy fields of an item doctype to item variant settings
|
||||
doc = frappe.get_doc('Item Variant Settings')
|
||||
doc.set_default_fields()
|
||||
doc.save()
|
||||
|
||||
def add_uom_data():
|
||||
# add UOMs
|
||||
uoms = json.loads(open(frappe.get_app_path("erpnext", "setup", "setup_wizard", "data", "uom_data.json")).read())
|
||||
@@ -327,7 +331,7 @@ def add_uom_data():
|
||||
"uom_name": _(d.get("uom_name")),
|
||||
"name": _(d.get("uom_name")),
|
||||
"must_be_whole_number": d.get("must_be_whole_number")
|
||||
}).insert(ignore_permissions=True)
|
||||
}).db_insert()
|
||||
|
||||
# bootstrap uom conversion factors
|
||||
uom_conversions = json.loads(open(frappe.get_app_path("erpnext", "setup", "setup_wizard", "data", "uom_conversion_data.json")).read())
|
||||
@@ -336,7 +340,7 @@ def add_uom_data():
|
||||
frappe.get_doc({
|
||||
"doctype": "UOM Category",
|
||||
"category_name": _(d.get("category"))
|
||||
}).insert(ignore_permissions=True)
|
||||
}).db_insert()
|
||||
|
||||
if not frappe.db.exists("UOM Conversion Factor", {"from_uom": _(d.get("from_uom")), "to_uom": _(d.get("to_uom"))}):
|
||||
uom_conversion = frappe.get_doc({
|
||||
@@ -369,8 +373,8 @@ def add_sale_stages():
|
||||
{"doctype": "Sales Stage", "stage_name": _("Proposal/Price Quote")},
|
||||
{"doctype": "Sales Stage", "stage_name": _("Negotiation/Review")}
|
||||
]
|
||||
|
||||
make_records(records)
|
||||
for sales_stage in records:
|
||||
frappe.get_doc(sales_stage).db_insert()
|
||||
|
||||
def install_company(args):
|
||||
records = [
|
||||
@@ -418,7 +422,14 @@ def install_post_company_fixtures(args=None):
|
||||
{'doctype': 'Department', 'department_name': _('Legal'), 'parent_department': _('All Departments'), 'company': args.company_name},
|
||||
]
|
||||
|
||||
make_records(records)
|
||||
# Make root department with NSM updation
|
||||
make_records(records[:1])
|
||||
|
||||
frappe.local.flags.ignore_update_nsm = True
|
||||
make_records(records[1:])
|
||||
frappe.local.flags.ignore_update_nsm = False
|
||||
|
||||
rebuild_tree("Department", "parent_department")
|
||||
|
||||
|
||||
def install_defaults(args=None):
|
||||
@@ -432,7 +443,17 @@ def install_defaults(args=None):
|
||||
|
||||
# enable default currency
|
||||
frappe.db.set_value("Currency", args.get("currency"), "enabled", 1)
|
||||
frappe.db.set_value("Stock Settings", None, "email_footer_address", args.get("company_name"))
|
||||
|
||||
set_global_defaults(args)
|
||||
set_active_domains(args)
|
||||
update_stock_settings()
|
||||
update_shopping_cart_settings(args)
|
||||
|
||||
args.update({"set_default": 1})
|
||||
create_bank_account(args)
|
||||
|
||||
def set_global_defaults(args):
|
||||
global_defaults = frappe.get_doc("Global Defaults", "Global Defaults")
|
||||
current_fiscal_year = frappe.get_all("Fiscal Year")[0]
|
||||
|
||||
@@ -445,13 +466,10 @@ def install_defaults(args=None):
|
||||
|
||||
global_defaults.save()
|
||||
|
||||
system_settings = frappe.get_doc("System Settings")
|
||||
system_settings.email_footer_address = args.get("company_name")
|
||||
system_settings.save()
|
||||
|
||||
domain_settings = frappe.get_single('Domain Settings')
|
||||
domain_settings.set_active_domains(args.get('domains'))
|
||||
def set_active_domains(args):
|
||||
frappe.get_single('Domain Settings').set_active_domains(args.get('domains'))
|
||||
|
||||
def update_stock_settings():
|
||||
stock_settings = frappe.get_doc("Stock Settings")
|
||||
stock_settings.item_naming_by = "Item Code"
|
||||
stock_settings.valuation_method = "FIFO"
|
||||
@@ -463,48 +481,47 @@ def install_defaults(args=None):
|
||||
stock_settings.set_qty_in_transactions_based_on_serial_no_input = 1
|
||||
stock_settings.save()
|
||||
|
||||
if args.bank_account:
|
||||
company_name = args.company_name
|
||||
bank_account_group = frappe.db.get_value("Account",
|
||||
{"account_type": "Bank", "is_group": 1, "root_type": "Asset",
|
||||
"company": company_name})
|
||||
if bank_account_group:
|
||||
bank_account = frappe.get_doc({
|
||||
"doctype": "Account",
|
||||
'account_name': args.bank_account,
|
||||
'parent_account': bank_account_group,
|
||||
'is_group':0,
|
||||
'company': company_name,
|
||||
"account_type": "Bank",
|
||||
})
|
||||
try:
|
||||
doc = bank_account.insert()
|
||||
def create_bank_account(args):
|
||||
if not args.get('bank_account'):
|
||||
return
|
||||
|
||||
frappe.db.set_value("Company", args.company_name, "default_bank_account", bank_account.name, update_modified=False)
|
||||
company_name = args.get('company_name')
|
||||
bank_account_group = frappe.db.get_value("Account",
|
||||
{"account_type": "Bank", "is_group": 1, "root_type": "Asset",
|
||||
"company": company_name})
|
||||
if bank_account_group:
|
||||
bank_account = frappe.get_doc({
|
||||
"doctype": "Account",
|
||||
'account_name': args.get('bank_account'),
|
||||
'parent_account': bank_account_group,
|
||||
'is_group':0,
|
||||
'company': company_name,
|
||||
"account_type": "Bank",
|
||||
})
|
||||
try:
|
||||
doc = bank_account.insert()
|
||||
|
||||
except RootNotEditable:
|
||||
frappe.throw(_("Bank account cannot be named as {0}").format(args.bank_account))
|
||||
except frappe.DuplicateEntryError:
|
||||
# bank account same as a CoA entry
|
||||
pass
|
||||
if args.get('set_default'):
|
||||
frappe.db.set_value("Company", args.get('company_name'), "default_bank_account", bank_account.name, update_modified=False)
|
||||
|
||||
# Now, with fixtures out of the way, onto concrete stuff
|
||||
records = [
|
||||
return doc
|
||||
|
||||
# Shopping cart: needs price lists
|
||||
{
|
||||
"doctype": "Shopping Cart Settings",
|
||||
"enabled": 1,
|
||||
'company': args.company_name,
|
||||
# uh oh
|
||||
'price_list': frappe.db.get_value("Price List", {"selling": 1}),
|
||||
'default_customer_group': _("Individual"),
|
||||
'quotation_series': "QTN-",
|
||||
},
|
||||
]
|
||||
|
||||
make_records(records)
|
||||
except RootNotEditable:
|
||||
frappe.throw(_("Bank account cannot be named as {0}").format(args.get('bank_account')))
|
||||
except frappe.DuplicateEntryError:
|
||||
# bank account same as a CoA entry
|
||||
pass
|
||||
|
||||
def update_shopping_cart_settings(args):
|
||||
shopping_cart = frappe.get_doc("Shopping Cart Settings")
|
||||
shopping_cart.update({
|
||||
"enabled": 1,
|
||||
'company': args.company_name,
|
||||
'price_list': frappe.db.get_value("Price List", {"selling": 1}),
|
||||
'default_customer_group': _("Individual"),
|
||||
'quotation_series': "QTN-",
|
||||
})
|
||||
shopping_cart.update_single(shopping_cart.get_valid_dict())
|
||||
|
||||
def get_fy_details(fy_start_date, fy_end_date):
|
||||
start_year = getdate(fy_start_date).year
|
||||
|
||||
@@ -1,123 +1,295 @@
|
||||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe, copy, os, json
|
||||
from frappe.utils import flt
|
||||
from erpnext.accounts.doctype.account.account import RootNotEditable
|
||||
|
||||
def create_sales_tax(args):
|
||||
country_wise_tax = get_country_wise_tax(args.get("country"))
|
||||
if country_wise_tax and len(country_wise_tax) > 0:
|
||||
for sales_tax, tax_data in country_wise_tax.items():
|
||||
make_tax_account_and_template(
|
||||
args.get("company_name"),
|
||||
tax_data.get('account_name'),
|
||||
tax_data.get('tax_rate'), sales_tax)
|
||||
import os
|
||||
import json
|
||||
|
||||
def make_tax_account_and_template(company, account_name, tax_rate, template_name=None):
|
||||
if not isinstance(account_name, (list, tuple)):
|
||||
account_name = [account_name]
|
||||
tax_rate = [tax_rate]
|
||||
import frappe
|
||||
from frappe import _
|
||||
|
||||
accounts = []
|
||||
for i, name in enumerate(account_name):
|
||||
tax_account = make_tax_account(company, account_name[i], tax_rate[i])
|
||||
if tax_account:
|
||||
accounts.append(tax_account)
|
||||
|
||||
try:
|
||||
if accounts:
|
||||
make_sales_and_purchase_tax_templates(accounts, template_name)
|
||||
make_item_tax_templates(accounts, template_name)
|
||||
except frappe.NameError:
|
||||
if frappe.message_log: frappe.message_log.pop()
|
||||
except RootNotEditable:
|
||||
pass
|
||||
def setup_taxes_and_charges(company_name: str, country: str):
|
||||
if not frappe.db.exists('Company', company_name):
|
||||
frappe.throw(_('Company {} does not exist yet. Taxes setup aborted.').format(company_name))
|
||||
|
||||
def make_tax_account(company, account_name, tax_rate):
|
||||
tax_group = get_tax_account_group(company)
|
||||
if tax_group:
|
||||
file_path = os.path.join(os.path.dirname(__file__), '..', 'data', 'country_wise_tax.json')
|
||||
with open(file_path, 'r') as json_file:
|
||||
tax_data = json.load(json_file)
|
||||
|
||||
country_wise_tax = tax_data.get(country)
|
||||
|
||||
if not country_wise_tax:
|
||||
return
|
||||
|
||||
if 'chart_of_accounts' not in country_wise_tax:
|
||||
country_wise_tax = simple_to_detailed(country_wise_tax)
|
||||
|
||||
from_detailed_data(company_name, country_wise_tax)
|
||||
update_regional_tax_settings(country, company_name)
|
||||
|
||||
|
||||
def simple_to_detailed(templates):
|
||||
"""
|
||||
Convert a simple taxes object into a more detailed data structure.
|
||||
|
||||
Example input:
|
||||
|
||||
{
|
||||
"France VAT 20%": {
|
||||
"account_name": "VAT 20%",
|
||||
"tax_rate": 20,
|
||||
"default": 1
|
||||
},
|
||||
"France VAT 10%": {
|
||||
"account_name": "VAT 10%",
|
||||
"tax_rate": 10
|
||||
}
|
||||
}
|
||||
"""
|
||||
return {
|
||||
'chart_of_accounts': {
|
||||
'*': {
|
||||
'item_tax_templates': [{
|
||||
'title': title,
|
||||
'taxes': [{
|
||||
'tax_type': {
|
||||
'account_name': data.get('account_name'),
|
||||
'tax_rate': data.get('tax_rate')
|
||||
}
|
||||
}]
|
||||
} for title, data in templates.items()],
|
||||
'*': [{
|
||||
'title': title,
|
||||
'is_default': data.get('default', 0),
|
||||
'taxes': [{
|
||||
'account_head': {
|
||||
'account_name': data.get('account_name'),
|
||||
'tax_rate': data.get('tax_rate')
|
||||
}
|
||||
}]
|
||||
} for title, data in templates.items()]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def from_detailed_data(company_name, data):
|
||||
"""Create Taxes and Charges Templates from detailed data."""
|
||||
coa_name = frappe.db.get_value('Company', company_name, 'chart_of_accounts')
|
||||
coa_data = data.get('chart_of_accounts', {})
|
||||
tax_templates = coa_data.get(coa_name) or coa_data.get('*', {})
|
||||
tax_categories = data.get('tax_categories')
|
||||
sales_tax_templates = tax_templates.get('sales_tax_templates') or tax_templates.get('*', {})
|
||||
purchase_tax_templates = tax_templates.get('purchase_tax_templates') or tax_templates.get('*', {})
|
||||
item_tax_templates = tax_templates.get('item_tax_templates') or tax_templates.get('*', {})
|
||||
|
||||
if tax_categories:
|
||||
for tax_category in tax_categories:
|
||||
make_tax_catgory(tax_category)
|
||||
|
||||
if sales_tax_templates:
|
||||
for template in sales_tax_templates:
|
||||
make_taxes_and_charges_template(company_name, 'Sales Taxes and Charges Template', template)
|
||||
|
||||
if purchase_tax_templates:
|
||||
for template in purchase_tax_templates:
|
||||
make_taxes_and_charges_template(company_name, 'Purchase Taxes and Charges Template', template)
|
||||
|
||||
if item_tax_templates:
|
||||
for template in item_tax_templates:
|
||||
make_item_tax_template(company_name, template)
|
||||
|
||||
|
||||
def update_regional_tax_settings(country, company):
|
||||
path = frappe.get_app_path('erpnext', 'regional', frappe.scrub(country))
|
||||
if os.path.exists(path.encode("utf-8")):
|
||||
try:
|
||||
return frappe.get_doc({
|
||||
"doctype":"Account",
|
||||
"company": company,
|
||||
"parent_account": tax_group,
|
||||
"account_name": account_name,
|
||||
"is_group": 0,
|
||||
"report_type": "Balance Sheet",
|
||||
"root_type": "Liability",
|
||||
"account_type": "Tax",
|
||||
"tax_rate": flt(tax_rate) if tax_rate else None
|
||||
}).insert(ignore_permissions=True, ignore_mandatory=True)
|
||||
except frappe.NameError:
|
||||
if frappe.message_log: frappe.message_log.pop()
|
||||
abbr = frappe.get_cached_value('Company', company, 'abbr')
|
||||
account = '{0} - {1}'.format(account_name, abbr)
|
||||
return frappe.get_doc('Account', account)
|
||||
module_name = "erpnext.regional.{0}.setup.update_regional_tax_settings".format(frappe.scrub(country))
|
||||
frappe.get_attr(module_name)(country, company)
|
||||
except Exception as e:
|
||||
# Log error and ignore if failed to setup regional tax settings
|
||||
frappe.log_error()
|
||||
pass
|
||||
|
||||
def make_sales_and_purchase_tax_templates(accounts, template_name=None):
|
||||
if not template_name:
|
||||
template_name = accounts[0].name
|
||||
def make_taxes_and_charges_template(company_name, doctype, template):
|
||||
template['company'] = company_name
|
||||
template['doctype'] = doctype
|
||||
|
||||
sales_tax_template = {
|
||||
"doctype": "Sales Taxes and Charges Template",
|
||||
"title": template_name,
|
||||
"company": accounts[0].company,
|
||||
'taxes': []
|
||||
}
|
||||
if frappe.db.exists(doctype, {'title': template.get('title'), 'company': company_name}):
|
||||
return
|
||||
|
||||
for account in accounts:
|
||||
sales_tax_template['taxes'].append({
|
||||
"category": "Total",
|
||||
"charge_type": "On Net Total",
|
||||
"account_head": account.name,
|
||||
"description": "{0} @ {1}".format(account.account_name, account.tax_rate),
|
||||
"rate": account.tax_rate
|
||||
})
|
||||
# Sales
|
||||
frappe.get_doc(copy.deepcopy(sales_tax_template)).insert(ignore_permissions=True)
|
||||
for tax_row in template.get('taxes'):
|
||||
account_data = tax_row.get('account_head')
|
||||
tax_row_defaults = {
|
||||
'category': 'Total',
|
||||
'charge_type': 'On Net Total'
|
||||
}
|
||||
|
||||
# Purchase
|
||||
purchase_tax_template = copy.deepcopy(sales_tax_template)
|
||||
purchase_tax_template["doctype"] = "Purchase Taxes and Charges Template"
|
||||
if doctype == 'Purchase Taxes and Charges Template':
|
||||
tax_row_defaults['add_deduct_tax'] = 'Add'
|
||||
|
||||
doc = frappe.get_doc(purchase_tax_template)
|
||||
# if account_head is a dict, search or create the account and get it's name
|
||||
if isinstance(account_data, dict):
|
||||
tax_row_defaults['description'] = '{0} @ {1}'.format(account_data.get('account_name'), account_data.get('tax_rate'))
|
||||
tax_row_defaults['rate'] = account_data.get('tax_rate')
|
||||
account = get_or_create_account(company_name, account_data)
|
||||
tax_row['account_head'] = account.name
|
||||
|
||||
# use the default value if nothing other is specified
|
||||
for fieldname, default_value in tax_row_defaults.items():
|
||||
if fieldname not in tax_row:
|
||||
tax_row[fieldname] = default_value
|
||||
|
||||
doc = frappe.get_doc(template)
|
||||
|
||||
# Data in country wise json is already pre validated, hence validations can be ignored
|
||||
# Ingone validations to make doctypes faster
|
||||
doc.flags.ignore_links = True
|
||||
doc.flags.ignore_validate = True
|
||||
doc.insert(ignore_permissions=True)
|
||||
return doc
|
||||
|
||||
def make_item_tax_templates(accounts, template_name=None):
|
||||
if not template_name:
|
||||
template_name = accounts[0].name
|
||||
def make_item_tax_template(company_name, template):
|
||||
"""Create an Item Tax Template.
|
||||
|
||||
item_tax_template = {
|
||||
"doctype": "Item Tax Template",
|
||||
"title": template_name,
|
||||
"company": accounts[0].company,
|
||||
'taxes': []
|
||||
}
|
||||
This requires a separate method because Item Tax Template is structured
|
||||
differently from Sales and Purchase Tax Templates.
|
||||
"""
|
||||
doctype = 'Item Tax Template'
|
||||
template['company'] = company_name
|
||||
template['doctype'] = doctype
|
||||
|
||||
if frappe.db.exists(doctype, {'title': template.get('title'), 'company': company_name}):
|
||||
return
|
||||
|
||||
for account in accounts:
|
||||
item_tax_template['taxes'].append({
|
||||
"tax_type": account.name,
|
||||
"tax_rate": account.tax_rate
|
||||
for tax_row in template.get('taxes'):
|
||||
account_data = tax_row.get('tax_type')
|
||||
|
||||
# if tax_type is a dict, search or create the account and get it's name
|
||||
if isinstance(account_data, dict):
|
||||
account = get_or_create_account(company_name, account_data)
|
||||
tax_row['tax_type'] = account.name
|
||||
if 'tax_rate' not in tax_row:
|
||||
tax_row['tax_rate'] = account_data.get('tax_rate')
|
||||
|
||||
doc = frappe.get_doc(template)
|
||||
|
||||
# Data in country wise json is already pre validated, hence validations can be ignored
|
||||
# Ingone validations to make doctypes faster
|
||||
doc.flags.ignore_links = True
|
||||
doc.flags.ignore_validate = True
|
||||
doc.insert(ignore_permissions=True)
|
||||
return doc
|
||||
|
||||
def make_tax_category(tax_category):
|
||||
""" Make tax category based on title if not already created """
|
||||
doctype = 'Tax Category'
|
||||
if not frappe.db.exists(doctype, tax_category['title']):
|
||||
tax_category['doctype'] = doctype
|
||||
doc = frappe.get_doc(tax_category)
|
||||
doc.flags.ignore_links = True
|
||||
doc.flags.ignore_validate = True
|
||||
doc.insert(ignore_permissions=True)
|
||||
|
||||
def get_or_create_account(company_name, account):
|
||||
"""
|
||||
Check if account already exists. If not, create it.
|
||||
Return a tax account or None.
|
||||
"""
|
||||
default_root_type = 'Liability'
|
||||
root_type = account.get('root_type', default_root_type)
|
||||
|
||||
existing_accounts = frappe.get_list('Account',
|
||||
filters={
|
||||
'company': company_name,
|
||||
'root_type': root_type
|
||||
},
|
||||
or_filters={
|
||||
'account_name': account.get('account_name'),
|
||||
'account_number': account.get('account_number')
|
||||
})
|
||||
|
||||
# Items
|
||||
frappe.get_doc(copy.deepcopy(item_tax_template)).insert(ignore_permissions=True)
|
||||
if existing_accounts:
|
||||
return frappe.get_doc('Account', existing_accounts[0].name)
|
||||
|
||||
def get_tax_account_group(company):
|
||||
tax_group = frappe.db.get_value("Account",
|
||||
{"account_name": "Duties and Taxes", "is_group": 1, "company": company})
|
||||
if not tax_group:
|
||||
tax_group = frappe.db.get_value("Account", {"is_group": 1, "root_type": "Liability",
|
||||
"account_type": "Tax", "company": company})
|
||||
tax_group = get_or_create_tax_group(company_name, root_type)
|
||||
|
||||
return tax_group
|
||||
account['doctype'] = 'Account'
|
||||
account['company'] = company_name
|
||||
account['parent_account'] = tax_group
|
||||
account['report_type'] = 'Balance Sheet'
|
||||
account['account_type'] = 'Tax'
|
||||
account['root_type'] = root_type
|
||||
account['is_group'] = 0
|
||||
|
||||
def get_country_wise_tax(country):
|
||||
data = {}
|
||||
with open (os.path.join(os.path.dirname(__file__), "..", "data", "country_wise_tax.json")) as countrywise_tax:
|
||||
data = json.load(countrywise_tax).get(country)
|
||||
doc = frappe.get_doc(account)
|
||||
doc.flags.ignore_links = True
|
||||
doc.flags.ignore_validate = True
|
||||
doc.insert(ignore_permissions=True, ignore_mandatory=True)
|
||||
return doc
|
||||
|
||||
return data
|
||||
def get_or_create_tax_group(company_name, root_type):
|
||||
# Look for a group account of type 'Tax'
|
||||
tax_group_name = frappe.db.get_value('Account', {
|
||||
'is_group': 1,
|
||||
'root_type': root_type,
|
||||
'account_type': 'Tax',
|
||||
'company': company_name
|
||||
})
|
||||
|
||||
if tax_group_name:
|
||||
return tax_group_name
|
||||
|
||||
# Look for a group account named 'Duties and Taxes' or 'Tax Assets'
|
||||
account_name = _('Duties and Taxes') if root_type == 'Liability' else _('Tax Assets')
|
||||
tax_group_name = frappe.db.get_value('Account', {
|
||||
'is_group': 1,
|
||||
'root_type': root_type,
|
||||
'account_name': account_name,
|
||||
'company': company_name
|
||||
})
|
||||
|
||||
if tax_group_name:
|
||||
return tax_group_name
|
||||
|
||||
# Create a new group account named 'Duties and Taxes' or 'Tax Assets' just
|
||||
# below the root account
|
||||
root_account = frappe.get_list('Account', {
|
||||
'is_group': 1,
|
||||
'root_type': root_type,
|
||||
'company': company_name,
|
||||
'report_type': 'Balance Sheet',
|
||||
'parent_account': ('is', 'not set')
|
||||
}, limit=1)[0]
|
||||
|
||||
tax_group_account = frappe.get_doc({
|
||||
'doctype': 'Account',
|
||||
'company': company_name,
|
||||
'is_group': 1,
|
||||
'report_type': 'Balance Sheet',
|
||||
'root_type': root_type,
|
||||
'account_type': 'Tax',
|
||||
'account_name': account_name,
|
||||
'parent_account': root_account.name
|
||||
})
|
||||
|
||||
tax_group_account.flags.ignore_links = True
|
||||
tax_group_account.flags.ignore_validate = True
|
||||
tax_group_account.insert(ignore_permissions=True)
|
||||
|
||||
tax_group_name = tax_group_account.name
|
||||
|
||||
return tax_group_name
|
||||
|
||||
|
||||
def make_tax_catgory(tax_category):
|
||||
doctype = 'Tax Category'
|
||||
if isinstance(tax_category, str):
|
||||
tax_category = {'title': tax_category}
|
||||
|
||||
tax_category['doctype'] = doctype
|
||||
if not frappe.db.exists(doctype, tax_category['title']):
|
||||
doc = frappe.get_doc(tax_category)
|
||||
doc.insert(ignore_permissions=True)
|
||||
|
||||
@@ -51,11 +51,6 @@ def get_setup_stages(args=None):
|
||||
'status': _('Setting defaults'),
|
||||
'fail_msg': 'Failed to set defaults',
|
||||
'tasks': [
|
||||
{
|
||||
'fn': setup_post_company_fixtures,
|
||||
'args': args,
|
||||
'fail_msg': _("Failed to setup post company fixtures")
|
||||
},
|
||||
{
|
||||
'fn': setup_defaults,
|
||||
'args': args,
|
||||
@@ -94,9 +89,6 @@ def stage_fixtures(args):
|
||||
def setup_company(args):
|
||||
fixtures.install_company(args)
|
||||
|
||||
def setup_post_company_fixtures(args):
|
||||
fixtures.install_post_company_fixtures(args)
|
||||
|
||||
def setup_defaults(args):
|
||||
fixtures.install_defaults(frappe._dict(args))
|
||||
|
||||
@@ -129,7 +121,6 @@ def login_as_first_user(args):
|
||||
def setup_complete(args=None):
|
||||
stage_fixtures(args)
|
||||
setup_company(args)
|
||||
setup_post_company_fixtures(args)
|
||||
setup_defaults(args)
|
||||
stage_four(args)
|
||||
fin(args)
|
||||
|
||||
@@ -9,5 +9,4 @@ def complete():
|
||||
'data', 'test_mfg.json'), 'r') as f:
|
||||
data = json.loads(f.read())
|
||||
|
||||
#setup_wizard.create_sales_tax(data)
|
||||
setup_complete(data)
|
||||
|
||||
@@ -11,10 +11,11 @@
|
||||
"hide_custom": 0,
|
||||
"icon": "settings",
|
||||
"idx": 0,
|
||||
"is_default": 0,
|
||||
"is_standard": 1,
|
||||
"label": "ERPNext Settings",
|
||||
"links": [],
|
||||
"modified": "2020-12-01 13:38:37.759596",
|
||||
"modified": "2021-06-12 01:58:11.399566",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "ERPNext Settings",
|
||||
@@ -109,6 +110,13 @@
|
||||
"label": "Domain Settings",
|
||||
"link_to": "Domain Settings",
|
||||
"type": "DocType"
|
||||
},
|
||||
{
|
||||
"doc_view": "",
|
||||
"icon": "retail",
|
||||
"label": "Products Settings",
|
||||
"link_to": "Products Settings",
|
||||
"type": "DocType"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,177 +248,9 @@
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Healthcare",
|
||||
"onboard": 0,
|
||||
"type": "Card Break"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Patient",
|
||||
"link_to": "Patient",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Diagnosis",
|
||||
"link_to": "Diagnosis",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Education",
|
||||
"onboard": 0,
|
||||
"type": "Card Break"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Student",
|
||||
"link_to": "Student",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Instructor",
|
||||
"link_to": "Instructor",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Course",
|
||||
"link_to": "Course",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Room",
|
||||
"link_to": "Room",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Non Profit",
|
||||
"onboard": 0,
|
||||
"type": "Card Break"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Donor",
|
||||
"link_to": "Donor",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Member",
|
||||
"link_to": "Member",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Volunteer",
|
||||
"link_to": "Volunteer",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Chapter",
|
||||
"link_to": "Chapter",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Agriculture",
|
||||
"onboard": 0,
|
||||
"type": "Card Break"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Location",
|
||||
"link_to": "Location",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Crop",
|
||||
"link_to": "Crop",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Crop Cycle",
|
||||
"link_to": "Crop Cycle",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
},
|
||||
{
|
||||
"dependencies": "",
|
||||
"hidden": 0,
|
||||
"is_query_report": 0,
|
||||
"label": "Fertilizer",
|
||||
"link_to": "Fertilizer",
|
||||
"link_type": "DocType",
|
||||
"onboard": 1,
|
||||
"type": "Link"
|
||||
}
|
||||
],
|
||||
"modified": "2021-03-16 15:59:58.416154",
|
||||
"modified": "2021-04-19 15:48:44.089927",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Home",
|
||||
|
||||
Reference in New Issue
Block a user