diff --git a/accounts/doctype/sales_invoice/test_sales_invoice.py b/accounts/doctype/sales_invoice/test_sales_invoice.py index dfc61eb172..777f51536f 100644 --- a/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -269,7 +269,7 @@ class TestSalesInvoice(unittest.TestCase): def test_sales_invoice_gl_entry_without_aii(self): webnotes.defaults.set_global_default("auto_inventory_accounting", 0) - si = webnotes.bean(webnotes.copy_doclist(test_records[1])) + si = webnotes.bean(copy=test_records[1]) si.insert() si.submit() @@ -711,7 +711,7 @@ test_records = [ "qty": 1.0, "basic_rate": 500.0, "amount": 500.0, - "export_rate": 500.0, + "ref_rate": 500.0, "export_amount": 500.0, "income_account": "Sales - _TC", "expense_account": "_Test Account Cost for Goods Sold - _TC", diff --git a/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.py b/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.py index 6cd2b4ffaa..bc55701f45 100644 --- a/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.py +++ b/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.py @@ -25,9 +25,9 @@ class DocType: def get_rate(self, arg): from webnotes.model.code import get_obj return get_obj('Sales Common').get_rate(arg) - - def update_other_default_charges(self): - webnotes.conn.sql("update `tabSales Taxes and Charges Master` set is_default = 0 where ifnull(is_default,0) = 1 and name != '%s' and company = '%s'" % (self.doc.name, self.doc.company)) - - def on_update(self): - self.update_other_default_charges() + + def validate(self): + if self.doc.is_default == 1: + webnotes.conn.sql("""update `tabSales Taxes and Charges Master` set is_default = 0 + where ifnull(is_default,0) = 1 and name != %s and company = %s""", + (self.doc.name, self.doc.company)) \ No newline at end of file diff --git a/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.txt b/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.txt index 8759cb7c63..5de944204c 100644 --- a/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.txt +++ b/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.txt @@ -2,7 +2,7 @@ { "creation": "2013-01-10 16:34:09", "docstatus": 0, - "modified": "2013-01-22 14:57:23", + "modified": "2013-06-20 16:49:12", "modified_by": "Administrator", "owner": "Administrator" }, @@ -55,14 +55,9 @@ "label": "Default" }, { - "description": "* Will be calculated in the transaction.", "doctype": "DocField", - "fieldname": "other_charges", - "fieldtype": "Table", - "label": "Sales Taxes and Charges Master", - "oldfieldname": "other_charges", - "oldfieldtype": "Table", - "options": "Sales Taxes and Charges" + "fieldname": "column_break_3", + "fieldtype": "Column Break" }, { "doctype": "DocField", @@ -76,6 +71,30 @@ "reqd": 1, "search_index": 0 }, + { + "doctype": "DocField", + "fieldname": "section_break_5", + "fieldtype": "Section Break" + }, + { + "description": "* Will be calculated in the transaction.", + "doctype": "DocField", + "fieldname": "other_charges", + "fieldtype": "Table", + "label": "Sales Taxes and Charges Master", + "oldfieldname": "other_charges", + "oldfieldtype": "Table", + "options": "Sales Taxes and Charges" + }, + { + "description": "Specify a list of Territories, for which, this Taxes Master is valid", + "doctype": "DocField", + "fieldname": "valid_for_territories", + "fieldtype": "Table", + "label": "Valid for Territories", + "options": "For Territory", + "reqd": 1 + }, { "amend": 0, "cancel": 0, diff --git a/buying/doctype/purchase_common/purchase_common.js b/buying/doctype/purchase_common/purchase_common.js index d3a1a60e47..f9694d0695 100644 --- a/buying/doctype/purchase_common/purchase_common.js +++ b/buying/doctype/purchase_common/purchase_common.js @@ -349,13 +349,6 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({ } }, - set_dynamic_labels: function(doc, dt, dn) { - var company_currency = this.get_company_currency(); - - this.change_form_labels(company_currency); - this.change_grid_labels(company_currency); - }, - change_form_labels: function(company_currency) { var me = this; var field_label_map = {}; diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py index 9ca68a7ee7..ec7e3e56a3 100644 --- a/controllers/accounts_controller.py +++ b/controllers/accounts_controller.py @@ -52,14 +52,16 @@ class AccountsController(TransactionBase): "price_list_name": self.doc.price_list_name, "buying_or_selling": buying_or_selling })) - - if not self.doc.plc_conversion_rate: - self.doc.plc_conversion_rate = flt(webnotes.conn.get_value("Price List", - self.doc.price_list_name, "conversion_rate")) + + if self.doc.price_list_currency: + if not self.doc.plc_conversion_rate: + exchange = self.doc.price_list_currency + "-" + get_company_currency(self.doc.company) + self.doc.plc_conversion_rate = flt(webnotes.conn.get_value("Currency Exchange", + exchange, "exchange_rate")) - if not self.doc.currency: - self.doc.currency = self.doc.price_list_currency - self.doc.conversion_rate = self.doc.plc_conversion_rate + if not self.doc.currency: + self.doc.currency = self.doc.price_list_currency + self.doc.conversion_rate = self.doc.plc_conversion_rate def set_missing_item_details(self, get_item_details): """set missing item values""" diff --git a/patches/april_2013/p08_price_list_country.py b/patches/april_2013/p08_price_list_country.py deleted file mode 100644 index 65643cc239..0000000000 --- a/patches/april_2013/p08_price_list_country.py +++ /dev/null @@ -1,5 +0,0 @@ -import webnotes - -def execute(): - webnotes.reload_doc("Setup", "DocType", "Price List") - webnotes.conn.sql("""update `tabPrice List` set valid_for_all_countries=1""") \ No newline at end of file diff --git a/patches/june_2013/p07_taxes_price_list_for_territory.py b/patches/june_2013/p07_taxes_price_list_for_territory.py new file mode 100644 index 0000000000..fbce11557a --- /dev/null +++ b/patches/june_2013/p07_taxes_price_list_for_territory.py @@ -0,0 +1,25 @@ +import webnotes + +def execute(): + webnotes.reload_doc("setup", "doctype", "for_territory") + webnotes.reload_doc("setup", "doctype", "price_list") + webnotes.reload_doc("accounts", "doctype", "sales_taxes_and_charges_master") + + from setup.utils import get_root_of + root_territory = get_root_of("Territory") + + for parenttype in ["Sales Taxes and Charges Master", "Price List"]: + for name in webnotes.conn.sql_list("""select name from `tab%s` main + where not exists (select parent from `tabFor Territory` territory + where territory.parenttype=%s and territory.parent=main.name)""" % \ + (parenttype, "%s"), (parenttype,)): + + doc = webnotes.doc({ + "doctype": "For Territory", + "__islocal": 1, + "parenttype": parenttype, + "parentfield": "valid_for_territories", + "parent": name, + "territory": root_territory + }) + doc.save() diff --git a/patches/june_2013/p08_shopping_cart_settings.py b/patches/june_2013/p08_shopping_cart_settings.py new file mode 100644 index 0000000000..4d5ebb3822 --- /dev/null +++ b/patches/june_2013/p08_shopping_cart_settings.py @@ -0,0 +1,11 @@ +import webnotes + +def execute(): + webnotes.reload_doc("website", "doctype", "shopping_cart_settings") + + # create two default territories, one for home country and one named Rest of the World + from setup.doctype.setup_control.setup_control import create_territories + create_territories() + + webnotes.conn.set_value("Shopping Cart Settings", None, "default_territory", "Rest of the World") + \ No newline at end of file diff --git a/patches/patch_list.py b/patches/patch_list.py index 035666c5a4..a5c4d805e4 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -226,7 +226,6 @@ patch_list = [ "execute:webnotes.reset_perms('File Data')", "patches.april_2013.p07_update_file_data_2", "patches.april_2013.rebuild_sales_browser", - "patches.april_2013.p08_price_list_country", "patches.may_2013.p01_selling_net_total_export", "patches.may_2013.repost_stock_for_no_posting_time", "patches.may_2013.p01_conversion_factor_and_aii", @@ -245,4 +244,5 @@ patch_list = [ "patches.june_2013.p04_fix_event_for_lead_oppty_project", "patches.june_2013.p05_remove_unused_doctypes", "patches.june_2013.p06_drop_unused_tables", + "patches.june_2013.p08_shopping_cart_settings", ] \ No newline at end of file diff --git a/public/js/transaction.js b/public/js/transaction.js index 9df0147851..0002f66259 100644 --- a/public/js/transaction.js +++ b/public/js/transaction.js @@ -76,9 +76,9 @@ erpnext.TransactionController = wn.ui.form.Controller.extend({ $.each(["currency", "price_list_currency"], function(i, fieldname) { if(!me.doc[fieldname]) { me.frm.set_value(fieldname, company_currency); + me[fieldname](); } }); - this.price_list_currency(); } }, @@ -87,10 +87,33 @@ erpnext.TransactionController = wn.ui.form.Controller.extend({ }, currency: function() { - if(this.frm.doc.currency === this.get_company_currency()) - this.frm.set_value("conversion_rate", 1.0); + var me = this; + this.set_dynamic_labels(); - this.price_list_currency(); + var company_currency = this.get_company_currency(); + if(this.frm.doc.currency !== company_currency) { + this.get_exchange_rate(this.frm.doc.currency, company_currency, + function(exchange_rate) { + if(exchange_rate) { + me.frm.set_value("conversion_rate", exchange_rate); + me.conversion_rate(); + } + }); + } else { + this.conversion_rate(); + } + }, + + conversion_rate: function() { + if(this.frm.doc.currency === this.get_company_currency() && + this.frm.doc.conversion_rate !== 1.0) { + this.frm.set_value("conversion_rate", 1.0); + } else if(this.frm.doc.currency === this.frm.doc.price_list_currency && + this.frm.doc.plc_conversion_rate !== this.frm.doc.conversion_rate) { + this.frm.set_value("plc_conversion_rate", this.frm.doc.conversion_rate); + } + + this.calculate_taxes_and_totals(); }, price_list_name: function(buying_or_selling) { @@ -98,7 +121,7 @@ erpnext.TransactionController = wn.ui.form.Controller.extend({ if(this.frm.doc.price_list_name) { this.frm.call({ method: "setup.utils.get_price_list_currency", - args: {args: { + args: { args: { price_list_name: this.frm.doc.price_list_name, buying_or_selling: buying_or_selling }}, @@ -111,26 +134,38 @@ erpnext.TransactionController = wn.ui.form.Controller.extend({ } }, + get_exchange_rate: function(from_currency, to_currency, callback) { + var exchange_name = from_currency + "-" + to_currency; + wn.model.with_doc("Currency Exchange", exchange_name, function(name) { + var exchange_doc = wn.model.get_doc("Currency Exchange", exchange_name); + callback(exchange_doc ? flt(exchange_doc.exchange_rate)) : 0); + }); + }, + price_list_currency: function() { - // What TODO? should we make price list system non-mandatory? - this.frm.toggle_reqd("plc_conversion_rate", - !!(this.frm.doc.price_list_name && this.frm.doc.price_list_currency)); - - if(this.frm.doc.price_list_currency === this.get_company_currency()) { - this.frm.set_value("plc_conversion_rate", 1.0); - } else if(this.frm.doc.price_list_currency === this.frm.doc.currency) { - this.frm.set_value("plc_conversion_rate", this.frm.doc.conversion_rate); - } this.set_dynamic_labels(); + + var company_currency = this.get_company_currency(); + if(this.frm.doc.price_list_currency !== company_currency) { + this.get_exchange_rate(this.frm.doc.price_list_currency, company_currency, + function(exchange_rate) { + if(exchange_rate) { + me.frm.set_value("price_list_currency", exchange_rate); + me.plc_conversion_rate(); + } + }); + } else { + this.plc_conversion_rate(); + } }, plc_conversion_rate: function() { - this.price_list_currency(); - }, - - conversion_rate: function() { - this.price_list_currency(); - this.calculate_taxes_and_totals(); + if(this.frm.doc.price_list_currency === this.get_company_currency()) { + this.frm.set_value("plc_conversion_rate", 1.0); + } else if(this.frm.doc.price_list_currency === this.frm.doc.currency) { + this.frm.set_value("conversion_rate", this.frm.doc.plc_conversion_rate); + this.calculate_taxes_and_totals(); + } }, qty: function(doc, cdt, cdn) { @@ -153,6 +188,16 @@ erpnext.TransactionController = wn.ui.form.Controller.extend({ } }, + set_dynamic_labels: function() { + // What TODO? should we make price list system non-mandatory? + this.frm.toggle_reqd("plc_conversion_rate", + !!(this.frm.doc.price_list_name && this.frm.doc.price_list_currency)); + + var company_currency = this.get_company_currency(); + this.change_form_labels(company_currency); + this.change_grid_labels(company_currency); + }, + recalculate: function() { this.calculate_taxes_and_totals(); }, diff --git a/selling/doctype/sales_common/sales_common.js b/selling/doctype/sales_common/sales_common.js index 0a7bef7e2f..2d30601f26 100644 --- a/selling/doctype/sales_common/sales_common.js +++ b/selling/doctype/sales_common/sales_common.js @@ -384,10 +384,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ }, set_dynamic_labels: function() { - var company_currency = this.get_company_currency(); - - this.change_form_labels(company_currency); - this.change_grid_labels(company_currency); + this._super(); set_sales_bom_help(this.frm.doc); }, diff --git a/setup/doctype/currency/currency.py b/setup/doctype/currency/currency.py index 7794430349..7f48feb2eb 100644 --- a/setup/doctype/currency/currency.py +++ b/setup/doctype/currency/currency.py @@ -19,4 +19,4 @@ import webnotes class DocType: def __init__(self, d, dl): - self.doc, self.doclist = d, dl + self.doc, self.doclist = d, dl \ No newline at end of file diff --git a/setup/doctype/price_list_country/__init__.py b/setup/doctype/currency_exchange/__init__.py similarity index 100% rename from setup/doctype/price_list_country/__init__.py rename to setup/doctype/currency_exchange/__init__.py diff --git a/setup/doctype/currency_exchange/currency_exchange.py b/setup/doctype/currency_exchange/currency_exchange.py new file mode 100644 index 0000000000..f1ff49ed93 --- /dev/null +++ b/setup/doctype/currency_exchange/currency_exchange.py @@ -0,0 +1,19 @@ +# For license information, please see license.txt + +from __future__ import unicode_literals +import webnotes +from webnotes import _, msgprint +from webnotes.model.controller import DocListController + +class DocType(DocListController): + def __init__(self, d, dl): + self.doc, self.doclist = d, dl + + def autoname(self): + self.doc.name = self.doc.from_currency + "-" + self.doc.to_currency + + def validate(self): + self.validate_value("exchange_rate", ">", 0) + + if self.doc.from_currency == self.doc.to_currency: + msgprint(_("From Currency and To Currency cannot be same"), raise_exception=True) \ No newline at end of file diff --git a/setup/doctype/currency_exchange/currency_exchange.txt b/setup/doctype/currency_exchange/currency_exchange.txt new file mode 100644 index 0000000000..1a05ebe908 --- /dev/null +++ b/setup/doctype/currency_exchange/currency_exchange.txt @@ -0,0 +1,50 @@ +[ + { + "creation": "2013-06-20 15:40:29", + "docstatus": 0, + "modified": "2013-06-20 15:40:29", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "allow_import": 1, + "description": "Specify Exchange Rate to convert one currency into another", + "doctype": "DocType", + "document_type": "Master", + "module": "Setup", + "name": "__common__" + }, + { + "doctype": "DocField", + "name": "__common__", + "parent": "Currency Exchange", + "parentfield": "fields", + "parenttype": "DocType", + "permlevel": 0, + "reqd": 1 + }, + { + "doctype": "DocType", + "name": "Currency Exchange" + }, + { + "doctype": "DocField", + "fieldname": "from_currency", + "fieldtype": "Link", + "label": "From Currency", + "options": "Currency" + }, + { + "doctype": "DocField", + "fieldname": "to_currency", + "fieldtype": "Link", + "label": "To Currency", + "options": "Currency" + }, + { + "doctype": "DocField", + "fieldname": "exchange_rate", + "fieldtype": "Float", + "label": "Exchange Rate" + } +] \ No newline at end of file diff --git a/setup/doctype/for_territory/__init__.py b/setup/doctype/for_territory/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/setup/doctype/price_list_country/price_list_country.py b/setup/doctype/for_territory/for_territory.py similarity index 100% rename from setup/doctype/price_list_country/price_list_country.py rename to setup/doctype/for_territory/for_territory.py diff --git a/setup/doctype/price_list_country/price_list_country.txt b/setup/doctype/for_territory/for_territory.txt similarity index 62% rename from setup/doctype/price_list_country/price_list_country.txt rename to setup/doctype/for_territory/for_territory.txt index 640b0a8052..658a11c7ac 100644 --- a/setup/doctype/price_list_country/price_list_country.txt +++ b/setup/doctype/for_territory/for_territory.txt @@ -1,13 +1,12 @@ [ { - "creation": "2013-04-29 18:24:32", + "creation": "2013-06-20 12:48:38", "docstatus": 0, - "modified": "2013-04-29 18:24:32", + "modified": "2013-06-20 12:48:38", "modified_by": "Administrator", "owner": "Administrator" }, { - "autoname": "PLCNTRY-.#####", "doctype": "DocType", "istable": 1, "module": "Setup", @@ -15,12 +14,12 @@ }, { "doctype": "DocField", - "fieldname": "country", + "fieldname": "territory", "fieldtype": "Link", - "label": "Country", + "label": "Territory", "name": "__common__", - "options": "Country", - "parent": "Price List Country", + "options": "Territory", + "parent": "For Territory", "parentfield": "fields", "parenttype": "DocType", "permlevel": 0, @@ -28,7 +27,7 @@ }, { "doctype": "DocType", - "name": "Price List Country" + "name": "For Territory" }, { "doctype": "DocField" diff --git a/setup/doctype/price_list/price_list.py b/setup/doctype/price_list/price_list.py index e6e7b7f61c..b40a46f040 100644 --- a/setup/doctype/price_list/price_list.py +++ b/setup/doctype/price_list/price_list.py @@ -17,7 +17,7 @@ from __future__ import unicode_literals import webnotes from webnotes import msgprint, _ -from webnotes.utils import cint, comma_or +from webnotes.utils import comma_or from webnotes.model.controller import DocListController class DocType(DocListController): @@ -26,33 +26,10 @@ class DocType(DocListController): where price_list_name=%s""", self.doc.name, as_dict=True, update={"doctype": "Item Price"})) def validate(self): - if not (cint(self.doc.valid_for_all_countries) or len(self.doclist.get({"parentfield": "valid_for_countries"}))): - msgprint(_("""Please check "Valid For All Countries" or \ - enter atlease one row in the "Countries" table."""), raise_exception=True) - if self.doc.buying_or_selling not in ["Buying", "Selling"]: msgprint(_(self.meta.get_label("buying_or_selling")) + " " + _("must be one of") + " " + comma_or(["Buying", "Selling"]), raise_exception=True) - self.validate_use_for_website() - - def validate_use_for_website(self): - if self.doc.use_for_website: - if self.doc.valid_for_all_countries: - if webnotes.conn.sql("""select name from `tabPrice List` where use_for_website=1 - and valid_for_all_countries=1 and name!=%s""", self.doc.name): - webnotes.msgprint(_("Error: Another Price List already exists that is used for website and is valid for all countries."), - raise_exception=True) - - elif self.doclist.get({"parentfield": "valid_for_countries"}): - for d in self.doclist.get({"parentfield": "valid_for_countries"}): - if webnotes.conn.sql("""select country from `tabPrice List Country` plc, `tabPrice List` pl - where plc.parent=pl.name and pl.use_for_website=1 and - ifnull(valid_for_all_countries, 0)=0 and country=%s and pl.name!=%s""", - (d.country, self.doc.name)): - webnotes.msgprint(_("Error: Another Price List already exists that is used for website and is valid for country") - + ": " + d.country, raise_exception=True) - def on_trash(self): webnotes.conn.sql("""delete from `tabItem Price` where price_list_name = %s""", self.doc.name) \ No newline at end of file diff --git a/setup/doctype/price_list/price_list.txt b/setup/doctype/price_list/price_list.txt index 8115f3d32b..9bc18dc062 100644 --- a/setup/doctype/price_list/price_list.txt +++ b/setup/doctype/price_list/price_list.txt @@ -2,7 +2,7 @@ { "creation": "2013-01-25 11:35:09", "docstatus": 0, - "modified": "2013-06-19 15:24:23", + "modified": "2013-06-20 12:53:10", "modified_by": "Administrator", "owner": "Administrator" }, @@ -60,13 +60,6 @@ "options": "Currency", "reqd": 1 }, - { - "doctype": "DocField", - "fieldname": "conversion_rate", - "fieldtype": "Float", - "label": "Conversion Rate", - "reqd": 1 - }, { "default": "Selling", "doctype": "DocField", @@ -76,31 +69,19 @@ "options": "Buying\nSelling", "reqd": 1 }, - { - "doctype": "DocField", - "fieldname": "use_for_website", - "fieldtype": "Check", - "label": "Use for Website" - }, { "doctype": "DocField", "fieldname": "column_break_3", "fieldtype": "Column Break" }, { - "default": "1", + "description": "Specify a list of Territories, for which, this Price List is valid", "doctype": "DocField", - "fieldname": "valid_for_all_countries", - "fieldtype": "Check", - "label": "Valid for all countries" - }, - { - "description": "Or specify a list of Countries, for which, this Price List is valid", - "doctype": "DocField", - "fieldname": "valid_for_countries", + "fieldname": "valid_for_territories", "fieldtype": "Table", - "label": "Valid for the following countries", - "options": "Price List Country" + "label": "Valid for Territories", + "options": "For Territory", + "reqd": 1 }, { "doctype": "DocField", diff --git a/setup/doctype/price_list/test_price_list.py b/setup/doctype/price_list/test_price_list.py index dc727c5ab7..f776972898 100644 --- a/setup/doctype/price_list/test_price_list.py +++ b/setup/doctype/price_list/test_price_list.py @@ -5,7 +5,6 @@ test_records = [ "currency": "INR", "valid_for_all_countries": 1, "buying_or_selling": "Selling", - "use_for_website": 1, "conversion_rate": 1.0 }] ] \ No newline at end of file diff --git a/setup/doctype/price_list_country/README.md b/setup/doctype/price_list_country/README.md deleted file mode 100644 index c2966e3e60..0000000000 --- a/setup/doctype/price_list_country/README.md +++ /dev/null @@ -1 +0,0 @@ -Countries where parent Price List is valid. \ No newline at end of file diff --git a/setup/doctype/setup_control/setup_control.py b/setup/doctype/setup_control/setup_control.py index 5bfe4a7d94..f8290da5e3 100644 --- a/setup/doctype/setup_control/setup_control.py +++ b/setup/doctype/setup_control/setup_control.py @@ -64,7 +64,6 @@ class DocType: # enable default currency webnotes.conn.set_value("Currency", args.get("currency"), "enabled", 1) - def_args = { 'current_fiscal_year':curr_fiscal_year, @@ -91,6 +90,8 @@ class DocType: cp_args[k] = args[k] self.set_cp_defaults(**cp_args) + + create_territories() self.create_feed_and_todo() @@ -102,9 +103,10 @@ class DocType: import webnotes.utils user_fullname = (args.get('first_name') or '') + (args.get('last_name') and (" " + args.get('last_name')) or '') + webnotes.conn.commit() return {'sys_defaults': webnotes.utils.get_defaults(), 'user_fullname': user_fullname} - + def create_feed_and_todo(self): """update activty feed and create todo for creation of item, customer, vendor""" import home @@ -245,4 +247,19 @@ def add_all_roles_to(name): if role[0] not in ["Administrator", "Guest", "All", "Customer", "Supplier", "Partner"]: d = profile.addchild("userroles", "UserRole") d.role = role[0] - d.insert() \ No newline at end of file + d.insert() + +def create_territories(): + """create two default territories, one for home country and one named Rest of the World""" + from setup.utils import get_root_of + country = webnotes.conn.get_value("Control Panel", None, "country") + root_territory = get_root_of("Territory") + for name in (country, "Rest Of The World"): + if not webnotes.conn.exists("Territory", name): + webnotes.bean({ + "doctype": "Territory", + "territory_name": name, + "parent_territory": root_territory, + "is_group": "No" + }).insert() + \ No newline at end of file diff --git a/setup/utils.py b/setup/utils.py index b4f38ceb8e..04c4527cec 100644 --- a/setup/utils.py +++ b/setup/utils.py @@ -29,6 +29,19 @@ def get_company_currency(company): return currency +def get_root_of(doctype): + """Get root element of a DocType with a tree structure""" + result = webnotes.conn.sql_list("""select name from `tab%s` + where lft=1 and rgt=(select max(rgt) from `tab%s`)""" % (doctype, doctype)) + return result[0] if result else None + +def get_ancestors_of(doctype, name): + """Get ancestor elements of a DocType with a tree structure""" + lft, rgt = webnotes.conn.get_value(doctype, name, ["lft", "rgt"]) + result = webnotes.conn.sql_list("""select name from `tab%s` + where lft<%s and rgt>%s""" % (doctype, "%s", "%s"), (lft, rgt)) + return result or None + @webnotes.whitelist() def get_price_list_currency(args): """ diff --git a/startup/install.py b/startup/install.py index bc8c38710d..a3eec66d09 100644 --- a/startup/install.py +++ b/startup/install.py @@ -137,8 +137,10 @@ def import_defaults(): {'doctype': 'Supplier Type', 'name': 'Default Supplier Type', 'supplier_type': 'Default Supplier Type'}, # Price List - {'doctype': 'Price List', 'name': 'Default Price List', 'price_list_name': 'Default Price List'}, - {'doctype': 'Price List', 'name': 'Standard', 'price_list_name': 'Standard'}, + {'doctype': 'Price List', 'name': 'Default Price List', 'price_list_name': 'Default Price List', + "buying_or_selling": "Selling"}, + {'doctype': 'Price List', 'name': 'Standard', 'price_list_name': 'Standard', + "buying_or_selling": "Selling"}, # warehouse type {'doctype': 'Warehouse Type', 'name': 'Default Warehouse Type', 'warehouse_type': 'Default Warehouse Type'}, @@ -174,6 +176,6 @@ def import_defaults(): ] for r in records: - doc = webnotes.doc(r) - doc.insert() + bean = webnotes.bean(r) + bean.insert() \ No newline at end of file diff --git a/website/doctype/shopping_cart_price_list/__init__.py b/website/doctype/shopping_cart_price_list/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/website/doctype/shopping_cart_price_list/shopping_cart_price_list.py b/website/doctype/shopping_cart_price_list/shopping_cart_price_list.py new file mode 100644 index 0000000000..928aa9ff9f --- /dev/null +++ b/website/doctype/shopping_cart_price_list/shopping_cart_price_list.py @@ -0,0 +1,8 @@ +# For license information, please see license.txt + +from __future__ import unicode_literals +import webnotes + +class DocType: + def __init__(self, d, dl): + self.doc, self.doclist = d, dl \ No newline at end of file diff --git a/website/doctype/shopping_cart_price_list/shopping_cart_price_list.txt b/website/doctype/shopping_cart_price_list/shopping_cart_price_list.txt new file mode 100644 index 0000000000..57ddc21cc3 --- /dev/null +++ b/website/doctype/shopping_cart_price_list/shopping_cart_price_list.txt @@ -0,0 +1,35 @@ +[ + { + "creation": "2013-06-20 16:00:18", + "docstatus": 0, + "modified": "2013-06-20 16:01:34", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "DocType", + "istable": 1, + "module": "Website", + "name": "__common__" + }, + { + "doctype": "DocField", + "fieldname": "price_list", + "fieldtype": "Link", + "label": "Price List", + "name": "__common__", + "options": "Price List", + "parent": "Shopping Cart Price List", + "parentfield": "fields", + "parenttype": "DocType", + "permlevel": 0, + "reqd": 1 + }, + { + "doctype": "DocType", + "name": "Shopping Cart Price List" + }, + { + "doctype": "DocField" + } +] \ No newline at end of file diff --git a/website/doctype/shopping_cart_settings/shopping_cart_settings.py b/website/doctype/shopping_cart_settings/shopping_cart_settings.py index 928aa9ff9f..516c96834f 100644 --- a/website/doctype/shopping_cart_settings/shopping_cart_settings.py +++ b/website/doctype/shopping_cart_settings/shopping_cart_settings.py @@ -2,7 +2,73 @@ from __future__ import unicode_literals import webnotes +from webnotes import _, msgprint +from webnotes.utils import comma_and +from webnotes.model.controller import DocListController -class DocType: +class ShoppingCartSetupError(webnotes.ValidationError): pass + +class DocType(DocListController): def __init__(self, d, dl): - self.doc, self.doclist = d, dl \ No newline at end of file + self.doc, self.doclist = d, dl + + def validate(self): + if self.doc.enabled: + self.validate_overlapping_territories("shopping_cart_price_lists", "price_list") + self.validate_overlapping_territories("shopping_cart_taxes_and_charges_masters", + "sales_taxes_and_charges_master") + self.validate_shipping_rules() + self.validate_exchange_rates_exist() + + def validate_overlapping_territories(self, parentfield, fieldname): + names = [doc.fields(fieldname) for doc in self.doclist.get({"parentfield": parentfield})] + doctype = self.meta.get_field(parentfield).options + parenttype = self.meta.get_field(fieldname, parentfield=parentfield).options + + if not names: + msgprint(_("Please specify at least one") + " " + _(doctype), + raise_exception=ShoppingCartSetupError) + + territory_name = webnotes.conn.sql("""select territory, parent from `tabFor Territory` + where parenttype=%s and parent in (%s)""" % ("%s", ", ".join(["%s"]*names)), + tuple([parenttype] + names)) + + territory_name_map = {} + for territory, name in territory_name: + territory_name_map.setdefault(territory, []).append(name) + + for territory, names in territory_name_map.items(): + if len(names) > 1: + msgprint(_("Error for") + " " + _(doctype) + ": " + comma_and(names) + + " " + _("have a common territory") + ": " + territory, + raise_exception=ShoppingCartSetupError) + + def validate_shipping_rules(self): + pass + + def validate_exchange_rates_exist(self): + """check if exchange rates exist for all Price List currencies (to company's currency)""" + company_currency = webnotes.conn.get_value("Company", self.doc.company, "default_currency") + if not company_currency: + msgprint(_("Please specify currency in Company") + ": " + self.doc.company, + raise_exception=ShoppingCartSetupError) + + price_list_currency_map = webnotes.conn.get_values("Price List", + [d.price_list for d in self.doclist.get({"parentfield": "shopping_cart_price_lists"})], + "currency") + + expected_to_exist = [currency + "-" + company_currency + for currency in price_list_currency_map.values() + if currency != company_currency] + + exists = webnotes.conn.sql_list("""select name from `tabCurrency Exchange` + where name in (%s)""" % (", ".join(["%s"]*len(expected_to_exist)),), + tuple(expected_to_exist)) + + missing = list(set(expected_to_exist).difference(exists)) + + if missing: + msgprint(_("Missing Currency Exchange Rates for" + ": " + comma_and(missing)), + raise_exception=ShoppingCartSetupError) + + \ No newline at end of file diff --git a/website/doctype/shopping_cart_settings/shopping_cart_settings.txt b/website/doctype/shopping_cart_settings/shopping_cart_settings.txt index 627c1274c6..82e3baed37 100644 --- a/website/doctype/shopping_cart_settings/shopping_cart_settings.txt +++ b/website/doctype/shopping_cart_settings/shopping_cart_settings.txt @@ -2,7 +2,7 @@ { "creation": "2013-06-19 15:57:32", "docstatus": 0, - "modified": "2013-06-19 16:01:25", + "modified": "2013-06-21 12:59:30", "modified_by": "Administrator", "owner": "Administrator" }, @@ -15,16 +15,11 @@ }, { "doctype": "DocField", - "fieldname": "territory", - "fieldtype": "Link", - "label": "Default Territory", "name": "__common__", - "options": "Territory", "parent": "Shopping Cart Settings", "parentfield": "fields", "parenttype": "DocType", - "permlevel": 0, - "reqd": 1 + "permlevel": 0 }, { "create": 1, @@ -43,7 +38,42 @@ "name": "Shopping Cart Settings" }, { - "doctype": "DocField" + "doctype": "DocField", + "fieldname": "enabled", + "fieldtype": "Check", + "label": "Enable Shopping Cart" + }, + { + "doctype": "DocField", + "fieldname": "default_territory", + "fieldtype": "Link", + "label": "Default Territory", + "options": "Territory", + "reqd": 1 + }, + { + "doctype": "DocField", + "fieldname": "shopping_cart_price_lists", + "fieldtype": "Table", + "label": "Shopping Cart Price Lists", + "options": "Shopping Cart Price List", + "reqd": 0 + }, + { + "doctype": "DocField", + "fieldname": "shopping_cart_taxes_and_charges_masters", + "fieldtype": "Table", + "label": "Shopping Cart Taxes and Charges Masters", + "options": "Shopping Cart Taxes and Charges Master", + "reqd": 0 + }, + { + "doctype": "DocField", + "fieldname": "company", + "fieldtype": "Link", + "label": "Company", + "options": "Company", + "reqd": 1 }, { "doctype": "DocPerm" diff --git a/website/doctype/shopping_cart_taxes_and_charges_master/__init__.py b/website/doctype/shopping_cart_taxes_and_charges_master/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/website/doctype/shopping_cart_taxes_and_charges_master/shopping_cart_taxes_and_charges_master.py b/website/doctype/shopping_cart_taxes_and_charges_master/shopping_cart_taxes_and_charges_master.py new file mode 100644 index 0000000000..928aa9ff9f --- /dev/null +++ b/website/doctype/shopping_cart_taxes_and_charges_master/shopping_cart_taxes_and_charges_master.py @@ -0,0 +1,8 @@ +# For license information, please see license.txt + +from __future__ import unicode_literals +import webnotes + +class DocType: + def __init__(self, d, dl): + self.doc, self.doclist = d, dl \ No newline at end of file diff --git a/website/doctype/shopping_cart_taxes_and_charges_master/shopping_cart_taxes_and_charges_master.txt b/website/doctype/shopping_cart_taxes_and_charges_master/shopping_cart_taxes_and_charges_master.txt new file mode 100644 index 0000000000..6cd9f382d8 --- /dev/null +++ b/website/doctype/shopping_cart_taxes_and_charges_master/shopping_cart_taxes_and_charges_master.txt @@ -0,0 +1,35 @@ +[ + { + "creation": "2013-06-20 16:57:03", + "docstatus": 0, + "modified": "2013-06-20 16:57:03", + "modified_by": "Administrator", + "owner": "Administrator" + }, + { + "doctype": "DocType", + "istable": 1, + "module": "Website", + "name": "__common__" + }, + { + "doctype": "DocField", + "fieldname": "sales_taxes_and_charges_master", + "fieldtype": "Link", + "label": "Tax Master", + "name": "__common__", + "options": "Sales Taxes and Charges Master", + "parent": "Shopping Cart Taxes and Charges Master", + "parentfield": "fields", + "parenttype": "DocType", + "permlevel": 0, + "reqd": 1 + }, + { + "doctype": "DocType", + "name": "Shopping Cart Taxes and Charges Master" + }, + { + "doctype": "DocField" + } +] \ No newline at end of file