[webshop] territories in price list, taxes, updates in shopping cart settings
This commit is contained in:
parent
d52b03a8cc
commit
61a2f68bc6
@ -269,7 +269,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
def test_sales_invoice_gl_entry_without_aii(self):
|
def test_sales_invoice_gl_entry_without_aii(self):
|
||||||
webnotes.defaults.set_global_default("auto_inventory_accounting", 0)
|
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.insert()
|
||||||
si.submit()
|
si.submit()
|
||||||
|
|
||||||
@ -711,7 +711,7 @@ test_records = [
|
|||||||
"qty": 1.0,
|
"qty": 1.0,
|
||||||
"basic_rate": 500.0,
|
"basic_rate": 500.0,
|
||||||
"amount": 500.0,
|
"amount": 500.0,
|
||||||
"export_rate": 500.0,
|
"ref_rate": 500.0,
|
||||||
"export_amount": 500.0,
|
"export_amount": 500.0,
|
||||||
"income_account": "Sales - _TC",
|
"income_account": "Sales - _TC",
|
||||||
"expense_account": "_Test Account Cost for Goods Sold - _TC",
|
"expense_account": "_Test Account Cost for Goods Sold - _TC",
|
||||||
|
@ -25,9 +25,9 @@ class DocType:
|
|||||||
def get_rate(self, arg):
|
def get_rate(self, arg):
|
||||||
from webnotes.model.code import get_obj
|
from webnotes.model.code import get_obj
|
||||||
return get_obj('Sales Common').get_rate(arg)
|
return get_obj('Sales Common').get_rate(arg)
|
||||||
|
|
||||||
def update_other_default_charges(self):
|
def validate(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))
|
if self.doc.is_default == 1:
|
||||||
|
webnotes.conn.sql("""update `tabSales Taxes and Charges Master` set is_default = 0
|
||||||
def on_update(self):
|
where ifnull(is_default,0) = 1 and name != %s and company = %s""",
|
||||||
self.update_other_default_charges()
|
(self.doc.name, self.doc.company))
|
@ -2,7 +2,7 @@
|
|||||||
{
|
{
|
||||||
"creation": "2013-01-10 16:34:09",
|
"creation": "2013-01-10 16:34:09",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"modified": "2013-01-22 14:57:23",
|
"modified": "2013-06-20 16:49:12",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"owner": "Administrator"
|
"owner": "Administrator"
|
||||||
},
|
},
|
||||||
@ -55,14 +55,9 @@
|
|||||||
"label": "Default"
|
"label": "Default"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "* Will be calculated in the transaction.",
|
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"fieldname": "other_charges",
|
"fieldname": "column_break_3",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Column Break"
|
||||||
"label": "Sales Taxes and Charges Master",
|
|
||||||
"oldfieldname": "other_charges",
|
|
||||||
"oldfieldtype": "Table",
|
|
||||||
"options": "Sales Taxes and Charges"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
@ -76,6 +71,30 @@
|
|||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 0
|
"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,
|
"amend": 0,
|
||||||
"cancel": 0,
|
"cancel": 0,
|
||||||
|
@ -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) {
|
change_form_labels: function(company_currency) {
|
||||||
var me = this;
|
var me = this;
|
||||||
var field_label_map = {};
|
var field_label_map = {};
|
||||||
|
@ -52,14 +52,16 @@ class AccountsController(TransactionBase):
|
|||||||
"price_list_name": self.doc.price_list_name,
|
"price_list_name": self.doc.price_list_name,
|
||||||
"buying_or_selling": buying_or_selling
|
"buying_or_selling": buying_or_selling
|
||||||
}))
|
}))
|
||||||
|
|
||||||
if not self.doc.plc_conversion_rate:
|
if self.doc.price_list_currency:
|
||||||
self.doc.plc_conversion_rate = flt(webnotes.conn.get_value("Price List",
|
if not self.doc.plc_conversion_rate:
|
||||||
self.doc.price_list_name, "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:
|
if not self.doc.currency:
|
||||||
self.doc.currency = self.doc.price_list_currency
|
self.doc.currency = self.doc.price_list_currency
|
||||||
self.doc.conversion_rate = self.doc.plc_conversion_rate
|
self.doc.conversion_rate = self.doc.plc_conversion_rate
|
||||||
|
|
||||||
def set_missing_item_details(self, get_item_details):
|
def set_missing_item_details(self, get_item_details):
|
||||||
"""set missing item values"""
|
"""set missing item values"""
|
||||||
|
@ -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""")
|
|
25
patches/june_2013/p07_taxes_price_list_for_territory.py
Normal file
25
patches/june_2013/p07_taxes_price_list_for_territory.py
Normal file
@ -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()
|
11
patches/june_2013/p08_shopping_cart_settings.py
Normal file
11
patches/june_2013/p08_shopping_cart_settings.py
Normal file
@ -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")
|
||||||
|
|
@ -226,7 +226,6 @@ patch_list = [
|
|||||||
"execute:webnotes.reset_perms('File Data')",
|
"execute:webnotes.reset_perms('File Data')",
|
||||||
"patches.april_2013.p07_update_file_data_2",
|
"patches.april_2013.p07_update_file_data_2",
|
||||||
"patches.april_2013.rebuild_sales_browser",
|
"patches.april_2013.rebuild_sales_browser",
|
||||||
"patches.april_2013.p08_price_list_country",
|
|
||||||
"patches.may_2013.p01_selling_net_total_export",
|
"patches.may_2013.p01_selling_net_total_export",
|
||||||
"patches.may_2013.repost_stock_for_no_posting_time",
|
"patches.may_2013.repost_stock_for_no_posting_time",
|
||||||
"patches.may_2013.p01_conversion_factor_and_aii",
|
"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.p04_fix_event_for_lead_oppty_project",
|
||||||
"patches.june_2013.p05_remove_unused_doctypes",
|
"patches.june_2013.p05_remove_unused_doctypes",
|
||||||
"patches.june_2013.p06_drop_unused_tables",
|
"patches.june_2013.p06_drop_unused_tables",
|
||||||
|
"patches.june_2013.p08_shopping_cart_settings",
|
||||||
]
|
]
|
@ -76,9 +76,9 @@ erpnext.TransactionController = wn.ui.form.Controller.extend({
|
|||||||
$.each(["currency", "price_list_currency"], function(i, fieldname) {
|
$.each(["currency", "price_list_currency"], function(i, fieldname) {
|
||||||
if(!me.doc[fieldname]) {
|
if(!me.doc[fieldname]) {
|
||||||
me.frm.set_value(fieldname, company_currency);
|
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() {
|
currency: function() {
|
||||||
if(this.frm.doc.currency === this.get_company_currency())
|
var me = this;
|
||||||
this.frm.set_value("conversion_rate", 1.0);
|
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) {
|
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) {
|
if(this.frm.doc.price_list_name) {
|
||||||
this.frm.call({
|
this.frm.call({
|
||||||
method: "setup.utils.get_price_list_currency",
|
method: "setup.utils.get_price_list_currency",
|
||||||
args: {args: {
|
args: { args: {
|
||||||
price_list_name: this.frm.doc.price_list_name,
|
price_list_name: this.frm.doc.price_list_name,
|
||||||
buying_or_selling: buying_or_selling
|
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() {
|
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();
|
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() {
|
plc_conversion_rate: function() {
|
||||||
this.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) {
|
||||||
conversion_rate: function() {
|
this.frm.set_value("conversion_rate", this.frm.doc.plc_conversion_rate);
|
||||||
this.price_list_currency();
|
this.calculate_taxes_and_totals();
|
||||||
this.calculate_taxes_and_totals();
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
qty: function(doc, cdt, cdn) {
|
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() {
|
recalculate: function() {
|
||||||
this.calculate_taxes_and_totals();
|
this.calculate_taxes_and_totals();
|
||||||
},
|
},
|
||||||
|
@ -384,10 +384,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
set_dynamic_labels: function() {
|
set_dynamic_labels: function() {
|
||||||
var company_currency = this.get_company_currency();
|
this._super();
|
||||||
|
|
||||||
this.change_form_labels(company_currency);
|
|
||||||
this.change_grid_labels(company_currency);
|
|
||||||
set_sales_bom_help(this.frm.doc);
|
set_sales_bom_help(this.frm.doc);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -19,4 +19,4 @@ import webnotes
|
|||||||
|
|
||||||
class DocType:
|
class DocType:
|
||||||
def __init__(self, d, dl):
|
def __init__(self, d, dl):
|
||||||
self.doc, self.doclist = d, dl
|
self.doc, self.doclist = d, dl
|
19
setup/doctype/currency_exchange/currency_exchange.py
Normal file
19
setup/doctype/currency_exchange/currency_exchange.py
Normal file
@ -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)
|
50
setup/doctype/currency_exchange/currency_exchange.txt
Normal file
50
setup/doctype/currency_exchange/currency_exchange.txt
Normal file
@ -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"
|
||||||
|
}
|
||||||
|
]
|
0
setup/doctype/for_territory/__init__.py
Normal file
0
setup/doctype/for_territory/__init__.py
Normal file
@ -1,13 +1,12 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"creation": "2013-04-29 18:24:32",
|
"creation": "2013-06-20 12:48:38",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"modified": "2013-04-29 18:24:32",
|
"modified": "2013-06-20 12:48:38",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"owner": "Administrator"
|
"owner": "Administrator"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"autoname": "PLCNTRY-.#####",
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"module": "Setup",
|
"module": "Setup",
|
||||||
@ -15,12 +14,12 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"fieldname": "country",
|
"fieldname": "territory",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Country",
|
"label": "Territory",
|
||||||
"name": "__common__",
|
"name": "__common__",
|
||||||
"options": "Country",
|
"options": "Territory",
|
||||||
"parent": "Price List Country",
|
"parent": "For Territory",
|
||||||
"parentfield": "fields",
|
"parentfield": "fields",
|
||||||
"parenttype": "DocType",
|
"parenttype": "DocType",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
@ -28,7 +27,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"name": "Price List Country"
|
"name": "For Territory"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"doctype": "DocField"
|
"doctype": "DocField"
|
@ -17,7 +17,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import webnotes
|
import webnotes
|
||||||
from webnotes import msgprint, _
|
from webnotes import msgprint, _
|
||||||
from webnotes.utils import cint, comma_or
|
from webnotes.utils import comma_or
|
||||||
from webnotes.model.controller import DocListController
|
from webnotes.model.controller import DocListController
|
||||||
|
|
||||||
class DocType(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"}))
|
where price_list_name=%s""", self.doc.name, as_dict=True, update={"doctype": "Item Price"}))
|
||||||
|
|
||||||
def validate(self):
|
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"]:
|
if self.doc.buying_or_selling not in ["Buying", "Selling"]:
|
||||||
msgprint(_(self.meta.get_label("buying_or_selling")) + " " + _("must be one of") + " " +
|
msgprint(_(self.meta.get_label("buying_or_selling")) + " " + _("must be one of") + " " +
|
||||||
comma_or(["Buying", "Selling"]), raise_exception=True)
|
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):
|
def on_trash(self):
|
||||||
webnotes.conn.sql("""delete from `tabItem Price` where price_list_name = %s""",
|
webnotes.conn.sql("""delete from `tabItem Price` where price_list_name = %s""",
|
||||||
self.doc.name)
|
self.doc.name)
|
@ -2,7 +2,7 @@
|
|||||||
{
|
{
|
||||||
"creation": "2013-01-25 11:35:09",
|
"creation": "2013-01-25 11:35:09",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"modified": "2013-06-19 15:24:23",
|
"modified": "2013-06-20 12:53:10",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"owner": "Administrator"
|
"owner": "Administrator"
|
||||||
},
|
},
|
||||||
@ -60,13 +60,6 @@
|
|||||||
"options": "Currency",
|
"options": "Currency",
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"doctype": "DocField",
|
|
||||||
"fieldname": "conversion_rate",
|
|
||||||
"fieldtype": "Float",
|
|
||||||
"label": "Conversion Rate",
|
|
||||||
"reqd": 1
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"default": "Selling",
|
"default": "Selling",
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
@ -76,31 +69,19 @@
|
|||||||
"options": "Buying\nSelling",
|
"options": "Buying\nSelling",
|
||||||
"reqd": 1
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"doctype": "DocField",
|
|
||||||
"fieldname": "use_for_website",
|
|
||||||
"fieldtype": "Check",
|
|
||||||
"label": "Use for Website"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"fieldname": "column_break_3",
|
"fieldname": "column_break_3",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "1",
|
"description": "Specify a list of Territories, for which, this Price List is valid",
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"fieldname": "valid_for_all_countries",
|
"fieldname": "valid_for_territories",
|
||||||
"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",
|
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"label": "Valid for the following countries",
|
"label": "Valid for Territories",
|
||||||
"options": "Price List Country"
|
"options": "For Territory",
|
||||||
|
"reqd": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
|
@ -5,7 +5,6 @@ test_records = [
|
|||||||
"currency": "INR",
|
"currency": "INR",
|
||||||
"valid_for_all_countries": 1,
|
"valid_for_all_countries": 1,
|
||||||
"buying_or_selling": "Selling",
|
"buying_or_selling": "Selling",
|
||||||
"use_for_website": 1,
|
|
||||||
"conversion_rate": 1.0
|
"conversion_rate": 1.0
|
||||||
}]
|
}]
|
||||||
]
|
]
|
@ -1 +0,0 @@
|
|||||||
Countries where parent Price List is valid.
|
|
@ -64,7 +64,6 @@ class DocType:
|
|||||||
|
|
||||||
# enable default currency
|
# enable default currency
|
||||||
webnotes.conn.set_value("Currency", args.get("currency"), "enabled", 1)
|
webnotes.conn.set_value("Currency", args.get("currency"), "enabled", 1)
|
||||||
|
|
||||||
|
|
||||||
def_args = {
|
def_args = {
|
||||||
'current_fiscal_year':curr_fiscal_year,
|
'current_fiscal_year':curr_fiscal_year,
|
||||||
@ -91,6 +90,8 @@ class DocType:
|
|||||||
cp_args[k] = args[k]
|
cp_args[k] = args[k]
|
||||||
|
|
||||||
self.set_cp_defaults(**cp_args)
|
self.set_cp_defaults(**cp_args)
|
||||||
|
|
||||||
|
create_territories()
|
||||||
|
|
||||||
self.create_feed_and_todo()
|
self.create_feed_and_todo()
|
||||||
|
|
||||||
@ -102,9 +103,10 @@ class DocType:
|
|||||||
import webnotes.utils
|
import webnotes.utils
|
||||||
user_fullname = (args.get('first_name') or '') + (args.get('last_name')
|
user_fullname = (args.get('first_name') or '') + (args.get('last_name')
|
||||||
and (" " + args.get('last_name')) or '')
|
and (" " + args.get('last_name')) or '')
|
||||||
|
|
||||||
webnotes.conn.commit()
|
webnotes.conn.commit()
|
||||||
return {'sys_defaults': webnotes.utils.get_defaults(), 'user_fullname': user_fullname}
|
return {'sys_defaults': webnotes.utils.get_defaults(), 'user_fullname': user_fullname}
|
||||||
|
|
||||||
def create_feed_and_todo(self):
|
def create_feed_and_todo(self):
|
||||||
"""update activty feed and create todo for creation of item, customer, vendor"""
|
"""update activty feed and create todo for creation of item, customer, vendor"""
|
||||||
import home
|
import home
|
||||||
@ -245,4 +247,19 @@ def add_all_roles_to(name):
|
|||||||
if role[0] not in ["Administrator", "Guest", "All", "Customer", "Supplier", "Partner"]:
|
if role[0] not in ["Administrator", "Guest", "All", "Customer", "Supplier", "Partner"]:
|
||||||
d = profile.addchild("userroles", "UserRole")
|
d = profile.addchild("userroles", "UserRole")
|
||||||
d.role = role[0]
|
d.role = role[0]
|
||||||
d.insert()
|
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()
|
||||||
|
|
@ -29,6 +29,19 @@ def get_company_currency(company):
|
|||||||
|
|
||||||
return currency
|
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()
|
@webnotes.whitelist()
|
||||||
def get_price_list_currency(args):
|
def get_price_list_currency(args):
|
||||||
"""
|
"""
|
||||||
|
@ -137,8 +137,10 @@ def import_defaults():
|
|||||||
{'doctype': 'Supplier Type', 'name': 'Default Supplier Type', 'supplier_type': 'Default Supplier Type'},
|
{'doctype': 'Supplier Type', 'name': 'Default Supplier Type', 'supplier_type': 'Default Supplier Type'},
|
||||||
|
|
||||||
# Price List
|
# Price List
|
||||||
{'doctype': 'Price List', 'name': 'Default Price List', 'price_list_name': 'Default Price List'},
|
{'doctype': 'Price List', 'name': 'Default Price List', 'price_list_name': 'Default Price List',
|
||||||
{'doctype': 'Price List', 'name': 'Standard', 'price_list_name': 'Standard'},
|
"buying_or_selling": "Selling"},
|
||||||
|
{'doctype': 'Price List', 'name': 'Standard', 'price_list_name': 'Standard',
|
||||||
|
"buying_or_selling": "Selling"},
|
||||||
|
|
||||||
# warehouse type
|
# warehouse type
|
||||||
{'doctype': 'Warehouse Type', 'name': 'Default Warehouse Type', 'warehouse_type': 'Default 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:
|
for r in records:
|
||||||
doc = webnotes.doc(r)
|
bean = webnotes.bean(r)
|
||||||
doc.insert()
|
bean.insert()
|
||||||
|
|
@ -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
|
@ -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"
|
||||||
|
}
|
||||||
|
]
|
@ -2,7 +2,73 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import webnotes
|
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):
|
def __init__(self, d, dl):
|
||||||
self.doc, self.doclist = d, dl
|
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)
|
||||||
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
|||||||
{
|
{
|
||||||
"creation": "2013-06-19 15:57:32",
|
"creation": "2013-06-19 15:57:32",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"modified": "2013-06-19 16:01:25",
|
"modified": "2013-06-21 12:59:30",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"owner": "Administrator"
|
"owner": "Administrator"
|
||||||
},
|
},
|
||||||
@ -15,16 +15,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"fieldname": "territory",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"label": "Default Territory",
|
|
||||||
"name": "__common__",
|
"name": "__common__",
|
||||||
"options": "Territory",
|
|
||||||
"parent": "Shopping Cart Settings",
|
"parent": "Shopping Cart Settings",
|
||||||
"parentfield": "fields",
|
"parentfield": "fields",
|
||||||
"parenttype": "DocType",
|
"parenttype": "DocType",
|
||||||
"permlevel": 0,
|
"permlevel": 0
|
||||||
"reqd": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"create": 1,
|
"create": 1,
|
||||||
@ -43,7 +38,42 @@
|
|||||||
"name": "Shopping Cart Settings"
|
"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"
|
"doctype": "DocPerm"
|
||||||
|
@ -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
|
@ -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"
|
||||||
|
}
|
||||||
|
]
|
Loading…
Reference in New Issue
Block a user