[fixed conflict]
This commit is contained in:
commit
44935e4608
@ -251,7 +251,7 @@ class DocType(SellingController):
|
||||
|
||||
# fetch charges
|
||||
if self.doc.charge and not len(self.doclist.get({"parentfield": "other_charges"})):
|
||||
self.set_taxes()
|
||||
self.set_taxes("other_charges", "charge")
|
||||
|
||||
def get_customer_account(self):
|
||||
"""Get Account Head to which amount needs to be Debited based on Customer"""
|
||||
|
@ -16,12 +16,10 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes.utils import cint
|
||||
from webnotes.model.controller import DocListController
|
||||
|
||||
class DocType:
|
||||
def __init__(self, doc, doclist=[]):
|
||||
self.doc = doc
|
||||
self.doclist = doclist
|
||||
|
||||
class DocType(DocListController):
|
||||
def get_rate(self, arg):
|
||||
from webnotes.model.code import get_obj
|
||||
return get_obj('Sales Common').get_rate(arg)
|
||||
@ -31,3 +29,11 @@ class DocType:
|
||||
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))
|
||||
|
||||
# at least one territory
|
||||
self.validate_table_has_rows("valid_for_territories")
|
||||
|
||||
def on_update(self):
|
||||
cart_settings = webnotes.get_obj("Shopping Cart Settings")
|
||||
if cint(cart_settings.doc.enabled):
|
||||
cart_settings.validate_tax_masters()
|
@ -0,0 +1,146 @@
|
||||
test_records = [
|
||||
[
|
||||
{
|
||||
"doctype": "Sales Taxes and Charges Master",
|
||||
"title": "_Test Sales Taxes and Charges Master",
|
||||
"company": "_Test Company"
|
||||
},
|
||||
{
|
||||
"account_head": "_Test Account VAT - _TC",
|
||||
"charge_type": "On Net Total",
|
||||
"description": "VAT",
|
||||
"doctype": "Sales Taxes and Charges",
|
||||
"parentfield": "other_charges",
|
||||
"rate": 6,
|
||||
},
|
||||
{
|
||||
"account_head": "_Test Account Service Tax - _TC",
|
||||
"charge_type": "On Net Total",
|
||||
"description": "Service Tax",
|
||||
"doctype": "Sales Taxes and Charges",
|
||||
"parentfield": "other_charges",
|
||||
"rate": 6.36,
|
||||
},
|
||||
{
|
||||
"doctype": "For Territory",
|
||||
"parentfield": "valid_for_territories",
|
||||
"territory": "All Territories"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"doctype": "Sales Taxes and Charges Master",
|
||||
"title": "_Test India Tax Master",
|
||||
"company": "_Test Company"
|
||||
},
|
||||
{
|
||||
"doctype": "Sales Taxes and Charges",
|
||||
"parentfield": "other_charges",
|
||||
"charge_type": "Actual",
|
||||
"account_head": "_Test Account Shipping Charges - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"description": "Shipping Charges",
|
||||
"rate": 100
|
||||
},
|
||||
{
|
||||
"doctype": "Sales Taxes and Charges",
|
||||
"parentfield": "other_charges",
|
||||
"charge_type": "On Net Total",
|
||||
"account_head": "_Test Account Customs Duty - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"description": "Customs Duty",
|
||||
"rate": 10
|
||||
},
|
||||
{
|
||||
"doctype": "Sales Taxes and Charges",
|
||||
"parentfield": "other_charges",
|
||||
"charge_type": "On Net Total",
|
||||
"account_head": "_Test Account Excise Duty - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"description": "Excise Duty",
|
||||
"rate": 12
|
||||
},
|
||||
{
|
||||
"doctype": "Sales Taxes and Charges",
|
||||
"parentfield": "other_charges",
|
||||
"charge_type": "On Previous Row Amount",
|
||||
"account_head": "_Test Account Education Cess - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"description": "Education Cess",
|
||||
"rate": 2,
|
||||
"row_id": 3
|
||||
},
|
||||
{
|
||||
"doctype": "Sales Taxes and Charges",
|
||||
"parentfield": "other_charges",
|
||||
"charge_type": "On Previous Row Amount",
|
||||
"account_head": "_Test Account S&H Education Cess - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"description": "S&H Education Cess",
|
||||
"rate": 1,
|
||||
"row_id": 3
|
||||
},
|
||||
{
|
||||
"doctype": "Sales Taxes and Charges",
|
||||
"parentfield": "other_charges",
|
||||
"charge_type": "On Previous Row Total",
|
||||
"account_head": "_Test Account CST - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"description": "CST",
|
||||
"rate": 2,
|
||||
"row_id": 5
|
||||
},
|
||||
{
|
||||
"doctype": "Sales Taxes and Charges",
|
||||
"parentfield": "other_charges",
|
||||
"charge_type": "On Net Total",
|
||||
"account_head": "_Test Account VAT - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"description": "VAT",
|
||||
"rate": 12.5
|
||||
},
|
||||
{
|
||||
"doctype": "Sales Taxes and Charges",
|
||||
"parentfield": "other_charges",
|
||||
"charge_type": "On Previous Row Total",
|
||||
"account_head": "_Test Account Discount - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"description": "Discount",
|
||||
"rate": -10,
|
||||
"row_id": 7
|
||||
},
|
||||
{
|
||||
"doctype": "For Territory",
|
||||
"parentfield": "valid_for_territories",
|
||||
"territory": "_Test Territory India"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"doctype": "Sales Taxes and Charges Master",
|
||||
"title": "_Test Sales Taxes and Charges Master 2",
|
||||
"company": "_Test Company"
|
||||
},
|
||||
{
|
||||
"account_head": "_Test Account VAT - _TC",
|
||||
"charge_type": "On Net Total",
|
||||
"description": "VAT",
|
||||
"doctype": "Sales Taxes and Charges",
|
||||
"parentfield": "other_charges",
|
||||
"rate": 12,
|
||||
},
|
||||
{
|
||||
"account_head": "_Test Account Service Tax - _TC",
|
||||
"charge_type": "On Net Total",
|
||||
"description": "Service Tax",
|
||||
"doctype": "Sales Taxes and Charges",
|
||||
"parentfield": "other_charges",
|
||||
"rate": 4,
|
||||
},
|
||||
{
|
||||
"doctype": "For Territory",
|
||||
"parentfield": "valid_for_territories",
|
||||
"territory": "All Territories"
|
||||
}
|
||||
],
|
||||
]
|
@ -16,6 +16,7 @@ class DocType(DocListController):
|
||||
self.doc, self.doclist = d, dl
|
||||
|
||||
def validate(self):
|
||||
self.validate_value("calculate_based_on", "in", ["Net Total", "Net Weight"])
|
||||
self.shipping_rule_conditions = self.doclist.get({"parentfield": "shipping_rule_conditions"})
|
||||
self.validate_from_to_values()
|
||||
self.sort_shipping_rule_conditions()
|
||||
@ -57,7 +58,7 @@ class DocType(DocListController):
|
||||
then condition y can only be like 50 to 99 or 301 to 400
|
||||
hence, non-overlapping condition = (x1 <= x2 < y1 <= y2) or (y1 <= y2 < x1 <= x2)
|
||||
"""
|
||||
separate = (x1 <= x2 < y1 <= y2) or (y1 <= y2 < x1 <= x2)
|
||||
separate = (x1 <= x2 <= y1 <= y2) or (y1 <= y2 <= x1 <= x2)
|
||||
return (not separate)
|
||||
|
||||
overlaps = []
|
||||
|
@ -2,11 +2,12 @@
|
||||
{
|
||||
"creation": "2013-06-25 11:48:03",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-06-25 12:15:21",
|
||||
"modified": "2013-07-04 16:28:42",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
{
|
||||
"autoname": "Prompt",
|
||||
"description": "Specify conditions to calculate shipping amount",
|
||||
"doctype": "DocType",
|
||||
"module": "Accounts",
|
||||
@ -37,7 +38,7 @@
|
||||
{
|
||||
"description": "example: Next Day Shipping",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "shipping_rule_label",
|
||||
"fieldname": "label",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Shipping Rule Label",
|
||||
@ -49,14 +50,16 @@
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "Amount",
|
||||
"default": "Net Total",
|
||||
"doctype": "DocField",
|
||||
"fieldname": "calculate_based_on",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Calculate Based On",
|
||||
"options": "Amount\nNet Weight",
|
||||
"reqd": 1
|
||||
"options": "Net Total\nNet Weight",
|
||||
"read_only": 1,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
|
@ -32,7 +32,7 @@ test_records = [
|
||||
[
|
||||
{
|
||||
"doctype": "Shipping Rule",
|
||||
"calculate_based_on": "Amount",
|
||||
"calculate_based_on": "Net Total",
|
||||
"company": "_Test Company",
|
||||
"account": "_Test Account Shipping Charges - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC"
|
||||
|
@ -106,6 +106,11 @@ wn.module_page["Accounts"] = [
|
||||
"doctype":"Shipping Rule",
|
||||
"description": wn._("Rules to calculate shipping amount for a sale")
|
||||
},
|
||||
{
|
||||
"label": wn._("Currency Exchange"),
|
||||
"doctype":"Currency Exchange",
|
||||
"description": wn._("Manage exchange rates for currency conversion")
|
||||
},
|
||||
{
|
||||
"label": wn._("Point-of-Sale Setting"),
|
||||
"doctype":"POS Setting",
|
||||
|
@ -361,7 +361,7 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
||||
|
||||
var setup_field_label_map = function(fields_list, currency) {
|
||||
$.each(fields_list, function(i, fname) {
|
||||
var docfield = wn.meta.get_docfield(me.frm.doc.doctype, fname);
|
||||
var docfield = wn.meta.docfield_map[me.frm.doc.doctype][fname];
|
||||
if(docfield) {
|
||||
var label = wn._(docfield.label || "").replace(/\([^\)]*\)/g, "");
|
||||
field_label_map[fname] = label.trim() + " (" + currency + ")";
|
||||
@ -407,7 +407,7 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
||||
var setup_field_label_map = function(fields_list, currency, parentfield) {
|
||||
var grid_doctype = me.frm.fields_dict[parentfield].grid.doctype;
|
||||
$.each(fields_list, function(i, fname) {
|
||||
var docfield = wn.meta.get_docfield(grid_doctype, fname);
|
||||
var docfield = wn.meta.docfield_map[grid_doctype][fname];
|
||||
if(docfield) {
|
||||
var label = wn._(docfield.label || "").replace(/\([^\)]*\)/g, "");
|
||||
field_label_map[grid_doctype + "-" + fname] =
|
||||
|
@ -31,6 +31,7 @@ class TestPurchaseOrder(unittest.TestCase):
|
||||
from controllers.buying_controller import WrongWarehouseCompany
|
||||
po = webnotes.bean(copy=test_records[0])
|
||||
po.doc.company = "_Test Company 1"
|
||||
po.doc.conversion_rate = 0.0167
|
||||
self.assertRaises(WrongWarehouseCompany, po.insert)
|
||||
|
||||
|
||||
|
@ -55,7 +55,11 @@ class AccountsController(TransactionBase):
|
||||
|
||||
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)
|
||||
company_currency = get_company_currency(self.doc.company)
|
||||
if self.doc.price_list_currency == company_currency:
|
||||
self.doc.plc_conversion_rate = 1.0
|
||||
else:
|
||||
exchange = self.doc.price_list_currency + "-" + company_currency
|
||||
self.doc.plc_conversion_rate = flt(webnotes.conn.get_value("Currency Exchange",
|
||||
exchange, "exchange_rate"))
|
||||
|
||||
@ -71,22 +75,32 @@ class AccountsController(TransactionBase):
|
||||
ret = get_item_details(args)
|
||||
for fieldname, value in ret.items():
|
||||
if self.meta.get_field(fieldname, parentfield=self.fname) and \
|
||||
item.fields.get(fieldname) is None:
|
||||
item.fields.get(fieldname) is None and value is not None:
|
||||
item.fields[fieldname] = value
|
||||
|
||||
def set_taxes(self, tax_doctype, tax_parentfield, tax_master_field):
|
||||
def set_taxes(self, tax_parentfield, tax_master_field):
|
||||
if not self.meta.get_field(tax_parentfield):
|
||||
return
|
||||
|
||||
tax_master_doctype = self.meta.get_field(tax_master_field).options
|
||||
|
||||
if not self.doclist.get({"parentfield": tax_parentfield}):
|
||||
if not self.doc.fields.get(tax_master_field):
|
||||
# get the default tax master
|
||||
self.doc.fields[tax_master_field] = \
|
||||
webnotes.conn.get_value(tax_doctype + " Master", {"is_default": 1})
|
||||
webnotes.conn.get_value(tax_master_doctype, {"is_default": 1})
|
||||
|
||||
self.append_taxes_from_master(tax_parentfield, tax_master_field, tax_master_doctype)
|
||||
|
||||
def append_taxes_from_master(self, tax_parentfield, tax_master_field, tax_master_doctype=None):
|
||||
if self.doc.fields.get(tax_master_field):
|
||||
if not tax_master_doctype:
|
||||
tax_master_doctype = self.meta.get_field(tax_master_field).options
|
||||
|
||||
tax_doctype = self.meta.get_field(tax_parentfield).options
|
||||
|
||||
from webnotes.model import default_fields
|
||||
tax_master = webnotes.bean(tax_doctype + " Master", self.doc.fields.get(tax_master_field))
|
||||
tax_master = webnotes.bean(tax_master_doctype, self.doc.fields.get(tax_master_field))
|
||||
|
||||
for i, tax in enumerate(tax_master.doclist.get({"parentfield": tax_parentfield})):
|
||||
for fieldname in default_fields:
|
||||
|
@ -30,7 +30,7 @@ class BuyingController(StockController):
|
||||
def onload_post_render(self):
|
||||
# contact, address, item details
|
||||
self.set_missing_values()
|
||||
self.set_taxes("Purchase Taxes and Charges", "purchase_tax_details", "purchase_other_charges")
|
||||
self.set_taxes("purchase_tax_details", "purchase_other_charges")
|
||||
|
||||
def validate(self):
|
||||
super(BuyingController, self).validate()
|
||||
@ -55,7 +55,7 @@ class BuyingController(StockController):
|
||||
|
||||
def get_purchase_tax_details(self):
|
||||
self.doclist = self.doc.clear_table(self.doclist, "purchase_tax_details")
|
||||
self.set_taxes("Purchase Taxes and Charges", "purchase_tax_details", "purchase_other_charges")
|
||||
self.set_taxes("purchase_tax_details", "purchase_other_charges")
|
||||
|
||||
def validate_warehouse_belongs_to_company(self):
|
||||
for warehouse, company in webnotes.conn.get_values("Warehouse",
|
||||
|
@ -28,48 +28,61 @@ class SellingController(StockController):
|
||||
# contact, address, item details and pos details (if applicable)
|
||||
self.set_missing_values()
|
||||
|
||||
self.set_taxes("Sales Taxes and Charges", "other_charges", "charge")
|
||||
self.set_taxes("other_charges", "charge")
|
||||
|
||||
def set_missing_values(self, for_validate=False):
|
||||
super(SellingController, self).set_missing_values(for_validate)
|
||||
|
||||
self.set_price_list_currency("Selling")
|
||||
|
||||
# set contact and address details for customer, if they are not mentioned
|
||||
self.set_missing_lead_customer_details()
|
||||
|
||||
self.set_missing_item_details(get_item_details)
|
||||
self.set_price_list_and_item_details()
|
||||
|
||||
def set_missing_lead_customer_details(self):
|
||||
if self.doc.customer:
|
||||
if not (self.doc.contact_person and self.doc.customer_address):
|
||||
for fieldname, val in self.get_default_address_and_contact("customer").items():
|
||||
if not (self.doc.contact_person and self.doc.customer_address and self.doc.customer_name):
|
||||
for fieldname, val in self.get_customer_defaults().items():
|
||||
if not self.doc.fields.get(fieldname) and self.meta.get_field(fieldname):
|
||||
self.doc.fields[fieldname] = val
|
||||
|
||||
customer_fetch = webnotes.conn.get_value("Customer", self.doc.customer,
|
||||
['customer_name', 'customer_group', 'territory'], as_dict=True)
|
||||
for fieldname in ['customer_name', 'customer_group', 'territory']:
|
||||
if not self.doc.fields.get(fieldname):
|
||||
self.doc.fields[fieldname] = customer_fetch[fieldname]
|
||||
|
||||
elif self.doc.lead:
|
||||
lead_fetch = webnotes.conn.get_value("Lead", self.doc.lead,
|
||||
['company_name', 'lead_name', 'territory'], as_dict=True)
|
||||
if not self.doc.customer_name:
|
||||
self.doc.customer_name = lead_fetch.company_name or lead_fetch.lead_name
|
||||
if not self.doc.territory:
|
||||
self.doc.territory = lead_fetch.territory
|
||||
if not (self.doc.customer_address and self.doc.customer_name and \
|
||||
self.doc.contact_display):
|
||||
for fieldname, val in self.get_lead_defaults().items():
|
||||
if not self.doc.fields.get(fieldname) and self.meta.get_field(fieldname):
|
||||
self.doc.fields[fieldname] = val
|
||||
|
||||
def set_price_list_and_item_details(self):
|
||||
self.set_price_list_currency("Selling")
|
||||
self.set_missing_item_details(get_item_details)
|
||||
|
||||
def get_other_charges(self):
|
||||
self.doclist = self.doc.clear_table(self.doclist, "other_charges")
|
||||
self.set_taxes("Sales Taxes and Charges", "other_charges", "charge")
|
||||
self.set_taxes("other_charges", "charge")
|
||||
|
||||
def set_customer_defaults(self):
|
||||
self.get_default_customer_address()
|
||||
def apply_shipping_rule(self):
|
||||
if self.doc.shipping_rule:
|
||||
shipping_rule = webnotes.bean("Shipping Rule", self.doc.shipping_rule)
|
||||
value = self.doc.net_total
|
||||
|
||||
if self.meta.get_field("shipping_address"):
|
||||
self.doc.fields.update(self.get_shipping_address(self.doc.customer))
|
||||
# TODO
|
||||
# shipping rule calculation based on item's net weight
|
||||
|
||||
shipping_amount = 0.0
|
||||
for condition in shipping_rule.doclist.get({"parentfield": "shipping_rule_conditions"}):
|
||||
if not condition.to_value or (flt(condition.from_value) <= value <= flt(condition.to_value)):
|
||||
shipping_amount = condition.shipping_amount
|
||||
break
|
||||
|
||||
self.doclist.append({
|
||||
"doctype": "Sales Taxes and Charges",
|
||||
"parentfield": "other_charges",
|
||||
"charge_type": "Actual",
|
||||
"account_head": shipping_rule.doc.account,
|
||||
"cost_center": shipping_rule.doc.cost_center,
|
||||
"description": shipping_rule.doc.label,
|
||||
"rate": shipping_amount
|
||||
})
|
||||
|
||||
def set_total_in_words(self):
|
||||
from webnotes.utils import money_in_words
|
||||
|
@ -84,6 +84,8 @@ $.extend(erpnext.complete_setup, {
|
||||
wn.container.wntoolbar.set_user_name();
|
||||
|
||||
setTimeout(function() { window.location.reload(); }, 3000);
|
||||
} else {
|
||||
$(this).done_working();
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -55,6 +55,15 @@ wn.call = function(opts) {
|
||||
$(opts.btn).addClass("btn-danger");
|
||||
setTimeout(function() { $(opts.btn).removeClass("btn-danger"); }, 1000);
|
||||
}
|
||||
try {
|
||||
var err = JSON.parse(data.exc);
|
||||
if($.isArray(err)) {
|
||||
err = err.join("\n");
|
||||
}
|
||||
console.error ? console.error(err) : console.log(err);
|
||||
} catch(e) {
|
||||
console.log(data.exc);
|
||||
}
|
||||
} else{
|
||||
if(opts.btn) {
|
||||
$(opts.btn).addClass("btn-success");
|
||||
@ -66,6 +75,9 @@ wn.call = function(opts) {
|
||||
}
|
||||
if(opts.callback)
|
||||
opts.callback(data);
|
||||
},
|
||||
error: function(response) {
|
||||
console.error ? console.error(response) : console.log(response);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -17,6 +17,30 @@
|
||||
cur_frm.cscript.tname = "Installation Note Item";
|
||||
cur_frm.cscript.fname = "installed_item_details";
|
||||
|
||||
wn.provide("erpnext.selling");
|
||||
// TODO commonify this code
|
||||
erpnext.selling.InstallationNote = wn.ui.form.Controller.extend({
|
||||
customer: function() {
|
||||
var me = this;
|
||||
if(this.frm.doc.customer) {
|
||||
this.frm.call({
|
||||
doc: this.frm.doc,
|
||||
method: "set_customer_defaults",
|
||||
callback: function(r) {
|
||||
if(!r.exc) me.frm.refresh_fields();
|
||||
}
|
||||
});
|
||||
|
||||
// TODO shift this to depends_on
|
||||
unhide_field(['customer_address', 'contact_person', 'customer_name',
|
||||
'address_display', 'contact_display', 'contact_mobile', 'contact_email',
|
||||
'territory', 'customer_group']);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$.extend(cur_frm.cscript, new erpnext.selling.InstallationNote({frm: cur_frm}));
|
||||
|
||||
cur_frm.cscript.onload = function(doc, dt, dn) {
|
||||
if(!doc.status) set_multiple(dt,dn,{status:'Draft'});
|
||||
if(doc.__islocal){
|
||||
@ -50,17 +74,6 @@ cur_frm.cscript.get_items = function(doc, dt, dn) {
|
||||
get_server_fields('pull_delivery_note_details','','',doc, dt, dn,1,callback);
|
||||
}
|
||||
|
||||
//customer
|
||||
cur_frm.cscript.customer = function(doc,dt,dn) {
|
||||
var callback = function(r,rt) {
|
||||
var doc = locals[cur_frm.doctype][cur_frm.docname];
|
||||
cur_frm.refresh();
|
||||
}
|
||||
|
||||
if(doc.customer) $c_obj(make_doclist(doc.doctype, doc.name), 'get_default_customer_address', '', callback);
|
||||
if(doc.customer) unhide_field(['customer_address','contact_person','customer_name','address_display','contact_display','contact_mobile','contact_email','territory','customer_group']);
|
||||
}
|
||||
|
||||
cur_frm.cscript.customer_address = cur_frm.cscript.contact_person = function(doc,dt,dn) {
|
||||
if(doc.customer) get_server_fields('get_customer_address', JSON.stringify({customer: doc.customer, address: doc.customer_address, contact: doc.contact_person}),'', doc, dt, dn, 1);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2013-04-10 11:45:37",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-07-03 10:22:31",
|
||||
"modified": "2013-07-03 10:24:00",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@ -314,13 +314,6 @@
|
||||
"oldfieldtype": "Select",
|
||||
"options": "\nProduct Enquiry\nRequest for Information\nSuggestions\nOther"
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "default_price_list",
|
||||
"fieldtype": "Link",
|
||||
"label": "Default Price List",
|
||||
"options": "Price List"
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "fiscal_year",
|
||||
|
@ -16,6 +16,30 @@
|
||||
|
||||
wn.require('app/utilities/doctype/sms_control/sms_control.js');
|
||||
|
||||
wn.provide("erpnext.selling");
|
||||
// TODO commonify this code
|
||||
erpnext.selling.Opportunity = wn.ui.form.Controller.extend({
|
||||
customer: function() {
|
||||
var me = this;
|
||||
if(this.frm.doc.customer) {
|
||||
this.frm.call({
|
||||
doc: this.frm.doc,
|
||||
method: "set_customer_defaults",
|
||||
callback: function(r) {
|
||||
if(!r.exc) me.frm.refresh_fields();
|
||||
}
|
||||
});
|
||||
|
||||
// TODO shift this to depends_on
|
||||
unhide_field(['customer_address', 'contact_person', 'customer_name',
|
||||
'address_display', 'contact_display', 'contact_mobile', 'contact_email',
|
||||
'territory', 'customer_group']);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$.extend(cur_frm.cscript, new erpnext.selling.Opportunity({frm: cur_frm}));
|
||||
|
||||
cur_frm.cscript.refresh = function(doc, cdt, cdn){
|
||||
erpnext.hide_naming_series();
|
||||
|
||||
@ -117,28 +141,6 @@ cur_frm.cscript.lead_cust_show = function(doc,cdt,cdn){
|
||||
}
|
||||
}
|
||||
|
||||
// customer
|
||||
cur_frm.cscript.customer = function(doc,dt,dn) {
|
||||
cur_frm.toggle_display("contact_info", doc.customer || doc.lead);
|
||||
|
||||
if(doc.customer) {
|
||||
cur_frm.call({
|
||||
doc: cur_frm.doc,
|
||||
method: "get_default_customer_address",
|
||||
args: { customer: doc.customer },
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
cur_frm.refresh();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
unhide_field(["customer_name", "customer_address", "contact_person",
|
||||
"address_display", "contact_display", "contact_mobile", "contact_email",
|
||||
"territory", "customer_group"]);
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.cscript.customer_address = cur_frm.cscript.contact_person = function(doc,dt,dn) {
|
||||
if(doc.customer) get_server_fields('get_customer_address', JSON.stringify({customer: doc.customer, address: doc.customer_address, contact: doc.contact_person}),'', doc, dt, dn, 1);
|
||||
}
|
||||
@ -167,7 +169,15 @@ cur_frm.cscript.lead = function(doc, cdt, cdn) {
|
||||
cur_frm.toggle_display("contact_info", doc.customer || doc.lead);
|
||||
|
||||
if(doc.lead) {
|
||||
get_server_fields('get_lead_details', doc.lead,'', doc, cdt, cdn, 1);
|
||||
cur_frm.call({
|
||||
doc: cur_frm.doc,
|
||||
method: "set_lead_defaults",
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
cur_frm.refresh_fields();
|
||||
}
|
||||
}
|
||||
});
|
||||
unhide_field(['customer_name', 'address_display','contact_mobile', 'contact_email',
|
||||
'territory']);
|
||||
}
|
||||
|
@ -24,9 +24,8 @@ from webnotes import msgprint
|
||||
sql = webnotes.conn.sql
|
||||
|
||||
from utilities.transaction_base import TransactionBase
|
||||
|
||||
class DocType(TransactionBase):
|
||||
def __init__(self,doc,doclist=[]):
|
||||
def __init__(self,doc,doclist):
|
||||
self.doc = doc
|
||||
self.doclist = doclist
|
||||
self.fname = 'enq_details'
|
||||
|
@ -99,7 +99,15 @@ cur_frm.fields_dict.lead.get_query = erpnext.utils.lead_query;
|
||||
|
||||
cur_frm.cscript.lead = function(doc, cdt, cdn) {
|
||||
if(doc.lead) {
|
||||
get_server_fields('get_lead_details', doc.lead,'', doc, cdt, cdn, 1);
|
||||
cur_frm.call({
|
||||
doc: cur_frm.doc,
|
||||
method: "set_lead_defaults",
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
cur_frm.refresh_fields();
|
||||
}
|
||||
}
|
||||
});
|
||||
unhide_field('territory');
|
||||
}
|
||||
}
|
||||
|
@ -26,10 +26,78 @@ wn.require("app/js/transaction.js");
|
||||
|
||||
erpnext.selling.SellingController = erpnext.TransactionController.extend({
|
||||
setup: function() {
|
||||
var me = this;
|
||||
|
||||
this.frm.add_fetch("sales_partner", "commission_rate", "commission_rate");
|
||||
|
||||
if(this.frm.fields_dict.shipping_address_name && this.frm.fields_dict.customer_address)
|
||||
this.frm.fields_dict.shipping_address_name.get_query = this.frm.fields_dict['customer_address'].get_query;
|
||||
if(this.frm.fields_dict.shipping_address_name && this.frm.fields_dict.customer_address) {
|
||||
this.frm.fields_dict.shipping_address_name.get_query =
|
||||
this.frm.fields_dict['customer_address'].get_query;
|
||||
}
|
||||
|
||||
this.frm.set_query("customer_address", function() {
|
||||
return 'SELECT name, address_line1, city FROM tabAddress \
|
||||
WHERE customer = "'+ me.frm.doc.customer +'" AND docstatus != 2 AND \
|
||||
%(key)s LIKE "%s" ORDER BY name ASC LIMIT 50';
|
||||
});
|
||||
|
||||
this.frm.set_query("contact_person", function() {
|
||||
return 'SELECT name, CONCAT(first_name," ",ifnull(last_name,"")) As FullName, \
|
||||
department, designation FROM tabContact WHERE customer = "'+ me.frm.doc.customer +
|
||||
'" AND docstatus != 2 AND %(key)s LIKE "%s" ORDER BY name ASC LIMIT 50';
|
||||
});
|
||||
|
||||
if(this.frm.fields_dict.charge) {
|
||||
this.frm.set_query("charge", function() {
|
||||
return 'SELECT DISTINCT `tabSales Taxes and Charges Master`.name FROM \
|
||||
`tabSales Taxes and Charges Master` \
|
||||
WHERE `tabSales Taxes and Charges Master`.company = "' + me.frm.doc.company +
|
||||
'" AND `tabSales Taxes and Charges Master`.company is not NULL \
|
||||
AND `tabSales Taxes and Charges Master`.docstatus != 2 \
|
||||
AND `tabSales Taxes and Charges Master`.%(key)s LIKE "%s" \
|
||||
ORDER BY `tabSales Taxes and Charges Master`.name LIMIT 50';
|
||||
});
|
||||
}
|
||||
|
||||
this.frm.fields_dict.customer.get_query = erpnext.utils.customer_query;
|
||||
|
||||
this.frm.fields_dict.lead && this.frm.set_query("lead", erpnext.utils.lead_query);
|
||||
|
||||
if(!this.fname) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.frm.fields_dict[this.fname].grid.get_field('item_code')) {
|
||||
this.frm.set_query("item_code", this.fname, function() {
|
||||
return me.frm.doc.order_type === "Maintenance" ?
|
||||
erpnext.queries.item({'ifnull(tabItem.is_service_item, "No")': "Yes"}) :
|
||||
erpnext.queries.item({'ifnull(tabItem.is_sales_item, "No")': "Yes"});
|
||||
});
|
||||
}
|
||||
|
||||
if(this.frm.fields_dict[this.fname].grid.get_field('batch_no')) {
|
||||
this.frm.set_query("batch_no", this.fname, function(doc, cdt, cdn) {
|
||||
var item = wn.model.get_doc(cdt, cdn);
|
||||
if(!item.item_code) {
|
||||
wn.throw("Please enter Item Code to get batch no");
|
||||
} else {
|
||||
if(item.warehouse) {
|
||||
return "select batch_no from `tabStock Ledger Entry` sle \
|
||||
where item_code = '" + item.item_code +
|
||||
"' and warehouse = '" + item.warehouse +
|
||||
"' and ifnull(is_cancelled, 'No') = 'No' and batch_no like '%s' \
|
||||
and exists(select * from `tabBatch` where \
|
||||
name = sle.batch_no and expiry_date >= '" + me.frm.doc.posting_date +
|
||||
"' and docstatus != 2) group by batch_no having sum(actual_qty) > 0 \
|
||||
order by batch_no desc limit 50";
|
||||
} else {
|
||||
return "SELECT name FROM tabBatch WHERE docstatus != 2 AND item = '" +
|
||||
item.item_code + "' and expiry_date >= '" + me.frm.doc.posting_date +
|
||||
"' AND name like '%s' ORDER BY name DESC LIMIT 50";
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
onload: function() {
|
||||
@ -403,7 +471,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
|
||||
|
||||
var setup_field_label_map = function(fields_list, currency) {
|
||||
$.each(fields_list, function(i, fname) {
|
||||
var docfield = wn.meta.get_docfield(me.frm.doc.doctype, fname);
|
||||
var docfield = wn.meta.docfield_map[me.frm.doc.doctype][fname];
|
||||
if(docfield) {
|
||||
var label = wn._(docfield.label || "").replace(/\([^\)]*\)/g, "");
|
||||
field_label_map[fname] = label.trim() + " (" + currency + ")";
|
||||
@ -448,7 +516,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
|
||||
var setup_field_label_map = function(fields_list, currency, parentfield) {
|
||||
var grid_doctype = me.frm.fields_dict[parentfield].grid.doctype;
|
||||
$.each(fields_list, function(i, fname) {
|
||||
var docfield = wn.meta.get_docfield(grid_doctype, fname);
|
||||
var docfield = wn.meta.docfield_map[grid_doctype][fname];
|
||||
if(docfield) {
|
||||
var label = wn._(docfield.label || "").replace(/\([^\)]*\)/g, "");
|
||||
field_label_map[grid_doctype + "-" + fname] =
|
||||
@ -508,15 +576,6 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
|
||||
}
|
||||
});
|
||||
|
||||
// to save previous state of cur_frm.cscript
|
||||
var prev_cscript = {};
|
||||
$.extend(prev_cscript, cur_frm.cscript);
|
||||
|
||||
cur_frm.cscript = new erpnext.selling.SellingController({frm: cur_frm});
|
||||
|
||||
// for backward compatibility: combine new and previous states
|
||||
$.extend(cur_frm.cscript, prev_cscript);
|
||||
|
||||
// Help for Sales BOM items
|
||||
var set_sales_bom_help = function(doc) {
|
||||
if(!cur_frm.fields_dict.packing_list) return;
|
||||
@ -540,61 +599,3 @@ var set_sales_bom_help = function(doc) {
|
||||
}
|
||||
refresh_field('sales_bom_help');
|
||||
}
|
||||
|
||||
cur_frm.fields_dict[cur_frm.cscript.fname].grid.get_field("item_code").get_query = function(doc, cdt, cdn) {
|
||||
if (doc.order_type == "Maintenance") {
|
||||
return erpnext.queries.item({
|
||||
'ifnull(tabItem.is_service_item, "No")': 'Yes'
|
||||
});
|
||||
} else {
|
||||
return erpnext.queries.item({
|
||||
'ifnull(tabItem.is_sales_item, "No")': 'Yes'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.fields_dict[cur_frm.cscript.fname].grid.get_field('batch_no').get_query =
|
||||
function(doc, cdt, cdn) {
|
||||
var d = locals[cdt][cdn];
|
||||
if(d.item_code) {
|
||||
if (d.warehouse) {
|
||||
return "select batch_no from `tabStock Ledger Entry` sle \
|
||||
where item_code = '" + d.item_code + "' and warehouse = '" + d.warehouse +
|
||||
"' and ifnull(is_cancelled, 'No') = 'No' and batch_no like '%s' \
|
||||
and exists(select * from `tabBatch` where \
|
||||
name = sle.batch_no and expiry_date >= '" + doc.posting_date +
|
||||
"' and docstatus != 2) group by batch_no having sum(actual_qty) > 0 \
|
||||
order by batch_no desc limit 50";
|
||||
} else {
|
||||
return "SELECT name FROM tabBatch WHERE docstatus != 2 AND item = '" +
|
||||
d.item_code + "' and expiry_date >= '" + doc.posting_date +
|
||||
"' AND name like '%s' ORDER BY name DESC LIMIT 50";
|
||||
}
|
||||
} else {
|
||||
msgprint("Please enter Item Code to get batch no");
|
||||
}
|
||||
}
|
||||
|
||||
cur_frm.fields_dict['customer_address'].get_query = function(doc, cdt, cdn) {
|
||||
return 'SELECT name, address_line1, city FROM tabAddress \
|
||||
WHERE customer = "'+ doc.customer +'" AND docstatus != 2 AND \
|
||||
%(key)s LIKE "%s" ORDER BY name ASC LIMIT 50';
|
||||
}
|
||||
|
||||
cur_frm.fields_dict['contact_person'].get_query = function(doc, cdt, cdn) {
|
||||
return 'SELECT name, CONCAT(first_name," ",ifnull(last_name,"")) As FullName, \
|
||||
department, designation FROM tabContact WHERE customer = "'+ doc.customer +
|
||||
'" AND docstatus != 2 AND %(key)s LIKE "%s" ORDER BY name ASC LIMIT 50';
|
||||
}
|
||||
|
||||
// ************* GET OTHER CHARGES BASED ON COMPANY *************
|
||||
cur_frm.fields_dict.charge.get_query = function(doc) {
|
||||
return 'SELECT DISTINCT `tabSales Taxes and Charges Master`.name FROM \
|
||||
`tabSales Taxes and Charges Master` WHERE `tabSales Taxes and Charges Master`.company = "'
|
||||
+doc.company+'" AND `tabSales Taxes and Charges Master`.company is not NULL \
|
||||
AND `tabSales Taxes and Charges Master`.docstatus != 2 \
|
||||
AND `tabSales Taxes and Charges Master`.%(key)s LIKE "%s" \
|
||||
ORDER BY `tabSales Taxes and Charges Master`.name LIMIT 50';
|
||||
}
|
||||
|
||||
cur_frm.fields_dict.customer.get_query = erpnext.utils.customer_query;
|
39
setup/doctype/currency_exchange/currency_exchange.js
Normal file
39
setup/doctype/currency_exchange/currency_exchange.js
Normal file
@ -0,0 +1,39 @@
|
||||
// ERPNext - web based ERP (http://erpnext.com)
|
||||
// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
$.extend(cur_frm.cscript, {
|
||||
refresh: function() {
|
||||
cur_frm.cscript.set_exchange_rate_label();
|
||||
},
|
||||
|
||||
from_currency: function() {
|
||||
cur_frm.cscript.set_exchange_rate_label();
|
||||
},
|
||||
|
||||
to_currency: function() {
|
||||
cur_frm.cscript.set_exchange_rate_label();
|
||||
},
|
||||
|
||||
set_exchange_rate_label: function() {
|
||||
if(cur_frm.doc.from_currency && cur_frm.doc.to_currency) {
|
||||
var default_label = wn._(wn.meta.docfield_map[cur_frm.doctype]["exchange_rate"].label);
|
||||
console.log(default_label +
|
||||
repl(" (1 %(from_currency)s = [?] %(to_currency)s)", cur_frm.doc));
|
||||
cur_frm.fields_dict.exchange_rate.set_label(default_label +
|
||||
repl(" (1 %(from_currency)s = [?] %(to_currency)s)", cur_frm.doc));
|
||||
}
|
||||
}
|
||||
});
|
@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2013-06-20 15:40:29",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-06-20 15:40:29",
|
||||
"modified": "2013-07-03 17:11:40",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@ -23,6 +23,16 @@
|
||||
"permlevel": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocPerm",
|
||||
"name": "__common__",
|
||||
"parent": "Currency Exchange",
|
||||
"parentfield": "permissions",
|
||||
"parenttype": "DocType",
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"report": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocType",
|
||||
"name": "Currency Exchange"
|
||||
@ -46,5 +56,24 @@
|
||||
"fieldname": "exchange_rate",
|
||||
"fieldtype": "Float",
|
||||
"label": "Exchange Rate"
|
||||
},
|
||||
{
|
||||
"cancel": 1,
|
||||
"create": 1,
|
||||
"doctype": "DocPerm",
|
||||
"role": "Accounts Manager",
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocPerm",
|
||||
"role": "Accounts User"
|
||||
},
|
||||
{
|
||||
"doctype": "DocPerm",
|
||||
"role": "Sales User"
|
||||
},
|
||||
{
|
||||
"doctype": "DocPerm",
|
||||
"role": "Purchase User"
|
||||
}
|
||||
]
|
14
setup/doctype/currency_exchange/test_currency_exchange.py
Normal file
14
setup/doctype/currency_exchange/test_currency_exchange.py
Normal file
@ -0,0 +1,14 @@
|
||||
test_records = [
|
||||
[{
|
||||
"doctype": "Currency Exchange",
|
||||
"from_currency": "USD",
|
||||
"to_currency": "INR",
|
||||
"exchange_rate": 1
|
||||
}],
|
||||
[{
|
||||
"doctype": "Currency Exchange",
|
||||
"from_currency": "USD",
|
||||
"to_currency": "EUR",
|
||||
"exchange_rate": 0.773
|
||||
}]
|
||||
]
|
@ -17,7 +17,7 @@
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
from webnotes import msgprint, _
|
||||
from webnotes.utils import comma_or
|
||||
from webnotes.utils import comma_or, cint
|
||||
from webnotes.model.controller import DocListController
|
||||
|
||||
class DocType(DocListController):
|
||||
@ -30,6 +30,14 @@ class DocType(DocListController):
|
||||
msgprint(_(self.meta.get_label("buying_or_selling")) + " " + _("must be one of") + " " +
|
||||
comma_or(["Buying", "Selling"]), raise_exception=True)
|
||||
|
||||
# at least one territory
|
||||
self.validate_table_has_rows("valid_for_territories")
|
||||
|
||||
def on_update(self):
|
||||
cart_settings = webnotes.get_obj("Shopping Cart Settings")
|
||||
if cint(cart_settings.doc.enabled):
|
||||
cart_settings.validate_price_lists()
|
||||
|
||||
def on_trash(self):
|
||||
webnotes.conn.sql("""delete from `tabItem Price` where price_list_name = %s""",
|
||||
self.doc.name)
|
@ -1,8 +1,59 @@
|
||||
test_records = [
|
||||
[{
|
||||
[
|
||||
{
|
||||
"doctype": "Price List",
|
||||
"price_list_name": "_Test Price List",
|
||||
"currency": "INR",
|
||||
"buying_or_selling": "Selling"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"doctype": "For Territory",
|
||||
"parentfield": "valid_for_territories",
|
||||
"territory": "All Territories"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"doctype": "Price List",
|
||||
"price_list_name": "_Test Price List 2",
|
||||
"currency": "INR",
|
||||
"buying_or_selling": "Selling"
|
||||
},
|
||||
{
|
||||
"doctype": "For Territory",
|
||||
"parentfield": "valid_for_territories",
|
||||
"territory": "_Test Territory Rest of the World"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"doctype": "Price List",
|
||||
"price_list_name": "_Test Price List India",
|
||||
"currency": "INR",
|
||||
"buying_or_selling": "Selling"
|
||||
},
|
||||
{
|
||||
"doctype": "For Territory",
|
||||
"parentfield": "valid_for_territories",
|
||||
"territory": "_Test Territory India"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"doctype": "Price List",
|
||||
"price_list_name": "_Test Price List Rest of the World",
|
||||
"currency": "USD",
|
||||
"buying_or_selling": "Selling"
|
||||
},
|
||||
{
|
||||
"doctype": "For Territory",
|
||||
"parentfield": "valid_for_territories",
|
||||
"territory": "_Test Territory Rest of the World"
|
||||
},
|
||||
{
|
||||
"doctype": "For Territory",
|
||||
"parentfield": "valid_for_territories",
|
||||
"territory": "_Test Territory United States"
|
||||
}
|
||||
],
|
||||
]
|
@ -87,18 +87,20 @@ class DocType:
|
||||
self.curr_fiscal_year = curr_fiscal_year
|
||||
|
||||
def create_price_lists(self, args):
|
||||
webnotes.bean({
|
||||
'doctype': 'Price List',
|
||||
'price_list_name': 'Standard Selling',
|
||||
"buying_or_selling": "Selling",
|
||||
for pl_type in ["Selling", "Buying"]:
|
||||
webnotes.bean([
|
||||
{
|
||||
"doctype": "Price List",
|
||||
"price_list_name": "Standard " + pl_type,
|
||||
"buying_or_selling": pl_type,
|
||||
"currency": args["currency"]
|
||||
}).insert(),
|
||||
webnotes.bean({
|
||||
'doctype': 'Price List',
|
||||
'price_list_name': 'Standard Buying',
|
||||
"buying_or_selling": "Buying",
|
||||
"currency": args["currency"]
|
||||
}).insert(),
|
||||
},
|
||||
{
|
||||
"doctype": "For Territory",
|
||||
"parentfield": "valid_for_territories",
|
||||
"territory": "All Territories"
|
||||
}
|
||||
]).insert()
|
||||
|
||||
def set_defaults(self, args):
|
||||
# enable default currency
|
||||
@ -207,15 +209,18 @@ class DocType:
|
||||
# ------------------------
|
||||
def get_fy_details(self, fy_start, last_year=False):
|
||||
st = {'1st Jan':'01-01','1st Apr':'04-01','1st Jul':'07-01', '1st Oct': '10-01'}
|
||||
curr_year = getdate(nowdate()).year
|
||||
if last_year:
|
||||
curr_year = curr_year - 1
|
||||
if cint(getdate(nowdate()).month) < cint((st[fy_start].split('-'))[0]):
|
||||
curr_year = getdate(nowdate()).year - 1
|
||||
else:
|
||||
curr_year = getdate(nowdate()).year
|
||||
|
||||
if last_year:
|
||||
curr_year = curr_year - 1
|
||||
|
||||
stdt = cstr(curr_year)+'-'+cstr(st[fy_start])
|
||||
|
||||
if(fy_start == '1st Jan'):
|
||||
fy = cstr(getdate(nowdate()).year)
|
||||
fy = cstr(curr_year)
|
||||
abbr = cstr(fy)[-2:]
|
||||
else:
|
||||
fy = cstr(curr_year) + '-' + cstr(curr_year+1)
|
||||
|
@ -4,5 +4,29 @@ test_records = [
|
||||
"territory_name": "_Test Territory",
|
||||
"parent_territory": "All Territories",
|
||||
"is_group": "No",
|
||||
}]
|
||||
}],
|
||||
[{
|
||||
"doctype": "Territory",
|
||||
"territory_name": "_Test Territory India",
|
||||
"parent_territory": "All Territories",
|
||||
"is_group": "Yes",
|
||||
}],
|
||||
[{
|
||||
"doctype": "Territory",
|
||||
"territory_name": "_Test Territory Maharashtra",
|
||||
"parent_territory": "_Test Territory India",
|
||||
"is_group": "No",
|
||||
}],
|
||||
[{
|
||||
"doctype": "Territory",
|
||||
"territory_name": "_Test Territory Rest of the World",
|
||||
"parent_territory": "All Territories",
|
||||
"is_group": "No",
|
||||
}],
|
||||
[{
|
||||
"doctype": "Territory",
|
||||
"territory_name": "_Test Territory United States",
|
||||
"parent_territory": "All Territories",
|
||||
"is_group": "No",
|
||||
}],
|
||||
]
|
@ -91,6 +91,8 @@ items = [
|
||||
},
|
||||
{ "doctype": "Sales Taxes and Charges Master" },
|
||||
{ "doctype": "Purchase Taxes and Charges Master" },
|
||||
{ "doctype": "Shipping Rule" },
|
||||
{ "doctype": "Currency Exchange" },
|
||||
{
|
||||
"type": "Section",
|
||||
"title": "Opening Accounts and Stock",
|
||||
|
@ -40,8 +40,8 @@ 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 and docstatus < 2""" % (doctype, "%s", "%s"), (lft, rgt))
|
||||
return result or None
|
||||
where lft<%s and rgt>%s order by lft desc""" % (doctype, "%s", "%s"), (lft, rgt))
|
||||
return result or []
|
||||
|
||||
@webnotes.whitelist()
|
||||
def get_price_list_currency(args):
|
||||
|
@ -48,9 +48,6 @@ class DocType(SellingController):
|
||||
'keyword': 'Delivered'
|
||||
}]
|
||||
|
||||
def set_customer_defaults(self):
|
||||
self.get_default_customer_shipping_address()
|
||||
|
||||
def validate_fiscal_year(self):
|
||||
get_obj('Sales Common').validate_fiscal_year(self.doc.fiscal_year,self.doc.posting_date,'Posting Date')
|
||||
|
||||
|
@ -14,6 +14,28 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
wn.provide("erpnext.support");
|
||||
// TODO commonify this code
|
||||
erpnext.support.CustomerIssue = wn.ui.form.Controller.extend({
|
||||
customer: function() {
|
||||
var me = this;
|
||||
if(this.frm.doc.customer) {
|
||||
this.frm.call({
|
||||
doc: this.frm.doc,
|
||||
method: "set_customer_defaults",
|
||||
callback: function(r) {
|
||||
if(!r.exc) me.frm.refresh_fields();
|
||||
}
|
||||
});
|
||||
|
||||
// TODO shift this to depends_on
|
||||
unhide_field(['customer_address', 'contact_person']);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$.extend(cur_frm.cscript, new erpnext.support.CustomerIssue({frm: cur_frm}));
|
||||
|
||||
cur_frm.cscript.onload = function(doc,cdt,cdn){
|
||||
if(!doc.status)
|
||||
set_multiple(dt,dn,{status:'Open'});
|
||||
@ -28,18 +50,6 @@ cur_frm.cscript.refresh = function(doc,ct,cdn){
|
||||
cur_frm.cscript['Make Maintenance Visit']);
|
||||
}
|
||||
|
||||
|
||||
//customer
|
||||
cur_frm.cscript.customer = function(doc,dt,dn) {
|
||||
var callback = function(r,rt) {
|
||||
var doc = locals[cur_frm.doctype][cur_frm.docname];
|
||||
cur_frm.refresh();
|
||||
}
|
||||
|
||||
if(doc.customer) $c_obj(make_doclist(doc.doctype, doc.name), 'get_default_customer_address', '', callback);
|
||||
if(doc.customer) unhide_field(['customer_address','contact_person']);
|
||||
}
|
||||
|
||||
cur_frm.cscript.customer_address = cur_frm.cscript.contact_person = function(doc,dt,dn) {
|
||||
if(doc.customer)
|
||||
get_server_fields('get_customer_address',
|
||||
|
@ -14,6 +14,31 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
wn.provide("erpnext.support");
|
||||
// TODO commonify this code
|
||||
erpnext.support.MaintenanceSchedule = wn.ui.form.Controller.extend({
|
||||
customer: function() {
|
||||
var me = this;
|
||||
if(this.frm.doc.customer) {
|
||||
this.frm.call({
|
||||
doc: this.frm.doc,
|
||||
method: "set_customer_defaults",
|
||||
callback: function(r) {
|
||||
if(!r.exc) me.frm.refresh_fields();
|
||||
}
|
||||
});
|
||||
|
||||
// TODO shift this to depends_on
|
||||
unhide_field(['customer_address', 'contact_person', 'customer_name',
|
||||
'address_display', 'contact_display', 'contact_mobile', 'contact_email',
|
||||
'territory', 'customer_group']);
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$.extend(cur_frm.cscript, new erpnext.support.MaintenanceSchedule({frm: cur_frm}));
|
||||
|
||||
cur_frm.cscript.onload = function(doc, dt, dn) {
|
||||
if(!doc.status) set_multiple(dt,dn,{status:'Draft'});
|
||||
|
||||
@ -23,18 +48,6 @@ cur_frm.cscript.onload = function(doc, dt, dn) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//customer
|
||||
cur_frm.cscript.customer = function(doc,dt,dn) {
|
||||
var callback = function(r,rt) {
|
||||
var doc = locals[cur_frm.doctype][cur_frm.docname];
|
||||
cur_frm.refresh();
|
||||
}
|
||||
|
||||
if(doc.customer) $c_obj(make_doclist(doc.doctype, doc.name), 'get_default_customer_address', '', callback);
|
||||
if(doc.customer) unhide_field(['customer_address','contact_person','customer_name','address_display','contact_display','contact_mobile','contact_email','territory','customer_group']);
|
||||
}
|
||||
|
||||
cur_frm.cscript.customer_address = cur_frm.cscript.contact_person = function(doc,dt,dn) {
|
||||
if(doc.customer) get_server_fields('get_customer_address', JSON.stringify({customer: doc.customer, address: doc.customer_address, contact: doc.contact_person}),'', doc, dt, dn, 1);
|
||||
}
|
||||
|
@ -14,6 +14,28 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
wn.provide("erpnext.support");
|
||||
// TODO commonify this code
|
||||
erpnext.support.MaintenanceVisit = wn.ui.form.Controller.extend({
|
||||
customer: function() {
|
||||
var me = this;
|
||||
if(this.frm.doc.customer) {
|
||||
this.frm.call({
|
||||
doc: this.frm.doc,
|
||||
method: "set_customer_defaults",
|
||||
callback: function(r) {
|
||||
if(!r.exc) me.frm.refresh_fields();
|
||||
}
|
||||
});
|
||||
|
||||
// TODO shift this to depends_on
|
||||
hide_contact_info(this.frm.doc);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$.extend(cur_frm.cscript, new erpnext.support.MaintenanceVisit({frm: cur_frm}));
|
||||
|
||||
cur_frm.cscript.onload = function(doc, dt, dn) {
|
||||
if(!doc.status) set_multiple(dt,dn,{status:'Draft'});
|
||||
if(doc.__islocal) set_multiple(dt,dn,{mntc_date:get_today()});
|
||||
@ -30,17 +52,6 @@ cur_frm.cscript.refresh = function(doc) {
|
||||
hide_contact_info(doc);
|
||||
}
|
||||
|
||||
//customer
|
||||
cur_frm.cscript.customer = function(doc,dt,dn) {
|
||||
var callback = function(r,rt) {
|
||||
var doc = locals[cur_frm.doctype][cur_frm.docname];
|
||||
cur_frm.refresh();
|
||||
}
|
||||
|
||||
if(doc.customer) $c_obj(make_doclist(doc.doctype, doc.name), 'get_default_customer_address', '', callback);
|
||||
hide_contact_info(doc);
|
||||
}
|
||||
|
||||
cur_frm.cscript.customer_address = cur_frm.cscript.contact_person = function(doc,dt,dn) {
|
||||
if(doc.customer) get_server_fields('get_customer_address', JSON.stringify({customer: doc.customer, address: doc.customer_address, contact: doc.contact_person}),'', doc, dt, dn, 1);
|
||||
}
|
||||
|
@ -16,6 +16,25 @@
|
||||
|
||||
cur_frm.fields_dict.customer.get_query = erpnext.utils.customer_query;
|
||||
|
||||
wn.provide("erpnext.support");
|
||||
// TODO commonify this code
|
||||
erpnext.support.CustomerIssue = wn.ui.form.Controller.extend({
|
||||
customer: function() {
|
||||
var me = this;
|
||||
if(this.frm.doc.customer) {
|
||||
this.frm.call({
|
||||
doc: this.frm.doc,
|
||||
method: "set_customer_defaults",
|
||||
callback: function(r) {
|
||||
if(!r.exc) me.frm.refresh_fields();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$.extend(cur_frm.cscript, new erpnext.support.CustomerIssue({frm: cur_frm}));
|
||||
|
||||
$.extend(cur_frm.cscript, {
|
||||
onload: function(doc, dt, dn) {
|
||||
if(in_list(user_roles,'System Manager')) {
|
||||
@ -67,17 +86,6 @@ $.extend(cur_frm.cscript, {
|
||||
|
||||
},
|
||||
|
||||
customer: function(doc, dt, dn) {
|
||||
var callback = function(r,rt) {
|
||||
var doc = locals[cur_frm.doctype][cur_frm.docname];
|
||||
if(!r.exc) {
|
||||
cur_frm.refresh();
|
||||
}
|
||||
}
|
||||
if(doc.customer) $c_obj(make_doclist(doc.doctype, doc.name),
|
||||
'get_default_customer_address', '', callback);
|
||||
},
|
||||
|
||||
'Close Ticket': function() {
|
||||
cur_frm.cscript.set_status("Closed");
|
||||
},
|
||||
|
@ -23,45 +23,88 @@ from webnotes.model.doc import addchild
|
||||
from controllers.status_updater import StatusUpdater
|
||||
|
||||
class TransactionBase(StatusUpdater):
|
||||
def get_default_address_and_contact(self, party_type):
|
||||
def get_default_address_and_contact(self, party_field, party_name=None):
|
||||
"""get a dict of default field values of address and contact for a given party type
|
||||
party_type can be one of: customer, supplier"""
|
||||
ret = {}
|
||||
if not party_name:
|
||||
party_name = self.doc.fields.get(party_field)
|
||||
|
||||
# {customer: self.doc.fields.get("customer")}
|
||||
args = {party_type: self.doc.fields.get(party_type)}
|
||||
return get_default_address_and_contact(party_field, party_name,
|
||||
fetch_shipping_address=True if self.meta.get_field("shipping_address_name") else False)
|
||||
|
||||
address_text, address_name = self.get_address_text(**args)
|
||||
ret.update({
|
||||
# customer_address
|
||||
(party_type + "_address"): address_name,
|
||||
"address_display": address_text
|
||||
def get_customer_defaults(self):
|
||||
out = self.get_default_address_and_contact("customer")
|
||||
|
||||
customer = webnotes.doc("Customer", self.doc.customer)
|
||||
for f in ['customer_name', 'customer_group', 'territory']:
|
||||
out[f] = customer.fields.get(f)
|
||||
|
||||
# fields prepended with default in Customer doctype
|
||||
for f in ['sales_partner', 'commission_rate', 'currency', 'price_list']:
|
||||
out[f] = customer.fields.get("default_" + f)
|
||||
|
||||
return out
|
||||
|
||||
def set_customer_defaults(self):
|
||||
"""
|
||||
For a customer:
|
||||
1. Sets default address and contact
|
||||
2. Sets values like Territory, Customer Group, etc.
|
||||
3. Clears existing Sales Team and fetches the one mentioned in Customer
|
||||
"""
|
||||
customer_defaults = self.get_customer_defaults()
|
||||
|
||||
# hack! TODO - add shipping_address_field in Delivery Note
|
||||
if self.doc.doctype == "Delivery Note":
|
||||
customer_defaults["customer_address"] = customer_defaults["shipping_address_name"]
|
||||
customer_defaults["address_display"] = customer_defaults["shipping_address"]
|
||||
|
||||
customer_defaults["price_list"] = customer_defaults["price_list"] or \
|
||||
webnotes.conn.get_value("Customer Group", self.doc.customer_group, "default_price_list") or \
|
||||
self.doc.price_list
|
||||
|
||||
self.doc.fields.update(customer_defaults)
|
||||
|
||||
if self.meta.get_field("sales_team"):
|
||||
self.set_sales_team_for_customer()
|
||||
|
||||
def set_sales_team_for_customer(self):
|
||||
from webnotes.model import default_fields
|
||||
|
||||
# clear table
|
||||
self.doclist = self.doc.clear_table(self.doclist, "sales_team")
|
||||
|
||||
sales_team = webnotes.conn.sql("""select * from `tabSales Team`
|
||||
where parenttype="Customer" and parent=%s""", self.doc.customer, as_dict=True)
|
||||
for i, sales_person in enumerate(sales_team):
|
||||
# remove default fields
|
||||
for fieldname in default_fields:
|
||||
if fieldname in sales_person:
|
||||
del sales_person[fieldname]
|
||||
|
||||
sales_person.update({
|
||||
"doctype": "Sales Team",
|
||||
"parentfield": "sales_team",
|
||||
"idx": i+1
|
||||
})
|
||||
ret.update(self.get_contact_text(**args))
|
||||
return ret
|
||||
|
||||
# Get Customer Default Primary Address - first load
|
||||
def get_default_customer_address(self, args=''):
|
||||
address_text, address_name = self.get_address_text(customer=self.doc.customer)
|
||||
self.doc.customer_address = address_name or ''
|
||||
self.doc.address_display = address_text or ''
|
||||
self.doc.fields.update(self.get_contact_text(customer=self.doc.customer))
|
||||
# add child
|
||||
self.doclist.append(sales_person)
|
||||
|
||||
if args != 'onload':
|
||||
self.get_customer_details(self.doc.customer)
|
||||
self.get_sales_person(self.doc.customer)
|
||||
def get_lead_defaults(self):
|
||||
out = self.get_default_address_and_contact("lead")
|
||||
|
||||
# Get Customer Default Shipping Address - first load
|
||||
# -----------------------
|
||||
def get_default_customer_shipping_address(self, args=''):
|
||||
address_text, address_name = self.get_address_text(customer=self.doc.customer,is_shipping_address=1)
|
||||
self.doc.customer_address = address_name or ''
|
||||
self.doc.address_display = address_text or ''
|
||||
self.doc.fields.update(self.get_contact_text(customer=self.doc.customer))
|
||||
lead = webnotes.conn.get_value("Lead", self.doc.lead,
|
||||
["territory", "company_name", "lead_name"], as_dict=True) or {}
|
||||
|
||||
out["territory"] = lead.get("territory")
|
||||
out["customer_name"] = lead.get("company_name") or lead.get("lead_name")
|
||||
|
||||
return out
|
||||
|
||||
def set_lead_defaults(self):
|
||||
self.doc.fields.update(self.get_lead_defaults())
|
||||
|
||||
if self.doc.doctype != 'Quotation' and args != 'onload':
|
||||
self.get_customer_details(self.doc.customer)
|
||||
self.get_sales_person(self.doc.customer)
|
||||
|
||||
# Get Customer Address
|
||||
# -----------------------
|
||||
@ -92,12 +135,13 @@ class TransactionBase(StatusUpdater):
|
||||
else:
|
||||
details = webnotes.conn.sql("select name, address_line1, address_line2, city, country, pincode, state, phone, fax from `tabAddress` where %s and docstatus != 2 order by is_primary_address desc limit 1" % cond, as_dict = 1)
|
||||
|
||||
extract = lambda x: details and details[0] and details[0].get(x,'') or ''
|
||||
address_fields = [('','address_line1'),('\n','address_line2'),('\n','city'),('\n','state'),(' ','pincode'),('\n','country'),('\nPhone: ','phone'),('\nFax: ', 'fax')]
|
||||
address_display = ''.join([a[0]+extract(a[1]) for a in address_fields if extract(a[1])])
|
||||
if address_display.startswith('\n'): address_display = address_display[1:]
|
||||
address_display = ""
|
||||
|
||||
if details:
|
||||
address_display = get_address_display(details[0])
|
||||
|
||||
address_name = details and details[0]['name'] or ''
|
||||
|
||||
return address_display, address_name
|
||||
|
||||
# Get Contact Text
|
||||
@ -126,41 +170,13 @@ class TransactionBase(StatusUpdater):
|
||||
"contact_department": details and details[0]["department"] or "",
|
||||
}
|
||||
|
||||
def get_customer_details(self, name):
|
||||
"""
|
||||
Get customer details like name, group, territory
|
||||
and other such defaults
|
||||
"""
|
||||
customer_details = webnotes.conn.sql("""\
|
||||
select
|
||||
customer_name, customer_group, territory,
|
||||
default_sales_partner, default_commission_rate, default_currency,
|
||||
default_price_list
|
||||
from `tabCustomer`
|
||||
where name = %s and docstatus < 2""", name, as_dict=1)
|
||||
if customer_details:
|
||||
for f in ['customer_name', 'customer_group', 'territory']:
|
||||
self.doc.fields[f] = customer_details[0][f] or self.doc.fields.get(f)
|
||||
|
||||
# fields prepended with default in Customer doctype
|
||||
for f in ['sales_partner', 'commission_rate', 'currency']:
|
||||
self.doc.fields[f] = customer_details[0]["default_%s" % f] or self.doc.fields.get(f)
|
||||
|
||||
# optionally fetch default price list from Customer Group
|
||||
self.doc.price_list_name = (customer_details[0]['default_price_list']
|
||||
or webnotes.conn.get_value('Customer Group', self.doc.customer_group,
|
||||
'default_price_list')
|
||||
or self.doc.fields.get('price_list_name'))
|
||||
|
||||
# Get Customer Shipping Address
|
||||
# -----------------------
|
||||
# TODO deprecate this - used only in sales_order.js
|
||||
def get_shipping_address(self, name):
|
||||
details = webnotes.conn.sql("select name, address_line1, address_line2, city, country, pincode, state, phone from `tabAddress` where customer = '%s' and docstatus != 2 order by is_shipping_address desc, is_primary_address desc limit 1" %(name), as_dict = 1)
|
||||
|
||||
extract = lambda x: details and details[0] and details[0].get(x,'') or ''
|
||||
address_fields = [('','address_line1'),('\n','address_line2'),('\n','city'),(' ','pincode'),('\n','state'),('\n','country'),('\nPhone: ','phone')]
|
||||
address_display = ''.join([a[0]+extract(a[1]) for a in address_fields if extract(a[1])])
|
||||
if address_display.startswith('\n'): address_display = address_display[1:]
|
||||
address_display = ""
|
||||
if details:
|
||||
address_display = get_address_display(details[0])
|
||||
|
||||
ret = {
|
||||
'shipping_address_name' : details and details[0]['name'] or '',
|
||||
@ -168,36 +184,6 @@ class TransactionBase(StatusUpdater):
|
||||
}
|
||||
return ret
|
||||
|
||||
# Get Lead Details
|
||||
# -----------------------
|
||||
def get_lead_details(self, name):
|
||||
details = webnotes.conn.sql("""select name, lead_name, address_line1, address_line2, city, country, state, pincode
|
||||
from `tabAddress` where lead=%s""", name, as_dict=True)
|
||||
lead = webnotes.conn.get_value("Lead", name,
|
||||
["territory", "phone", "mobile_no", "email_id", "company_name", "lead_name"], as_dict=True) or {}
|
||||
|
||||
address_display = ""
|
||||
if details:
|
||||
details = details[0]
|
||||
for separator, fieldname in (('','address_line1'), ('\n','address_line2'), ('\n','city'),
|
||||
(' ','pincode'), ('\n','state'), ('\n','country'), ('\nPhone: ', 'phone')):
|
||||
if details.get(fieldname):
|
||||
address_display += separator + details.get(fieldname)
|
||||
|
||||
if address_display.startswith('\n'):
|
||||
address_display = address_display[1:]
|
||||
|
||||
ret = {
|
||||
'contact_display' : lead.get('lead_name'),
|
||||
'address_display' : address_display,
|
||||
'territory' : lead.get('territory'),
|
||||
'contact_mobile' : lead.get('mobile_no'),
|
||||
'contact_email' : lead.get('email_id'),
|
||||
'customer_name' : lead.get('company_name') or lead.get('lead_name')
|
||||
}
|
||||
return ret
|
||||
|
||||
|
||||
# Get Supplier Default Primary Address - first load
|
||||
# -----------------------
|
||||
def get_default_supplier_address(self, args):
|
||||
@ -313,19 +299,111 @@ class TransactionBase(StatusUpdater):
|
||||
|
||||
webnotes.bean(event_doclist).insert()
|
||||
|
||||
def get_default_address_and_contact(party_field, party_name, fetch_shipping_address=False):
|
||||
out = {}
|
||||
|
||||
# get addresses
|
||||
billing_address = get_address_dict(party_field, party_name)
|
||||
if billing_address:
|
||||
out[party_field + "_address"] = billing_address["name"]
|
||||
out["address_display"] = get_address_display(billing_address)
|
||||
else:
|
||||
out[party_field + "_address"] = out["address_display"] = None
|
||||
|
||||
if fetch_shipping_address:
|
||||
shipping_address = get_address_dict(party_field, party_name, is_shipping_address=True)
|
||||
if shipping_address:
|
||||
out["shipping_address_name"] = shipping_address["name"]
|
||||
out["shipping_address"] = get_address_display(shipping_address)
|
||||
else:
|
||||
out["shipping_address_name"] = out["shipping_address"] = None
|
||||
|
||||
# get contact
|
||||
if party_field == "lead":
|
||||
out["customer_address"] = out.get("lead_address")
|
||||
out.update(map_lead_fields(party_name))
|
||||
else:
|
||||
out.update(map_contact_fields(party_field, party_name))
|
||||
|
||||
return out
|
||||
|
||||
def get_address_dict(party_field, party_name, is_shipping_address=None):
|
||||
order_by = "is_shipping_address desc, is_primary_address desc, name asc" if \
|
||||
is_shipping_address else "is_primary_address desc, name asc"
|
||||
|
||||
address = webnotes.conn.sql("""select * from `tabAddress` where `%s`=%s order by %s
|
||||
limit 1""" % (party_field, "%s", order_by), party_name, as_dict=True,
|
||||
update={"doctype": "Address"})
|
||||
|
||||
return address[0] if address else None
|
||||
|
||||
def get_address_display(address_dict):
|
||||
def _prepare_for_display(a_dict, sequence):
|
||||
display = ""
|
||||
for separator, fieldname in sequence:
|
||||
if a_dict.get(fieldname):
|
||||
display += separator + a_dict.get(fieldname)
|
||||
|
||||
return display.strip()
|
||||
|
||||
meta = webnotes.get_doctype("Address")
|
||||
address_sequence = (("", "address_line1"), ("\n", "address_line2"), ("\n", "city"),
|
||||
("\n", "state"), ("\n" + meta.get_label("pincode") + ": ", "pincode"), ("\n", "country"),
|
||||
("\n" + meta.get_label("phone") + ": ", "phone"), ("\n" + meta.get_label("fax") + ": ", "fax"))
|
||||
|
||||
address_display = ""
|
||||
for separator, fieldname in address_sequence:
|
||||
if address_dict.get(fieldname):
|
||||
address_display += separator + address_dict.get(fieldname)
|
||||
return _prepare_for_display(address_dict, address_sequence)
|
||||
|
||||
return address_display
|
||||
def map_lead_fields(party_name):
|
||||
out = {}
|
||||
for fieldname in ["contact_display", "contact_email", "contact_mobile", "contact_phone"]:
|
||||
out[fieldname] = None
|
||||
|
||||
lead = webnotes.conn.sql("""select * from `tabLead` where name=%s""", party_name, as_dict=True)
|
||||
if lead:
|
||||
lead = lead[0]
|
||||
out.update({
|
||||
"contact_display": lead.get("lead_name"),
|
||||
"contact_email": lead.get("email_id"),
|
||||
"contact_mobile": lead.get("mobile_no"),
|
||||
"contact_phone": lead.get("phone"),
|
||||
})
|
||||
|
||||
return out
|
||||
|
||||
def map_contact_fields(party_field, party_name):
|
||||
out = {}
|
||||
for fieldname in ["contact_person", "contact_display", "contact_email",
|
||||
"contact_mobile", "contact_phone", "contact_designation", "contact_department"]:
|
||||
out[fieldname] = None
|
||||
|
||||
contact = webnotes.conn.sql("""select * from `tabContact` where `%s`=%s
|
||||
order by is_primary_contact desc, name asc limit 1""" % (party_field, "%s"),
|
||||
(party_name,), as_dict=True)
|
||||
if contact:
|
||||
contact = contact[0]
|
||||
out.update({
|
||||
"contact_person": contact.get("name"),
|
||||
"contact_display": " ".join(filter(None,
|
||||
[contact.get("first_name"), contact.get("last_name")])),
|
||||
"contact_email": contact.get("email_id"),
|
||||
"contact_mobile": contact.get("mobile_no"),
|
||||
"contact_phone": contact.get("phone"),
|
||||
"contact_designation": contact.get("designation"),
|
||||
"contact_department": contact.get("department")
|
||||
})
|
||||
|
||||
return out
|
||||
|
||||
def get_address_territory(address_doc):
|
||||
territory = None
|
||||
for fieldname in ("city", "state", "country"):
|
||||
value = address_doc.fields.get(fieldname)
|
||||
if value:
|
||||
territory = webnotes.conn.get_value("Territory", value.strip())
|
||||
if territory:
|
||||
break
|
||||
|
||||
return territory
|
||||
|
||||
def validate_conversion_rate(currency, conversion_rate, conversion_rate_label, company):
|
||||
"""common validation for currency and price list currency"""
|
||||
|
@ -10,6 +10,10 @@ a {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
|
@ -9,42 +9,70 @@ from webnotes.model.controller import DocListController
|
||||
class ShoppingCartSetupError(webnotes.ValidationError): pass
|
||||
|
||||
class DocType(DocListController):
|
||||
def __init__(self, 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_price_lists()
|
||||
self.validate_tax_masters()
|
||||
self.validate_exchange_rates_exist()
|
||||
|
||||
def validate_overlapping_territories(self, parentfield, fieldname):
|
||||
names = [doc.fields(fieldname) for doc in self.doclist.get({"parentfield": parentfield})]
|
||||
# for displaying message
|
||||
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)
|
||||
# specify atleast one entry in the table
|
||||
self.validate_table_has_rows(parentfield, raise_exception=ShoppingCartSetupError)
|
||||
|
||||
territory_name_map = self.get_territory_name_map(parentfield, fieldname)
|
||||
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
|
||||
return territory_name_map
|
||||
|
||||
def validate_price_lists(self):
|
||||
territory_name_map = self.validate_overlapping_territories("price_lists",
|
||||
"price_list")
|
||||
|
||||
# validate that a Shopping Cart Price List exists for the root territory
|
||||
# as a catch all!
|
||||
from setup.utils import get_root_of
|
||||
root_territory = get_root_of("Territory")
|
||||
|
||||
if root_territory not in territory_name_map.keys():
|
||||
msgprint(_("Please specify a Price List which is valid for Territory") +
|
||||
": " + root_territory, raise_exception=ShoppingCartSetupError)
|
||||
|
||||
def validate_tax_masters(self):
|
||||
self.validate_overlapping_territories("sales_taxes_and_charges_masters",
|
||||
"sales_taxes_and_charges_master")
|
||||
|
||||
def get_territory_name_map(self, parentfield, fieldname):
|
||||
territory_name_map = {}
|
||||
|
||||
# entries in table
|
||||
names = [doc.fields.get(fieldname) for doc in self.doclist.get({"parentfield": parentfield})]
|
||||
|
||||
if names:
|
||||
# for condition in territory check
|
||||
parenttype = self.meta.get_field(fieldname, parentfield=parentfield).options
|
||||
|
||||
# to validate territory overlap
|
||||
# make a map of territory: [list of names]
|
||||
# if list against each territory has more than one element, raise exception
|
||||
territory_name = webnotes.conn.sql("""select `territory`, `parent`
|
||||
from `tabFor Territory`
|
||||
where `parenttype`=%s and `parent` in (%s)""" %
|
||||
("%s", ", ".join(["%s"]*len(names))), tuple([parenttype] + names))
|
||||
|
||||
for territory, name in territory_name:
|
||||
territory_name_map.setdefault(territory, []).append(name)
|
||||
|
||||
if len(territory_name_map[territory]) > 1:
|
||||
territory_name_map[territory].sort(key=lambda val: names.index(val))
|
||||
|
||||
return territory_name_map
|
||||
|
||||
def validate_exchange_rates_exist(self):
|
||||
"""check if exchange rates exist for all Price List currencies (to company's currency)"""
|
||||
@ -54,7 +82,7 @@ class DocType(DocListController):
|
||||
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"})],
|
||||
[d.price_list for d in self.doclist.get({"parentfield": "price_lists"})],
|
||||
"currency")
|
||||
|
||||
expected_to_exist = [currency + "-" + company_currency
|
||||
@ -71,4 +99,40 @@ class DocType(DocListController):
|
||||
msgprint(_("Missing Currency Exchange Rates for" + ": " + comma_and(missing)),
|
||||
raise_exception=ShoppingCartSetupError)
|
||||
|
||||
def get_name_from_territory(self, territory, parentfield, fieldname):
|
||||
name = None
|
||||
territory_name_map = self.get_territory_name_map(parentfield, fieldname)
|
||||
|
||||
if territory_name_map.get(territory):
|
||||
name = territory_name_map.get(territory)
|
||||
else:
|
||||
territory_ancestry = self.get_territory_ancestry(territory)
|
||||
for ancestor in territory_ancestry:
|
||||
if territory_name_map.get(ancestor):
|
||||
name = territory_name_map.get(ancestor)
|
||||
break
|
||||
|
||||
return name
|
||||
|
||||
def get_price_list(self, billing_territory):
|
||||
price_list = self.get_name_from_territory(billing_territory, "price_lists", "price_list")
|
||||
return price_list and price_list[0] or None
|
||||
|
||||
def get_tax_master(self, billing_territory):
|
||||
tax_master = self.get_name_from_territory(billing_territory, "sales_taxes_and_charges_masters",
|
||||
"sales_taxes_and_charges_master")
|
||||
return tax_master and tax_master[0] or None
|
||||
|
||||
def get_shipping_rules(self, shipping_territory):
|
||||
return self.get_name_from_territory(shipping_territory, "shipping_rules", "shipping_rule")
|
||||
|
||||
def get_territory_ancestry(self, territory):
|
||||
from setup.utils import get_ancestors_of
|
||||
|
||||
if not hasattr(self, "_territory_ancestry"):
|
||||
self._territory_ancestry = {}
|
||||
|
||||
if not self._territory_ancestry.get(territory):
|
||||
self._territory_ancestry[territory] = get_ancestors_of("Territory", territory)
|
||||
|
||||
return self._territory_ancestry[territory]
|
@ -2,7 +2,7 @@
|
||||
{
|
||||
"creation": "2013-06-19 15:57:32",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-06-21 12:59:30",
|
||||
"modified": "2013-07-03 21:01:00",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
@ -53,7 +53,7 @@
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "shopping_cart_price_lists",
|
||||
"fieldname": "price_lists",
|
||||
"fieldtype": "Table",
|
||||
"label": "Shopping Cart Price Lists",
|
||||
"options": "Shopping Cart Price List",
|
||||
@ -61,12 +61,20 @@
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "shopping_cart_taxes_and_charges_masters",
|
||||
"fieldname": "sales_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": "shipping_rules",
|
||||
"fieldtype": "Table",
|
||||
"label": "Shopping Cart Shipping Rules",
|
||||
"options": "Shopping Cart Shipping Rule",
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "company",
|
||||
|
@ -0,0 +1,78 @@
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
import unittest
|
||||
from website.doctype.shopping_cart_settings.shopping_cart_settings import ShoppingCartSetupError
|
||||
|
||||
class TestShoppingCartSettings(unittest.TestCase):
|
||||
def setUp(self):
|
||||
webnotes.conn.sql("""delete from `tabSingles` where doctype="Shipping Cart Settings" """)
|
||||
webnotes.conn.sql("""delete from `tabShopping Cart Price List`""")
|
||||
webnotes.conn.sql("""delete from `tabShopping Cart Taxes and Charges Master`""")
|
||||
webnotes.conn.sql("""delete from `tabShopping Cart Shipping Rule`""")
|
||||
|
||||
def get_cart_settings(self):
|
||||
return webnotes.bean({"doctype": "Shopping Cart Settings",
|
||||
"company": "_Test Company"})
|
||||
|
||||
def test_price_list_territory_overlap(self):
|
||||
cart_settings = self.get_cart_settings()
|
||||
|
||||
def _add_price_list(price_list):
|
||||
cart_settings.doclist.append({
|
||||
"doctype": "Shopping Cart Price List",
|
||||
"parentfield": "price_lists",
|
||||
"price_list": price_list
|
||||
})
|
||||
|
||||
for price_list in ("_Test Price List Rest of the World", "_Test Price List India",
|
||||
"_Test Price List"):
|
||||
_add_price_list(price_list)
|
||||
|
||||
controller = cart_settings.make_controller()
|
||||
controller.validate_overlapping_territories("price_lists", "price_list")
|
||||
|
||||
_add_price_list("_Test Price List 2")
|
||||
|
||||
controller = cart_settings.make_controller()
|
||||
self.assertRaises(ShoppingCartSetupError, controller.validate_overlapping_territories,
|
||||
"price_lists", "price_list")
|
||||
|
||||
return cart_settings
|
||||
|
||||
def test_taxes_territory_overlap(self):
|
||||
cart_settings = self.get_cart_settings()
|
||||
|
||||
def _add_tax_master(tax_master):
|
||||
cart_settings.doclist.append({
|
||||
"doctype": "Shopping Cart Taxes and Charges Master",
|
||||
"parentfield": "sales_taxes_and_charges_masters",
|
||||
"sales_taxes_and_charges_master": tax_master
|
||||
})
|
||||
|
||||
for tax_master in ("_Test Sales Taxes and Charges Master", "_Test India Tax Master"):
|
||||
_add_tax_master(tax_master)
|
||||
|
||||
controller = cart_settings.make_controller()
|
||||
controller.validate_overlapping_territories("sales_taxes_and_charges_masters",
|
||||
"sales_taxes_and_charges_master")
|
||||
|
||||
_add_tax_master("_Test Sales Taxes and Charges Master 2")
|
||||
|
||||
controller = cart_settings.make_controller()
|
||||
self.assertRaises(ShoppingCartSetupError, controller.validate_overlapping_territories,
|
||||
"sales_taxes_and_charges_masters", "sales_taxes_and_charges_master")
|
||||
|
||||
def test_exchange_rate_exists(self):
|
||||
webnotes.conn.sql("""delete from `tabCurrency Exchange`""")
|
||||
|
||||
cart_settings = self.test_price_list_territory_overlap()
|
||||
controller = cart_settings.make_controller()
|
||||
self.assertRaises(ShoppingCartSetupError, controller.validate_exchange_rates_exist)
|
||||
|
||||
from setup.doctype.currency_exchange.test_currency_exchange import test_records as \
|
||||
currency_exchange_records
|
||||
webnotes.bean(currency_exchange_records[0]).insert()
|
||||
controller.validate_exchange_rates_exist()
|
||||
|
@ -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-07-03 13:15:34",
|
||||
"docstatus": 0,
|
||||
"modified": "2013-07-03 13:19:02",
|
||||
"modified_by": "Administrator",
|
||||
"owner": "Administrator"
|
||||
},
|
||||
{
|
||||
"doctype": "DocType",
|
||||
"istable": 1,
|
||||
"module": "Website",
|
||||
"name": "__common__"
|
||||
},
|
||||
{
|
||||
"doctype": "DocField",
|
||||
"fieldname": "shipping_rule",
|
||||
"fieldtype": "Link",
|
||||
"label": "Shipping Rule",
|
||||
"name": "__common__",
|
||||
"options": "Shipping Rule",
|
||||
"parent": "Shopping Cart Shipping Rule",
|
||||
"parentfield": "fields",
|
||||
"parenttype": "DocType",
|
||||
"permlevel": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"doctype": "DocType",
|
||||
"name": "Shopping Cart Shipping Rule"
|
||||
},
|
||||
{
|
||||
"doctype": "DocField"
|
||||
}
|
||||
]
|
@ -4,7 +4,7 @@
|
||||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
import webnotes.defaults
|
||||
from webnotes.utils import cint, get_fullname, fmt_money
|
||||
from webnotes.utils import flt, get_fullname, fmt_money
|
||||
|
||||
class WebsitePriceListMissingError(webnotes.ValidationError): pass
|
||||
|
||||
@ -18,14 +18,15 @@ def get_cart_quotation(doclist=None):
|
||||
return {
|
||||
"doclist": decorate_quotation_doclist(doclist),
|
||||
"addresses": [{"name": address.name, "display": address.display}
|
||||
for address in get_address_docs(party)]
|
||||
for address in get_address_docs(party)],
|
||||
"shipping_rules": get_applicable_shipping_rules(party)
|
||||
}
|
||||
|
||||
@webnotes.whitelist()
|
||||
def update_cart(item_code, qty, with_doclist=0):
|
||||
quotation = _get_cart_quotation()
|
||||
|
||||
qty = cint(qty)
|
||||
qty = flt(qty)
|
||||
if qty == 0:
|
||||
quotation.set_doclist(quotation.doclist.get({"item_code": ["!=", item_code]}))
|
||||
else:
|
||||
@ -40,8 +41,7 @@ def update_cart(item_code, qty, with_doclist=0):
|
||||
else:
|
||||
quotation_items[0].qty = qty
|
||||
|
||||
quotation.ignore_permissions = True
|
||||
quotation.save()
|
||||
apply_cart_settings(quotation=quotation)
|
||||
|
||||
if with_doclist:
|
||||
return get_cart_quotation(quotation.doclist)
|
||||
@ -70,6 +70,8 @@ def update_cart_address(address_fieldname, address_name):
|
||||
quotation.ignore_permissions = True
|
||||
quotation.save()
|
||||
|
||||
apply_cart_settings(quotation=quotation)
|
||||
|
||||
return get_cart_quotation(quotation.doclist)
|
||||
|
||||
@webnotes.whitelist()
|
||||
@ -131,8 +133,7 @@ def get_lead_or_customer():
|
||||
"doctype": "Lead",
|
||||
"email_id": webnotes.session.user,
|
||||
"lead_name": get_fullname(webnotes.session.user),
|
||||
"territory": webnotes.conn.get_value("Shopping Cart Settings", None, "territory") or \
|
||||
"All Territories",
|
||||
"territory": guess_territory(),
|
||||
"status": "Open" # TODO: set something better???
|
||||
})
|
||||
lead_bean.ignore_permissions = True
|
||||
@ -140,6 +141,16 @@ def get_lead_or_customer():
|
||||
|
||||
return lead_bean.doc
|
||||
|
||||
def guess_territory():
|
||||
territory = None
|
||||
geoip_country = webnotes.session.get("session_country")
|
||||
if geoip_country:
|
||||
territory = webnotes.conn.get_value("Territory", geoip_country)
|
||||
|
||||
return territory or \
|
||||
webnotes.conn.get_value("Shopping Cart Settings", None, "territory") or \
|
||||
"All Territories"
|
||||
|
||||
def decorate_quotation_doclist(doclist):
|
||||
for d in doclist:
|
||||
if d.item_code:
|
||||
@ -147,6 +158,12 @@ def decorate_quotation_doclist(doclist):
|
||||
["website_image", "web_short_description", "page_name"], as_dict=True))
|
||||
d.formatted_rate = fmt_money(d.export_rate, currency=doclist[0].currency)
|
||||
d.formatted_amount = fmt_money(d.export_amount, currency=doclist[0].currency)
|
||||
elif d.charge_type:
|
||||
d.formatted_tax_amount = fmt_money(d.tax_amount / doclist[0].conversion_rate,
|
||||
currency=doclist[0].currency)
|
||||
|
||||
doclist[0].formatted_grand_total_export = fmt_money(doclist[0].grand_total_export,
|
||||
currency=doclist[0].currency)
|
||||
|
||||
return [d.fields for d in doclist]
|
||||
|
||||
@ -168,41 +185,121 @@ def _get_cart_quotation(party=None):
|
||||
"order_type": "Shopping Cart",
|
||||
"status": "Draft",
|
||||
"__islocal": 1,
|
||||
"price_list_name": get_price_list(party),
|
||||
(party.doctype.lower()): party.name
|
||||
})
|
||||
qbean.run_method("onload_post_render")
|
||||
apply_cart_settings(party, qbean)
|
||||
|
||||
return qbean
|
||||
|
||||
def get_price_list(party):
|
||||
if not party.default_price_list:
|
||||
party.default_price_list = get_price_list_using_geoip()
|
||||
party.save()
|
||||
def apply_cart_settings(party=None, quotation=None):
|
||||
if not party:
|
||||
party = get_lead_or_customer()
|
||||
if not quotation:
|
||||
quotation = _get_cart_quotation(party)
|
||||
|
||||
return party.default_price_list
|
||||
cart_settings = webnotes.get_obj("Shopping Cart Settings")
|
||||
|
||||
def get_price_list_using_geoip():
|
||||
country = webnotes.session.get("session_country")
|
||||
price_list_name = None
|
||||
billing_territory = get_address_territory(quotation.doc.customer_address) or \
|
||||
party.territory
|
||||
|
||||
if country:
|
||||
price_list_name = webnotes.conn.sql("""select parent
|
||||
from `tabPrice List Country` plc
|
||||
where country=%s and exists (select name from `tabPrice List` pl
|
||||
where use_for_website=1 and ifnull(valid_for_all_countries, 0)=0 and
|
||||
pl.name = plc.parent)""", country)
|
||||
set_price_list_and_rate(quotation, cart_settings, billing_territory)
|
||||
|
||||
if price_list_name:
|
||||
price_list_name = price_list_name[0][0]
|
||||
else:
|
||||
price_list_name = webnotes.conn.get_value("Price List",
|
||||
{"use_for_website": 1, "valid_for_all_countries": 1})
|
||||
quotation.run_method("calculate_taxes_and_totals")
|
||||
|
||||
if not price_list_name:
|
||||
raise WebsitePriceListMissingError, "No website Price List specified"
|
||||
set_taxes(quotation, cart_settings, billing_territory)
|
||||
|
||||
return price_list_name
|
||||
_apply_shipping_rule(party, quotation, cart_settings)
|
||||
|
||||
quotation.ignore_permissions = True
|
||||
quotation.save()
|
||||
|
||||
def set_price_list_and_rate(quotation, cart_settings, billing_territory):
|
||||
"""set price list based on billing territory"""
|
||||
quotation.doc.price_list_name = cart_settings.get_price_list(billing_territory)
|
||||
|
||||
# reset values
|
||||
quotation.doc.price_list_currency = quotation.doc.currency = \
|
||||
quotation.doc.plc_conversion_rate = quotation.doc.conversion_rate = None
|
||||
for item in quotation.doclist.get({"parentfield": "quotation_details"}):
|
||||
item.ref_rate = item.adj_rate = item.export_rate = item.export_amount = None
|
||||
|
||||
# refetch values
|
||||
quotation.run_method("set_price_list_and_item_details")
|
||||
|
||||
def set_taxes(quotation, cart_settings, billing_territory):
|
||||
"""set taxes based on billing territory"""
|
||||
quotation.doc.charge = cart_settings.get_tax_master(billing_territory)
|
||||
|
||||
# clear table
|
||||
quotation.doclist = quotation.doc.clear_table(quotation.doclist, "other_charges")
|
||||
|
||||
# append taxes
|
||||
controller = quotation.make_controller()
|
||||
controller.append_taxes_from_master("other_charges", "charge")
|
||||
quotation.set_doclist(controller.doclist)
|
||||
|
||||
@webnotes.whitelist()
|
||||
def apply_shipping_rule(shipping_rule):
|
||||
quotation = _get_cart_quotation()
|
||||
|
||||
quotation.doc.shipping_rule = shipping_rule
|
||||
|
||||
apply_cart_settings(quotation=quotation)
|
||||
|
||||
quotation.save()
|
||||
|
||||
return get_cart_quotation(quotation.doclist)
|
||||
|
||||
def _apply_shipping_rule(party=None, quotation=None, cart_settings=None):
|
||||
shipping_rules = get_shipping_rules(party, quotation, cart_settings)
|
||||
|
||||
if not shipping_rules:
|
||||
return
|
||||
|
||||
elif quotation.doc.shipping_rule not in shipping_rules:
|
||||
quotation.doc.shipping_rule = shipping_rules[0]
|
||||
|
||||
quotation.run_method("apply_shipping_rule")
|
||||
quotation.run_method("calculate_taxes_and_totals")
|
||||
|
||||
def get_applicable_shipping_rules(party=None, quotation=None):
|
||||
shipping_rules = get_shipping_rules(party, quotation)
|
||||
|
||||
if shipping_rules:
|
||||
rule_label_map = webnotes.conn.get_values("Shipping Rule", shipping_rules, "label")
|
||||
# we need this in sorted order as per the position of the rule in the settings page
|
||||
return [[rule, rule_label_map.get(rule)] for rule in shipping_rules]
|
||||
|
||||
def get_shipping_rules(party=None, quotation=None, cart_settings=None):
|
||||
if not party:
|
||||
party = get_lead_or_customer()
|
||||
if not quotation:
|
||||
quotation = _get_cart_quotation()
|
||||
if not cart_settings:
|
||||
cart_settings = webnotes.get_obj("Shopping Cart Settings")
|
||||
|
||||
# set shipping rule based on shipping territory
|
||||
shipping_territory = get_address_territory(quotation.doc.shipping_address_name) or \
|
||||
party.territory
|
||||
|
||||
shipping_rules = cart_settings.get_shipping_rules(shipping_territory)
|
||||
|
||||
return shipping_rules
|
||||
|
||||
def get_address_territory(address_name):
|
||||
"""Tries to match city, state and country of address to existing territory"""
|
||||
territory = None
|
||||
|
||||
if address_name:
|
||||
address_fields = webnotes.conn.get_value("Address", address_name,
|
||||
["city", "state", "country"])
|
||||
for value in address_fields:
|
||||
territory = webnotes.conn.get_value("Territory", value)
|
||||
if territory:
|
||||
break
|
||||
|
||||
return territory
|
||||
|
||||
@webnotes.whitelist()
|
||||
def checkout():
|
||||
|
@ -38,7 +38,6 @@ $(document).ready(function() {
|
||||
} else {
|
||||
wn.cart.render(r.message);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -84,6 +83,7 @@ $.extend(wn.cart, {
|
||||
|
||||
var $cart_items = $("#cart-items").empty();
|
||||
var $cart_taxes = $("#cart-taxes").empty();
|
||||
var $cart_totals = $("#cart-totals").empty();
|
||||
var $cart_billing_address = $("#cart-billing-address").empty();
|
||||
var $cart_shipping_address = $("#cart-shipping-address").empty();
|
||||
|
||||
@ -94,10 +94,37 @@ $.extend(wn.cart, {
|
||||
return;
|
||||
}
|
||||
|
||||
var shipping_rule_added = false;
|
||||
var taxes_exist = false;
|
||||
var shipping_rule_labels = $.map(out.shipping_rules, function(rule) { return rule[1]; });
|
||||
$.each(doclist, function(i, doc) {
|
||||
if(doc.doctype === "Quotation Item") {
|
||||
wn.cart.render_item_row($cart_items, doc);
|
||||
} else if (doc.doctype === "Sales Taxes and Charges") {
|
||||
if(out.shipping_rules && out.shipping_rules.length &&
|
||||
shipping_rule_labels.indexOf(doc.description)!==-1) {
|
||||
shipping_rule_added = true;
|
||||
wn.cart.render_tax_row($cart_taxes, doc, out.shipping_rules);
|
||||
} else {
|
||||
wn.cart.render_tax_row($cart_taxes, doc);
|
||||
}
|
||||
|
||||
taxes_exist = true;
|
||||
}
|
||||
});
|
||||
|
||||
if(out.shipping_rules && out.shipping_rules.length && !shipping_rule_added) {
|
||||
wn.cart.render_tax_row($cart_taxes, {description: "", formatted_tax_amount: ""},
|
||||
out.shipping_rules);
|
||||
taxes_exist = true;
|
||||
}
|
||||
|
||||
if(taxes_exist)
|
||||
$('<hr>').appendTo($cart_taxes);
|
||||
|
||||
wn.cart.render_tax_row($cart_totals, {
|
||||
description: "<strong>Total</strong>",
|
||||
formatted_tax_amount: "<strong>" + doclist[0].formatted_grand_total_export + "</strong>"
|
||||
});
|
||||
|
||||
if(!(addresses && addresses.length)) {
|
||||
@ -125,10 +152,10 @@ $.extend(wn.cart, {
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="col col-lg-3 col-sm-3">\
|
||||
<div class="col col-lg-3 col-sm-3 text-right">\
|
||||
<div class="input-group item-update-cart">\
|
||||
<input type="text" placeholder="Qty" value="%(qty)s" \
|
||||
data-item-code="%(item_code)s">\
|
||||
data-item-code="%(item_code)s" class="text-right">\
|
||||
<div class="input-group-btn">\
|
||||
<button class="btn btn-primary" data-item-code="%(item_code)s">\
|
||||
<i class="icon-ok"></i></button>\
|
||||
@ -140,6 +167,53 @@ $.extend(wn.cart, {
|
||||
</div><hr>', doc)).appendTo($cart_items);
|
||||
},
|
||||
|
||||
render_tax_row: function($cart_taxes, doc, shipping_rules) {
|
||||
var shipping_selector;
|
||||
if(shipping_rules) {
|
||||
shipping_selector = '<select>' + $.map(shipping_rules, function(rule) {
|
||||
return '<option value="' + rule[0] + '">' + rule[1] + '</option>' }).join("\n") +
|
||||
'</select>';
|
||||
}
|
||||
|
||||
var $tax_row = $(repl('<div class="row">\
|
||||
<div class="col col-lg-9 col-sm-9">\
|
||||
<div class="row">\
|
||||
<div class="col col-lg-9 col-offset-3">' +
|
||||
(shipping_selector || '<p>%(description)s</p>') +
|
||||
'</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="col col-lg-3 col-sm-3 text-right">\
|
||||
<p' + (shipping_selector ? ' style="margin-top: 5px;"' : "") + '>%(formatted_tax_amount)s</p>\
|
||||
</div>\
|
||||
</div>', doc)).appendTo($cart_taxes);
|
||||
|
||||
if(shipping_selector) {
|
||||
$tax_row.find('select option').each(function(i, opt) {
|
||||
if($(opt).html() == doc.description) {
|
||||
$(opt).attr("selected", "selected");
|
||||
}
|
||||
});
|
||||
$tax_row.find('select').on("change", function() {
|
||||
wn.cart.apply_shipping_rule($(this).val(), this);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
apply_shipping_rule: function(rule, btn) {
|
||||
wn.call({
|
||||
btn: btn,
|
||||
type: "POST",
|
||||
method: "website.helpers.cart.apply_shipping_rule",
|
||||
args: { shipping_rule: rule },
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
wn.cart.render(r.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
render_address: function($address_wrapper, addresses, address_name) {
|
||||
$.each(addresses, function(i, address) {
|
||||
$(repl('<div class="accordion-group"> \
|
||||
|
@ -19,16 +19,17 @@
|
||||
<div class="row">
|
||||
<div class="col col-lg-9 col-sm-9">
|
||||
<div class="row">
|
||||
<div class="col col-lg-3"></div>
|
||||
<div class="col col-lg-9"><h4>Item Details</h4></div>
|
||||
<div class="col col-lg-9 col-offset-3"><h4>Item Details</h4></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col col-lg-3 col-sm-3"><h4>Qty</h4></div>
|
||||
<div class="col col-lg-3 col-sm-3 text-right"><h4>Qty, Amount</h4></div>
|
||||
</div><hr>
|
||||
<div id="cart-items">
|
||||
</div>
|
||||
<div id="cart-taxes">
|
||||
</div>
|
||||
<div id="cart-totals">
|
||||
</div>
|
||||
<hr>
|
||||
<div id="cart-addresses">
|
||||
<div class="row">
|
||||
@ -37,16 +38,15 @@
|
||||
<div id="cart-shipping-address" class="accordion"
|
||||
data-fieldname="shipping_address_name"></div>
|
||||
<button class="btn btn-default" type="button" id="cart-add-shipping-address">
|
||||
<span class="icon icon-plus"></span> New Address</button>
|
||||
<span class="icon icon-plus"></span> New Shipping Address</button>
|
||||
</div>
|
||||
<div class="col col-lg-6">
|
||||
<h4>Billing Address</h4>
|
||||
<div id="cart-billing-address" class="accordion"
|
||||
data-fieldname="customer_address"></div>
|
||||
<button class="btn btn-default" type="button" id="cart-add-billing-address">
|
||||
<span class="icon icon-plus"></span> New Address</button>
|
||||
<span class="icon icon-plus"></span> New Billing Address</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<hr>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user