[calculations] [client/server] first cut
This commit is contained in:
parent
2168e39bf3
commit
3543f30046
@ -34,67 +34,12 @@ erpnext.buying.PurchaseInvoiceController = erpnext.buying.BuyingController.exten
|
|||||||
|
|
||||||
cur_frm.cscript.is_opening(doc);
|
cur_frm.cscript.is_opening(doc);
|
||||||
},
|
},
|
||||||
onload_post_render: function(doc, dt, dn) {
|
|
||||||
var me = this;
|
|
||||||
var callback1 = function(doc, dt, dn) {
|
|
||||||
var callback2 = function(doc, dt, dn) {
|
|
||||||
if(doc.__islocal && doc.supplier) cur_frm.cscript.supplier(doc, dt, dn);
|
|
||||||
}
|
|
||||||
me.update_item_details(doc, dt, dn, callback2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: improve this
|
|
||||||
if(this.frm.doc.__islocal) {
|
|
||||||
if (this.frm.fields_dict.price_list_name && this.frm.doc.price_list_name) {
|
|
||||||
this.price_list_name(callback1);
|
|
||||||
} else {
|
|
||||||
callback1(doc, dt, dn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// for backward compatibility: combine new and previous states
|
// for backward compatibility: combine new and previous states
|
||||||
$.extend(cur_frm.cscript, new erpnext.buying.PurchaseInvoiceController({frm: cur_frm}));
|
$.extend(cur_frm.cscript, new erpnext.buying.PurchaseInvoiceController({frm: cur_frm}));
|
||||||
|
|
||||||
|
|
||||||
cur_frm.cscript.onload = function(doc,dt,dn) {
|
|
||||||
if(!doc.posting_date) set_multiple(dt,dn,{posting_date:get_today()});
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_frm.cscript.supplier = function(doc,dt,dn) {
|
|
||||||
var callback = function(r,rt) {
|
|
||||||
var doc = locals[cur_frm.doctype][cur_frm.docname];
|
|
||||||
get_server_fields('get_credit_to','','',doc, dt, dn, 0, callback2);
|
|
||||||
}
|
|
||||||
|
|
||||||
var callback2 = function(r,rt){
|
|
||||||
var doc = locals[cur_frm.doctype][cur_frm.docname];
|
|
||||||
var el = getchildren('Purchase Invoice Item',doc.name,'entries');
|
|
||||||
for(var i in el){
|
|
||||||
if(el[i].item_code && (!el[i].expense_head || !el[i].cost_center)){
|
|
||||||
args = {
|
|
||||||
item_code: el[i].item_code,
|
|
||||||
expense_head: el[i].expense_head,
|
|
||||||
cost_center: el[i].cost_center
|
|
||||||
};
|
|
||||||
get_server_fields('get_default_values', JSON.stringify(args), 'entries', doc, el[i].doctype, el[i].name, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cur_frm.cscript.calc_amount(doc, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doc.supplier) {
|
|
||||||
get_server_fields('get_default_supplier_address',
|
|
||||||
JSON.stringify({ supplier: doc.supplier }),'', doc, dt, dn, 1, function(doc, dt, dn) {
|
|
||||||
cur_frm.refresh();
|
|
||||||
callback(doc, dt, dn);
|
|
||||||
});
|
|
||||||
unhide_field(['supplier_address','contact_person']);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_frm.cscript.supplier_address = cur_frm.cscript.contact_person = function(doc,dt,dn) {
|
cur_frm.cscript.supplier_address = cur_frm.cscript.contact_person = function(doc,dt,dn) {
|
||||||
if(doc.supplier) get_server_fields('get_supplier_address', JSON.stringify({supplier: doc.supplier, address: doc.supplier_address, contact: doc.contact_person}),'', doc, dt, dn, 1);
|
if(doc.supplier) get_server_fields('get_supplier_address', JSON.stringify({supplier: doc.supplier, address: doc.supplier_address, contact: doc.contact_person}),'', doc, dt, dn, 1);
|
||||||
}
|
}
|
||||||
|
@ -91,6 +91,11 @@ class DocType(BuyingController):
|
|||||||
msgprint("%s does not have an Account Head in %s. You must first create it from the Supplier Master" % (self.doc.supplier, self.doc.company))
|
msgprint("%s does not have an Account Head in %s. You must first create it from the Supplier Master" % (self.doc.supplier, self.doc.company))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
def set_supplier_defaults(self):
|
||||||
|
# TODO cleanup these methods
|
||||||
|
self.doc.fields.update(self.get_credit_to())
|
||||||
|
super(DocType, self).set_supplier_defaults()
|
||||||
|
|
||||||
def get_cust(self):
|
def get_cust(self):
|
||||||
ret = {}
|
ret = {}
|
||||||
if self.doc.credit_to:
|
if self.doc.credit_to:
|
||||||
@ -100,31 +105,6 @@ class DocType(BuyingController):
|
|||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def get_default_values(self, args):
|
|
||||||
if isinstance(args, basestring):
|
|
||||||
import json
|
|
||||||
args = json.loads(args)
|
|
||||||
|
|
||||||
out = webnotes._dict()
|
|
||||||
|
|
||||||
item = webnotes.conn.sql("""select name, purchase_account, cost_center,
|
|
||||||
is_stock_item from `tabItem` where name=%s""", args.get("item_code"), as_dict=1)
|
|
||||||
|
|
||||||
if item and item[0]:
|
|
||||||
item = item[0]
|
|
||||||
|
|
||||||
if cint(webnotes.defaults.get_global_default("auto_inventory_accounting")) and \
|
|
||||||
item.is_stock_item == "Yes":
|
|
||||||
# unset expense head for stock item and auto inventory accounting
|
|
||||||
out.expense_head = out.cost_center = None
|
|
||||||
else:
|
|
||||||
if not args.get("expense_head"):
|
|
||||||
out.expense_head = item.purchase_account
|
|
||||||
if not args.get("cost_center"):
|
|
||||||
out.cost_center = item.cost_center
|
|
||||||
|
|
||||||
return out
|
|
||||||
|
|
||||||
def pull_details(self):
|
def pull_details(self):
|
||||||
if self.doc.purchase_receipt_main:
|
if self.doc.purchase_receipt_main:
|
||||||
self.validate_duplicate_docname('purchase_receipt')
|
self.validate_duplicate_docname('purchase_receipt')
|
||||||
|
@ -119,25 +119,6 @@ class TestPurchaseInvoice(unittest.TestCase):
|
|||||||
wrapper.insert()
|
wrapper.insert()
|
||||||
wrapper.load_from_db()
|
wrapper.load_from_db()
|
||||||
|
|
||||||
self.assertEqual(wrapper.doclist[0].net_total, 1250)
|
|
||||||
|
|
||||||
# tax amounts
|
|
||||||
expected_values = [
|
|
||||||
["_Test Account Shipping Charges - _TC", 100, 1350],
|
|
||||||
["_Test Account Customs Duty - _TC", 125, 1350],
|
|
||||||
["_Test Account Excise Duty - _TC", 140, 1490],
|
|
||||||
["_Test Account Education Cess - _TC", 2.8, 1492.8],
|
|
||||||
["_Test Account S&H Education Cess - _TC", 1.4, 1494.2],
|
|
||||||
["_Test Account CST - _TC", 29.88, 1524.08],
|
|
||||||
["_Test Account VAT - _TC", 156.25, 1680.33],
|
|
||||||
["_Test Account Discount - _TC", 168.03, 1512.30],
|
|
||||||
]
|
|
||||||
|
|
||||||
for i, tax in enumerate(wrapper.doclist.get({"parentfield": "purchase_tax_details"})):
|
|
||||||
self.assertEqual(tax.account_head, expected_values[i][0])
|
|
||||||
self.assertEqual(tax.tax_amount, expected_values[i][1])
|
|
||||||
self.assertEqual(tax.total, expected_values[i][2])
|
|
||||||
|
|
||||||
expected_values = [
|
expected_values = [
|
||||||
["_Test Item Home Desktop 100", 90, 59],
|
["_Test Item Home Desktop 100", 90, 59],
|
||||||
["_Test Item Home Desktop 200", 135, 177]
|
["_Test Item Home Desktop 200", 135, 177]
|
||||||
@ -147,13 +128,6 @@ class TestPurchaseInvoice(unittest.TestCase):
|
|||||||
self.assertEqual(item.item_tax_amount, expected_values[i][1])
|
self.assertEqual(item.item_tax_amount, expected_values[i][1])
|
||||||
self.assertEqual(item.valuation_rate, expected_values[i][2])
|
self.assertEqual(item.valuation_rate, expected_values[i][2])
|
||||||
|
|
||||||
def test_purchase_invoice_with_subcontracted_item(self):
|
|
||||||
wrapper = webnotes.bean(copy=test_records[0])
|
|
||||||
wrapper.doclist[1].item_code = "_Test FG Item"
|
|
||||||
wrapper.run_method("calculate_taxes_and_totals")
|
|
||||||
wrapper.insert()
|
|
||||||
wrapper.load_from_db()
|
|
||||||
|
|
||||||
self.assertEqual(wrapper.doclist[0].net_total, 1250)
|
self.assertEqual(wrapper.doclist[0].net_total, 1250)
|
||||||
|
|
||||||
# tax amounts
|
# tax amounts
|
||||||
@ -173,6 +147,13 @@ class TestPurchaseInvoice(unittest.TestCase):
|
|||||||
self.assertEqual(tax.tax_amount, expected_values[i][1])
|
self.assertEqual(tax.tax_amount, expected_values[i][1])
|
||||||
self.assertEqual(tax.total, expected_values[i][2])
|
self.assertEqual(tax.total, expected_values[i][2])
|
||||||
|
|
||||||
|
def test_purchase_invoice_with_subcontracted_item(self):
|
||||||
|
wrapper = webnotes.bean(copy=test_records[0])
|
||||||
|
wrapper.doclist[1].item_code = "_Test FG Item"
|
||||||
|
wrapper.run_method("calculate_taxes_and_totals")
|
||||||
|
wrapper.insert()
|
||||||
|
wrapper.load_from_db()
|
||||||
|
|
||||||
expected_values = [
|
expected_values = [
|
||||||
["_Test FG Item", 90, 7059],
|
["_Test FG Item", 90, 7059],
|
||||||
["_Test Item Home Desktop 200", 135, 177]
|
["_Test Item Home Desktop 200", 135, 177]
|
||||||
@ -182,6 +163,25 @@ class TestPurchaseInvoice(unittest.TestCase):
|
|||||||
self.assertEqual(item.item_tax_amount, expected_values[i][1])
|
self.assertEqual(item.item_tax_amount, expected_values[i][1])
|
||||||
self.assertEqual(item.valuation_rate, expected_values[i][2])
|
self.assertEqual(item.valuation_rate, expected_values[i][2])
|
||||||
|
|
||||||
|
self.assertEqual(wrapper.doclist[0].net_total, 1250)
|
||||||
|
|
||||||
|
# tax amounts
|
||||||
|
expected_values = [
|
||||||
|
["_Test Account Shipping Charges - _TC", 100, 1350],
|
||||||
|
["_Test Account Customs Duty - _TC", 125, 1350],
|
||||||
|
["_Test Account Excise Duty - _TC", 140, 1490],
|
||||||
|
["_Test Account Education Cess - _TC", 2.8, 1492.8],
|
||||||
|
["_Test Account S&H Education Cess - _TC", 1.4, 1494.2],
|
||||||
|
["_Test Account CST - _TC", 29.88, 1524.08],
|
||||||
|
["_Test Account VAT - _TC", 156.25, 1680.33],
|
||||||
|
["_Test Account Discount - _TC", 168.03, 1512.30],
|
||||||
|
]
|
||||||
|
|
||||||
|
for i, tax in enumerate(wrapper.doclist.get({"parentfield": "purchase_tax_details"})):
|
||||||
|
self.assertEqual(tax.account_head, expected_values[i][0])
|
||||||
|
self.assertEqual(tax.tax_amount, expected_values[i][1])
|
||||||
|
self.assertEqual(tax.total, expected_values[i][2])
|
||||||
|
|
||||||
def test_purchase_invoice_with_advance(self):
|
def test_purchase_invoice_with_advance(self):
|
||||||
from accounts.doctype.journal_voucher.test_journal_voucher \
|
from accounts.doctype.journal_voucher.test_journal_voucher \
|
||||||
import test_records as jv_test_records
|
import test_records as jv_test_records
|
||||||
|
@ -110,8 +110,8 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
for i, tax in enumerate(si.doclist.get({"parentfield": "other_charges"})):
|
for i, tax in enumerate(si.doclist.get({"parentfield": "other_charges"})):
|
||||||
tax.idx = i+1
|
tax.idx = i+1
|
||||||
|
|
||||||
si.doclist[1].export_rate = 62.5
|
si.doclist[1].ref_rate = 62.5
|
||||||
si.doclist[1].export_rate = 191
|
si.doclist[1].ref_rate = 191
|
||||||
for i in [3, 5, 6, 7, 8, 9]:
|
for i in [3, 5, 6, 7, 8, 9]:
|
||||||
si.doclist[i].included_in_print_rate = 1
|
si.doclist[i].included_in_print_rate = 1
|
||||||
|
|
||||||
@ -173,9 +173,9 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
si = webnotes.bean(copy=test_records[3])
|
si = webnotes.bean(copy=test_records[3])
|
||||||
si.doc.currency = "USD"
|
si.doc.currency = "USD"
|
||||||
si.doc.conversion_rate = 50
|
si.doc.conversion_rate = 50
|
||||||
si.doclist[1].export_rate = 50
|
si.doclist[1].ref_rate = 55.56
|
||||||
si.doclist[1].adj_rate = 10
|
si.doclist[1].adj_rate = 10
|
||||||
si.doclist[2].export_rate = 150
|
si.doclist[2].ref_rate = 187.5
|
||||||
si.doclist[2].adj_rate = 20
|
si.doclist[2].adj_rate = 20
|
||||||
si.doclist[9].rate = 5000
|
si.doclist[9].rate = 5000
|
||||||
|
|
||||||
@ -317,7 +317,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
pos[0]["cash_bank_account"] = "_Test Account Bank Account - _TC"
|
pos[0]["cash_bank_account"] = "_Test Account Bank Account - _TC"
|
||||||
pos[0]["paid_amount"] = 600.0
|
pos[0]["paid_amount"] = 600.0
|
||||||
|
|
||||||
si = webnotes.bean(pos)
|
si = webnotes.bean(copy=pos)
|
||||||
si.insert()
|
si.insert()
|
||||||
si.submit()
|
si.submit()
|
||||||
|
|
||||||
@ -340,11 +340,11 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
|
|
||||||
expected_gl_entries = sorted([
|
expected_gl_entries = sorted([
|
||||||
[si.doc.debit_to, 630.0, 0.0],
|
[si.doc.debit_to, 630.0, 0.0],
|
||||||
[test_records[1][1]["income_account"], 0.0, 500.0],
|
[pos[1]["income_account"], 0.0, 500.0],
|
||||||
[test_records[1][2]["account_head"], 0.0, 80.0],
|
[pos[2]["account_head"], 0.0, 80.0],
|
||||||
[test_records[1][3]["account_head"], 0.0, 50.0],
|
[pos[3]["account_head"], 0.0, 50.0],
|
||||||
[stock_in_hand_account, 0.0, 375.0],
|
[stock_in_hand_account, 0.0, 375.0],
|
||||||
[test_records[1][1]["expense_account"], 375.0, 0.0],
|
[pos[1]["expense_account"], 375.0, 0.0],
|
||||||
[si.doc.debit_to, 0.0, 600.0],
|
[si.doc.debit_to, 0.0, 600.0],
|
||||||
["_Test Account Bank Account - _TC", 600.0, 0.0]
|
["_Test Account Bank Account - _TC", 600.0, 0.0]
|
||||||
])
|
])
|
||||||
@ -760,6 +760,7 @@ test_records = [
|
|||||||
"item_code": "_Test Item Home Desktop 100",
|
"item_code": "_Test Item Home Desktop 100",
|
||||||
"item_name": "_Test Item Home Desktop 100",
|
"item_name": "_Test Item Home Desktop 100",
|
||||||
"qty": 10,
|
"qty": 10,
|
||||||
|
"ref_rate": 50,
|
||||||
"export_rate": 50,
|
"export_rate": 50,
|
||||||
"stock_uom": "_Test UOM",
|
"stock_uom": "_Test UOM",
|
||||||
"item_tax_rate": json.dumps({"_Test Account Excise Duty - _TC": 10}),
|
"item_tax_rate": json.dumps({"_Test Account Excise Duty - _TC": 10}),
|
||||||
@ -773,6 +774,7 @@ test_records = [
|
|||||||
"item_code": "_Test Item Home Desktop 200",
|
"item_code": "_Test Item Home Desktop 200",
|
||||||
"item_name": "_Test Item Home Desktop 200",
|
"item_name": "_Test Item Home Desktop 200",
|
||||||
"qty": 5,
|
"qty": 5,
|
||||||
|
"ref_rate": 150,
|
||||||
"export_rate": 150,
|
"export_rate": 150,
|
||||||
"stock_uom": "_Test UOM",
|
"stock_uom": "_Test UOM",
|
||||||
"income_account": "Sales - _TC",
|
"income_account": "Sales - _TC",
|
||||||
@ -883,6 +885,7 @@ test_records = [
|
|||||||
"item_code": "_Test Item Home Desktop 100",
|
"item_code": "_Test Item Home Desktop 100",
|
||||||
"item_name": "_Test Item Home Desktop 100",
|
"item_name": "_Test Item Home Desktop 100",
|
||||||
"qty": 10,
|
"qty": 10,
|
||||||
|
"ref_rate": 62.5,
|
||||||
"export_rate": 62.5,
|
"export_rate": 62.5,
|
||||||
"stock_uom": "_Test UOM",
|
"stock_uom": "_Test UOM",
|
||||||
"item_tax_rate": json.dumps({"_Test Account Excise Duty - _TC": 10}),
|
"item_tax_rate": json.dumps({"_Test Account Excise Duty - _TC": 10}),
|
||||||
@ -896,6 +899,7 @@ test_records = [
|
|||||||
"item_code": "_Test Item Home Desktop 200",
|
"item_code": "_Test Item Home Desktop 200",
|
||||||
"item_name": "_Test Item Home Desktop 200",
|
"item_name": "_Test Item Home Desktop 200",
|
||||||
"qty": 5,
|
"qty": 5,
|
||||||
|
"ref_rate": 190.66,
|
||||||
"export_rate": 190.66,
|
"export_rate": 190.66,
|
||||||
"stock_uom": "_Test UOM",
|
"stock_uom": "_Test UOM",
|
||||||
"income_account": "Sales - _TC",
|
"income_account": "Sales - _TC",
|
||||||
|
@ -20,8 +20,9 @@
|
|||||||
// cur_frm.cscript.fname - Details fieldname
|
// cur_frm.cscript.fname - Details fieldname
|
||||||
|
|
||||||
wn.provide("erpnext.buying");
|
wn.provide("erpnext.buying");
|
||||||
|
wn.require("app/js/transaction.js");
|
||||||
|
|
||||||
erpnext.buying.BuyingController = wn.ui.form.Controller.extend({
|
erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
||||||
setup: function() {
|
setup: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
|
|
||||||
@ -42,50 +43,39 @@ erpnext.buying.BuyingController = wn.ui.form.Controller.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: function() {
|
validate: function() {
|
||||||
this.frm.clear_custom_buttons();
|
|
||||||
erpnext.hide_naming_series();
|
|
||||||
|
|
||||||
if(this.frm.fields_dict.supplier)
|
|
||||||
this.frm.toggle_display("contact_section", this.frm.doc.supplier);
|
|
||||||
|
|
||||||
if(this.frm.fields_dict.currency)
|
|
||||||
this.set_dynamic_labels();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
price_list_name: function(callback_fn) {
|
supplier: function() {
|
||||||
|
if(this.frm.doc.supplier || this.frm.doc.credit_to) {
|
||||||
|
if(!this.frm.doc.company) {
|
||||||
|
this.frm.set_value("supplier", null);
|
||||||
|
msgprint(wn._("Please specify Company"));
|
||||||
|
} else {
|
||||||
var me = this;
|
var me = this;
|
||||||
|
var price_list_name = this.frm.doc.price_list_name;
|
||||||
|
|
||||||
if(this.frm.doc.price_list_name) {
|
|
||||||
if(!this.frm.doc.price_list_currency) {
|
|
||||||
// set price list currency
|
|
||||||
this.frm.call({
|
this.frm.call({
|
||||||
method: "setup.utils.get_price_list_currency",
|
doc: this.frm.doc,
|
||||||
args: {args: {
|
method: "set_supplier_defaults",
|
||||||
price_list_name: this.frm.doc.price_list_name,
|
freeze: true,
|
||||||
use_for: "buying"
|
|
||||||
}},
|
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
if(!r.exc) {
|
if(!r.exc) {
|
||||||
me.price_list_currency();
|
me.frm.refresh_fields();
|
||||||
if (typeof callback_fn === "function")
|
if(me.frm.doc.price_list_name !== price_list_name) me.price_list_name();
|
||||||
callback_fn(me.frm.doc, me.frm.doc.doctype, me.frm.doc.name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
me.price_list_currency();
|
|
||||||
if (typeof callback_fn === "function")
|
|
||||||
callback_fn(me.frm.doc, me.frm.doc.doctype, me.frm.doc.name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
item_code: function(doc, cdt, cdn) {
|
item_code: function(doc, cdt, cdn) {
|
||||||
var me = this;
|
var me = this;
|
||||||
var item = wn.model.get_doc(cdt, cdn);
|
var item = wn.model.get_doc(cdt, cdn);
|
||||||
if(item.item_code) {
|
if(item.item_code) {
|
||||||
if(!this.validate_company_and_party()) {
|
if(!this.validate_company_and_party("supplier")) {
|
||||||
item.item_code = null;
|
item.item_code = null;
|
||||||
refresh_field("item_code", item.name, item.parentfield);
|
refresh_field("item_code", item.name, item.parentfield);
|
||||||
} else {
|
} else {
|
||||||
@ -108,66 +98,116 @@ erpnext.buying.BuyingController = wn.ui.form.Controller.extend({
|
|||||||
currency: me.frm.doc.currency
|
currency: me.frm.doc.currency
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
callback: function(r) {
|
|
||||||
// TODO: calculate
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
validate_company_and_party: function() {
|
|
||||||
var valid = true;
|
|
||||||
$.each(["company", "supplier"], function(i, fieldname) {
|
|
||||||
if(!me.frm.doc[fieldname]) {
|
|
||||||
valid = false;
|
|
||||||
msgprint(wn._("Please specify") + ": " +
|
|
||||||
wn.meta.get_label(me.frm.doc.doctype, fieldname, me.frm.doc.name) +
|
|
||||||
". " + wn._("It is needed to fetch Item Details."));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return valid;
|
|
||||||
},
|
|
||||||
|
|
||||||
update_item_details: function(doc, dt, dn, callback) {
|
|
||||||
if(!this.frm.doc.__islocal) return;
|
|
||||||
|
|
||||||
var me = this;
|
|
||||||
var children = getchildren(this.tname, this.frm.doc.name, this.fname);
|
|
||||||
if(children && children.length) {
|
|
||||||
this.frm.call({
|
|
||||||
doc: me.frm.doc,
|
|
||||||
method: "update_item_details",
|
|
||||||
callback: function(r) {
|
callback: function(r) {
|
||||||
if(!r.exc) {
|
if(!r.exc) {
|
||||||
refresh_field(me.fname);
|
me.ref_rate(me.frm.doc, cdt, cdn);
|
||||||
me.load_defaults(me.frm.doc, dt, dn, callback);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
} else {
|
}
|
||||||
this.load_taxes(doc, dt, dn, callback);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
currency: function() {
|
price_list_name: function(callback_fn) {
|
||||||
this.price_list_currency();
|
this._super("buying");
|
||||||
},
|
},
|
||||||
|
|
||||||
company: function() {
|
calculate_taxes_and_totals: function() {
|
||||||
this.set_dynamic_labels();
|
this._super();
|
||||||
|
this.calculate_outstanding_amount();
|
||||||
|
this.frm.refresh_fields();
|
||||||
},
|
},
|
||||||
|
|
||||||
price_list_currency: function() {
|
calculate_item_values: function() {
|
||||||
this.frm.toggle_reqd("plc_conversion_rate",
|
var me = this;
|
||||||
!!(this.frm.doc.price_list_name && this.frm.doc.price_list_currency));
|
|
||||||
|
|
||||||
this.set_dynamic_labels();
|
if(this.frm.doc.doctype != "Purchase Invoice") {
|
||||||
|
wn.meta.docfield_map[this.tname]["rate"] = $.extend({},
|
||||||
|
wn.meta.docfield_map[this.tname]["purchase_rate"]);
|
||||||
|
}
|
||||||
|
|
||||||
if(this.frm.doc.price_list_currency === this.get_company_currency())
|
$.each(this.frm.item_doclist, function(i, item) {
|
||||||
this.frm.set_value("plc_conversion_rate", 1.0);
|
if(me.frm.doc.doctype != "Purchase Invoice") {
|
||||||
else if(this.frm.doc.price_list_currency === this.frm.doc.currency)
|
item.rate = item.purchase_rate;
|
||||||
this.frm.set_value("plc_conversion_rate", this.frm.doc.conversion_rate || 1.0);
|
}
|
||||||
|
|
||||||
|
wn.model.round_floats_in(item);
|
||||||
|
item.import_amount = flt(item.import_rate * item.qty, precision("import_amount", item));
|
||||||
|
item.item_tax_amount = 0.0;
|
||||||
|
|
||||||
|
me._set_in_company_currency(item, "import_ref_rate", "purchase_ref_rate");
|
||||||
|
me._set_in_company_currency(item, "import_rate", "rate");
|
||||||
|
me._set_in_company_currency(item, "import_amount", "amount");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
calculate_net_total: function() {
|
||||||
|
var me = this;
|
||||||
|
|
||||||
|
this.frm.doc.net_total = this.frm.doc.net_total_import = 0.0;
|
||||||
|
$.each(this.frm.item_doclist, function(i, item) {
|
||||||
|
me.frm.doc.net_total += item.amount;
|
||||||
|
me.frm.doc.net_total_import += item.import_amount;
|
||||||
|
});
|
||||||
|
|
||||||
|
wn.model.round_floats_in(this.frm.doc, ["net_total", "net_total_import"]);
|
||||||
|
},
|
||||||
|
|
||||||
|
calculate_totals: function() {
|
||||||
|
var tax_count = this.frm.tax_doclist.length;
|
||||||
|
this.frm.doc.grand_total = flt(
|
||||||
|
tax_count ? this.frm.tax_doclist[tax_count - 1].total : this.frm.doc.net_total,
|
||||||
|
precision("grand_total"));
|
||||||
|
this.frm.doc.grand_total_import = flt(this.frm.doc.grand_total / this.frm.doc.conversion_rate,
|
||||||
|
precision("grand_total_import"));
|
||||||
|
|
||||||
|
this.frm.doc.total_tax = flt(this.frm.doc.grand_total - this.frm.doc.net_total,
|
||||||
|
precision("total_tax"));
|
||||||
|
|
||||||
|
if(wn.meta.get_docfield(this.frm.doc.doctype, "rounded_total", this.frm.doc.name)) {
|
||||||
|
this.frm.doc.rounded_total = Math.round(this.frm.doc.grand_total);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(wn.meta.get_docfield(this.frm.doc.doctype, "rounded_total_import", this.frm.doc.name)) {
|
||||||
|
this.frm.doc.rounded_total_import = Math.round(this.frm.doc.grand_total_import);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_cleanup: function() {
|
||||||
|
this._super();
|
||||||
|
this.frm.doc.in_words = this.frm.doc.in_words_import = "";
|
||||||
|
|
||||||
|
// except in purchase invoice, rate field is purchase_rate
|
||||||
|
// reset fieldname of rate
|
||||||
|
if(this.frm.doc.doctype != "Purchase Invoice") {
|
||||||
|
delete wn.meta.docfield_map[this.tname]["rate"];
|
||||||
|
|
||||||
|
$.each(this.frm.item_doclist, function(i, item) {
|
||||||
|
item.purchase_rate = item.rate;
|
||||||
|
delete item["rate"];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
calculate_outstanding_amount: function() {
|
||||||
|
if(this.frm.doc.doctype == "Purchase Invoice" && this.frm.doc.docstatus < 2) {
|
||||||
|
wn.model.round_floats_in(this.frm.doc, ["total_advance", "write_off_amount"]);
|
||||||
|
this.frm.doc.total_amount_to_pay = flt(this.frm.doc.grand_total - this.frm.doc.write_off_amount,
|
||||||
|
precision("total_amount_to_pay"));
|
||||||
|
this.frm.doc.outstanding_amount = flt(this.frm.doc.total_amount_to_pay - this.frm.doc.total_advance,
|
||||||
|
precision("outstanding_amount"));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
set_item_tax_amount: function(item, tax, current_tax_amount) {
|
||||||
|
// item_tax_amount is the total tax amount applied on that item
|
||||||
|
// stored for valuation
|
||||||
|
//
|
||||||
|
// TODO: rename item_tax_amount to valuation_tax_amount
|
||||||
|
if(["Valuation", "Valuation and Total"].indexOf(tax.category) != -1) {
|
||||||
|
// accumulate only if tax is for Valuation / Valuation and Total
|
||||||
|
item.item_tax_amount += flt(current_tax_amount, precision("item_tax_amount", item));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
set_dynamic_labels: function(doc, dt, dn) {
|
set_dynamic_labels: function(doc, dt, dn) {
|
||||||
@ -265,10 +305,6 @@ erpnext.buying.BuyingController = wn.ui.form.Controller.extend({
|
|||||||
$wrapper.find('[data-grid-fieldname="'+fname+'"]').text(label);
|
$wrapper.find('[data-grid-fieldname="'+fname+'"]').text(label);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
get_company_currency: function() {
|
|
||||||
return erpnext.get_currency(this.frm.doc.company);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// to save previous state of cur_frm.cscript
|
// to save previous state of cur_frm.cscript
|
||||||
@ -284,54 +320,6 @@ $.extend(cur_frm.cscript, prev_cscript);
|
|||||||
var tname = cur_frm.cscript.tname;
|
var tname = cur_frm.cscript.tname;
|
||||||
var fname = cur_frm.cscript.fname;
|
var fname = cur_frm.cscript.fname;
|
||||||
|
|
||||||
cur_frm.cscript.get_default_schedule_date = function(doc) {
|
|
||||||
var ch = getchildren( tname, doc.name, fname);
|
|
||||||
if (flt(ch.length) > 0){
|
|
||||||
$c_obj(make_doclist(doc.doctype, doc.name), 'get_default_schedule_date', '', function(r, rt) { refresh_field(fname); });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_frm.cscript.load_taxes = function(doc, cdt, cdn, callback) {
|
|
||||||
// run if this is not executed from dt_map...
|
|
||||||
doc = locals[doc.doctype][doc.name];
|
|
||||||
if(doc.supplier || getchildren('Purchase Taxes and Charges', doc.name, 'purchase_tax_details', doc.doctype).length) {
|
|
||||||
if(callback) {
|
|
||||||
callback(doc, cdt, cdn);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$c_obj(make_doclist(doc.doctype, doc.name),'load_default_taxes','',function(r,rt){
|
|
||||||
refresh_field('purchase_tax_details');
|
|
||||||
if(callback) callback(doc, cdt, cdn);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Gets called after existing item details are update to fill in
|
|
||||||
// remaining default values
|
|
||||||
cur_frm.cscript.load_defaults = function(doc, dt, dn, callback) {
|
|
||||||
if(!cur_frm.doc.__islocal) { return; }
|
|
||||||
|
|
||||||
doc = locals[doc.doctype][doc.name];
|
|
||||||
var fields_to_refresh = wn.model.set_default_values(doc);
|
|
||||||
if(fields_to_refresh) { refresh_many(fields_to_refresh); }
|
|
||||||
|
|
||||||
fields_to_refresh = null;
|
|
||||||
var children = getchildren(cur_frm.cscript.tname, doc.name, cur_frm.cscript.fname);
|
|
||||||
if(!children) { return; }
|
|
||||||
for(var i=0; i<children.length; i++) {
|
|
||||||
wn.model.set_default_values(children[i]);
|
|
||||||
}
|
|
||||||
refresh_field(cur_frm.cscript.fname);
|
|
||||||
cur_frm.cscript.load_taxes(doc, dt, dn, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ======================== Conversion Rate ==========================================
|
|
||||||
cur_frm.cscript.conversion_rate = function(doc,cdt,cdn) {
|
|
||||||
cur_frm.cscript.calc_amount( doc, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//==================== Item Code Get Query =======================================================
|
//==================== Item Code Get Query =======================================================
|
||||||
// Only Is Purchase Item = 'Yes' and Items not moved to trash are allowed.
|
// Only Is Purchase Item = 'Yes' and Items not moved to trash are allowed.
|
||||||
cur_frm.fields_dict[fname].grid.get_field("item_code").get_query = function(doc, cdt, cdn) {
|
cur_frm.fields_dict[fname].grid.get_field("item_code").get_query = function(doc, cdt, cdn) {
|
||||||
|
@ -69,17 +69,6 @@ class DocType(BuyingController):
|
|||||||
msgprint(_("Hey there! You need to put at least one item in \
|
msgprint(_("Hey there! You need to put at least one item in \
|
||||||
the item table."), raise_exception=True)
|
the item table."), raise_exception=True)
|
||||||
|
|
||||||
|
|
||||||
def get_default_schedule_date( self, obj):
|
|
||||||
for d in getlist( obj.doclist, obj.fname):
|
|
||||||
item = sql("select lead_time_days from `tabItem` where name = '%s' and (ifnull(end_of_life,'')='' or end_of_life = '0000-00-00' or end_of_life > now())" % cstr(d.item_code) , as_dict = 1)
|
|
||||||
ltd = item and cint(item[0]['lead_time_days']) or 0
|
|
||||||
if ltd and obj.doc.transaction_date:
|
|
||||||
if d.fields.has_key('lead_time_date') or obj.doc.doctype == 'Material Request':
|
|
||||||
d.lead_time_date = cstr(add_days( obj.doc.transaction_date, cint(ltd)))
|
|
||||||
if not d.fields.has_key('prevdoc_docname') or (d.fields.has_key('prevdoc_docname') and not d.prevdoc_docname):
|
|
||||||
d.schedule_date = cstr( add_days( obj.doc.transaction_date, cint(ltd)))
|
|
||||||
|
|
||||||
# Client Trigger functions
|
# Client Trigger functions
|
||||||
#------------------------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -39,26 +39,6 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
|||||||
cur_frm.add_custom_button('Unstop Purchase Order', cur_frm.cscript['Unstop Purchase Order']);
|
cur_frm.add_custom_button('Unstop Purchase Order', cur_frm.cscript['Unstop Purchase Order']);
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onload_post_render: function(doc, dt, dn) {
|
|
||||||
var me = this;
|
|
||||||
var callback1 = function(doc, dt, dn) {
|
|
||||||
var callback2 = function(doc, dt, dn) {
|
|
||||||
if(doc.__islocal) cur_frm.cscript.get_default_schedule_date(doc);
|
|
||||||
}
|
|
||||||
me.update_item_details(doc, dt, dn, callback2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: improve this
|
|
||||||
if(this.frm.doc.__islocal) {
|
|
||||||
if (this.frm.fields_dict.price_list_name && this.frm.doc.price_list_name) {
|
|
||||||
this.price_list_name(callback1);
|
|
||||||
} else {
|
|
||||||
callback1(doc, dt, dn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var new_cscript = new erpnext.buying.PurchaseOrderController({frm: cur_frm});
|
var new_cscript = new erpnext.buying.PurchaseOrderController({frm: cur_frm});
|
||||||
@ -66,28 +46,6 @@ var new_cscript = new erpnext.buying.PurchaseOrderController({frm: cur_frm});
|
|||||||
// for backward compatibility: combine new and previous states
|
// for backward compatibility: combine new and previous states
|
||||||
$.extend(cur_frm.cscript, new_cscript);
|
$.extend(cur_frm.cscript, new_cscript);
|
||||||
|
|
||||||
cur_frm.cscript.onload = function(doc, cdt, cdn) {
|
|
||||||
// set missing values in parent doc
|
|
||||||
set_missing_values(doc, {
|
|
||||||
fiscal_year: sys_defaults.fiscal_year,
|
|
||||||
conversion_rate: 1,
|
|
||||||
currency: sys_defaults.currency,
|
|
||||||
status: "Draft",
|
|
||||||
transaction_date: get_today(),
|
|
||||||
is_subcontracted: "No"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_frm.cscript.supplier = function(doc,dt,dn) {
|
|
||||||
if (doc.supplier) {
|
|
||||||
get_server_fields('get_default_supplier_address',
|
|
||||||
JSON.stringify({ supplier: doc.supplier }),'', doc, dt, dn, 1, function() {
|
|
||||||
cur_frm.refresh();
|
|
||||||
});
|
|
||||||
$(cur_frm.fields_dict.contact_section.row.wrapper).toggle(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_frm.cscript.supplier_address = cur_frm.cscript.contact_person = function(doc,dt,dn) {
|
cur_frm.cscript.supplier_address = cur_frm.cscript.contact_person = function(doc,dt,dn) {
|
||||||
if(doc.supplier) get_server_fields('get_supplier_address', JSON.stringify({supplier: doc.supplier, address: doc.supplier_address, contact: doc.contact_person}),'', doc, dt, dn, 1);
|
if(doc.supplier) get_server_fields('get_supplier_address', JSON.stringify({supplier: doc.supplier, address: doc.supplier_address, contact: doc.contact_person}),'', doc, dt, dn, 1);
|
||||||
}
|
}
|
||||||
@ -111,10 +69,6 @@ cur_frm.fields_dict.contact_person.on_new = function(dn) {
|
|||||||
locals['Contact'][dn].supplier_name = locals[cur_frm.doctype][cur_frm.docname].supplier_name;
|
locals['Contact'][dn].supplier_name = locals[cur_frm.doctype][cur_frm.docname].supplier_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_frm.cscript.transaction_date = function(doc,cdt,cdn){
|
|
||||||
if(doc.__islocal){ cur_frm.cscript.get_default_schedule_date(doc); }
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_frm.fields_dict['po_details'].grid.get_field('project_name').get_query = function(doc, cdt, cdn) {
|
cur_frm.fields_dict['po_details'].grid.get_field('project_name').get_query = function(doc, cdt, cdn) {
|
||||||
return 'SELECT `tabProject`.name FROM `tabProject` \
|
return 'SELECT `tabProject`.name FROM `tabProject` \
|
||||||
WHERE `tabProject`.status not in ("Completed", "Cancelled") \
|
WHERE `tabProject`.status not in ("Completed", "Cancelled") \
|
||||||
|
@ -65,10 +65,6 @@ class DocType(BuyingController):
|
|||||||
self.validate_for_subcontracting()
|
self.validate_for_subcontracting()
|
||||||
self.update_raw_materials_supplied("po_raw_material_details")
|
self.update_raw_materials_supplied("po_raw_material_details")
|
||||||
|
|
||||||
|
|
||||||
def get_default_schedule_date(self):
|
|
||||||
get_obj(dt = 'Purchase Common').get_default_schedule_date(self)
|
|
||||||
|
|
||||||
def validate_fiscal_year(self):
|
def validate_fiscal_year(self):
|
||||||
get_obj(dt = 'Purchase Common').validate_fiscal_year(self.doc.fiscal_year,self.doc.transaction_date,'PO Date')
|
get_obj(dt = 'Purchase Common').validate_fiscal_year(self.doc.fiscal_year,self.doc.transaction_date,'PO Date')
|
||||||
|
|
||||||
@ -101,7 +97,6 @@ class DocType(BuyingController):
|
|||||||
"""[['Supplier Quotation', 'Purchase Order'],
|
"""[['Supplier Quotation', 'Purchase Order'],
|
||||||
['Supplier Quotation Item', 'Purchase Order Item'],
|
['Supplier Quotation Item', 'Purchase Order Item'],
|
||||||
['Purchase Taxes and Charges', 'Purchase Taxes and Charges']]""")
|
['Purchase Taxes and Charges', 'Purchase Taxes and Charges']]""")
|
||||||
self.get_default_schedule_date()
|
|
||||||
for d in getlist(self.doclist, 'po_details'):
|
for d in getlist(self.doclist, 'po_details'):
|
||||||
if d.prevdoc_detail_docname and not d.schedule_date:
|
if d.prevdoc_detail_docname and not d.schedule_date:
|
||||||
d.schedule_date = webnotes.conn.get_value("Material Request Item",
|
d.schedule_date = webnotes.conn.get_value("Material Request Item",
|
||||||
|
@ -27,28 +27,10 @@ erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.ext
|
|||||||
refresh: function() {
|
refresh: function() {
|
||||||
this._super();
|
this._super();
|
||||||
|
|
||||||
|
|
||||||
if (this.frm.doc.docstatus === 1) {
|
if (this.frm.doc.docstatus === 1) {
|
||||||
cur_frm.add_custom_button("Make Purchase Order", cur_frm.cscript.make_purchase_order);
|
cur_frm.add_custom_button("Make Purchase Order", cur_frm.cscript.make_purchase_order);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onload_post_render: function(doc, dt, dn) {
|
|
||||||
var me = this;
|
|
||||||
var callback = function(doc, dt, dn) {
|
|
||||||
cur_frm.cscript.load_taxes(me.frm.doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: improve this
|
|
||||||
if(this.frm.doc.__islocal) {
|
|
||||||
if (this.frm.fields_dict.price_list_name && this.frm.doc.price_list_name) {
|
|
||||||
this.price_list_name(callback);
|
|
||||||
} else {
|
|
||||||
callback(doc, dt, dn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var new_cscript = new erpnext.buying.SupplierQuotationController({frm: cur_frm});
|
var new_cscript = new erpnext.buying.SupplierQuotationController({frm: cur_frm});
|
||||||
@ -56,19 +38,6 @@ var new_cscript = new erpnext.buying.SupplierQuotationController({frm: cur_frm})
|
|||||||
// for backward compatibility: combine new and previous states
|
// for backward compatibility: combine new and previous states
|
||||||
$.extend(cur_frm.cscript, new_cscript);
|
$.extend(cur_frm.cscript, new_cscript);
|
||||||
|
|
||||||
|
|
||||||
cur_frm.cscript.onload = function(doc, dt, dn) {
|
|
||||||
// set missing values in parent doc
|
|
||||||
set_missing_values(doc, {
|
|
||||||
fiscal_year: sys_defaults.fiscal_year,
|
|
||||||
conversion_rate: 1,
|
|
||||||
currency: sys_defaults.currency,
|
|
||||||
status: "Draft",
|
|
||||||
transaction_date: get_today(),
|
|
||||||
is_subcontracted: "No"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_frm.cscript.make_purchase_order = function() {
|
cur_frm.cscript.make_purchase_order = function() {
|
||||||
var new_po_name = wn.model.make_new_doc_and_get_name("Purchase Order");
|
var new_po_name = wn.model.make_new_doc_and_get_name("Purchase Order");
|
||||||
$c("dt_map", {
|
$c("dt_map", {
|
||||||
|
@ -66,6 +66,9 @@ def get_item_details(args):
|
|||||||
out.import_ref_rate = out.import_rate = 0.0
|
out.import_ref_rate = out.import_rate = 0.0
|
||||||
out.update(_get_price_list_rate(args, item_bean, meta))
|
out.update(_get_price_list_rate(args, item_bean, meta))
|
||||||
|
|
||||||
|
if args.doctype == "Material Request":
|
||||||
|
out.min_order_qty = flt(item.min_order_qty)
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
def _get_basic_details(args, item_bean):
|
def _get_basic_details(args, item_bean):
|
||||||
|
@ -16,14 +16,254 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import webnotes
|
import webnotes
|
||||||
from webnotes.utils import flt
|
from webnotes import _, msgprint
|
||||||
|
from webnotes.utils import flt, cint
|
||||||
from utilities.transaction_base import TransactionBase
|
from setup.utils import get_company_currency, get_price_list_currency
|
||||||
|
from utilities.transaction_base import TransactionBase, validate_conversion_rate
|
||||||
|
import json
|
||||||
|
|
||||||
class AccountsController(TransactionBase):
|
class AccountsController(TransactionBase):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
if self.meta.get_field("grand_total"):
|
self.set_missing_values(for_validate=True)
|
||||||
|
|
||||||
|
if self.meta.get_field("currency"):
|
||||||
|
self.company_currency = get_company_currency(self.doc.company)
|
||||||
|
|
||||||
|
validate_conversion_rate(self.doc.currency, self.doc.conversion_rate,
|
||||||
|
self.meta.get_label("conversion_rate"), self.doc.company)
|
||||||
|
|
||||||
|
# self.calculate_taxes_and_totals()
|
||||||
self.validate_value("grand_total", ">=", 0)
|
self.validate_value("grand_total", ">=", 0)
|
||||||
|
self.set_total_in_words()
|
||||||
|
|
||||||
|
def set_price_list_currency(self, buying_or_selling):
|
||||||
|
# TODO - change this, since price list now has only one currency allowed
|
||||||
|
if self.meta.get_field("price_list_name") and self.doc.price_list_name and \
|
||||||
|
not self.doc.price_list_currency:
|
||||||
|
self.doc.fields.update(get_price_list_currency({
|
||||||
|
"price_list_name": self.doc.price_list_name,
|
||||||
|
"use_for": buying_or_selling
|
||||||
|
}))
|
||||||
|
|
||||||
|
def set_missing_item_details(self, get_item_details):
|
||||||
|
"""set missing item values"""
|
||||||
|
for item in self.doclist.get({"parentfield": self.fname}):
|
||||||
|
if item.fields.get("item_code"):
|
||||||
|
args = item.fields.copy().update(self.doc.fields)
|
||||||
|
ret = get_item_details(args)
|
||||||
|
for fieldname, value in ret.items():
|
||||||
|
if self.meta.get_field(fieldname, parentfield=self.fname) and \
|
||||||
|
not item.fields.get(fieldname):
|
||||||
|
item.fields[fieldname] = value
|
||||||
|
|
||||||
|
def set_taxes(self, tax_doctype, tax_parentfield, tax_master_field):
|
||||||
|
if not self.meta.get_field(tax_parentfield):
|
||||||
|
return
|
||||||
|
|
||||||
|
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})
|
||||||
|
|
||||||
|
if self.doc.fields.get(tax_master_field):
|
||||||
|
from webnotes.model import default_fields
|
||||||
|
tax_master = webnotes.bean(tax_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:
|
||||||
|
tax.fields[fieldname] = None
|
||||||
|
|
||||||
|
tax.fields.update({
|
||||||
|
"doctype": tax_doctype,
|
||||||
|
"parentfield": tax_parentfield,
|
||||||
|
"idx": i+1
|
||||||
|
})
|
||||||
|
|
||||||
|
self.doclist.append(tax)
|
||||||
|
|
||||||
|
def calculate_taxes_and_totals(self):
|
||||||
|
self.doc.conversion_rate = flt(self.doc.conversion_rate)
|
||||||
|
|
||||||
|
# TODO validate conversion rate
|
||||||
|
|
||||||
|
self.item_doclist = self.doclist.get({"parentfield": self.fname})
|
||||||
|
self.tax_doclist = self.doclist.get({"parentfield": self.other_fname})
|
||||||
|
|
||||||
|
self.calculate_item_values()
|
||||||
|
self.initialize_taxes()
|
||||||
|
|
||||||
|
if hasattr(self, "determine_exclusive_rate"):
|
||||||
|
self.determine_exclusive_rate()
|
||||||
|
|
||||||
|
self.calculate_net_total()
|
||||||
|
self.calculate_taxes()
|
||||||
|
self.calculate_totals()
|
||||||
|
self._cleanup()
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
# print format: show net_total_export instead of net_total
|
||||||
|
|
||||||
|
def initialize_taxes(self):
|
||||||
|
for tax in self.tax_doclist:
|
||||||
|
tax.item_wise_tax_detail = {}
|
||||||
|
for fieldname in ["tax_amount", "total",
|
||||||
|
"tax_amount_for_current_item", "grand_total_for_current_item",
|
||||||
|
"tax_fraction_for_current_item", "grand_total_fraction_for_current_item"]:
|
||||||
|
tax.fields[fieldname] = 0.0
|
||||||
|
|
||||||
|
self.validate_on_previous_row(tax)
|
||||||
|
self.validate_inclusive_tax(tax)
|
||||||
|
self.round_floats_in(tax)
|
||||||
|
|
||||||
|
def validate_on_previous_row(self, tax):
|
||||||
|
"""
|
||||||
|
validate if a valid row id is mentioned in case of
|
||||||
|
On Previous Row Amount and On Previous Row Total
|
||||||
|
"""
|
||||||
|
if tax.charge_type in ["On Previous Row Amount", "On Previous Row Total"] and \
|
||||||
|
(not tax.row_id or cint(tax.row_id) >= tax.idx):
|
||||||
|
msgprint((_("Row") + " # %(idx)s [%(taxes_doctype)s]: " + \
|
||||||
|
_("Please specify a valid") + " %(row_id_label)s") % {
|
||||||
|
"idx": tax.idx,
|
||||||
|
"taxes_doctype": tax.doctype,
|
||||||
|
"row_id_label": self.meta.get_label("row_id",
|
||||||
|
parentfield=self.other_fname)
|
||||||
|
}, raise_exception=True)
|
||||||
|
|
||||||
|
def validate_inclusive_tax(self, tax):
|
||||||
|
def _on_previous_row_error(row_range):
|
||||||
|
msgprint((_("Row") + " # %(idx)s [%(doctype)s]: " +
|
||||||
|
_("to be included in Item's rate, it is required that: ") +
|
||||||
|
" [" + _("Row") + " # %(row_range)s] " + _("also be included in Item's rate")) % {
|
||||||
|
"idx": tax.idx,
|
||||||
|
"doctype": tax.doctype,
|
||||||
|
"inclusive_label": self.meta.get_label("included_in_print_rate",
|
||||||
|
parentfield=self.other_fname),
|
||||||
|
"charge_type_label": self.meta.get_label("charge_type",
|
||||||
|
parentfield=self.other_fname),
|
||||||
|
"charge_type": tax.charge_type,
|
||||||
|
"row_range": row_range
|
||||||
|
}, raise_exception=True)
|
||||||
|
|
||||||
|
if cint(tax.included_in_print_rate):
|
||||||
|
if tax.charge_type == "Actual":
|
||||||
|
# inclusive tax cannot be of type Actual
|
||||||
|
msgprint((_("Row")
|
||||||
|
+ " # %(idx)s [%(doctype)s]: %(charge_type_label)s = \"%(charge_type)s\" "
|
||||||
|
+ "cannot be included in Item's rate") % {
|
||||||
|
"idx": tax.idx,
|
||||||
|
"doctype": tax.doctype,
|
||||||
|
"charge_type_label": self.meta.get_label("charge_type",
|
||||||
|
parentfield=self.other_fname),
|
||||||
|
"charge_type": tax.charge_type,
|
||||||
|
}, raise_exception=True)
|
||||||
|
elif tax.charge_type == "On Previous Row Amount" and \
|
||||||
|
not cint(self.tax_doclist[tax.row_id - 1].included_in_print_rate):
|
||||||
|
# referred row should also be inclusive
|
||||||
|
_on_previous_row_error(tax.row_id)
|
||||||
|
elif tax.charge_type == "On Previous Row Total" and \
|
||||||
|
not all([cint(t.included_in_print_rate) for t in self.tax_doclist[:tax.row_id - 1]]):
|
||||||
|
# all rows about the reffered tax should be inclusive
|
||||||
|
_on_previous_row_error("1 - %d" % (tax.row_id,))
|
||||||
|
|
||||||
|
def calculate_taxes(self):
|
||||||
|
for item in self.item_doclist:
|
||||||
|
item_tax_map = self._load_item_tax_rate(item.item_tax_rate)
|
||||||
|
|
||||||
|
for i, tax in enumerate(self.tax_doclist):
|
||||||
|
# tax_amount represents the amount of tax for the current step
|
||||||
|
current_tax_amount = self.get_current_tax_amount(item, tax, item_tax_map)
|
||||||
|
|
||||||
|
if hasattr(self, "set_item_tax_amount"):
|
||||||
|
self.set_item_tax_amount(item, tax, current_tax_amount)
|
||||||
|
|
||||||
|
# case when net total is 0 but there is an actual type charge
|
||||||
|
# in this case add the actual amount to tax.tax_amount
|
||||||
|
# and tax.grand_total_for_current_item for the first such iteration
|
||||||
|
if tax.charge_type=="Actual" and \
|
||||||
|
not (current_tax_amount or self.doc.net_total or tax.tax_amount):
|
||||||
|
zero_net_total_adjustment = flt(tax.rate, self.precision("tax_amount", tax))
|
||||||
|
current_tax_amount += zero_net_total_adjustment
|
||||||
|
|
||||||
|
# store tax_amount for current item as it will be used for
|
||||||
|
# charge type = 'On Previous Row Amount'
|
||||||
|
tax.tax_amount_for_current_item = current_tax_amount
|
||||||
|
|
||||||
|
# accumulate tax amount into tax.tax_amount
|
||||||
|
tax.tax_amount += current_tax_amount
|
||||||
|
|
||||||
|
# store tax breakup for each item
|
||||||
|
tax.item_wise_tax_detail[item.item_code] = current_tax_amount
|
||||||
|
|
||||||
|
if tax.category:
|
||||||
|
# if just for valuation, do not add the tax amount in total
|
||||||
|
# hence, setting it as 0 for further steps
|
||||||
|
current_tax_amount = 0.0 if (tax.category == "Valuation") else current_tax_amount
|
||||||
|
|
||||||
|
current_tax_amount *= -1.0 if (tax.add_deduct_tax == "Deduct") else 1.0
|
||||||
|
|
||||||
|
# Calculate tax.total viz. grand total till that step
|
||||||
|
# note: grand_total_for_current_item contains the contribution of
|
||||||
|
# item's amount, previously applied tax and the current tax on that item
|
||||||
|
if i==0:
|
||||||
|
tax.grand_total_for_current_item = flt(item.amount +
|
||||||
|
current_tax_amount, self.precision("total", tax))
|
||||||
|
|
||||||
|
else:
|
||||||
|
tax.grand_total_for_current_item = \
|
||||||
|
flt(self.tax_doclist[i-1].grand_total_for_current_item +
|
||||||
|
current_tax_amount, self.precision("total", tax))
|
||||||
|
|
||||||
|
# in tax.total, accumulate grand total of each item
|
||||||
|
tax.total += tax.grand_total_for_current_item
|
||||||
|
|
||||||
|
def get_current_tax_amount(self, item, tax, item_tax_map):
|
||||||
|
tax_rate = self._get_tax_rate(tax, item_tax_map)
|
||||||
|
current_tax_amount = 0.0
|
||||||
|
|
||||||
|
if tax.charge_type == "Actual":
|
||||||
|
# distribute the tax amount proportionally to each item row
|
||||||
|
actual = flt(tax.rate, self.precision("tax_amount", tax))
|
||||||
|
current_tax_amount = (self.doc.net_total
|
||||||
|
and ((item.amount / self.doc.net_total) * actual)
|
||||||
|
or 0)
|
||||||
|
elif tax.charge_type == "On Net Total":
|
||||||
|
current_tax_amount = (tax_rate / 100.0) * item.amount
|
||||||
|
elif tax.charge_type == "On Previous Row Amount":
|
||||||
|
current_tax_amount = (tax_rate / 100.0) * \
|
||||||
|
self.tax_doclist[cint(tax.row_id) - 1].tax_amount_for_current_item
|
||||||
|
elif tax.charge_type == "On Previous Row Total":
|
||||||
|
current_tax_amount = (tax_rate / 100.0) * \
|
||||||
|
self.tax_doclist[cint(tax.row_id) - 1].grand_total_for_current_item
|
||||||
|
|
||||||
|
return flt(current_tax_amount, self.precision("tax_amount", tax))
|
||||||
|
|
||||||
|
def _load_item_tax_rate(self, item_tax_rate):
|
||||||
|
return json.loads(item_tax_rate) if item_tax_rate else {}
|
||||||
|
|
||||||
|
def _get_tax_rate(self, tax, item_tax_map):
|
||||||
|
if item_tax_map.has_key(tax.account_head):
|
||||||
|
return flt(item_tax_map.get(tax.account_head), self.precision("rate", tax))
|
||||||
|
else:
|
||||||
|
return tax.rate
|
||||||
|
|
||||||
|
def _cleanup(self):
|
||||||
|
for tax in self.tax_doclist:
|
||||||
|
for fieldname in ("grand_total_for_current_item",
|
||||||
|
"tax_amount_for_current_item",
|
||||||
|
"tax_fraction_for_current_item",
|
||||||
|
"grand_total_fraction_for_current_item"):
|
||||||
|
if fieldname in tax.fields:
|
||||||
|
del tax.fields[fieldname]
|
||||||
|
|
||||||
|
tax.item_wise_tax_detail = json.dumps(tax.item_wise_tax_detail)
|
||||||
|
|
||||||
|
def _set_in_company_currency(self, item, print_field, base_field):
|
||||||
|
"""set values in base currency"""
|
||||||
|
item.fields[base_field] = flt((flt(item.fields[print_field],
|
||||||
|
self.precision(print_field, item)) * self.doc.conversion_rate),
|
||||||
|
self.precision(base_field, item))
|
||||||
|
|
||||||
def get_gl_dict(self, args, cancel=None):
|
def get_gl_dict(self, args, cancel=None):
|
||||||
"""this method populates the common properties of a gl entry record"""
|
"""this method populates the common properties of a gl entry record"""
|
||||||
|
@ -17,33 +17,44 @@
|
|||||||
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 flt, cint
|
from webnotes.utils import flt
|
||||||
import json
|
|
||||||
|
|
||||||
from buying.utils import get_item_details
|
from buying.utils import get_item_details
|
||||||
from setup.utils import get_company_currency
|
from setup.utils import get_company_currency
|
||||||
from utilities.transaction_base import validate_conversion_rate
|
|
||||||
|
|
||||||
from controllers.stock_controller import StockController
|
from controllers.stock_controller import StockController
|
||||||
|
|
||||||
class WrongWarehouseCompany(Exception): pass
|
class WrongWarehouseCompany(Exception): pass
|
||||||
|
|
||||||
class BuyingController(StockController):
|
class BuyingController(StockController):
|
||||||
|
def onload_post_render(self):
|
||||||
|
self.set_price_list_currency("buying")
|
||||||
|
|
||||||
|
# contact, address, item details
|
||||||
|
self.set_missing_values()
|
||||||
|
|
||||||
|
self.set_taxes("Purchase Taxes and Charges", "purchase_tax_details", "purchase_other_charges")
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
super(BuyingController, self).validate()
|
super(BuyingController, self).validate()
|
||||||
self.validate_stock_or_nonstock_items()
|
self.validate_stock_or_nonstock_items()
|
||||||
self.validate_warehouse_belongs_to_company()
|
self.validate_warehouse_belongs_to_company()
|
||||||
|
|
||||||
if self.meta.get_field("currency"):
|
def set_missing_values(self, for_validate=False):
|
||||||
self.company_currency = get_company_currency(self.doc.company)
|
# set contact and address details for supplier, if they are not mentioned
|
||||||
validate_conversion_rate(self.doc.currency, self.doc.conversion_rate,
|
if self.doc.supplier and not (self.doc.contact_person and self.doc.supplier_address):
|
||||||
self.meta.get_label("conversion_rate"), self.doc.company)
|
for fieldname, val in self.get_default_address_and_contact("supplier").items():
|
||||||
|
if not self.doc.fields.get(fieldname) and self.meta.get_field(fieldname):
|
||||||
|
self.doc.fields[fieldname] = val
|
||||||
|
|
||||||
# IMPORTANT: enable this only when client side code is similar to this one
|
self.set_missing_item_details(get_item_details)
|
||||||
# self.calculate_taxes_and_totals()
|
|
||||||
|
|
||||||
# set total in words
|
def set_supplier_defaults(self):
|
||||||
self.set_total_in_words()
|
self.get_default_supplier_address()
|
||||||
|
|
||||||
|
def get_purchase_tax_details(self):
|
||||||
|
self.doclist = self.doc.clear_table(self.doclist, "purchase_tax_details")
|
||||||
|
self.set_taxes()
|
||||||
|
|
||||||
def validate_warehouse_belongs_to_company(self):
|
def validate_warehouse_belongs_to_company(self):
|
||||||
for warehouse, company in webnotes.conn.get_values("Warehouse",
|
for warehouse, company in webnotes.conn.get_values("Warehouse",
|
||||||
@ -70,24 +81,6 @@ class BuyingController(StockController):
|
|||||||
webnotes.msgprint(_("""Tax Category can not be 'Valuation' or 'Valuation and Total'
|
webnotes.msgprint(_("""Tax Category can not be 'Valuation' or 'Valuation and Total'
|
||||||
as all items are non-stock items"""), raise_exception=1)
|
as all items are non-stock items"""), raise_exception=1)
|
||||||
|
|
||||||
def update_item_details(self):
|
|
||||||
for item in self.doclist.get({"parentfield": self.fname}):
|
|
||||||
ret = get_item_details({
|
|
||||||
"doctype": self.doc.doctype,
|
|
||||||
"docname": self.doc.name,
|
|
||||||
"item_code": item.item_code,
|
|
||||||
"warehouse": item.warehouse,
|
|
||||||
"supplier": self.doc.supplier,
|
|
||||||
"transaction_date": self.doc.posting_date,
|
|
||||||
"conversion_rate": self.doc.conversion_rate,
|
|
||||||
"price_list_name": self.doc.price_list_name,
|
|
||||||
"price_list_currency": self.doc.price_list_currency,
|
|
||||||
"plc_conversion_rate": self.doc.plc_conversion_rate
|
|
||||||
})
|
|
||||||
for r in ret:
|
|
||||||
if not item.fields.get(r):
|
|
||||||
item.fields[r] = ret[r]
|
|
||||||
|
|
||||||
def set_total_in_words(self):
|
def set_total_in_words(self):
|
||||||
from webnotes.utils import money_in_words
|
from webnotes.utils import money_in_words
|
||||||
company_currency = get_company_currency(self.doc.company)
|
company_currency = get_company_currency(self.doc.company)
|
||||||
@ -98,26 +91,11 @@ class BuyingController(StockController):
|
|||||||
self.doc.currency)
|
self.doc.currency)
|
||||||
|
|
||||||
def calculate_taxes_and_totals(self):
|
def calculate_taxes_and_totals(self):
|
||||||
self.doc.conversion_rate = flt(self.doc.conversion_rate)
|
self.other_fname = "purchase_tax_details"
|
||||||
self.item_doclist = self.doclist.get({"parentfield": self.fname})
|
super(BuyingController, self).calculate_taxes_and_totals()
|
||||||
self.tax_doclist = self.doclist.get({"parentfield": "purchase_tax_details"})
|
|
||||||
|
|
||||||
self.calculate_item_values()
|
|
||||||
self.initialize_taxes()
|
|
||||||
self.calculate_net_total()
|
|
||||||
self.calculate_taxes()
|
|
||||||
self.calculate_totals()
|
|
||||||
self.calculate_outstanding_amount()
|
self.calculate_outstanding_amount()
|
||||||
|
|
||||||
self._cleanup()
|
|
||||||
|
|
||||||
def calculate_item_values(self):
|
def calculate_item_values(self):
|
||||||
def _set_base(item, print_field, base_field):
|
|
||||||
"""set values in base currency"""
|
|
||||||
item.fields[base_field] = flt((flt(item.fields[print_field],
|
|
||||||
self.precision(print_field, item)) * self.doc.conversion_rate),
|
|
||||||
self.precision(base_field, item))
|
|
||||||
|
|
||||||
# hack! - cleaned up in _cleanup()
|
# hack! - cleaned up in _cleanup()
|
||||||
if self.doc.doctype != "Purchase Invoice":
|
if self.doc.doctype != "Purchase Invoice":
|
||||||
df = self.meta.get_field("purchase_rate", parentfield=self.fname)
|
df = self.meta.get_field("purchase_rate", parentfield=self.fname)
|
||||||
@ -130,119 +108,36 @@ class BuyingController(StockController):
|
|||||||
|
|
||||||
self.round_floats_in(item)
|
self.round_floats_in(item)
|
||||||
|
|
||||||
if item.discount_rate == 100:
|
if item.discount_rate == 100.0:
|
||||||
item.import_ref_rate = item.import_ref_rate or item.import_rate
|
item.import_rate = 0.0
|
||||||
item.import_rate = 0
|
elif item.import_ref_rate:
|
||||||
else:
|
|
||||||
if item.import_ref_rate:
|
|
||||||
item.import_rate = flt(item.import_ref_rate * (1.0 - (item.discount_rate / 100.0)),
|
item.import_rate = flt(item.import_ref_rate * (1.0 - (item.discount_rate / 100.0)),
|
||||||
self.precision("import_rate", item))
|
self.precision("import_rate", item))
|
||||||
else:
|
|
||||||
# assume that print rate and discount_rate are specified
|
|
||||||
item.import_ref_rate = flt(item.import_rate / (1.0 - (item.discount_rate / 100.0)),
|
|
||||||
self.precision("import_ref_rate", item))
|
|
||||||
|
|
||||||
item.import_amount = flt(item.import_rate * item.qty,
|
item.import_amount = flt(item.import_rate * item.qty,
|
||||||
self.precision("import_amount", item))
|
self.precision("import_amount", item))
|
||||||
|
item.item_tax_amount = 0.0;
|
||||||
|
|
||||||
_set_base(item, "import_ref_rate", "purchase_ref_rate")
|
self._set_in_company_currency(item, "import_ref_rate", "purchase_ref_rate")
|
||||||
_set_base(item, "import_rate", "rate")
|
self._set_in_company_currency(item, "import_rate", "rate")
|
||||||
_set_base(item, "import_amount", "amount")
|
self._set_in_company_currency(item, "import_amount", "amount")
|
||||||
|
|
||||||
def initialize_taxes(self):
|
|
||||||
for tax in self.tax_doclist:
|
|
||||||
# initialize totals to 0
|
|
||||||
tax.tax_amount = tax.total = 0.0
|
|
||||||
|
|
||||||
# temporary fields
|
|
||||||
tax.tax_amount_for_current_item = tax.grand_total_for_current_item = 0.0
|
|
||||||
|
|
||||||
tax.item_wise_tax_detail = {}
|
|
||||||
|
|
||||||
self.validate_on_previous_row(tax)
|
|
||||||
|
|
||||||
self.round_floats_in(tax)
|
|
||||||
|
|
||||||
def calculate_net_total(self):
|
def calculate_net_total(self):
|
||||||
self.doc.net_total = 0
|
self.doc.net_total = self.doc.net_total_import = 0.0
|
||||||
self.doc.net_total_import = 0
|
|
||||||
|
|
||||||
for item in self.item_doclist:
|
for item in self.item_doclist:
|
||||||
self.doc.net_total += item.amount
|
self.doc.net_total += item.amount
|
||||||
self.doc.net_total_import += item.import_amount
|
self.doc.net_total_import += item.import_amount
|
||||||
|
|
||||||
self.doc.net_total = flt(self.doc.net_total, self.precision("net_total"))
|
self.round_floats_in(self.doc, ["net_total", "net_total_import"])
|
||||||
self.doc.net_total_import = flt(self.doc.net_total_import,
|
|
||||||
self.precision("net_total_import"))
|
|
||||||
|
|
||||||
def calculate_taxes(self):
|
|
||||||
for item in self.item_doclist:
|
|
||||||
item_tax_map = self._load_item_tax_rate(item.item_tax_rate)
|
|
||||||
item.item_tax_amount = 0
|
|
||||||
|
|
||||||
for i, tax in enumerate(self.tax_doclist):
|
|
||||||
# tax_amount represents the amount of tax for the current step
|
|
||||||
current_tax_amount = self.get_current_tax_amount(item, tax, item_tax_map)
|
|
||||||
|
|
||||||
self.set_item_tax_amount(item, tax, current_tax_amount)
|
|
||||||
|
|
||||||
# case when net total is 0 but there is an actual type charge
|
|
||||||
# in this case add the actual amount to tax.tax_amount
|
|
||||||
# and tax.grand_total_for_current_item for the first such iteration
|
|
||||||
if not (current_tax_amount or self.doc.net_total or tax.tax_amount) and \
|
|
||||||
tax.charge_type=="Actual":
|
|
||||||
zero_net_total_adjustment = flt(tax.rate, self.precision("tax_amount", tax))
|
|
||||||
current_tax_amount += zero_net_total_adjustment
|
|
||||||
|
|
||||||
# store tax_amount for current item as it will be used for
|
|
||||||
# charge type = 'On Previous Row Amount'
|
|
||||||
tax.tax_amount_for_current_item = current_tax_amount
|
|
||||||
|
|
||||||
# accumulate tax amount into tax.tax_amount
|
|
||||||
tax.tax_amount += tax.tax_amount_for_current_item
|
|
||||||
|
|
||||||
if tax.category == "Valuation":
|
|
||||||
# if just for valuation, do not add the tax amount in total
|
|
||||||
# hence, setting it as 0 for further steps
|
|
||||||
current_tax_amount = 0
|
|
||||||
else:
|
|
||||||
current_tax_amount *= tax.add_deduct_tax == "Deduct" and -1.0 or 1.0
|
|
||||||
|
|
||||||
# Calculate tax.total viz. grand total till that step
|
|
||||||
# note: grand_total_for_current_item contains the contribution of
|
|
||||||
# item's amount, previously applied tax and the current tax on that item
|
|
||||||
if i==0:
|
|
||||||
tax.grand_total_for_current_item = flt(item.amount +
|
|
||||||
current_tax_amount, self.precision("total", tax))
|
|
||||||
|
|
||||||
else:
|
|
||||||
tax.grand_total_for_current_item = \
|
|
||||||
flt(self.tax_doclist[i-1].grand_total_for_current_item +
|
|
||||||
current_tax_amount, self.precision("total", tax))
|
|
||||||
|
|
||||||
# in tax.total, accumulate grand total of each item
|
|
||||||
tax.total += tax.grand_total_for_current_item
|
|
||||||
|
|
||||||
# store tax_breakup for each item
|
|
||||||
# DOUBT: should valuation type amount also be stored?
|
|
||||||
tax.item_wise_tax_detail[item.item_code] = current_tax_amount
|
|
||||||
|
|
||||||
def calculate_totals(self):
|
def calculate_totals(self):
|
||||||
if self.tax_doclist:
|
self.doc.grand_total = flt(self.tax_doclist and \
|
||||||
self.doc.grand_total = flt(self.tax_doclist[-1].total,
|
self.tax_doclist[-1].total or self.doc.net_total, self.precision("grand_total"))
|
||||||
self.precision("grand_total"))
|
self.doc.grand_total_import = flt(self.doc.grand_total / self.doc.conversion_rate,
|
||||||
self.doc.grand_total_import = flt(
|
|
||||||
self.doc.grand_total / self.doc.conversion_rate,
|
|
||||||
self.precision("grand_total_import"))
|
|
||||||
else:
|
|
||||||
self.doc.grand_total = flt(self.doc.net_total,
|
|
||||||
self.precision("grand_total"))
|
|
||||||
self.doc.grand_total_import = flt(
|
|
||||||
self.doc.grand_total / self.doc.conversion_rate,
|
|
||||||
self.precision("grand_total_import"))
|
self.precision("grand_total_import"))
|
||||||
|
|
||||||
self.doc.total_tax = \
|
self.doc.total_tax = flt(self.doc.grand_total - self.doc.net_total,
|
||||||
flt(self.doc.grand_total - self.doc.net_total,
|
|
||||||
self.precision("total_tax"))
|
self.precision("total_tax"))
|
||||||
|
|
||||||
if self.meta.get_field("rounded_total"):
|
if self.meta.get_field("rounded_total"):
|
||||||
@ -261,67 +156,17 @@ class BuyingController(StockController):
|
|||||||
self.precision("outstanding_amount"))
|
self.precision("outstanding_amount"))
|
||||||
|
|
||||||
def _cleanup(self):
|
def _cleanup(self):
|
||||||
for tax in self.tax_doclist:
|
super(BuyingController, self)._cleanup()
|
||||||
del tax.fields["grand_total_for_current_item"]
|
|
||||||
del tax.fields["tax_amount_for_current_item"]
|
|
||||||
tax.item_wise_tax_detail = json.dumps(tax.item_wise_tax_detail)
|
|
||||||
|
|
||||||
# except in purchase invoice, rate field is purchase_rate
|
# except in purchase invoice, rate field is purchase_rate
|
||||||
if self.doc.doctype != "Purchase Invoice":
|
|
||||||
for item in self.item_doclist:
|
|
||||||
item.purchase_rate = item.rate
|
|
||||||
del item.fields["rate"]
|
|
||||||
|
|
||||||
# reset fieldname of rate
|
# reset fieldname of rate
|
||||||
if self.doc.doctype != "Purchase Invoice":
|
if self.doc.doctype != "Purchase Invoice":
|
||||||
df = self.meta.get_field("rate", parentfield=self.fname)
|
df = self.meta.get_field("rate", parentfield=self.fname)
|
||||||
df.fieldname = "purchase_rate"
|
df.fieldname = "purchase_rate"
|
||||||
|
|
||||||
def validate_on_previous_row(self, tax):
|
for item in self.item_doclist:
|
||||||
"""
|
item.purchase_rate = item.rate
|
||||||
validate if a valid row id is mentioned in case of
|
del item.fields["rate"]
|
||||||
On Previous Row Amount and On Previous Row Total
|
|
||||||
"""
|
|
||||||
if tax.charge_type in ["On Previous Row Amount", "On Previous Row Total"] and \
|
|
||||||
(not tax.row_id or cint(tax.row_id) >= tax.idx):
|
|
||||||
msgprint((_("Row") + " # %(idx)s [%(taxes_doctype)s]: " + \
|
|
||||||
_("Please specify a valid") + " %(row_id_label)s") % {
|
|
||||||
"idx": tax.idx,
|
|
||||||
"taxes_doctype": tax.parenttype,
|
|
||||||
"row_id_label": self.meta.get_label("row_id",
|
|
||||||
parentfield="purchase_tax_details")
|
|
||||||
}, raise_exception=True)
|
|
||||||
|
|
||||||
def _load_item_tax_rate(self, item_tax_rate):
|
|
||||||
if not item_tax_rate:
|
|
||||||
return {}
|
|
||||||
return json.loads(item_tax_rate)
|
|
||||||
|
|
||||||
def get_current_tax_amount(self, item, tax, item_tax_map):
|
|
||||||
tax_rate = self._get_tax_rate(tax, item_tax_map)
|
|
||||||
|
|
||||||
if tax.charge_type == "Actual":
|
|
||||||
# distribute the tax amount proportionally to each item row
|
|
||||||
actual = flt(tax.rate, self.precision("tax_amount", tax))
|
|
||||||
current_tax_amount = (self.doc.net_total
|
|
||||||
and ((item.amount / self.doc.net_total) * actual)
|
|
||||||
or 0)
|
|
||||||
elif tax.charge_type == "On Net Total":
|
|
||||||
current_tax_amount = (tax_rate / 100.0) * item.amount
|
|
||||||
elif tax.charge_type == "On Previous Row Amount":
|
|
||||||
current_tax_amount = (tax_rate / 100.0) * \
|
|
||||||
self.tax_doclist[cint(tax.row_id) - 1].tax_amount_for_current_item
|
|
||||||
elif tax.charge_type == "On Previous Row Total":
|
|
||||||
current_tax_amount = (tax_rate / 100.0) * \
|
|
||||||
self.tax_doclist[cint(tax.row_id) - 1].grand_total_for_current_item
|
|
||||||
|
|
||||||
return flt(current_tax_amount, self.precision("tax_amount", tax))
|
|
||||||
|
|
||||||
def _get_tax_rate(self, tax, item_tax_map):
|
|
||||||
if item_tax_map.has_key(tax.account_head):
|
|
||||||
return flt(item_tax_map.get(tax.account_head), self.precision("rate", tax))
|
|
||||||
else:
|
|
||||||
return tax.rate
|
|
||||||
|
|
||||||
def set_item_tax_amount(self, item, tax, current_tax_amount):
|
def set_item_tax_amount(self, item, tax, current_tax_amount):
|
||||||
"""
|
"""
|
||||||
@ -330,10 +175,8 @@ class BuyingController(StockController):
|
|||||||
|
|
||||||
TODO: rename item_tax_amount to valuation_tax_amount
|
TODO: rename item_tax_amount to valuation_tax_amount
|
||||||
"""
|
"""
|
||||||
if tax.category in ["Valuation", "Valuation and Total"] and \
|
if tax.category in ["Valuation", "Valuation and Total"]:
|
||||||
item.item_code in self.stock_items:
|
item.item_tax_amount += flt(current_tax_amount, self.precision("item_tax_amount", item))
|
||||||
item.item_tax_amount += flt(current_tax_amount,
|
|
||||||
self.precision("item_tax_amount", item))
|
|
||||||
|
|
||||||
# update valuation rate
|
# update valuation rate
|
||||||
def update_valuation_rate(self, parentfield):
|
def update_valuation_rate(self, parentfield):
|
||||||
|
@ -18,33 +18,19 @@ from __future__ import unicode_literals
|
|||||||
import webnotes
|
import webnotes
|
||||||
from webnotes.utils import cint, flt, comma_or
|
from webnotes.utils import cint, flt, comma_or
|
||||||
from setup.utils import get_company_currency
|
from setup.utils import get_company_currency
|
||||||
|
from selling.utils import get_item_details
|
||||||
from webnotes import msgprint, _
|
from webnotes import msgprint, _
|
||||||
import json
|
|
||||||
|
|
||||||
from controllers.stock_controller import StockController
|
from controllers.stock_controller import StockController
|
||||||
|
|
||||||
class SellingController(StockController):
|
class SellingController(StockController):
|
||||||
def onload_post_render(self):
|
def onload_post_render(self):
|
||||||
self.set_price_list_currency()
|
self.set_price_list_currency("selling")
|
||||||
|
|
||||||
# contact, address, item details and pos details (if applicable)
|
# contact, address, item details and pos details (if applicable)
|
||||||
self.set_missing_values()
|
self.set_missing_values()
|
||||||
|
|
||||||
if self.meta.get_field("other_charges"):
|
self.set_taxes("Sales Taxes and Charges", "other_charges", "charge")
|
||||||
self.set_taxes()
|
|
||||||
|
|
||||||
def validate(self):
|
|
||||||
super(SellingController, self).validate()
|
|
||||||
# self.calculate_taxes_and_totals()
|
|
||||||
self.set_total_in_words()
|
|
||||||
self.set_missing_values(for_validate=True)
|
|
||||||
|
|
||||||
def set_price_list_currency(self):
|
|
||||||
if self.doc.price_list_name and not self.doc.price_list_currency:
|
|
||||||
# TODO - change this, since price list now has only one currency allowed
|
|
||||||
from setup.utils import get_price_list_currency
|
|
||||||
self.doc.fields.update(get_price_list_currency(
|
|
||||||
{"price_list_name": self.doc.price_list_name, "use_for": "selling"}))
|
|
||||||
|
|
||||||
def set_missing_values(self, for_validate=False):
|
def set_missing_values(self, for_validate=False):
|
||||||
# set contact and address details for customer, if they are not mentioned
|
# set contact and address details for customer, if they are not mentioned
|
||||||
@ -53,42 +39,11 @@ class SellingController(StockController):
|
|||||||
if not self.doc.fields.get(fieldname) and self.meta.get_field(fieldname):
|
if not self.doc.fields.get(fieldname) and self.meta.get_field(fieldname):
|
||||||
self.doc.fields[fieldname] = val
|
self.doc.fields[fieldname] = val
|
||||||
|
|
||||||
# set missing item values
|
self.set_missing_item_details(get_item_details)
|
||||||
from selling.utils import get_item_details
|
|
||||||
for item in self.doclist.get({"parentfield": "entries"}):
|
|
||||||
if item.fields.get("item_code"):
|
|
||||||
args = item.fields.copy().update(self.doc.fields)
|
|
||||||
ret = get_item_details(args)
|
|
||||||
for fieldname, value in ret.items():
|
|
||||||
if self.meta.get_field(fieldname, parentfield="entries") and \
|
|
||||||
not item.fields.get(fieldname):
|
|
||||||
item.fields[fieldname] = value
|
|
||||||
|
|
||||||
def set_taxes(self):
|
|
||||||
if not self.doclist.get({"parentfield": "other_charges"}):
|
|
||||||
if not self.doc.charge:
|
|
||||||
# get the default tax master
|
|
||||||
self.doc.charge = webnotes.conn.get_value("Sales Taxes and Charges Master",
|
|
||||||
{"is_default": 1})
|
|
||||||
|
|
||||||
if self.doc.charge:
|
|
||||||
from webnotes.model import default_fields
|
|
||||||
tax_master = webnotes.bean("Sales Taxes and Charges Master", self.doc.charge)
|
|
||||||
for i, tax in enumerate(tax_master.doclist.get({"parentfield": "other_charges"})):
|
|
||||||
for fieldname in default_fields:
|
|
||||||
tax.fields[fieldname] = None
|
|
||||||
|
|
||||||
tax.fields.update({
|
|
||||||
"doctype": "Sales Taxes and Charges",
|
|
||||||
"parentfield": "other_charges",
|
|
||||||
"idx": i+1
|
|
||||||
})
|
|
||||||
|
|
||||||
self.doclist.append(tax)
|
|
||||||
|
|
||||||
def get_other_charges(self):
|
def get_other_charges(self):
|
||||||
self.doclist = self.doc.clear_table(self.doclist, "other_charges")
|
self.doclist = self.doc.clear_table(self.doclist, "other_charges")
|
||||||
self.set_taxes()
|
self.set_taxes("Sales Taxes and Charges", "other_charges", "charge")
|
||||||
|
|
||||||
def set_customer_defaults(self):
|
def set_customer_defaults(self):
|
||||||
self.get_default_customer_address()
|
self.get_default_customer_address()
|
||||||
@ -140,23 +95,13 @@ class SellingController(StockController):
|
|||||||
raise_exception=1)
|
raise_exception=1)
|
||||||
|
|
||||||
def calculate_taxes_and_totals(self):
|
def calculate_taxes_and_totals(self):
|
||||||
self.doc.conversion_rate = flt(self.doc.conversion_rate)
|
self.other_fname = "other_charges"
|
||||||
self.item_doclist = self.doclist.get({"parentfield": self.fname})
|
|
||||||
self.tax_doclist = self.doclist.get({"parentfield": "other_charges"})
|
super(SellingController, self).calculate_taxes_and_totals()
|
||||||
|
|
||||||
self.calculate_item_values()
|
|
||||||
self.initialize_taxes()
|
|
||||||
self.determine_exclusive_rate()
|
|
||||||
self.calculate_net_total()
|
|
||||||
self.calculate_taxes()
|
|
||||||
self.calculate_totals()
|
|
||||||
self.calculate_commission()
|
self.calculate_commission()
|
||||||
self.calculate_contribution()
|
self.calculate_contribution()
|
||||||
# self.calculate_outstanding_amount()
|
# self.calculate_outstanding_amount()
|
||||||
self._cleanup()
|
|
||||||
|
|
||||||
# TODO
|
|
||||||
# print format: show net_total_export instead of net_total
|
|
||||||
|
|
||||||
def determine_exclusive_rate(self):
|
def determine_exclusive_rate(self):
|
||||||
if not any((cint(tax.included_in_print_rate) for tax in self.tax_doclist)):
|
if not any((cint(tax.included_in_print_rate) for tax in self.tax_doclist)):
|
||||||
@ -215,45 +160,21 @@ class SellingController(StockController):
|
|||||||
return current_tax_fraction
|
return current_tax_fraction
|
||||||
|
|
||||||
def calculate_item_values(self):
|
def calculate_item_values(self):
|
||||||
def _set_base(item, print_field, base_field):
|
|
||||||
"""set values in base currency"""
|
|
||||||
item.fields[base_field] = flt((flt(item.fields[print_field],
|
|
||||||
self.precision(print_field, item)) * self.doc.conversion_rate),
|
|
||||||
self.precision(base_field, item))
|
|
||||||
|
|
||||||
for item in self.item_doclist:
|
for item in self.item_doclist:
|
||||||
self.round_floats_in(item)
|
self.round_floats_in(item)
|
||||||
|
|
||||||
if item.adj_rate == 100:
|
if item.adj_rate == 100:
|
||||||
item.ref_rate = item.ref_rate or item.export_rate
|
|
||||||
item.export_rate = 0
|
item.export_rate = 0
|
||||||
else:
|
elif item.ref_rate:
|
||||||
if item.ref_rate:
|
|
||||||
item.export_rate = flt(item.ref_rate * (1.0 - (item.adj_rate / 100.0)),
|
item.export_rate = flt(item.ref_rate * (1.0 - (item.adj_rate / 100.0)),
|
||||||
self.precision("export_rate", item))
|
self.precision("export_rate", item))
|
||||||
else:
|
|
||||||
# assume that print rate and discount are specified
|
|
||||||
item.ref_rate = flt(item.export_rate / (1.0 - (item.adj_rate / 100.0)),
|
|
||||||
self.precision("ref_rate", item))
|
|
||||||
|
|
||||||
item.export_amount = flt(item.export_rate * item.qty,
|
item.export_amount = flt(item.export_rate * item.qty,
|
||||||
self.precision("export_amount", item))
|
self.precision("export_amount", item))
|
||||||
|
|
||||||
_set_base(item, "ref_rate", "base_ref_rate")
|
self._set_in_company_currency(item, "ref_rate", "base_ref_rate")
|
||||||
_set_base(item, "export_rate", "basic_rate")
|
self._set_in_company_currency(item, "export_rate", "basic_rate")
|
||||||
_set_base(item, "export_amount", "amount")
|
self._set_in_company_currency(item, "export_amount", "amount")
|
||||||
|
|
||||||
def initialize_taxes(self):
|
|
||||||
for tax in self.tax_doclist:
|
|
||||||
tax.tax_amount = tax.total = 0.0
|
|
||||||
tax.item_wise_tax_detail = {}
|
|
||||||
|
|
||||||
# temporary fields
|
|
||||||
tax.tax_amount_for_current_item = tax.grand_total_for_current_item = 0.0
|
|
||||||
|
|
||||||
self.validate_on_previous_row(tax)
|
|
||||||
self.validate_inclusive_tax(tax)
|
|
||||||
self.round_floats_in(tax)
|
|
||||||
|
|
||||||
def calculate_net_total(self):
|
def calculate_net_total(self):
|
||||||
self.doc.net_total = self.doc.net_total_export = 0.0
|
self.doc.net_total = self.doc.net_total_export = 0.0
|
||||||
@ -264,47 +185,6 @@ class SellingController(StockController):
|
|||||||
|
|
||||||
self.round_floats_in(self.doc, ["net_total", "net_total_export"])
|
self.round_floats_in(self.doc, ["net_total", "net_total_export"])
|
||||||
|
|
||||||
def calculate_taxes(self):
|
|
||||||
for item in self.item_doclist:
|
|
||||||
item_tax_map = self._load_item_tax_rate(item.item_tax_rate)
|
|
||||||
|
|
||||||
for i, tax in enumerate(self.tax_doclist):
|
|
||||||
# tax_amount represents the amount of tax for the current step
|
|
||||||
current_tax_amount = self.get_current_tax_amount(item, tax, item_tax_map)
|
|
||||||
|
|
||||||
# case when net total is 0 but there is an actual type charge
|
|
||||||
# in this case add the actual amount to tax.tax_amount
|
|
||||||
# and tax.grand_total_for_current_item for the first such iteration
|
|
||||||
if tax.charge_type=="Actual" and \
|
|
||||||
not (current_tax_amount or self.doc.net_total or tax.tax_amount):
|
|
||||||
zero_net_total_adjustment = flt(tax.rate, self.precision("tax_amount", tax))
|
|
||||||
current_tax_amount += zero_net_total_adjustment
|
|
||||||
|
|
||||||
# store tax_amount for current item as it will be used for
|
|
||||||
# charge type = 'On Previous Row Amount'
|
|
||||||
tax.tax_amount_for_current_item = current_tax_amount
|
|
||||||
|
|
||||||
# accumulate tax amount into tax.tax_amount
|
|
||||||
tax.tax_amount += current_tax_amount
|
|
||||||
|
|
||||||
# Calculate tax.total viz. grand total till that step
|
|
||||||
# note: grand_total_for_current_item contains the contribution of
|
|
||||||
# item's amount, previously applied tax and the current tax on that item
|
|
||||||
if i==0:
|
|
||||||
tax.grand_total_for_current_item = flt(item.amount +
|
|
||||||
current_tax_amount, self.precision("total", tax))
|
|
||||||
|
|
||||||
else:
|
|
||||||
tax.grand_total_for_current_item = \
|
|
||||||
flt(self.tax_doclist[i-1].grand_total_for_current_item +
|
|
||||||
current_tax_amount, self.precision("total", tax))
|
|
||||||
|
|
||||||
# in tax.total, accumulate grand total of each item
|
|
||||||
tax.total += tax.grand_total_for_current_item
|
|
||||||
|
|
||||||
# store tax breakup for each item
|
|
||||||
tax.item_wise_tax_detail[item.item_code] = current_tax_amount
|
|
||||||
|
|
||||||
def calculate_totals(self):
|
def calculate_totals(self):
|
||||||
self.doc.grand_total = flt(self.tax_doclist and \
|
self.doc.grand_total = flt(self.tax_doclist and \
|
||||||
self.tax_doclist[-1].total or self.doc.net_total, self.precision("grand_total"))
|
self.tax_doclist[-1].total or self.doc.net_total, self.precision("grand_total"))
|
||||||
@ -345,98 +225,6 @@ class SellingController(StockController):
|
|||||||
_(self.meta.get_label("allocated_percentage", parentfield="sales_team")) +
|
_(self.meta.get_label("allocated_percentage", parentfield="sales_team")) +
|
||||||
" " + _("should be 100%"), raise_exception=True)
|
" " + _("should be 100%"), raise_exception=True)
|
||||||
|
|
||||||
def get_current_tax_amount(self, item, tax, item_tax_map):
|
|
||||||
tax_rate = self._get_tax_rate(tax, item_tax_map)
|
|
||||||
current_tax_amount = 0.0
|
|
||||||
|
|
||||||
if tax.charge_type == "Actual":
|
|
||||||
# distribute the tax amount proportionally to each item row
|
|
||||||
actual = flt(tax.rate, self.precision("tax_amount", tax))
|
|
||||||
current_tax_amount = (self.doc.net_total
|
|
||||||
and ((item.amount / self.doc.net_total) * actual)
|
|
||||||
or 0)
|
|
||||||
elif tax.charge_type == "On Net Total":
|
|
||||||
current_tax_amount = (tax_rate / 100.0) * item.amount
|
|
||||||
elif tax.charge_type == "On Previous Row Amount":
|
|
||||||
current_tax_amount = (tax_rate / 100.0) * \
|
|
||||||
self.tax_doclist[cint(tax.row_id) - 1].tax_amount_for_current_item
|
|
||||||
elif tax.charge_type == "On Previous Row Total":
|
|
||||||
current_tax_amount = (tax_rate / 100.0) * \
|
|
||||||
self.tax_doclist[cint(tax.row_id) - 1].grand_total_for_current_item
|
|
||||||
|
|
||||||
return flt(current_tax_amount, self.precision("tax_amount", tax))
|
|
||||||
|
|
||||||
def validate_on_previous_row(self, tax):
|
|
||||||
"""
|
|
||||||
validate if a valid row id is mentioned in case of
|
|
||||||
On Previous Row Amount and On Previous Row Total
|
|
||||||
"""
|
|
||||||
if tax.charge_type in ["On Previous Row Amount", "On Previous Row Total"] and \
|
|
||||||
(not tax.row_id or cint(tax.row_id) >= tax.idx):
|
|
||||||
msgprint((_("Row") + " # %(idx)s [%(taxes_doctype)s]: " + \
|
|
||||||
_("Please specify a valid") + " %(row_id_label)s") % {
|
|
||||||
"idx": tax.idx,
|
|
||||||
"taxes_doctype": tax.doctype,
|
|
||||||
"row_id_label": self.meta.get_label("row_id",
|
|
||||||
parentfield="other_charges")
|
|
||||||
}, raise_exception=True)
|
|
||||||
|
|
||||||
def validate_inclusive_tax(self, tax):
|
|
||||||
def _on_previous_row_error(row_range):
|
|
||||||
msgprint((_("Row") + " # %(idx)s [%(doctype)s]: " +
|
|
||||||
_("to be included in Item's rate, it is required that: ") +
|
|
||||||
" [" + _("Row") + " # %(row_range)s] " + _("also be included in Item's rate")) % {
|
|
||||||
"idx": tax.idx,
|
|
||||||
"doctype": tax.doctype,
|
|
||||||
"inclusive_label": self.meta.get_label("included_in_print_rate",
|
|
||||||
parentfield="other_charges"),
|
|
||||||
"charge_type_label": self.meta.get_label("charge_type",
|
|
||||||
parentfield="other_charges"),
|
|
||||||
"charge_type": tax.charge_type,
|
|
||||||
"row_range": row_range
|
|
||||||
}, raise_exception=True)
|
|
||||||
|
|
||||||
if cint(tax.included_in_print_rate):
|
|
||||||
if tax.charge_type == "Actual":
|
|
||||||
# inclusive tax cannot be of type Actual
|
|
||||||
msgprint((_("Row")
|
|
||||||
+ " # %(idx)s [%(doctype)s]: %(charge_type_label)s = \"%(charge_type)s\" "
|
|
||||||
+ "cannot be included in Item's rate") % {
|
|
||||||
"idx": tax.idx,
|
|
||||||
"doctype": tax.doctype,
|
|
||||||
"charge_type_label": self.meta.get_label("charge_type",
|
|
||||||
parentfield="other_charges"),
|
|
||||||
"charge_type": tax.charge_type,
|
|
||||||
}, raise_exception=True)
|
|
||||||
elif tax.charge_type == "On Previous Row Amount" and \
|
|
||||||
not cint(self.tax_doclist[tax.row_id - 1].included_in_print_rate):
|
|
||||||
# referred row should also be inclusive
|
|
||||||
_on_previous_row_error(tax.row_id)
|
|
||||||
elif tax.charge_type == "On Previous Row Total" and \
|
|
||||||
not all([cint(t.included_in_print_rate) for t in self.tax_doclist[:tax.row_id - 1]]):
|
|
||||||
# all rows about the reffered tax should be inclusive
|
|
||||||
_on_previous_row_error("1 - %d" % (tax.row_id,))
|
|
||||||
|
|
||||||
def _load_item_tax_rate(self, item_tax_rate):
|
|
||||||
return json.loads(item_tax_rate) if item_tax_rate else {}
|
|
||||||
|
|
||||||
def _get_tax_rate(self, tax, item_tax_map):
|
|
||||||
if item_tax_map.has_key(tax.account_head):
|
|
||||||
return flt(item_tax_map.get(tax.account_head), self.precision("rate", tax))
|
|
||||||
else:
|
|
||||||
return tax.rate
|
|
||||||
|
|
||||||
def _cleanup(self):
|
|
||||||
for tax in self.tax_doclist:
|
|
||||||
for fieldname in ("grand_total_for_current_item",
|
|
||||||
"tax_amount_for_current_item",
|
|
||||||
"tax_fraction_for_current_item",
|
|
||||||
"grand_total_fraction_for_current_item"):
|
|
||||||
if fieldname in tax.fields:
|
|
||||||
del tax.fields[fieldname]
|
|
||||||
|
|
||||||
tax.item_wise_tax_detail = json.dumps(tax.item_wise_tax_detail)
|
|
||||||
|
|
||||||
def validate_order_type(self):
|
def validate_order_type(self):
|
||||||
valid_types = ["Sales", "Maintenance"]
|
valid_types = ["Sales", "Maintenance"]
|
||||||
if self.doc.order_type not in valid_types:
|
if self.doc.order_type not in valid_types:
|
||||||
|
443
public/js/transaction.js
Normal file
443
public/js/transaction.js
Normal file
@ -0,0 +1,443 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
wn.provide("erpnext");
|
||||||
|
|
||||||
|
erpnext.TransactionController = wn.ui.form.Controller.extend({
|
||||||
|
onload: function() {
|
||||||
|
if(this.frm.doc.__islocal) {
|
||||||
|
var me = this,
|
||||||
|
today = get_today(),
|
||||||
|
currency = wn.defaults.get_default("currency");
|
||||||
|
|
||||||
|
$.each({
|
||||||
|
"posting_date": today,
|
||||||
|
"due_date": today,
|
||||||
|
"transaction_date": today,
|
||||||
|
"currency": currency,
|
||||||
|
"price_list_currency": currency,
|
||||||
|
"status": "Draft",
|
||||||
|
"fiscal_year": wn.defaults.get_default("fiscal_year"),
|
||||||
|
"is_subcontracted": "No",
|
||||||
|
"conversion_rate": 1.0,
|
||||||
|
"plc_conversion_rate": 1.0
|
||||||
|
}, function(fieldname, value) {
|
||||||
|
if(me.frm.fields_dict[fieldname] && !me.frm.doc[fieldname])
|
||||||
|
me.frm.set_value(fieldname, value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
refresh: function() {
|
||||||
|
this.frm.clear_custom_buttons();
|
||||||
|
erpnext.hide_naming_series();
|
||||||
|
this.show_item_wise_taxes();
|
||||||
|
|
||||||
|
if(this.frm.fields_dict.currency)
|
||||||
|
this.currency();
|
||||||
|
},
|
||||||
|
|
||||||
|
onload_post_render: function() {
|
||||||
|
if(this.frm.doc.__islocal && this.frm.doc.company) {
|
||||||
|
var me = this;
|
||||||
|
this.frm.call({
|
||||||
|
doc: this.frm.doc,
|
||||||
|
method: "onload_post_render",
|
||||||
|
freeze: true,
|
||||||
|
callback: function(r) {
|
||||||
|
// remove this call when using client side mapper
|
||||||
|
me.set_default_values();
|
||||||
|
me.frm.refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
company: function() {
|
||||||
|
if(this.frm.doc.company) {
|
||||||
|
var me = this;
|
||||||
|
var company_currency = this.get_company_currency();
|
||||||
|
$.each(["currency", "price_list_currency"], function(i, fieldname) {
|
||||||
|
if(!me.doc[fieldname]) {
|
||||||
|
me.frm.set_value(fieldname, company_currency);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.price_list_currency();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
get_company_currency: function() {
|
||||||
|
return erpnext.get_currency(this.frm.doc.company);
|
||||||
|
},
|
||||||
|
|
||||||
|
currency: function() {
|
||||||
|
this.price_list_currency();
|
||||||
|
},
|
||||||
|
|
||||||
|
price_list_name: function(use_for) {
|
||||||
|
var me = this;
|
||||||
|
if(this.frm.doc.price_list_name) {
|
||||||
|
this.frm.call({
|
||||||
|
method: "setup.utils.get_price_list_currency",
|
||||||
|
args: {args: {
|
||||||
|
price_list_name: this.frm.doc.price_list_name,
|
||||||
|
use_for: use_for
|
||||||
|
}},
|
||||||
|
callback: function(r) {
|
||||||
|
if(!r.exc) {
|
||||||
|
me.price_list_currency();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
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();
|
||||||
|
},
|
||||||
|
|
||||||
|
plc_conversion_rate: function() {
|
||||||
|
this.price_list_currency();
|
||||||
|
},
|
||||||
|
|
||||||
|
conversion_rate: function() {
|
||||||
|
this.price_list_currency();
|
||||||
|
this.calculate_taxes_and_totals();
|
||||||
|
},
|
||||||
|
|
||||||
|
qty: function(doc, cdt, cdn) {
|
||||||
|
this.calculate_taxes_and_totals();
|
||||||
|
},
|
||||||
|
|
||||||
|
included_in_print_rate: function(doc, cdt, cdn) {
|
||||||
|
var tax = wn.model.get_doc(cdt, cdn);
|
||||||
|
try {
|
||||||
|
this.validate_on_previous_row(tax);
|
||||||
|
this.validate_inclusive_tax(tax);
|
||||||
|
this.calculate_taxes_and_totals();
|
||||||
|
} catch(e) {
|
||||||
|
tax.included_in_print_rate = 0;
|
||||||
|
refresh_field("included_in_print_rate", tax.name, tax.parentfield);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
validate_on_previous_row: function(tax) {
|
||||||
|
// validate if a valid row id is mentioned in case of
|
||||||
|
// On Previous Row Amount and On Previous Row Total
|
||||||
|
if((["On Previous Row Amount", "On Previous Row Total"].indexOf(tax.charge_type) != -1) &&
|
||||||
|
(!tax.row_id || cint(tax.row_id) >= tax.idx)) {
|
||||||
|
var msg = repl(wn._("Row") + " # %(idx)s [%(doctype)s]: " +
|
||||||
|
wn._("Please specify a valid") + " %(row_id_label)s", {
|
||||||
|
idx: tax.idx,
|
||||||
|
doctype: tax.doctype,
|
||||||
|
row_id_label: wn.meta.get_label(tax.doctype, "row_id", tax.name)
|
||||||
|
});
|
||||||
|
msgprint(msg);
|
||||||
|
throw msg;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
validate_inclusive_tax: function(tax) {
|
||||||
|
if(!this.frm.tax_doclist) this.frm.tax_doclist = this.get_tax_doclist();
|
||||||
|
|
||||||
|
var actual_type_error = function() {
|
||||||
|
var msg = repl(wn._("For row") + " # %(idx)s [%(doctype)s]: " +
|
||||||
|
"%(charge_type_label)s = \"%(charge_type)s\" " +
|
||||||
|
wn._("cannot be included in Item's rate"), {
|
||||||
|
idx: tax.idx,
|
||||||
|
doctype: tax.doctype,
|
||||||
|
charge_type_label: wn.meta.get_label(tax.doctype, "charge_type", tax.name),
|
||||||
|
charge_type: tax.charge_type
|
||||||
|
});
|
||||||
|
msgprint(msg);
|
||||||
|
throw msg;
|
||||||
|
};
|
||||||
|
|
||||||
|
var on_previous_row_error = function(row_range) {
|
||||||
|
var msg = repl(wn._("For row") + " # %(idx)s [%(doctype)s]: " +
|
||||||
|
wn._("to be included in Item's rate, it is required that: ") +
|
||||||
|
" [" + wn._("Row") + " # %(row_range)s] " + wn._("also be included in Item's rate"), {
|
||||||
|
idx: tax.idx,
|
||||||
|
doctype: tax.doctype,
|
||||||
|
charge_type_label: wn.meta.get_label(tax.doctype, "charge_type", tax.name),
|
||||||
|
charge_type: tax.charge_type,
|
||||||
|
inclusive_label: wn.meta.get_label(tax.doctype, "included_in_print_rate", tax.name),
|
||||||
|
row_range: row_range,
|
||||||
|
});
|
||||||
|
|
||||||
|
msgprint(msg);
|
||||||
|
throw msg;
|
||||||
|
};
|
||||||
|
|
||||||
|
if(cint(tax.included_in_print_rate)) {
|
||||||
|
if(tax.charge_type == "Actual") {
|
||||||
|
// inclusive tax cannot be of type Actual
|
||||||
|
actual_type_error();
|
||||||
|
} else if(tax.charge_type == "On Previous Row Amount" &&
|
||||||
|
!cint(this.frm.tax_doclist[tax.row_id - 1].included_in_print_rate)) {
|
||||||
|
// referred row should also be an inclusive tax
|
||||||
|
on_previous_row_error(tax.row_id);
|
||||||
|
} else if(tax.charge_type == "On Previous Row Total") {
|
||||||
|
var taxes_not_included = $.map(this.frm.tax_doclist.slice(0, tax.row_id),
|
||||||
|
function(t) { return cint(t.included_in_print_rate) ? null : t; });
|
||||||
|
if(taxes_not_included.length > 0) {
|
||||||
|
// all rows above this tax should be inclusive
|
||||||
|
on_previous_row_error(tax.row_id == 1 ? "1" : "1 - " + tax.row_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_load_item_tax_rate: function(item_tax_rate) {
|
||||||
|
return item_tax_rate ? JSON.parse(item_tax_rate) : {};
|
||||||
|
},
|
||||||
|
|
||||||
|
_get_tax_rate: function(tax, item_tax_map) {
|
||||||
|
return (keys(item_tax_map).indexOf(tax.account_head) != -1) ?
|
||||||
|
flt(item_tax_map[tax.account_head], precision("rate", tax)) :
|
||||||
|
tax.rate;
|
||||||
|
},
|
||||||
|
|
||||||
|
get_item_wise_taxes_html: function() {
|
||||||
|
var item_tax = {};
|
||||||
|
var tax_accounts = [];
|
||||||
|
var company_currency = this.get_company_currency();
|
||||||
|
|
||||||
|
$.each(this.get_tax_doclist(), function(i, tax) {
|
||||||
|
var tax_amount_precision = precision("tax_amount", tax);
|
||||||
|
$.each(JSON.parse(tax.item_wise_tax_detail || '{}'),
|
||||||
|
function(item_code, tax_amount) {
|
||||||
|
if(!item_tax[item_code]) item_tax[item_code] = {};
|
||||||
|
item_tax[item_code][tax.account_head] = flt(tax_amount, tax_amount_precision);
|
||||||
|
});
|
||||||
|
tax_accounts.push(tax.account_head);
|
||||||
|
});
|
||||||
|
|
||||||
|
var headings = $.map([wn._("Item Name")].concat(tax_accounts),
|
||||||
|
function(head) { return '<th style="min-width: 100px;">' + (head || "") + "</th>" }).join("\n");
|
||||||
|
|
||||||
|
var rows = $.map(this.get_item_doclist(), function(item) {
|
||||||
|
var item_tax_record = item_tax[item.item_code || item.item_name];
|
||||||
|
return repl("<tr><td>%(item_name)s</td>%(taxes)s</tr>", {
|
||||||
|
item_name: item.item_name,
|
||||||
|
taxes: $.map(tax_accounts, function(head) {
|
||||||
|
return "<td>" + format_currency(item_tax_record[head], company_currency) + "</td>"
|
||||||
|
}).join("\n")
|
||||||
|
});
|
||||||
|
}).join("\n");
|
||||||
|
|
||||||
|
return '<div style="overflow-x: scroll;"><table class="table table-bordered table-hover">\
|
||||||
|
<thead><tr>' + headings + '</tr></thead> \
|
||||||
|
<tbody>' + rows + '</tbody> \
|
||||||
|
</table></div>';
|
||||||
|
},
|
||||||
|
|
||||||
|
set_default_values: function() {
|
||||||
|
$.each(wn.model.get_doclist(this.frm.doctype, this.frm.docname), function(i, doc) {
|
||||||
|
var updated = wn.model.set_default_values(doc);
|
||||||
|
if(doc.parentfield) {
|
||||||
|
refresh_field(doc.parentfield);
|
||||||
|
} else {
|
||||||
|
refresh_field(updated);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
validate_company_and_party: function(party_field) {
|
||||||
|
var valid = true;
|
||||||
|
$.each(["company", party_field], function(i, fieldname) {
|
||||||
|
if(!me.frm.doc[fieldname]) {
|
||||||
|
valid = false;
|
||||||
|
msgprint(wn._("Please specify") + ": " +
|
||||||
|
wn.meta.get_label(me.frm.doc.doctype, fieldname, me.frm.doc.name) +
|
||||||
|
". " + wn._("It is needed to fetch Item Details."));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return valid;
|
||||||
|
},
|
||||||
|
|
||||||
|
get_item_doclist: function() {
|
||||||
|
return wn.model.get_doclist(this.frm.doc.doctype, this.frm.doc.name,
|
||||||
|
{parentfield: this.fname});
|
||||||
|
},
|
||||||
|
|
||||||
|
get_tax_doclist: function() {
|
||||||
|
return wn.model.get_doclist(this.frm.doc.doctype, this.frm.doc.name,
|
||||||
|
{parentfield: this.other_fname});
|
||||||
|
},
|
||||||
|
|
||||||
|
validate_conversion_rate: function() {
|
||||||
|
this.frm.doc.conversion_rate = flt(this.frm.doc.conversion_rate, precision("conversion_rate"));
|
||||||
|
var conversion_rate_label = wn.meta.get_label(this.frm.doc.doctype, "conversion_rate",
|
||||||
|
this.frm.doc.name);
|
||||||
|
|
||||||
|
if(this.frm.doc.conversion_rate == 0) {
|
||||||
|
wn.throw(wn._(conversion_rate_label) + " " + wn._("cannot be 0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
var company_currency = this.get_company_currency();
|
||||||
|
var valid_conversion_rate = conversion_rate ?
|
||||||
|
((this.frm.doc.currency == company_currency && this.frm.doc.conversion_rate == 1.0) ||
|
||||||
|
(this.frm.doc.currency != company_currency && this.frm.doc.conversion_rate != 1.0)) :
|
||||||
|
false;
|
||||||
|
|
||||||
|
if(!valid_conversion_rate) {
|
||||||
|
wn.throw(wn._("Please enter valid") + " " + wn._(conversion_rate_label) +
|
||||||
|
" 1 " + this.frm.doc.currency + " = [?] " + company_currency);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
calculate_taxes_and_totals: function() {
|
||||||
|
this.validate_conversion_rate();
|
||||||
|
this.frm.item_doclist = this.get_item_doclist();
|
||||||
|
this.frm.tax_doclist = this.get_tax_doclist();
|
||||||
|
|
||||||
|
this.calculate_item_values();
|
||||||
|
this.initialize_taxes();
|
||||||
|
this.determine_exclusive_rate && this.determine_exclusive_rate();
|
||||||
|
this.calculate_net_total();
|
||||||
|
this.calculate_taxes();
|
||||||
|
this.calculate_totals();
|
||||||
|
this._cleanup();
|
||||||
|
this.show_item_wise_taxes();
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize_taxes: function() {
|
||||||
|
var me = this;
|
||||||
|
$.each(this.frm.tax_doclist, function(i, tax) {
|
||||||
|
tax.item_wise_tax_detail = {};
|
||||||
|
$.each(["tax_amount", "total",
|
||||||
|
"tax_amount_for_current_item", "grand_total_for_current_item",
|
||||||
|
"tax_fraction_for_current_item", "grand_total_fraction_for_current_item"],
|
||||||
|
function(i, fieldname) { tax[fieldname] = 0.0 });
|
||||||
|
|
||||||
|
me.validate_on_previous_row(tax);
|
||||||
|
me.validate_inclusive_tax(tax);
|
||||||
|
wn.model.round_floats_in(tax);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
calculate_taxes: function() {
|
||||||
|
var me = this;
|
||||||
|
|
||||||
|
$.each(this.frm.item_doclist, function(n, item) {
|
||||||
|
var item_tax_map = me._load_item_tax_rate(item.item_tax_rate);
|
||||||
|
|
||||||
|
$.each(me.frm.tax_doclist, function(i, tax) {
|
||||||
|
// tax_amount represents the amount of tax for the current step
|
||||||
|
var current_tax_amount = me.get_current_tax_amount(item, tax, item_tax_map);
|
||||||
|
|
||||||
|
me.set_item_tax_amount && me.set_item_tax_amount(item, tax, current_tax_amount);
|
||||||
|
|
||||||
|
// case when net total is 0 but there is an actual type charge
|
||||||
|
// in this case add the actual amount to tax.tax_amount
|
||||||
|
// and tax.grand_total_for_current_item for the first such iteration
|
||||||
|
if(tax.charge_type == "Actual" &&
|
||||||
|
!(current_tax_amount || me.frm.doc.net_total || tax.tax_amount)) {
|
||||||
|
var zero_net_total_adjustment = flt(tax.rate, precision("tax_amount", tax));
|
||||||
|
current_tax_amount += zero_net_total_adjustment;
|
||||||
|
}
|
||||||
|
|
||||||
|
// store tax_amount for current item as it will be used for
|
||||||
|
// charge type = 'On Previous Row Amount'
|
||||||
|
tax.tax_amount_for_current_item = current_tax_amount;
|
||||||
|
|
||||||
|
// accumulate tax amount into tax.tax_amount
|
||||||
|
tax.tax_amount += current_tax_amount;
|
||||||
|
|
||||||
|
// store tax breakup for each item
|
||||||
|
tax.item_wise_tax_detail[item.item_code || item.item_name] = current_tax_amount;
|
||||||
|
|
||||||
|
// for buying
|
||||||
|
if(tax.category) {
|
||||||
|
// if just for valuation, do not add the tax amount in total
|
||||||
|
// hence, setting it as 0 for further steps
|
||||||
|
current_tax_amount = (tax.category == "Valuation") ? 0.0 : current_tax_amount;
|
||||||
|
|
||||||
|
current_tax_amount *= (tax.add_deduct_tax == "Deduct") ? -1.0 : 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate tax.total viz. grand total till that step
|
||||||
|
// note: grand_total_for_current_item contains the contribution of
|
||||||
|
// item's amount, previously applied tax and the current tax on that item
|
||||||
|
if(i==0) {
|
||||||
|
tax.grand_total_for_current_item = flt(item.amount + current_tax_amount,
|
||||||
|
precision("total", tax));
|
||||||
|
} else {
|
||||||
|
tax.grand_total_for_current_item =
|
||||||
|
flt(me.frm.tax_doclist[i-1].grand_total_for_current_item + current_tax_amount,
|
||||||
|
precision("total", tax));
|
||||||
|
}
|
||||||
|
|
||||||
|
// in tax.total, accumulate grand total for each item
|
||||||
|
tax.total += tax.grand_total_for_current_item;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
get_current_tax_amount: function(item, tax, item_tax_map) {
|
||||||
|
var tax_rate = this._get_tax_rate(tax, item_tax_map);
|
||||||
|
var current_tax_amount = 0.0;
|
||||||
|
|
||||||
|
if(tax.charge_type == "Actual") {
|
||||||
|
// distribute the tax amount proportionally to each item row
|
||||||
|
var actual = flt(tax.rate, precision("tax_amount", tax));
|
||||||
|
current_tax_amount = this.frm.doc.net_total ?
|
||||||
|
((item.amount / this.frm.doc.net_total) * actual) :
|
||||||
|
0.0;
|
||||||
|
|
||||||
|
} else if(tax.charge_type == "On Net Total") {
|
||||||
|
current_tax_amount = (tax_rate / 100.0) * item.amount;
|
||||||
|
|
||||||
|
} else if(tax.charge_type == "On Previous Row Amount") {
|
||||||
|
current_tax_amount = (tax_rate / 100.0) *
|
||||||
|
this.frm.tax_doclist[cint(tax.row_id) - 1].tax_amount_for_current_item;
|
||||||
|
|
||||||
|
} else if(tax.charge_type == "On Previous Row Total") {
|
||||||
|
current_tax_amount = (tax_rate / 100.0) *
|
||||||
|
this.frm.tax_doclist[cint(tax.row_id) - 1].grand_total_for_current_item;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return flt(current_tax_amount, precision("tax_amount", tax));
|
||||||
|
},
|
||||||
|
|
||||||
|
_cleanup: function() {
|
||||||
|
$.each(this.frm.tax_doclist, function(i, tax) {
|
||||||
|
$.each(["tax_amount_for_current_item", "grand_total_for_current_item",
|
||||||
|
"tax_fraction_for_current_item", "grand_total_fraction_for_current_item"],
|
||||||
|
function(i, fieldname) { delete tax[fieldname]; });
|
||||||
|
|
||||||
|
tax.item_wise_tax_detail = JSON.stringify(tax.item_wise_tax_detail);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_set_in_company_currency: function(item, print_field, base_field) {
|
||||||
|
// set values in base currency
|
||||||
|
item[base_field] = flt(item[print_field] * this.frm.doc.conversion_rate,
|
||||||
|
precision(base_field, item));
|
||||||
|
},
|
||||||
|
});
|
@ -53,14 +53,6 @@ cur_frm.cscript.onload = function(doc, cdt, cdn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_frm.cscript.onload_post_render = function(doc, dt, dn) {
|
|
||||||
var callback = function(doc, dt, dn) {
|
|
||||||
// defined in sales_common.js
|
|
||||||
cur_frm.cscript.update_item_details(doc, dt, dn);
|
|
||||||
}
|
|
||||||
cur_frm.cscript.hide_price_list_currency(doc, dt, dn, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
// hide - unhide fields based on lead or customer..
|
// hide - unhide fields based on lead or customer..
|
||||||
// =======================================================================================================================
|
// =======================================================================================================================
|
||||||
cur_frm.cscript.lead_cust_show = function(doc,cdt,cdn){
|
cur_frm.cscript.lead_cust_show = function(doc,cdt,cdn){
|
||||||
|
@ -22,61 +22,19 @@
|
|||||||
// cur_frm.cscript.sales_team_fname - Sales Team fieldname
|
// cur_frm.cscript.sales_team_fname - Sales Team fieldname
|
||||||
|
|
||||||
wn.provide("erpnext.selling");
|
wn.provide("erpnext.selling");
|
||||||
|
wn.require("app/js/transaction.js");
|
||||||
|
|
||||||
erpnext.selling.SellingController = wn.ui.form.Controller.extend({
|
erpnext.selling.SellingController = erpnext.TransactionController.extend({
|
||||||
setup: function() {
|
setup: function() {
|
||||||
this.frm.add_fetch("sales_partner", "commission_rate", "commission_rate");
|
this.frm.add_fetch("sales_partner", "commission_rate", "commission_rate");
|
||||||
},
|
},
|
||||||
|
|
||||||
// events when rendering form
|
|
||||||
// 1
|
// 1
|
||||||
onload: function() {
|
onload: function() {
|
||||||
var me = this;
|
this._super();
|
||||||
this.toggle_rounded_total();
|
this.toggle_rounded_total();
|
||||||
if(this.frm.doc.__islocal) {
|
|
||||||
// set date fields
|
|
||||||
$.each(["posting_date", "due_date", "transaction_date"], function(i, fieldname) {
|
|
||||||
if(me.frm.fields_dict[fieldname] && !me.frm.doc[fieldname]) {
|
|
||||||
me.frm.set_value(fieldname, get_today());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// set currency fields
|
|
||||||
$.each(["currency", "price_list_currency"], function(i, fieldname) {
|
|
||||||
if(me.frm.fields_dict[fieldname] && !me.frm.doc[fieldname]) {
|
|
||||||
me.frm.set_value(fieldname, wn.defaults.get_default("currency"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// status
|
|
||||||
if(!this.frm.doc.status) this.frm.set_value("status", "Draft");
|
|
||||||
|
|
||||||
// TODO set depends_on for customer related fields
|
// TODO set depends_on for customer related fields
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 2
|
|
||||||
refresh: function() {
|
|
||||||
erpnext.hide_naming_series();
|
|
||||||
this.show_item_wise_taxes();
|
|
||||||
this.set_dynamic_labels();
|
|
||||||
},
|
|
||||||
|
|
||||||
// 3
|
|
||||||
onload_post_render: function() {
|
|
||||||
if(this.frm.doc.__islocal && this.frm.doc.company) {
|
|
||||||
var me = this;
|
|
||||||
this.frm.call({
|
|
||||||
doc: this.frm.doc,
|
|
||||||
method: "onload_post_render",
|
|
||||||
freeze: true,
|
|
||||||
callback: function(r) {
|
|
||||||
// remove this call when using client side mapper
|
|
||||||
me.set_default_values();
|
|
||||||
me.frm.refresh();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
validate: function() {
|
validate: function() {
|
||||||
@ -85,6 +43,32 @@ erpnext.selling.SellingController = wn.ui.form.Controller.extend({
|
|||||||
// TODO calc adjustment amount
|
// TODO calc adjustment amount
|
||||||
},
|
},
|
||||||
|
|
||||||
|
customer: function() {
|
||||||
|
if(this.frm.doc.customer || this.frm.doc.debit_to) {
|
||||||
|
if(!this.frm.doc.company) {
|
||||||
|
this.frm.set_value("customer", null);
|
||||||
|
msgprint(wn._("Please specify Company"));
|
||||||
|
} else {
|
||||||
|
var me = this;
|
||||||
|
var price_list_name = this.frm.doc.price_list_name;
|
||||||
|
|
||||||
|
this.frm.call({
|
||||||
|
doc: this.frm.doc,
|
||||||
|
method: "set_customer_defaults",
|
||||||
|
freeze: true,
|
||||||
|
callback: function(r) {
|
||||||
|
if(!r.exc) {
|
||||||
|
me.frm.refresh_fields();
|
||||||
|
if(me.frm.doc.price_list_name !== price_list_name) me.price_list_name();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO hide/unhide related fields
|
||||||
|
},
|
||||||
|
|
||||||
barcode: function(doc, cdt, cdn) {
|
barcode: function(doc, cdt, cdn) {
|
||||||
this.item_code(doc, cdt, cdn);
|
this.item_code(doc, cdt, cdn);
|
||||||
},
|
},
|
||||||
@ -93,7 +77,7 @@ erpnext.selling.SellingController = wn.ui.form.Controller.extend({
|
|||||||
var me = this;
|
var me = this;
|
||||||
var item = wn.model.get_doc(cdt, cdn);
|
var item = wn.model.get_doc(cdt, cdn);
|
||||||
if(item.item_code || item.barcode) {
|
if(item.item_code || item.barcode) {
|
||||||
if(!this.validate_company_and_party()) {
|
if(!this.validate_company_and_party("customer")) {
|
||||||
item.item_code = null;
|
item.item_code = null;
|
||||||
refresh_field("item_code", item.name, item.parentfield);
|
refresh_field("item_code", item.name, item.parentfield);
|
||||||
} else {
|
} else {
|
||||||
@ -128,90 +112,8 @@ erpnext.selling.SellingController = wn.ui.form.Controller.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
company: function() {
|
|
||||||
if(this.frm.doc.company) {
|
|
||||||
var me = this;
|
|
||||||
var company_currency = this.get_company_currency();
|
|
||||||
$.each(["currency", "price_list_currency"], function(i, fieldname) {
|
|
||||||
if(!me.doc[fieldname]) {
|
|
||||||
me.frm.set_value(fieldname, company_currency);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.price_list_currency();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
customer: function() {
|
|
||||||
if(this.frm.doc.customer || this.frm.doc.debit_to) {
|
|
||||||
if(!this.frm.doc.company) {
|
|
||||||
this.frm.set_value("customer", null);
|
|
||||||
msgprint(wn._("Please specify Company"));
|
|
||||||
} else {
|
|
||||||
var me = this;
|
|
||||||
var price_list_name = this.frm.doc.price_list_name;
|
|
||||||
|
|
||||||
this.frm.call({
|
|
||||||
doc: this.frm.doc,
|
|
||||||
method: "set_customer_defaults",
|
|
||||||
freeze: true,
|
|
||||||
callback: function(r) {
|
|
||||||
if(!r.exc) {
|
|
||||||
me.frm.refresh_fields();
|
|
||||||
if(me.frm.doc.price_list_name !== price_list_name) me.price_list_name();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO hide/unhide related fields
|
|
||||||
},
|
|
||||||
|
|
||||||
price_list_name: function() {
|
price_list_name: function() {
|
||||||
var me = this;
|
this._super("selling");
|
||||||
if(this.frm.doc.price_list_name) {
|
|
||||||
this.frm.call({
|
|
||||||
method: "setup.utils.get_price_list_currency",
|
|
||||||
args: {args: {
|
|
||||||
price_list_name: this.frm.doc.price_list_name,
|
|
||||||
use_for: "selling"
|
|
||||||
}},
|
|
||||||
callback: function(r) {
|
|
||||||
if(!r.exc) {
|
|
||||||
me.price_list_currency();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
currency: function() {
|
|
||||||
this.price_list_currency();
|
|
||||||
},
|
|
||||||
|
|
||||||
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);
|
|
||||||
this.calculate_taxes_and_totals();
|
|
||||||
} 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.calculate_taxes_and_totals();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.set_dynamic_labels();
|
|
||||||
},
|
|
||||||
|
|
||||||
conversion_rate: function() {
|
|
||||||
this.price_list_currency();
|
|
||||||
this.calculate_taxes_and_totals();
|
|
||||||
},
|
|
||||||
|
|
||||||
plc_conversion_rate: function() {
|
|
||||||
this.price_list_currency();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
ref_rate: function(doc, cdt, cdn) {
|
ref_rate: function(doc, cdt, cdn) {
|
||||||
@ -224,10 +126,6 @@ erpnext.selling.SellingController = wn.ui.form.Controller.extend({
|
|||||||
this.calculate_taxes_and_totals();
|
this.calculate_taxes_and_totals();
|
||||||
},
|
},
|
||||||
|
|
||||||
qty: function(doc, cdt, cdn) {
|
|
||||||
this.calculate_taxes_and_totals();
|
|
||||||
},
|
|
||||||
|
|
||||||
adj_rate: function(doc, cdt, cdn) {
|
adj_rate: function(doc, cdt, cdn) {
|
||||||
this.ref_rate(doc, cdt, cdn);
|
this.ref_rate(doc, cdt, cdn);
|
||||||
},
|
},
|
||||||
@ -246,19 +144,6 @@ erpnext.selling.SellingController = wn.ui.form.Controller.extend({
|
|||||||
this.calculate_taxes_and_totals();
|
this.calculate_taxes_and_totals();
|
||||||
},
|
},
|
||||||
|
|
||||||
included_in_print_rate: function(doc, cdt, cdn) {
|
|
||||||
var tax = wn.model.get_doc(cdt, cdn);
|
|
||||||
try {
|
|
||||||
this.validate_on_previous_row(tax);
|
|
||||||
this.validate_inclusive_tax(tax);
|
|
||||||
this.calculate_taxes_and_totals();
|
|
||||||
} catch(e) {
|
|
||||||
tax.included_in_print_rate = 0;
|
|
||||||
refresh_field("included_in_print_rate", tax.name, tax.parentfield);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
commission_rate: function() {
|
commission_rate: function() {
|
||||||
this.calculate_commission();
|
this.calculate_commission();
|
||||||
refresh_field("total_commission");
|
refresh_field("total_commission");
|
||||||
@ -307,49 +192,10 @@ erpnext.selling.SellingController = wn.ui.form.Controller.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
validate_company_and_party: function() {
|
|
||||||
var me = this;
|
|
||||||
var valid = true;
|
|
||||||
$.each(["company", "customer"], function(i, fieldname) {
|
|
||||||
if(!me.frm.doc[fieldname]) {
|
|
||||||
valid = false;
|
|
||||||
msgprint(wn._("Please specify") + ": " +
|
|
||||||
wn.meta.get_label(me.frm.doc.doctype, fieldname, me.frm.doc.name) +
|
|
||||||
". " + wn._("It is needed to fetch Item Details."));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return valid;
|
|
||||||
},
|
|
||||||
|
|
||||||
set_default_values: function() {
|
|
||||||
$.each(wn.model.get_doclist(this.frm.doctype, this.frm.docname), function(i, doc) {
|
|
||||||
var updated = wn.model.set_default_values(doc);
|
|
||||||
if(doc.parentfield) {
|
|
||||||
refresh_field(doc.parentfield);
|
|
||||||
} else {
|
|
||||||
refresh_field(updated);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
calculate_taxes_and_totals: function() {
|
calculate_taxes_and_totals: function() {
|
||||||
this.frm.doc.conversion_rate = flt(this.frm.doc.conversion_rate, precision("conversion_rate"));
|
this._super();
|
||||||
|
|
||||||
// TODO validate conversion rate
|
|
||||||
|
|
||||||
this.frm.item_doclist = this.get_item_doclist();
|
|
||||||
this.frm.tax_doclist = this.get_tax_doclist();
|
|
||||||
|
|
||||||
this.calculate_item_values();
|
|
||||||
this.initialize_taxes();
|
|
||||||
this.determine_exclusive_rate();
|
|
||||||
this.calculate_net_total();
|
|
||||||
this.calculate_taxes();
|
|
||||||
this.calculate_totals();
|
|
||||||
this.calculate_commission();
|
this.calculate_commission();
|
||||||
this.calculate_contribution();
|
this.calculate_contribution();
|
||||||
this._cleanup();
|
|
||||||
this.frm.doc.in_words = this.frm.doc.in_words_export = "";
|
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// outstanding amount
|
// outstanding amount
|
||||||
@ -357,57 +203,21 @@ erpnext.selling.SellingController = wn.ui.form.Controller.extend({
|
|||||||
// check for custom_recalc in custom scripts of server
|
// check for custom_recalc in custom scripts of server
|
||||||
|
|
||||||
this.frm.refresh_fields();
|
this.frm.refresh_fields();
|
||||||
this.show_item_wise_taxes();
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
get_item_doclist: function() {
|
|
||||||
return wn.model.get_doclist(this.frm.doc.doctype, this.frm.doc.name,
|
|
||||||
{parentfield: this.fname});
|
|
||||||
},
|
|
||||||
|
|
||||||
get_tax_doclist: function() {
|
|
||||||
return wn.model.get_doclist(this.frm.doc.doctype, this.frm.doc.name,
|
|
||||||
{parentfield: "other_charges"});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
calculate_item_values: function() {
|
calculate_item_values: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
|
|
||||||
var _set_base = function(item, print_field, base_field) {
|
|
||||||
// set values in base currency
|
|
||||||
item[base_field] = flt(item[print_field] * me.frm.doc.conversion_rate,
|
|
||||||
precision(base_field, item));
|
|
||||||
};
|
|
||||||
|
|
||||||
$.each(this.frm.item_doclist, function(i, item) {
|
$.each(this.frm.item_doclist, function(i, item) {
|
||||||
wn.model.round_floats_in(item);
|
wn.model.round_floats_in(item);
|
||||||
item.export_amount = flt(item.export_rate * item.qty, precision("export_amount", item));
|
item.export_amount = flt(item.export_rate * item.qty, precision("export_amount", item));
|
||||||
|
|
||||||
_set_base(item, "ref_rate", "base_ref_rate");
|
me._set_in_company_currency(item, "ref_rate", "base_ref_rate");
|
||||||
_set_base(item, "export_rate", "basic_rate");
|
me._set_in_company_currency(item, "export_rate", "basic_rate");
|
||||||
_set_base(item, "export_amount", "amount");
|
me._set_in_company_currency(item, "export_amount", "amount");
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
initialize_taxes: function() {
|
|
||||||
var me = this;
|
|
||||||
$.each(this.frm.tax_doclist, function(i, tax) {
|
|
||||||
tax.tax_amount = tax.total = 0.0;
|
|
||||||
tax.item_wise_tax_detail = {};
|
|
||||||
|
|
||||||
// temporary fields
|
|
||||||
tax.tax_amount_for_current_item = tax.grand_total_for_current_item = 0.0;
|
|
||||||
tax.tax_fraction_for_current_item = tax.grand_total_fraction_for_current_item = 0.0;
|
|
||||||
|
|
||||||
me.validate_on_previous_row(tax);
|
|
||||||
me.validate_inclusive_tax(tax);
|
|
||||||
|
|
||||||
wn.model.round_floats_in(tax);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
determine_exclusive_rate: function() {
|
determine_exclusive_rate: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
$.each(me.frm.item_doclist, function(n, item) {
|
$.each(me.frm.item_doclist, function(n, item) {
|
||||||
@ -482,81 +292,6 @@ erpnext.selling.SellingController = wn.ui.form.Controller.extend({
|
|||||||
wn.model.round_floats_in(this.frm.doc, ["net_total", "net_total_export"]);
|
wn.model.round_floats_in(this.frm.doc, ["net_total", "net_total_export"]);
|
||||||
},
|
},
|
||||||
|
|
||||||
calculate_taxes: function() {
|
|
||||||
var me = this;
|
|
||||||
|
|
||||||
$.each(this.frm.item_doclist, function(n, item) {
|
|
||||||
var item_tax_map = me._load_item_tax_rate(item.item_tax_rate);
|
|
||||||
|
|
||||||
$.each(me.frm.tax_doclist, function(i, tax) {
|
|
||||||
// tax_amount represents the amount of tax for the current step
|
|
||||||
var current_tax_amount = me.get_current_tax_amount(item, tax, item_tax_map);
|
|
||||||
|
|
||||||
// case when net total is 0 but there is an actual type charge
|
|
||||||
// in this case add the actual amount to tax.tax_amount
|
|
||||||
// and tax.grand_total_for_current_item for the first such iteration
|
|
||||||
if(tax.charge_type == "Actual" &&
|
|
||||||
!(current_tax_amount || me.frm.doc.net_total || tax.tax_amount)) {
|
|
||||||
var zero_net_total_adjustment = flt(tax.rate, precision("tax_amount", tax));
|
|
||||||
current_tax_amount += zero_net_total_adjustment;
|
|
||||||
}
|
|
||||||
|
|
||||||
// store tax_amount for current item as it will be used for
|
|
||||||
// charge type = 'On Previous Row Amount'
|
|
||||||
tax.tax_amount_for_current_item = current_tax_amount;
|
|
||||||
|
|
||||||
// accumulate tax amount into tax.tax_amount
|
|
||||||
tax.tax_amount += current_tax_amount;
|
|
||||||
|
|
||||||
// Calculate tax.total viz. grand total till that step
|
|
||||||
// note: grand_total_for_current_item contains the contribution of
|
|
||||||
// item's amount, previously applied tax and the current tax on that item
|
|
||||||
if(i==0) {
|
|
||||||
tax.grand_total_for_current_item = flt(item.amount + current_tax_amount,
|
|
||||||
precision("total", tax));
|
|
||||||
} else {
|
|
||||||
tax.grand_total_for_current_item =
|
|
||||||
flt(me.frm.tax_doclist[i-1].grand_total_for_current_item + current_tax_amount,
|
|
||||||
precision("total", tax));
|
|
||||||
}
|
|
||||||
|
|
||||||
// in tax.total, accumulate grand total for each item
|
|
||||||
tax.total += tax.grand_total_for_current_item;
|
|
||||||
|
|
||||||
// store tax breakup for each item
|
|
||||||
tax.item_wise_tax_detail[item.item_code || item.item_name] = current_tax_amount;
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
get_current_tax_amount: function(item, tax, item_tax_map) {
|
|
||||||
var tax_rate = this._get_tax_rate(tax, item_tax_map);
|
|
||||||
var current_tax_amount = 0.0;
|
|
||||||
|
|
||||||
if(tax.charge_type == "Actual") {
|
|
||||||
// distribute the tax amount proportionally to each item row
|
|
||||||
var actual = flt(tax.rate, precision("tax_amount", tax));
|
|
||||||
current_tax_amount = this.frm.doc.net_total ?
|
|
||||||
((item.amount / this.frm.doc.net_total) * actual) :
|
|
||||||
0.0;
|
|
||||||
|
|
||||||
} else if(tax.charge_type == "On Net Total") {
|
|
||||||
current_tax_amount = (tax_rate / 100.0) * item.amount;
|
|
||||||
|
|
||||||
} else if(tax.charge_type == "On Previous Row Amount") {
|
|
||||||
current_tax_amount = (tax_rate / 100.0) *
|
|
||||||
this.frm.tax_doclist[cint(tax.row_id) - 1].tax_amount_for_current_item;
|
|
||||||
|
|
||||||
} else if(tax.charge_type == "On Previous Row Total") {
|
|
||||||
current_tax_amount = (tax_rate / 100.0) *
|
|
||||||
this.frm.tax_doclist[cint(tax.row_id) - 1].grand_total_for_current_item;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return flt(current_tax_amount, precision("tax_amount", tax));
|
|
||||||
},
|
|
||||||
|
|
||||||
calculate_totals: function() {
|
calculate_totals: function() {
|
||||||
var tax_count = this.frm.tax_doclist.length;
|
var tax_count = this.frm.tax_doclist.length;
|
||||||
this.frm.doc.grand_total = flt(
|
this.frm.doc.grand_total = flt(
|
||||||
@ -601,91 +336,8 @@ erpnext.selling.SellingController = wn.ui.form.Controller.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_cleanup: function() {
|
_cleanup: function() {
|
||||||
$.each(this.frm.tax_doclist, function(i, tax) {
|
this._super();
|
||||||
var tax_fields = keys(tax);
|
this.frm.doc.in_words = this.frm.doc.in_words_export = "";
|
||||||
$.each(["tax_amount_for_current_item", "grand_total_for_current_item",
|
|
||||||
"tax_fraction_for_current_item", "grand_total_fraction_for_current_item"],
|
|
||||||
function(i, fieldname) { delete tax[fieldname];});
|
|
||||||
|
|
||||||
tax.item_wise_tax_detail = JSON.stringify(tax.item_wise_tax_detail);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
validate_on_previous_row: function(tax) {
|
|
||||||
// validate if a valid row id is mentioned in case of
|
|
||||||
// On Previous Row Amount and On Previous Row Total
|
|
||||||
if((["On Previous Row Amount", "On Previous Row Total"].indexOf(tax.charge_type) != -1) &&
|
|
||||||
(!tax.row_id || cint(tax.row_id) >= tax.idx)) {
|
|
||||||
var msg = repl(wn._("Row") + " # %(idx)s [%(doctype)s]: " +
|
|
||||||
wn._("Please specify a valid") + " %(row_id_label)s", {
|
|
||||||
idx: tax.idx,
|
|
||||||
doctype: tax.doctype,
|
|
||||||
row_id_label: wn.meta.get_label(tax.doctype, "row_id", tax.name)
|
|
||||||
});
|
|
||||||
msgprint(msg);
|
|
||||||
throw msg;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
validate_inclusive_tax: function(tax) {
|
|
||||||
if(!this.frm.tax_doclist) this.frm.tax_doclist = this.get_tax_doclist();
|
|
||||||
|
|
||||||
var actual_type_error = function() {
|
|
||||||
var msg = repl(wn._("For row") + " # %(idx)s [%(doctype)s]: " +
|
|
||||||
"%(charge_type_label)s = \"%(charge_type)s\" " +
|
|
||||||
wn._("cannot be included in Item's rate"), {
|
|
||||||
idx: tax.idx,
|
|
||||||
doctype: tax.doctype,
|
|
||||||
charge_type_label: wn.meta.get_label(tax.doctype, "charge_type", tax.name),
|
|
||||||
charge_type: tax.charge_type
|
|
||||||
});
|
|
||||||
msgprint(msg);
|
|
||||||
throw msg;
|
|
||||||
};
|
|
||||||
|
|
||||||
var on_previous_row_error = function(row_range) {
|
|
||||||
var msg = repl(wn._("For row") + " # %(idx)s [%(doctype)s]: " +
|
|
||||||
wn._("to be included in Item's rate, it is required that: ") +
|
|
||||||
" [" + wn._("Row") + " # %(row_range)s] " + wn._("also be included in Item's rate"), {
|
|
||||||
idx: tax.idx,
|
|
||||||
doctype: tax.doctype,
|
|
||||||
charge_type_label: wn.meta.get_label(tax.doctype, "charge_type", tax.name),
|
|
||||||
charge_type: tax.charge_type,
|
|
||||||
inclusive_label: wn.meta.get_label(tax.doctype, "included_in_print_rate", tax.name),
|
|
||||||
row_range: row_range,
|
|
||||||
});
|
|
||||||
|
|
||||||
msgprint(msg);
|
|
||||||
throw msg;
|
|
||||||
};
|
|
||||||
|
|
||||||
if(cint(tax.included_in_print_rate)) {
|
|
||||||
if(tax.charge_type == "Actual") {
|
|
||||||
// inclusive tax cannot be of type Actual
|
|
||||||
actual_type_error();
|
|
||||||
} else if(tax.charge_type == "On Previous Row Amount" &&
|
|
||||||
!cint(this.frm.tax_doclist[tax.row_id - 1].included_in_print_rate)) {
|
|
||||||
// referred row should also be an inclusive tax
|
|
||||||
on_previous_row_error(tax.row_id);
|
|
||||||
} else if(tax.charge_type == "On Previous Row Total") {
|
|
||||||
var taxes_not_included = $.map(this.frm.tax_doclist.slice(0, tax.row_id),
|
|
||||||
function(t) { return cint(t.included_in_print_rate) ? null : t; });
|
|
||||||
if(taxes_not_included.length > 0) {
|
|
||||||
// all rows above this tax should be inclusive
|
|
||||||
on_previous_row_error(tax.row_id == 1 ? "1" : "1 - " + tax.row_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_load_item_tax_rate: function(item_tax_rate) {
|
|
||||||
return item_tax_rate ? JSON.parse(item_tax_rate) : {};
|
|
||||||
},
|
|
||||||
|
|
||||||
_get_tax_rate: function(tax, item_tax_map) {
|
|
||||||
return (keys(item_tax_map).indexOf(tax.account_head) != -1) ?
|
|
||||||
flt(item_tax_map[tax.account_head], precision("rate", tax)) :
|
|
||||||
tax.rate;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
show_item_wise_taxes: function() {
|
show_item_wise_taxes: function() {
|
||||||
@ -693,40 +345,6 @@ erpnext.selling.SellingController = wn.ui.form.Controller.extend({
|
|||||||
.appendTo($(this.frm.fields_dict.other_charges_calculation.wrapper).empty());
|
.appendTo($(this.frm.fields_dict.other_charges_calculation.wrapper).empty());
|
||||||
},
|
},
|
||||||
|
|
||||||
get_item_wise_taxes_html: function() {
|
|
||||||
var item_tax = {};
|
|
||||||
var tax_accounts = [];
|
|
||||||
var company_currency = this.get_company_currency();
|
|
||||||
|
|
||||||
$.each(this.get_tax_doclist(), function(i, tax) {
|
|
||||||
var tax_amount_precision = precision("tax_amount", tax);
|
|
||||||
$.each(JSON.parse(tax.item_wise_tax_detail || '{}'),
|
|
||||||
function(item_code, tax_amount) {
|
|
||||||
if(!item_tax[item_code]) item_tax[item_code] = {};
|
|
||||||
item_tax[item_code][tax.account_head] = flt(tax_amount, tax_amount_precision);
|
|
||||||
});
|
|
||||||
tax_accounts.push(tax.account_head);
|
|
||||||
});
|
|
||||||
|
|
||||||
var headings = $.map([wn._("Item Name")].concat(tax_accounts),
|
|
||||||
function(head) { return '<th style="min-width: 100px;">' + (head || "") + "</th>" }).join("\n");
|
|
||||||
|
|
||||||
var rows = $.map(this.get_item_doclist(), function(item) {
|
|
||||||
var item_tax_record = item_tax[item.item_code || item.item_name];
|
|
||||||
return repl("<tr><td>%(item_name)s</td>%(taxes)s</tr>", {
|
|
||||||
item_name: item.item_name,
|
|
||||||
taxes: $.map(tax_accounts, function(head) {
|
|
||||||
return "<td>" + format_currency(item_tax_record[head], company_currency) + "</td>"
|
|
||||||
}).join("\n")
|
|
||||||
});
|
|
||||||
}).join("\n");
|
|
||||||
|
|
||||||
return '<div style="overflow-x: scroll;"><table class="table table-bordered table-hover">\
|
|
||||||
<thead><tr>' + headings + '</tr></thead> \
|
|
||||||
<tbody>' + rows + '</tbody> \
|
|
||||||
</table></div>';
|
|
||||||
},
|
|
||||||
|
|
||||||
get_charges: function() {
|
get_charges: function() {
|
||||||
var me = this;
|
var me = this;
|
||||||
if(this.frm.doc.charge) {
|
if(this.frm.doc.charge) {
|
||||||
@ -837,9 +455,6 @@ erpnext.selling.SellingController = wn.ui.form.Controller.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
get_company_currency: function() {
|
|
||||||
return erpnext.get_currency(this.frm.doc.company);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// to save previous state of cur_frm.cscript
|
// to save previous state of cur_frm.cscript
|
||||||
|
@ -28,7 +28,7 @@ wn.require('app/utilities/doctype/sms_control/sms_control.js');
|
|||||||
|
|
||||||
|
|
||||||
cur_frm.cscript.onload = function(doc, cdt, cdn) {
|
cur_frm.cscript.onload = function(doc, cdt, cdn) {
|
||||||
cur_frm.cscript.manage_rounded_total();
|
cur_frm.cscript.toggle_rounded_total();
|
||||||
|
|
||||||
if(!doc.status) set_multiple(cdt,cdn,{status:'Draft'});
|
if(!doc.status) set_multiple(cdt,cdn,{status:'Draft'});
|
||||||
if(!doc.transaction_date) set_multiple(cdt,cdn,{transaction_date:get_today()});
|
if(!doc.transaction_date) set_multiple(cdt,cdn,{transaction_date:get_today()});
|
||||||
@ -42,25 +42,10 @@ cur_frm.cscript.onload = function(doc, cdt, cdn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) {
|
|
||||||
var callback = function(doc, cdt, cdn) {
|
|
||||||
if(doc.__islocal) {
|
|
||||||
// defined in sales_common.js
|
|
||||||
cur_frm.cscript.update_item_details(doc, cdt, cdn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_frm.cscript.hide_price_list_currency(doc, cdt, cdn, callback);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
|
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
|
||||||
cur_frm.clear_custom_buttons();
|
cur_frm.clear_custom_buttons();
|
||||||
erpnext.hide_naming_series();
|
erpnext.hide_naming_series();
|
||||||
|
|
||||||
if (!cur_frm.cscript.is_onload) cur_frm.cscript.hide_price_list_currency(doc, cdt, cdn);
|
|
||||||
|
|
||||||
cur_frm.toggle_display("contact_info", doc.customer);
|
cur_frm.toggle_display("contact_info", doc.customer);
|
||||||
|
|
||||||
if(doc.docstatus==1) {
|
if(doc.docstatus==1) {
|
||||||
|
@ -43,15 +43,6 @@ cur_frm.cscript.onload = function(doc, dt, dn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_frm.cscript.onload_post_render = function(doc, dt, dn) {
|
|
||||||
// defined in sales_common.js
|
|
||||||
var callback = function(doc, dt, dn) {
|
|
||||||
if(doc.__islocal) cur_frm.cscript.update_item_details(doc, dt, dn);
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_frm.cscript.hide_price_list_currency(doc, dt, dn, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
// REFRESH
|
// REFRESH
|
||||||
// ================================================================================================
|
// ================================================================================================
|
||||||
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
|
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
|
||||||
|
@ -57,14 +57,6 @@ var new_cscript = new erpnext.buying.MaterialRequestController({frm: cur_frm});
|
|||||||
$.extend(cur_frm.cscript, new_cscript);
|
$.extend(cur_frm.cscript, new_cscript);
|
||||||
|
|
||||||
|
|
||||||
cur_frm.cscript.onload = function(doc, cdt, cdn) {
|
|
||||||
if (!doc.transaction_date) doc.transaction_date = dateutil.obj_to_str(new Date());
|
|
||||||
if (!doc.status) doc.status = 'Draft';
|
|
||||||
|
|
||||||
// defined in purchase_common.js
|
|
||||||
//cur_frm.cscript.update_item_details(doc, cdt, cdn);
|
|
||||||
};
|
|
||||||
|
|
||||||
cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) {
|
cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) {
|
||||||
// second call
|
// second call
|
||||||
if(doc.__islocal){
|
if(doc.__islocal){
|
||||||
@ -79,12 +71,6 @@ cur_frm.cscript.get_item_defaults = function(doc) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
cur_frm.cscript.transaction_date = function(doc,cdt,cdn){
|
|
||||||
if(doc.__islocal){
|
|
||||||
cur_frm.cscript.get_default_schedule_date(doc);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
cur_frm.cscript.qty = function(doc, cdt, cdn) {
|
cur_frm.cscript.qty = function(doc, cdt, cdn) {
|
||||||
var d = locals[cdt][cdn];
|
var d = locals[cdt][cdn];
|
||||||
if (flt(d.qty) < flt(d.min_order_qty))
|
if (flt(d.qty) < flt(d.min_order_qty))
|
||||||
|
@ -17,9 +17,6 @@ class DocType(BuyingController):
|
|||||||
self.tname = 'Material Request Item'
|
self.tname = 'Material Request Item'
|
||||||
self.fname = 'indent_details'
|
self.fname = 'indent_details'
|
||||||
|
|
||||||
def get_default_schedule_date(self):
|
|
||||||
get_obj(dt = 'Purchase Common').get_default_schedule_date(self)
|
|
||||||
|
|
||||||
# get available qty at warehouse
|
# get available qty at warehouse
|
||||||
def get_bin_details(self, arg = ''):
|
def get_bin_details(self, arg = ''):
|
||||||
return get_obj(dt='Purchase Common').get_bin_details(arg)
|
return get_obj(dt='Purchase Common').get_bin_details(arg)
|
||||||
@ -30,22 +27,12 @@ class DocType(BuyingController):
|
|||||||
self.check_if_already_pulled()
|
self.check_if_already_pulled()
|
||||||
if self.doc.sales_order_no:
|
if self.doc.sales_order_no:
|
||||||
get_obj('DocType Mapper', 'Sales Order-Material Request', with_children=1).dt_map('Sales Order', 'Material Request', self.doc.sales_order_no, self.doc, self.doclist, "[['Sales Order', 'Material Request'],['Sales Order Item', 'Material Request Item']]")
|
get_obj('DocType Mapper', 'Sales Order-Material Request', with_children=1).dt_map('Sales Order', 'Material Request', self.doc.sales_order_no, self.doc, self.doclist, "[['Sales Order', 'Material Request'],['Sales Order Item', 'Material Request Item']]")
|
||||||
self.get_item_defaults()
|
|
||||||
else:
|
else:
|
||||||
msgprint("Please select Sales Order whose details need to pull")
|
msgprint("Please select Sales Order whose details need to pull")
|
||||||
|
|
||||||
def check_if_already_pulled(self):
|
def check_if_already_pulled(self):
|
||||||
pass#if self.[d.sales_order_no for d in getlist(self.doclist, 'indent_details')]
|
pass#if self.[d.sales_order_no for d in getlist(self.doclist, 'indent_details')]
|
||||||
|
|
||||||
|
|
||||||
# Get item's other details
|
|
||||||
#- ------------------------
|
|
||||||
def get_item_defaults(self):
|
|
||||||
self.get_default_schedule_date()
|
|
||||||
for d in getlist(self.doclist, 'indent_details'):
|
|
||||||
det = webnotes.conn.sql("select min_order_qty from tabItem where name = '%s'" % d.item_code)
|
|
||||||
d.min_order_qty = det and flt(det[0][0]) or 0
|
|
||||||
|
|
||||||
# Validate so items
|
# Validate so items
|
||||||
# ----------------------------
|
# ----------------------------
|
||||||
def validate_qty_against_so(self):
|
def validate_qty_against_so(self):
|
||||||
|
@ -38,20 +38,6 @@ erpnext.buying.PurchaseReceiptController = erpnext.buying.BuyingController.exten
|
|||||||
unhide_field(['challan_no', 'challan_date']);
|
unhide_field(['challan_no', 'challan_date']);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onload_post_render: function(doc, dt, dn) {
|
|
||||||
var me = this;
|
|
||||||
var callback = function(doc, dt, dn) {
|
|
||||||
me.update_item_details(doc, dt, dn, function(r,rt) { });
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: improve this
|
|
||||||
if(this.frm.doc.__islocal) {
|
|
||||||
if (this.frm.fields_dict.price_list_name && this.frm.doc.price_list_name)
|
|
||||||
this.price_list_name(callback);
|
|
||||||
else
|
|
||||||
callback(doc, dt, dn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var new_cscript = new erpnext.buying.PurchaseReceiptController({frm: cur_frm});
|
var new_cscript = new erpnext.buying.PurchaseReceiptController({frm: cur_frm});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user