Merge branch 'master' of github.com:webnotes/erpnext into webshop
diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.js b/accounts/doctype/purchase_invoice/purchase_invoice.js
index 92f1748..3ddf907 100644
--- a/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -34,69 +34,12 @@
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);
- }
- }
- }
});
-var new_cscript = new erpnext.buying.PurchaseInvoiceController({frm: cur_frm});
-
// for backward compatibility: combine new and previous states
-$.extend(cur_frm.cscript, new_cscript);
+$.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) {
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);
}
diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.py b/accounts/doctype/purchase_invoice/purchase_invoice.py
index c53b6d9..7f8ad63 100644
--- a/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -91,6 +91,11 @@
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
+ 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):
ret = {}
if self.doc.credit_to:
@@ -100,31 +105,6 @@
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):
if self.doc.purchase_receipt_main:
self.validate_duplicate_docname('purchase_receipt')
@@ -466,9 +446,9 @@
# expense will be booked in sales invoice
stock_item_and_auto_inventory_accounting = True
- valuation_amt = (flt(item.amount, self.precision.item.amount) +
- flt(item.item_tax_amount, self.precision.item.item_tax_amount) +
- flt(item.rm_supp_cost, self.precision.item.rm_supp_cost))
+ valuation_amt = (flt(item.amount, self.precision("amount", item)) +
+ flt(item.item_tax_amount, self.precision("item_tax_amount", item)) +
+ flt(item.rm_supp_cost, self.precision("rm_supp_cost", item)))
gl_entries.append(
self.get_gl_dict({
diff --git a/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index a70c932..ebd44d4 100644
--- a/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -119,25 +119,6 @@
wrapper.insert()
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 = [
["_Test Item Home Desktop 100", 90, 59],
["_Test Item Home Desktop 200", 135, 177]
@@ -147,13 +128,41 @@
self.assertEqual(item.item_tax_amount, expected_values[i][1])
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_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 = [
+ ["_Test FG Item", 90, 7059],
+ ["_Test Item Home Desktop 200", 135, 177]
+ ]
+ for i, item in enumerate(wrapper.doclist.get({"parentfield": "entries"})):
+ self.assertEqual(item.item_code, expected_values[i][0])
+ self.assertEqual(item.item_tax_amount, expected_values[i][1])
+ self.assertEqual(item.valuation_rate, expected_values[i][2])
+
self.assertEqual(wrapper.doclist[0].net_total, 1250)
# tax amounts
@@ -172,15 +181,6 @@
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 = [
- ["_Test FG Item", 90, 7059],
- ["_Test Item Home Desktop 200", 135, 177]
- ]
- for i, item in enumerate(wrapper.doclist.get({"parentfield": "entries"})):
- self.assertEqual(item.item_code, expected_values[i][0])
- self.assertEqual(item.item_tax_amount, expected_values[i][1])
- self.assertEqual(item.valuation_rate, expected_values[i][2])
def test_purchase_invoice_with_advance(self):
from accounts.doctype.journal_voucher.test_journal_voucher \
diff --git a/accounts/doctype/sales_invoice/sales_invoice.js b/accounts/doctype/sales_invoice/sales_invoice.js
index be6ec3d..800cd2b 100644
--- a/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/accounts/doctype/sales_invoice/sales_invoice.js
@@ -26,48 +26,62 @@
wn.require('app/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js');
wn.require('app/utilities/doctype/sms_control/sms_control.js');
-// On Load
-// -------
-cur_frm.cscript.onload = function(doc,dt,dn) {
- cur_frm.cscript.manage_rounded_total();
- if(!doc.customer && doc.debit_to) wn.meta.get_docfield(dt, 'debit_to', dn).print_hide = 0;
- if (doc.__islocal) {
- if(!doc.due_date) set_multiple(dt,dn,{due_date:get_today()});
- if(!doc.posting_date) set_multiple(dt,dn,{posting_date:get_today()});
- if(!doc.currency && sys_defaults.currency) set_multiple(dt,dn,{currency:sys_defaults.currency});
- if(!doc.price_list_currency) set_multiple(dt, dn, {price_list_currency: doc.currency, plc_conversion_rate: 1});
+erpnext.selling.SalesInvoiceController = erpnext.selling.SellingController.extend({
+ onload: function() {
+ this._super();
+
+ // show debit_to in print format
+ if(!this.frm.doc.customer && this.frm.doc.debit_to) {
+ this.frm.set_df_property("debit_to", "print_hide", 0);
+ }
+ },
+
+ refresh: function(doc, dt, dn) {
+ this._super();
+
+ cur_frm.cscript.is_opening(doc, dt, dn);
- }
-}
+ // Show / Hide button
+ cur_frm.clear_custom_buttons();
+ // if (!cur_frm.cscript.is_onload) cur_frm.cscript.hide_price_list_currency(doc, dt, dn);
-cur_frm.cscript.onload_post_render = function(doc, dt, dn) {
- var callback = function(doc, dt, dn) {
- // called from mapper, update the account names for items and customer
- var callback2 = function(doc, dt, dn) {
- if(doc.customer && doc.__islocal) {
- $c_obj(make_doclist(doc.doctype,doc.name),
- 'load_default_accounts','',
- function(r,rt) {
- refresh_field('entries');
- cur_frm.cscript.customer(doc,dt,dn,onload=true);
- }
- );
+ if(doc.docstatus==1) {
+ cur_frm.add_custom_button('View Ledger', cur_frm.cscript.view_ledger_entry);
+ cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms);
+
+ if(doc.is_pos==1 && doc.update_stock!=1)
+ cur_frm.add_custom_button('Make Delivery', cur_frm.cscript['Make Delivery Note']);
+
+ if(doc.outstanding_amount!=0)
+ cur_frm.add_custom_button('Make Payment Entry', cur_frm.cscript.make_bank_voucher);
+ }
+ cur_frm.cscript.hide_fields(doc, dt, dn);
+ },
+
+ is_pos: function() {
+ if(cint(this.frm.doc.is_pos)) {
+ if(!this.frm.doc.company) {
+ this.frm.set_value("is_pos", 0);
+ msgprint(wn._("Please specify Company to proceed"));
+ } else {
+ var me = this;
+ this.frm.call({
+ doc: me.frm.doc,
+ method: "set_missing_values",
+ });
}
}
- // defined in sales_common.js
- var callback1 = function(doc, dt, dn) {
- //for previously created sales invoice, set required field related to pos
- cur_frm.cscript.update_item_details(doc, dt, dn, callback2);
- }
- if(doc.is_pos ==1) cur_frm.cscript.is_pos(doc, dt, dn,callback1);
- else cur_frm.cscript.update_item_details(doc, dt, dn, callback2);
- }
+ // TODO toggle display of fields
+ },
+
+ debit_to: function() {
+ this.customer();
+ },
+});
- cur_frm.cscript.hide_price_list_currency(doc, dt, dn, callback);
-
-}
-
+// for backward compatibility: combine new and previous states
+$.extend(cur_frm.cscript, new erpnext.selling.SalesInvoiceController({frm: cur_frm}));
// Hide Fields
// ------------
@@ -104,50 +118,6 @@
}
-// Refresh
-// -------
-cur_frm.cscript.refresh = function(doc, dt, dn) {
- cur_frm.cscript.is_opening(doc, dt, dn);
- erpnext.hide_naming_series();
-
- // Show / Hide button
- cur_frm.clear_custom_buttons();
- if (!cur_frm.cscript.is_onload) cur_frm.cscript.hide_price_list_currency(doc, dt, dn);
-
- if(doc.docstatus==1) {
- cur_frm.add_custom_button('View Ledger', cur_frm.cscript.view_ledger_entry);
- cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms);
-
- if(doc.is_pos==1 && doc.update_stock!=1)
- cur_frm.add_custom_button('Make Delivery', cur_frm.cscript['Make Delivery Note']);
-
- if(doc.outstanding_amount!=0)
- cur_frm.add_custom_button('Make Payment Entry', cur_frm.cscript.make_bank_voucher);
- }
- cur_frm.cscript.hide_fields(doc, dt, dn);
-
-}
-
-//fetch retail transaction related fields
-//--------------------------------------------
-cur_frm.cscript.is_pos = function(doc,dt,dn,callback){
- cur_frm.cscript.hide_fields(doc, dt, dn);
- if(doc.is_pos == 1){
- if (!doc.company) {
- msgprint("Please select company to proceed");
- doc.is_pos = 0;
- refresh_field('is_pos');
- }
- else {
- var callback1 = function(r,rt){
- if(callback) callback(doc, dt, dn);
- cur_frm.refresh();
- }
- $c_obj(make_doclist(dt,dn),'set_pos_fields','',callback1);
- }
- }
-}
-
cur_frm.cscript.mode_of_payment = function(doc) {
cur_frm.call({
method: "get_bank_cash_account",
@@ -168,66 +138,10 @@
}
}
-
-
-//Customer
-cur_frm.cscript.customer = function(doc,dt,dn,onload) {
- cur_frm.toggle_display("contact_section", doc.customer);
-
- var pl = doc.price_list_name;
- var callback = function(r,rt) {
- var callback2 = function(doc, dt, dn) {
- doc = locals[dt][dn];
- if(doc.debit_to && doc.posting_date){
- get_server_fields('get_cust_and_due_date','','',doc,dt,dn,1,
- function(doc, dt, dn) {
- cur_frm.refresh();
- if (!onload && (pl != doc.price_list_name)) cur_frm.cscript.price_list_name(doc, dt, dn);
- });
-
- }
- }
- var doc = locals[cur_frm.doctype][cur_frm.docname];
- get_server_fields('get_debit_to','','',doc, dt, dn, 0, callback2);
- }
- var args = onload ? 'onload':''
- if(doc.customer) $c_obj(make_doclist(doc.doctype, doc.name), 'get_default_customer_address', args, callback);
-
-}
-
-
-
cur_frm.cscript.customer_address = cur_frm.cscript.contact_person = function(doc,dt,dn) {
if(doc.customer) get_server_fields('get_customer_address', JSON.stringify({customer: doc.customer, address: doc.customer_address, contact: doc.contact_person}),'', doc, dt, dn, 1);
}
-// Set Due Date = posting date + credit days
-cur_frm.cscript.debit_to = function(doc,dt,dn) {
-
- var callback2 = function(r,rt) {
- var doc = locals[cur_frm.doctype][cur_frm.docname];
- cur_frm.refresh();
- }
-
- var callback = function(r,rt) {
- var doc = locals[cur_frm.doctype][cur_frm.docname];
- if(doc.customer) $c_obj(make_doclist(dt,dn), 'get_default_customer_address', '', callback2);
- cur_frm.toggle_display("contact_section", doc.customer);
-
- cur_frm.refresh();
- }
-
- if(doc.debit_to && doc.posting_date){
- get_server_fields('get_cust_and_due_date','','',doc,dt,dn,1,callback);
- }
-}
-
-
-
-//refresh advance amount
-//-------------------------------------------------
-
-
cur_frm.cscript.write_off_outstanding_amount_automatically = function(doc) {
if (doc.write_off_outstanding_amount_automatically == 1)
doc.write_off_amount = flt(doc.grand_total) - flt(doc.paid_amount);
@@ -244,9 +158,6 @@
cur_frm.cscript.write_off_outstanding_amount_automatically(doc);
}
-
-//Set debit and credit to zero on adding new row
-//----------------------------------------------
cur_frm.fields_dict['entries'].grid.onrowadd = function(doc, cdt, cdn){
cl = getchildren('Sales Invoice Item', doc.name, cur_frm.cscript.fname, doc.doctype);
diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py
index 6871b1e..d313a32 100644
--- a/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/accounts/doctype/sales_invoice/sales_invoice.py
@@ -41,7 +41,6 @@
def validate(self):
super(DocType, self).validate()
- self.fetch_missing_values()
self.validate_posting_time()
self.so_dn_required()
self.validate_proj_cust()
@@ -50,7 +49,6 @@
sales_com_obj.check_active_sales_items(self)
sales_com_obj.check_conversion_rate(self)
sales_com_obj.validate_max_discount(self, 'entries')
- sales_com_obj.get_allocated_sum(self)
sales_com_obj.validate_fiscal_year(self.doc.fiscal_year,
self.doc.posting_date,'Posting Date')
self.validate_customer()
@@ -136,25 +134,16 @@
self.validate_recurring_invoice()
self.convert_to_recurring()
- def fetch_missing_values(self):
- # fetch contact and address details for customer, if they are not mentioned
- if not (self.doc.contact_person and self.doc.customer_address):
- for fieldname, val in self.get_default_address_and_contact("customer").items():
- if not self.doc.fields.get(fieldname) and self.meta.get_field(fieldname):
- self.doc.fields[fieldname] = val
-
- # fetch missing item values
- for item in self.doclist.get({"parentfield": "entries"}):
- if item.fields.get("item_code"):
- ret = get_obj('Sales Common').get_item_details(item.fields, self)
- 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_missing_values(self, for_validate=False):
+ super(DocType, self).set_missing_values(for_validate)
+ self.set_pos_fields(for_validate)
- # fetch pos details, if they are not fetched
- if cint(self.doc.is_pos):
- self.set_pos_fields(for_validate=True)
+ def set_customer_defaults(self):
+ # TODO cleanup these methods
+ self.doc.fields.update(self.get_debit_to())
+ self.get_cust_and_due_date()
+
+ super(DocType, self).set_customer_defaults()
def update_time_log_batch(self, sales_invoice):
for d in self.doclist.get({"doctype":"Sales Invoice Item"}):
@@ -175,10 +164,11 @@
"""Set retail related fields from pos settings"""
if cint(self.doc.is_pos) != 1:
return
+
+ from selling.utils import get_pos_settings, apply_pos_settings
+ pos = get_pos_settings(self.doc.company)
- if self.pos_settings:
- pos = self.pos_settings[0]
-
+ if pos:
self.doc.conversion_rate = flt(pos.conversion_rate)
if not self.doc.debit_to:
@@ -195,7 +185,7 @@
# set pos values in items
for item in self.doclist.get({"parentfield": "entries"}):
if item.fields.get('item_code'):
- for fieldname, val in self.apply_pos_settings(item.fields).items():
+ for fieldname, val in apply_pos_settings(pos, item.fields).items():
if (not for_validate) or (for_validate and not item.fields.get(fieldname)):
item.fields[fieldname] = val
@@ -205,7 +195,7 @@
# fetch charges
if self.doc.charge and not len(self.doclist.get({"parentfield": "other_charges"})):
- self.get_other_charges()
+ self.set_taxes()
def get_customer_account(self):
"""Get Account Head to which amount needs to be Debited based on Customer"""
@@ -275,86 +265,14 @@
ret = self.get_debit_to()
self.doc.debit_to = ret.get('debit_to')
-
- def load_default_accounts(self):
- """
- Loads default accounts from items, customer when called from mapper
- """
- self.get_income_expense_account('entries')
-
-
- def get_income_expense_account(self,doctype):
- for d in getlist(self.doclist, doctype):
- if d.item_code:
- item = webnotes.conn.get_value("Item", d.item_code, ["default_income_account",
- "default_sales_cost_center", "purchase_account"], as_dict=True)
- d.income_account = item['default_income_account'] or ""
- d.cost_center = item['default_sales_cost_center'] or ""
-
- if cint(webnotes.defaults.get_global_default("auto_inventory_accounting")) \
- and cint(self.doc.is_pos) and cint(self.doc.update_stock):
- d.expense_account = item['purchase_account'] or ""
-
- def get_item_details(self, args=None):
- import json
- args = args and json.loads(args) or {}
- if args.get('item_code'):
- ret = get_obj('Sales Common').get_item_details(args, self)
-
- if cint(self.doc.is_pos) == 1 and self.pos_settings:
- ret = self.apply_pos_settings(args, ret)
-
- return ret
-
- elif cint(self.doc.is_pos) == 1 and self.pos_settings:
- for doc in self.doclist.get({"parentfield": "entries"}):
- if doc.fields.get('item_code'):
- ret = self.apply_pos_settings(doc.fields)
- for r in ret:
- if not doc.fields.get(r):
- doc.fields[r] = ret[r]
-
@property
def pos_settings(self):
if not hasattr(self, "_pos_settings"):
- dtl = webnotes.conn.sql("""select * from `tabPOS Setting` where user = %s
- and company = %s""", (webnotes.session['user'], self.doc.company), as_dict=1)
- if not dtl:
- dtl = webnotes.conn.sql("""select * from `tabPOS Setting`
- where ifnull(user,'') = '' and company = %s""", self.doc.company, as_dict=1)
- self._pos_settings = dtl
+ from selling.utils import get_pos_settings
+ self._pos_settings = get_pos_settings({"company": self.doc.company})
return self._pos_settings
- def apply_pos_settings(self, args, ret=None):
- if not ret: ret = {}
-
- pos = self.pos_settings[0]
-
- item = webnotes.conn.sql("""select default_income_account, default_sales_cost_center,
- default_warehouse, purchase_account from tabItem where name = %s""",
- args.get('item_code'), as_dict=1)
-
- if item:
- item = item[0]
-
- ret.update({
- "income_account": item.get("default_income_account") \
- or pos.get("income_account") or args.get("income_account"),
- "cost_center": item.get("default_sales_cost_center") \
- or pos.get("cost_center") or args.get("cost_center"),
- "warehouse": item.get("default_warehouse") \
- or pos.get("warehouse") or args.get("warehouse"),
- "expense_account": item.get("purchase_account") \
- or pos.get("expense_account") or args.get("expense_account")
- })
-
- if ret.get("warehouse"):
- ret["actual_qty"] = flt(webnotes.conn.get_value("Bin",
- {"item_code": args.get("item_code"), "warehouse": args.get("warehouse")},
- "actual_qty"))
- return ret
-
def get_barcode_details(self, barcode):
return get_obj('Sales Common').get_barcode_details(barcode)
@@ -378,14 +296,6 @@
return get_obj('Sales Common').get_tc_details(self)
- def load_default_taxes(self):
- self.doclist = get_obj('Sales Common').load_default_taxes(self)
-
-
- def get_other_charges(self):
- self.doclist = get_obj('Sales Common').get_other_charges(self)
-
-
def get_advances(self):
super(DocType, self).get_advances(self.doc.debit_to,
"Sales Invoice Advance", "advance_adjustment_details", "credit")
@@ -629,7 +539,9 @@
else:
self.doclist = self.doc.clear_table(self.doclist, 'packing_details')
webnotes.conn.set(self.doc,'paid_amount',0)
-
+
+ # TODO
+ # move to calculations
webnotes.conn.set(self.doc, 'outstanding_amount',
flt(self.doc.grand_total) - flt(self.doc.total_advance) -
flt(self.doc.paid_amount) - flt(self.doc.write_off_amount))
@@ -740,7 +652,7 @@
"against": self.doc.debit_to,
"credit": flt(tax.tax_amount),
"remarks": self.doc.remarks,
- "cost_center": tax.cost_center_other_charges
+ "cost_center": tax.cost_center
})
)
diff --git a/accounts/doctype/sales_invoice/sales_invoice.txt b/accounts/doctype/sales_invoice/sales_invoice.txt
index a2c422f..8b114e7 100644
--- a/accounts/doctype/sales_invoice/sales_invoice.txt
+++ b/accounts/doctype/sales_invoice/sales_invoice.txt
@@ -1,8 +1,8 @@
[
{
- "creation": "2013-04-19 11:00:14",
+ "creation": "2013-05-21 16:16:41",
"docstatus": 0,
- "modified": "2013-04-22 11:59:28",
+ "modified": "2013-05-21 18:25:07",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -10,6 +10,7 @@
"allow_attach": 1,
"autoname": "naming_series:",
"doctype": "DocType",
+ "document_type": "Transaction",
"is_submittable": 1,
"module": "Accounts",
"name": "__common__",
@@ -30,6 +31,7 @@
"parent": "Sales Invoice",
"parentfield": "permissions",
"parenttype": "DocType",
+ "permlevel": 0,
"read": 1
},
{
@@ -222,11 +224,12 @@
"doctype": "DocField",
"fieldname": "entries",
"fieldtype": "Table",
- "label": "Entries",
+ "label": "Sales Invoice Items",
"oldfieldname": "entries",
"oldfieldtype": "Table",
"options": "Sales Invoice Item",
- "read_only": 0
+ "read_only": 0,
+ "reqd": 1
},
{
"doctype": "DocField",
@@ -251,7 +254,6 @@
"width": "50%"
},
{
- "description": "Will be calculated automatically when you enter the details",
"doctype": "DocField",
"fieldname": "net_total",
"fieldtype": "Currency",
@@ -259,12 +261,21 @@
"oldfieldname": "net_total",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
- "print_hide": 0,
+ "print_hide": 1,
"read_only": 1,
"reqd": 1
},
{
"doctype": "DocField",
+ "fieldname": "net_total_export",
+ "fieldtype": "Currency",
+ "label": "Net Total (Export)",
+ "options": "currency",
+ "print_hide": 0,
+ "read_only": 1
+ },
+ {
+ "doctype": "DocField",
"fieldname": "recalculate_values",
"fieldtype": "Button",
"label": "Re-Calculate Values",
@@ -452,6 +463,15 @@
},
{
"doctype": "DocField",
+ "fieldname": "other_charges_total_export",
+ "fieldtype": "Currency",
+ "label": "Total Taxes and Charges (Export)",
+ "options": "currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "doctype": "DocField",
"fieldname": "other_charges_calculation",
"fieldtype": "HTML",
"label": "Taxes and Charges Calculation",
@@ -1288,7 +1308,6 @@
"cancel": 1,
"create": 1,
"doctype": "DocPerm",
- "permlevel": 0,
"report": 1,
"role": "Accounts User",
"submit": 1,
@@ -1297,8 +1316,7 @@
{
"doctype": "DocPerm",
"match": "customer",
- "permlevel": 0,
- "report": 1,
+ "report": 0,
"role": "Customer"
- },
+ }
]
\ No newline at end of file
diff --git a/accounts/doctype/sales_invoice/test_sales_invoice.py b/accounts/doctype/sales_invoice/test_sales_invoice.py
index b46cdd1..7c4b8b1 100644
--- a/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -1,12 +1,226 @@
import webnotes
-import unittest
+import unittest, json
+from webnotes.utils import flt
class TestSalesInvoice(unittest.TestCase):
def make(self):
- w = webnotes.bean(webnotes.copy_doclist(test_records[0]))
+ w = webnotes.bean(copy=test_records[0])
w.insert()
w.submit()
return w
+
+ def test_sales_invoice_calculation_base_currency(self):
+ si = webnotes.bean(copy=test_records[2])
+ si.run_method("calculate_taxes_and_totals")
+ si.insert()
+
+ expected_values = {
+ "keys": ["ref_rate", "adj_rate", "export_rate", "export_amount",
+ "base_ref_rate", "basic_rate", "amount"],
+ "_Test Item Home Desktop 100": [50, 0, 50, 500, 50, 50, 500],
+ "_Test Item Home Desktop 200": [150, 0, 150, 750, 150, 150, 750],
+ }
+
+ # check if children are saved
+ self.assertEquals(len(si.doclist.get({"parentfield": "entries"})),
+ len(expected_values)-1)
+
+ # check if item values are calculated
+ for d in si.doclist.get({"parentfield": "entries"}):
+ for i, k in enumerate(expected_values["keys"]):
+ self.assertEquals(d.fields.get(k), expected_values[d.item_code][i])
+
+ # check net total
+ self.assertEquals(si.doc.net_total, 1250)
+ self.assertEquals(si.doc.net_total_export, 1250)
+
+ # check tax calculation
+ expected_values = {
+ "keys": ["tax_amount", "total"],
+ "_Test Account Shipping Charges - _TC": [100, 1350],
+ "_Test Account Customs Duty - _TC": [125, 1475],
+ "_Test Account Excise Duty - _TC": [140, 1615],
+ "_Test Account Education Cess - _TC": [2.8, 1617.8],
+ "_Test Account S&H Education Cess - _TC": [1.4, 1619.2],
+ "_Test Account CST - _TC": [32.38, 1651.58],
+ "_Test Account VAT - _TC": [156.25, 1807.83],
+ "_Test Account Discount - _TC": [-180.78, 1627.05]
+ }
+
+ for d in si.doclist.get({"parentfield": "other_charges"}):
+ for i, k in enumerate(expected_values["keys"]):
+ self.assertEquals(d.fields.get(k), expected_values[d.account_head][i])
+
+ self.assertEquals(si.doc.grand_total, 1627.05)
+ self.assertEquals(si.doc.grand_total_export, 1627.05)
+
+ def test_sales_invoice_calculation_export_currency(self):
+ si = webnotes.bean(copy=test_records[2])
+ si.doc.currency = "USD"
+ si.doc.conversion_rate = 50
+ si.doclist[1].export_rate = 1
+ si.doclist[1].ref_rate = 1
+ si.doclist[2].export_rate = 3
+ si.doclist[2].ref_rate = 3
+ si.run_method("calculate_taxes_and_totals")
+ si.insert()
+
+ expected_values = {
+ "keys": ["ref_rate", "adj_rate", "export_rate", "export_amount",
+ "base_ref_rate", "basic_rate", "amount"],
+ "_Test Item Home Desktop 100": [1, 0, 1, 10, 50, 50, 500],
+ "_Test Item Home Desktop 200": [3, 0, 3, 15, 150, 150, 750],
+ }
+
+ # check if children are saved
+ self.assertEquals(len(si.doclist.get({"parentfield": "entries"})),
+ len(expected_values)-1)
+
+ # check if item values are calculated
+ for d in si.doclist.get({"parentfield": "entries"}):
+ for i, k in enumerate(expected_values["keys"]):
+ self.assertEquals(d.fields.get(k), expected_values[d.item_code][i])
+
+ # check net total
+ self.assertEquals(si.doc.net_total, 1250)
+ self.assertEquals(si.doc.net_total_export, 25)
+
+ # check tax calculation
+ expected_values = {
+ "keys": ["tax_amount", "total"],
+ "_Test Account Shipping Charges - _TC": [100, 1350],
+ "_Test Account Customs Duty - _TC": [125, 1475],
+ "_Test Account Excise Duty - _TC": [140, 1615],
+ "_Test Account Education Cess - _TC": [2.8, 1617.8],
+ "_Test Account S&H Education Cess - _TC": [1.4, 1619.2],
+ "_Test Account CST - _TC": [32.38, 1651.58],
+ "_Test Account VAT - _TC": [156.25, 1807.83],
+ "_Test Account Discount - _TC": [-180.78, 1627.05]
+ }
+
+ for d in si.doclist.get({"parentfield": "other_charges"}):
+ for i, k in enumerate(expected_values["keys"]):
+ self.assertEquals(d.fields.get(k), expected_values[d.account_head][i])
+
+ self.assertEquals(si.doc.grand_total, 1627.05)
+ self.assertEquals(si.doc.grand_total_export, 32.54)
+
+ def test_inclusive_rate_validations(self):
+ si = webnotes.bean(copy=test_records[2])
+ for i, tax in enumerate(si.doclist.get({"parentfield": "other_charges"})):
+ tax.idx = i+1
+
+ si.doclist[1].ref_rate = 62.5
+ si.doclist[1].ref_rate = 191
+ for i in [3, 5, 6, 7, 8, 9]:
+ si.doclist[i].included_in_print_rate = 1
+
+ # tax type "Actual" cannot be inclusive
+ self.assertRaises(webnotes.ValidationError, si.run_method, "calculate_taxes_and_totals")
+
+ # taxes above included type 'On Previous Row Total' should also be included
+ si.doclist[3].included_in_print_rate = 0
+ self.assertRaises(webnotes.ValidationError, si.run_method, "calculate_taxes_and_totals")
+
+ def test_sales_invoice_calculation_base_currency_with_tax_inclusive_price(self):
+ # prepare
+ si = webnotes.bean(copy=test_records[3])
+ si.run_method("calculate_taxes_and_totals")
+ si.insert()
+
+ expected_values = {
+ "keys": ["ref_rate", "adj_rate", "export_rate", "export_amount",
+ "base_ref_rate", "basic_rate", "amount"],
+ "_Test Item Home Desktop 100": [62.5, 0, 62.5, 625.0, 50, 50, 500],
+ "_Test Item Home Desktop 200": [190.66, 0, 190.66, 953.3, 150, 150, 750],
+ }
+
+ # check if children are saved
+ self.assertEquals(len(si.doclist.get({"parentfield": "entries"})),
+ len(expected_values)-1)
+
+ # check if item values are calculated
+ for d in si.doclist.get({"parentfield": "entries"}):
+ for i, k in enumerate(expected_values["keys"]):
+ self.assertEquals(d.fields.get(k), expected_values[d.item_code][i])
+
+ # check net total
+ self.assertEquals(si.doc.net_total, 1250)
+ self.assertEquals(si.doc.net_total_export, 1578.3)
+
+ # check tax calculation
+ expected_values = {
+ "keys": ["tax_amount", "total"],
+ "_Test Account Excise Duty - _TC": [140, 1390],
+ "_Test Account Education Cess - _TC": [2.8, 1392.8],
+ "_Test Account S&H Education Cess - _TC": [1.4, 1394.2],
+ "_Test Account CST - _TC": [27.88, 1422.08],
+ "_Test Account VAT - _TC": [156.25, 1578.33],
+ "_Test Account Customs Duty - _TC": [125, 1703.33],
+ "_Test Account Shipping Charges - _TC": [100, 1803.33],
+ "_Test Account Discount - _TC": [-180.33, 1623]
+ }
+
+ for d in si.doclist.get({"parentfield": "other_charges"}):
+ for i, k in enumerate(expected_values["keys"]):
+ self.assertEquals(flt(d.fields.get(k), 6), expected_values[d.account_head][i])
+
+ self.assertEquals(si.doc.grand_total, 1623)
+ self.assertEquals(si.doc.grand_total_export, 1623)
+
+ def test_sales_invoice_calculation_export_currency_with_tax_inclusive_price(self):
+ # prepare
+ si = webnotes.bean(copy=test_records[3])
+ si.doc.currency = "USD"
+ si.doc.conversion_rate = 50
+ si.doclist[1].ref_rate = 55.56
+ si.doclist[1].adj_rate = 10
+ si.doclist[2].ref_rate = 187.5
+ si.doclist[2].adj_rate = 20
+ si.doclist[9].rate = 5000
+
+ si.run_method("calculate_taxes_and_totals")
+ si.insert()
+
+ expected_values = {
+ "keys": ["ref_rate", "adj_rate", "export_rate", "export_amount",
+ "base_ref_rate", "basic_rate", "amount"],
+ "_Test Item Home Desktop 100": [55.56, 10, 50, 500, 2222.11, 1999.9, 19999.0],
+ "_Test Item Home Desktop 200": [187.5, 20, 150, 750, 7375.66, 5900.53, 29502.65],
+ }
+
+ # check if children are saved
+ self.assertEquals(len(si.doclist.get({"parentfield": "entries"})),
+ len(expected_values)-1)
+
+ # check if item values are calculated
+ for d in si.doclist.get({"parentfield": "entries"}):
+ for i, k in enumerate(expected_values["keys"]):
+ self.assertEquals(d.fields.get(k), expected_values[d.item_code][i])
+
+ # check net total
+ self.assertEquals(si.doc.net_total, 49501.65)
+ self.assertEquals(si.doc.net_total_export, 1250)
+
+ # check tax calculation
+ expected_values = {
+ "keys": ["tax_amount", "total"],
+ "_Test Account Excise Duty - _TC": [5540.22, 55041.87],
+ "_Test Account Education Cess - _TC": [110.81, 55152.68],
+ "_Test Account S&H Education Cess - _TC": [55.4, 55208.08],
+ "_Test Account CST - _TC": [1104.16, 56312.24],
+ "_Test Account VAT - _TC": [6187.71, 62499.95],
+ "_Test Account Customs Duty - _TC": [4950.17, 67450.12],
+ "_Test Account Shipping Charges - _TC": [5000, 72450.12],
+ "_Test Account Discount - _TC": [-7245.01, 65205.11]
+ }
+
+ for d in si.doclist.get({"parentfield": "other_charges"}):
+ for i, k in enumerate(expected_values["keys"]):
+ self.assertEquals(flt(d.fields.get(k), 6), expected_values[d.account_head][i])
+
+ self.assertEquals(si.doc.grand_total, 65205.11)
+ self.assertEquals(si.doc.grand_total_export, 1304.1)
def test_outstanding(self):
w = self.make()
@@ -103,7 +317,7 @@
pos[0]["cash_bank_account"] = "_Test Account Bank Account - _TC"
pos[0]["paid_amount"] = 600.0
- si = webnotes.bean(pos)
+ si = webnotes.bean(copy=pos)
si.insert()
si.submit()
@@ -126,11 +340,11 @@
expected_gl_entries = sorted([
[si.doc.debit_to, 630.0, 0.0],
- [test_records[1][1]["income_account"], 0.0, 500.0],
- [test_records[1][2]["account_head"], 0.0, 80.0],
- [test_records[1][3]["account_head"], 0.0, 50.0],
+ [pos[1]["income_account"], 0.0, 500.0],
+ [pos[2]["account_head"], 0.0, 80.0],
+ [pos[3]["account_head"], 0.0, 50.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],
["_Test Account Bank Account - _TC", 600.0, 0.0]
])
@@ -520,4 +734,267 @@
"tax_amount": 50.0,
}
],
+ [
+ {
+ "naming_series": "_T-Sales Invoice-",
+ "company": "_Test Company",
+ "conversion_rate": 1.0,
+ "currency": "INR",
+ "debit_to": "_Test Customer - _TC",
+ "customer": "_Test Customer",
+ "customer_name": "_Test Customer",
+ "doctype": "Sales Invoice",
+ "due_date": "2013-01-23",
+ "fiscal_year": "_Test Fiscal Year 2013",
+ "grand_total_export": 0,
+ "plc_conversion_rate": 1.0,
+ "posting_date": "2013-01-23",
+ "price_list_currency": "INR",
+ "price_list_name": "_Test Price List",
+ "territory": "_Test Territory",
+ },
+ # items
+ {
+ "doctype": "Sales Invoice Item",
+ "parentfield": "entries",
+ "item_code": "_Test Item Home Desktop 100",
+ "item_name": "_Test Item Home Desktop 100",
+ "qty": 10,
+ "ref_rate": 50,
+ "export_rate": 50,
+ "stock_uom": "_Test UOM",
+ "item_tax_rate": json.dumps({"_Test Account Excise Duty - _TC": 10}),
+ "income_account": "Sales - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+
+ },
+ {
+ "doctype": "Sales Invoice Item",
+ "parentfield": "entries",
+ "item_code": "_Test Item Home Desktop 200",
+ "item_name": "_Test Item Home Desktop 200",
+ "qty": 5,
+ "ref_rate": 150,
+ "export_rate": 150,
+ "stock_uom": "_Test UOM",
+ "income_account": "Sales - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+
+ },
+ # taxes
+ {
+ "doctype": "Sales Taxes and Charges",
+ "parentfield": "other_charges",
+ "charge_type": "Actual",
+ "account_head": "_Test Account Shipping Charges - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "Shipping Charges",
+ "rate": 100
+ },
+ {
+ "doctype": "Sales Taxes and Charges",
+ "parentfield": "other_charges",
+ "charge_type": "On Net Total",
+ "account_head": "_Test Account Customs Duty - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "Customs Duty",
+ "rate": 10
+ },
+ {
+ "doctype": "Sales Taxes and Charges",
+ "parentfield": "other_charges",
+ "charge_type": "On Net Total",
+ "account_head": "_Test Account Excise Duty - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "Excise Duty",
+ "rate": 12
+ },
+ {
+ "doctype": "Sales Taxes and Charges",
+ "parentfield": "other_charges",
+ "charge_type": "On Previous Row Amount",
+ "account_head": "_Test Account Education Cess - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "Education Cess",
+ "rate": 2,
+ "row_id": 3
+ },
+ {
+ "doctype": "Sales Taxes and Charges",
+ "parentfield": "other_charges",
+ "charge_type": "On Previous Row Amount",
+ "account_head": "_Test Account S&H Education Cess - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "S&H Education Cess",
+ "rate": 1,
+ "row_id": 3
+ },
+ {
+ "doctype": "Sales Taxes and Charges",
+ "parentfield": "other_charges",
+ "charge_type": "On Previous Row Total",
+ "account_head": "_Test Account CST - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "CST",
+ "rate": 2,
+ "row_id": 5
+ },
+ {
+ "doctype": "Sales Taxes and Charges",
+ "parentfield": "other_charges",
+ "charge_type": "On Net Total",
+ "account_head": "_Test Account VAT - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "VAT",
+ "rate": 12.5
+ },
+ {
+ "doctype": "Sales Taxes and Charges",
+ "parentfield": "other_charges",
+ "charge_type": "On Previous Row Total",
+ "account_head": "_Test Account Discount - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "Discount",
+ "rate": -10,
+ "row_id": 7
+ },
+ ],
+ [
+ {
+ "naming_series": "_T-Sales Invoice-",
+ "company": "_Test Company",
+ "conversion_rate": 1.0,
+ "currency": "INR",
+ "debit_to": "_Test Customer - _TC",
+ "customer": "_Test Customer",
+ "customer_name": "_Test Customer",
+ "doctype": "Sales Invoice",
+ "due_date": "2013-01-23",
+ "fiscal_year": "_Test Fiscal Year 2013",
+ "grand_total_export": 0,
+ "plc_conversion_rate": 1.0,
+ "posting_date": "2013-01-23",
+ "price_list_currency": "INR",
+ "price_list_name": "_Test Price List",
+ "territory": "_Test Territory",
+ },
+ # items
+ {
+ "doctype": "Sales Invoice Item",
+ "parentfield": "entries",
+ "item_code": "_Test Item Home Desktop 100",
+ "item_name": "_Test Item Home Desktop 100",
+ "qty": 10,
+ "ref_rate": 62.5,
+ "export_rate": 62.5,
+ "stock_uom": "_Test UOM",
+ "item_tax_rate": json.dumps({"_Test Account Excise Duty - _TC": 10}),
+ "income_account": "Sales - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+
+ },
+ {
+ "doctype": "Sales Invoice Item",
+ "parentfield": "entries",
+ "item_code": "_Test Item Home Desktop 200",
+ "item_name": "_Test Item Home Desktop 200",
+ "qty": 5,
+ "ref_rate": 190.66,
+ "export_rate": 190.66,
+ "stock_uom": "_Test UOM",
+ "income_account": "Sales - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+
+ },
+ # taxes
+ {
+ "doctype": "Sales Taxes and Charges",
+ "parentfield": "other_charges",
+ "charge_type": "On Net Total",
+ "account_head": "_Test Account Excise Duty - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "Excise Duty",
+ "rate": 12,
+ "included_in_print_rate": 1,
+ "idx": 1
+ },
+ {
+ "doctype": "Sales Taxes and Charges",
+ "parentfield": "other_charges",
+ "charge_type": "On Previous Row Amount",
+ "account_head": "_Test Account Education Cess - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "Education Cess",
+ "rate": 2,
+ "row_id": 1,
+ "included_in_print_rate": 1,
+ "idx": 2
+ },
+ {
+ "doctype": "Sales Taxes and Charges",
+ "parentfield": "other_charges",
+ "charge_type": "On Previous Row Amount",
+ "account_head": "_Test Account S&H Education Cess - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "S&H Education Cess",
+ "rate": 1,
+ "row_id": 1,
+ "included_in_print_rate": 1,
+ "idx": 3
+ },
+ {
+ "doctype": "Sales Taxes and Charges",
+ "parentfield": "other_charges",
+ "charge_type": "On Previous Row Total",
+ "account_head": "_Test Account CST - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "CST",
+ "rate": 2,
+ "row_id": 3,
+ "included_in_print_rate": 1,
+ "idx": 4
+ },
+ {
+ "doctype": "Sales Taxes and Charges",
+ "parentfield": "other_charges",
+ "charge_type": "On Net Total",
+ "account_head": "_Test Account VAT - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "VAT",
+ "rate": 12.5,
+ "included_in_print_rate": 1,
+ "idx": 5
+ },
+ {
+ "doctype": "Sales Taxes and Charges",
+ "parentfield": "other_charges",
+ "charge_type": "On Net Total",
+ "account_head": "_Test Account Customs Duty - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "Customs Duty",
+ "rate": 10,
+ "idx": 6
+ },
+ {
+ "doctype": "Sales Taxes and Charges",
+ "parentfield": "other_charges",
+ "charge_type": "Actual",
+ "account_head": "_Test Account Shipping Charges - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "Shipping Charges",
+ "rate": 100,
+ "idx": 7
+ },
+ {
+ "doctype": "Sales Taxes and Charges",
+ "parentfield": "other_charges",
+ "charge_type": "On Previous Row Total",
+ "account_head": "_Test Account Discount - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "Discount",
+ "rate": -10,
+ "row_id": 7,
+ "idx": 8
+ },
+ ],
]
\ No newline at end of file
diff --git a/accounts/doctype/sales_invoice_item/sales_invoice_item.txt b/accounts/doctype/sales_invoice_item/sales_invoice_item.txt
index 89c86f8..014a9f4 100644
--- a/accounts/doctype/sales_invoice_item/sales_invoice_item.txt
+++ b/accounts/doctype/sales_invoice_item/sales_invoice_item.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-04-19 11:00:07",
"docstatus": 0,
- "modified": "2013-05-22 12:06:15",
+ "modified": "2013-05-22 12:07:00",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -107,7 +107,7 @@
"oldfieldtype": "Currency",
"options": "currency",
"print_hide": 1,
- "read_only": 0,
+ "read_only": 1,
"reqd": 0
},
{
@@ -163,7 +163,7 @@
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"print_hide": 1,
- "read_only": 0,
+ "read_only": 1,
"reqd": 1,
"search_index": 0
},
diff --git a/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.txt b/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.txt
index 161eb00..55a41a9 100644
--- a/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.txt
+++ b/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-02-22 01:27:41",
"docstatus": 0,
- "modified": "2013-04-17 14:05:18",
+ "modified": "2013-04-17 14:05:50",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -50,7 +50,7 @@
{
"default": ":Company",
"doctype": "DocField",
- "fieldname": "cost_center_other_charges",
+ "fieldname": "cost_center",
"fieldtype": "Link",
"label": "Cost Center",
"oldfieldname": "cost_center_other_charges",
diff --git a/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js b/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js
index 1e72010..5787427 100644
--- a/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js
+++ b/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js
@@ -140,7 +140,7 @@
return 'SELECT tabAccount.name FROM tabAccount WHERE tabAccount.group_or_ledger="Ledger" AND tabAccount.docstatus != 2 AND tabAccount.account_type in ("Tax", "Chargeable", "Income Account") AND tabAccount.company = "'+doc.company+'" AND tabAccount.name LIKE "%s"'
}
-cur_frm.fields_dict['other_charges'].grid.get_field("cost_center_other_charges").get_query = function(doc) {
+cur_frm.fields_dict['other_charges'].grid.get_field("cost_center").get_query = function(doc) {
return 'SELECT `tabCost Center`.`name` FROM `tabCost Center` WHERE `tabCost Center`.`company_name` = "' +doc.company+'" AND `tabCost Center`.%(key)s LIKE "%s" AND `tabCost Center`.`group_or_ledger` = "Ledger" AND `tabCost Center`.`docstatus`!= 2 ORDER BY `tabCost Center`.`name` ASC LIMIT 50';
}
diff --git a/buying/doctype/purchase_common/purchase_common.js b/buying/doctype/purchase_common/purchase_common.js
index dacee80..3202122 100644
--- a/buying/doctype/purchase_common/purchase_common.js
+++ b/buying/doctype/purchase_common/purchase_common.js
@@ -20,8 +20,9 @@
// cur_frm.cscript.fname - Details fieldname
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() {
var me = this;
@@ -42,109 +43,171 @@
}
},
- refresh: function() {
- this.frm.clear_custom_buttons();
- erpnext.hide_naming_series();
+ validate: function() {
- 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) {
- var me = this;
-
- if(this.frm.doc.price_list_name) {
- if(!this.frm.doc.price_list_currency) {
- // set price list currency
+ 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 price_list_name = 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: "buying"
- }},
+ doc: this.frm.doc,
+ method: "set_supplier_defaults",
+ freeze: true,
callback: function(r) {
if(!r.exc) {
- me.price_list_currency();
- if (typeof callback_fn === "function")
- callback_fn(me.frm.doc, me.frm.doc.doctype, me.frm.doc.name);
+ me.frm.refresh_fields();
+ if(me.frm.doc.price_list_name !== price_list_name) me.price_list_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) {
var me = this;
- var item = locals[cdt][cdn];
-
+ var item = wn.model.get_doc(cdt, cdn);
if(item.item_code) {
- this.frm.call({
- method: "buying.utils.get_item_details",
- child: item,
- args: {
+ if(!this.validate_company_and_party("supplier")) {
+ item.item_code = null;
+ refresh_field("item_code", item.name, item.parentfield);
+ } else {
+ this.frm.call({
+ method: "buying.utils.get_item_details",
+ child: item,
args: {
- doctype: me.frm.doc.doctype,
- docname: me.frm.doc.name,
- item_code: item.item_code,
- warehouse: item.warehouse,
- supplier: me.frm.doc.supplier,
- conversion_rate: me.frm.doc.conversion_rate,
- price_list_name: me.frm.doc.price_list_name,
- price_list_currency: me.frm.doc.price_list_currency,
- plc_conversion_rate: me.frm.doc.plc_conversion_rate
+ args: {
+ item_code: item.item_code,
+ warehouse: item.warehouse,
+ doctype: me.frm.doc.doctype,
+ docname: me.frm.doc.name,
+ supplier: me.frm.doc.supplier,
+ conversion_rate: me.frm.doc.conversion_rate,
+ price_list_name: me.frm.doc.price_list_name,
+ price_list_currency: me.frm.doc.price_list_currency,
+ plc_conversion_rate: me.frm.doc.plc_conversion_rate,
+ is_subcontracted: me.frm.doc.is_subcontracted,
+ company: me.frm.doc.company,
+ currency: me.frm.doc.currency
+ }
+ },
+ callback: function(r) {
+ if(!r.exc) {
+ me.ref_rate(me.frm.doc, cdt, cdn);
+ }
}
- },
+ });
+ }
+ }
+ },
+
+ price_list_name: function(callback_fn) {
+ this._super("buying");
+ },
+
+ calculate_taxes_and_totals: function() {
+ this._super();
+ this.calculate_outstanding_amount();
+ this.frm.refresh_fields();
+ },
+
+ calculate_item_values: function() {
+ var me = this;
+
+ if(this.frm.doc.doctype != "Purchase Invoice") {
+ wn.meta.docfield_map[this.tname]["rate"] = $.extend({},
+ wn.meta.docfield_map[this.tname]["purchase_rate"]);
+ }
+
+ $.each(this.frm.item_doclist, function(i, item) {
+ if(me.frm.doc.doctype != "Purchase Invoice") {
+ item.rate = item.purchase_rate;
+ }
+
+ 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"];
});
}
},
- 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) {
- if(!r.exc) {
- refresh_field(me.fname);
- me.load_defaults(me.frm.doc, dt, dn, callback);
- }
- }
- })
- } else {
- this.load_taxes(doc, dt, dn, callback);
+ 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"));
}
},
- currency: function() {
- this.set_dynamic_labels();
- },
-
- company: function() {
- this.set_dynamic_labels();
- },
-
- price_list_currency: function() {
- this.frm.toggle_reqd("plc_conversion_rate",
- !!(this.frm.doc.price_list_name && this.frm.doc.price_list_currency));
-
- this.set_dynamic_labels();
-
- 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 || 1.0);
+ 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) {
@@ -166,7 +229,8 @@
field_label_map[fname] = label.trim() + " (" + currency + ")";
}
});
- }
+ };
+
setup_field_label_map(["net_total", "total_tax", "grand_total", "in_words",
"other_charges_added", "other_charges_deducted",
@@ -188,6 +252,9 @@
this.frm.toggle_display(["conversion_rate", "net_total", "grand_total",
"in_words", "other_charges_added", "other_charges_deducted"],
this.frm.doc.currency != company_currency);
+
+ this.frm.toggle_display(["plc_conversion_rate"],
+ this.frm.price_list_currency != company_currency)
// set labels
$.each(field_label_map, function(fname, label) {
@@ -204,8 +271,9 @@
$.each(fields_list, function(i, fname) {
var docfield = wn.meta.get_docfield(grid_doctype, fname);
if(docfield) {
+ var label = wn._((docfield.label || "")).replace(/\([^\)]*\)/g, "");
field_label_map[grid_doctype + "-" + fname] =
- docfield.label + " (" + currency + ")";
+ label.trim() + " (" + currency + ")";
}
});
}
@@ -237,10 +305,6 @@
$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
@@ -256,54 +320,6 @@
var tname = cur_frm.cscript.tname;
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 =======================================================
// 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) {
diff --git a/buying/doctype/purchase_common/purchase_common.py b/buying/doctype/purchase_common/purchase_common.py
index d5b563b..7945954 100644
--- a/buying/doctype/purchase_common/purchase_common.py
+++ b/buying/doctype/purchase_common/purchase_common.py
@@ -69,17 +69,6 @@
msgprint(_("Hey there! You need to put at least one item in \
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
#------------------------------------------------------------------------------------------------
diff --git a/buying/doctype/purchase_order/purchase_order.js b/buying/doctype/purchase_order/purchase_order.js
index afe4741..ad2db91 100644
--- a/buying/doctype/purchase_order/purchase_order.js
+++ b/buying/doctype/purchase_order/purchase_order.js
@@ -39,26 +39,6 @@
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});
@@ -66,28 +46,6 @@
// for backward compatibility: combine new and previous states
$.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) {
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 @@
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) {
return 'SELECT `tabProject`.name FROM `tabProject` \
WHERE `tabProject`.status not in ("Completed", "Cancelled") \
diff --git a/buying/doctype/purchase_order/purchase_order.py b/buying/doctype/purchase_order/purchase_order.py
index 218d4bf..bf59389 100644
--- a/buying/doctype/purchase_order/purchase_order.py
+++ b/buying/doctype/purchase_order/purchase_order.py
@@ -65,10 +65,6 @@
self.validate_for_subcontracting()
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):
get_obj(dt = 'Purchase Common').validate_fiscal_year(self.doc.fiscal_year,self.doc.transaction_date,'PO Date')
@@ -101,7 +97,6 @@
"""[['Supplier Quotation', 'Purchase Order'],
['Supplier Quotation Item', 'Purchase Order Item'],
['Purchase Taxes and Charges', 'Purchase Taxes and Charges']]""")
- self.get_default_schedule_date()
for d in getlist(self.doclist, 'po_details'):
if d.prevdoc_detail_docname and not d.schedule_date:
d.schedule_date = webnotes.conn.get_value("Material Request Item",
diff --git a/buying/doctype/supplier_quotation/supplier_quotation.js b/buying/doctype/supplier_quotation/supplier_quotation.js
index 1e4f6cb..4e5b62b 100644
--- a/buying/doctype/supplier_quotation/supplier_quotation.js
+++ b/buying/doctype/supplier_quotation/supplier_quotation.js
@@ -26,29 +26,11 @@
erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.extend({
refresh: function() {
this._super();
-
if (this.frm.doc.docstatus === 1) {
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});
@@ -56,19 +38,6 @@
// for backward compatibility: combine new and previous states
$.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() {
var new_po_name = wn.model.make_new_doc_and_get_name("Purchase Order");
$c("dt_map", {
diff --git a/buying/utils.py b/buying/utils.py
index 0431e64..2c29e2c 100644
--- a/buying/utils.py
+++ b/buying/utils.py
@@ -16,6 +16,7 @@
from __future__ import unicode_literals
import webnotes
+from webnotes import msgprint, _
from webnotes.utils import getdate, flt, add_days
import json
@@ -29,7 +30,11 @@
"warehouse": None,
"supplier": None,
"transaction_date": None,
- "conversion_rate": 1.0
+ "conversion_rate": 1.0,
+ "price_list_name": None,
+ "price_list_currency": None,
+ "plc_conversion_rate": 1.0,
+ "is_subcontracted": "Yes" / "No"
}
"""
if isinstance(args, basestring):
@@ -37,36 +42,14 @@
args = webnotes._dict(args)
- item_wrapper = webnotes.bean("Item", args.item_code)
- item = item_wrapper.doc
+ item_bean = webnotes.bean("Item", args.item_code)
+ item = item_bean.doc
- from stock.utils import validate_end_of_life
- validate_end_of_life(item.name, item.end_of_life)
+ _validate_item_details(args, item)
- # fetch basic values
- out = webnotes._dict()
- out.update({
- "item_name": item.item_name,
- "item_group": item.item_group,
- "brand": item.brand,
- "description": item.description,
- "qty": 0,
- "stock_uom": item.stock_uom,
- "uom": item.stock_uom,
- "conversion_factor": 1.0,
- "warehouse": args.warehouse or item.default_warehouse,
- "item_tax_rate": json.dumps(dict(([d.tax_type, d.tax_rate] for d in
- item_wrapper.doclist.get({"parentfield": "item_tax"})))),
- "batch_no": None,
- "expense_head": item.purchase_account,
- "cost_center": item.cost_center
- })
+ out = _get_basic_details(args, item_bean)
- if args.supplier:
- item_supplier = item_wrapper.doclist.get({"parentfield": "item_supplier_details",
- "supplier": args.supplier})
- if item_supplier:
- out["supplier_part_no"] = item_supplier[0].supplier_part_no
+ out.supplier_part_no = _get_supplier_part_no(args, item_bean)
if out.warehouse:
out.projected_qty = webnotes.conn.get_value("Bin", {"item_code": item.name,
@@ -76,47 +59,85 @@
out.schedule_date = out.lead_time_date = add_days(args.transaction_date,
item.lead_time_days)
- # set zero
- out.purchase_ref_rate = out.discount_rate = out.purchase_rate = \
- out.import_ref_rate = out.import_rate = 0.0
+ meta = webnotes.get_doctype(args.doctype)
- if args.doctype in ["Purchase Order", "Purchase Invoice", "Purchase Receipt",
- "Supplier Quotation"]:
- # try fetching from price list
- if args.price_list_name and args.price_list_currency:
- rates_as_per_price_list = get_rates_as_per_price_list(args, item_wrapper.doclist)
- if rates_as_per_price_list:
- out.update(rates_as_per_price_list)
-
- # if not found, fetch from last purchase transaction
- if not out.purchase_rate:
- last_purchase = get_last_purchase_details(item.name, args.docname, args.conversion_rate)
- if last_purchase:
- out.update(last_purchase)
-
+ if meta.get_field("currency"):
+ out.purchase_ref_rate = out.discount_rate = out.purchase_rate = \
+ out.import_ref_rate = out.import_rate = 0.0
+ 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
-
-def get_rates_as_per_price_list(args, item_doclist=None):
- if not item_doclist:
- item_doclist = webnotes.bean("Item", args.item_code).doclist
- result = item_doclist.get({"parentfield": "ref_rate_details",
- "price_list_name": args.price_list_name, "ref_currency": args.price_list_currency,
- "buying": 1})
+def _get_basic_details(args, item_bean):
+ item = item_bean.doc
+
+ out = webnotes._dict({
+ "description": item.description_html or item.description,
+ "qty": 0.0,
+ "uom": item.stock_uom,
+ "conversion_factor": 1.0,
+ "warehouse": args.warehouse or item.default_warehouse,
+ "item_tax_rate": json.dumps(dict(([d.tax_type, d.tax_rate] for d in
+ item_bean.doclist.get({"parentfield": "item_tax"})))),
+ "batch_no": None,
+ "expense_head": item.purchase_account,
+ "cost_center": item.cost_center
+ })
+
+ for fieldname in ("item_name", "item_group", "brand", "stock_uom"):
+ out[fieldname] = item.fields.get(fieldname)
+
+ return out
+
+def _get_price_list_rate(args, item_bean, meta=None):
+ from utilities.transaction_base import validate_currency
+ item = item_bean.doc
+ out = webnotes._dict()
+
+ # try fetching from price list
+ if args.price_list_name and args.price_list_currency:
+ price_list_rate = item_bean.doclist.get({
+ "parentfield": "ref_rate_details",
+ "price_list_name": args.price_list_name,
+ "ref_currency": args.price_list_currency,
+ "buying": 1})
+ if price_list_rate:
+ out.purchase_ref_rate = flt(price_list_rate[0].ref_rate) * flt(args.plc_conversion_rate)
- if result:
- purchase_ref_rate = flt(result[0].ref_rate) * flt(args.plc_conversion_rate)
- conversion_rate = flt(args.conversion_rate) or 1.0
- return webnotes._dict({
- "purchase_ref_rate": purchase_ref_rate,
- "purchase_rate": purchase_ref_rate,
- "rate": purchase_ref_rate,
- "discount_rate": 0,
- "import_ref_rate": purchase_ref_rate / conversion_rate,
- "import_rate": purchase_ref_rate / conversion_rate
- })
- else:
- return webnotes._dict()
+ # if not found, fetch from last purchase transaction
+ if not out.purchase_ref_rate:
+ last_purchase = get_last_purchase_details(item.name, args.docname, args.conversion_rate)
+ if last_purchase:
+ out.update(last_purchase)
+
+ if out.purchase_ref_rate or out.purchase_rate or out.rate:
+ validate_currency(args, item, meta)
+
+ return out
+
+def _get_supplier_part_no(args, item_bean):
+ item_supplier = item_bean.doclist.get({"parentfield": "item_supplier_details",
+ "supplier": args.supplier})
+
+ return item_supplier and item_supplier[0].supplier_part_no or None
+
+def _validate_item_details(args, item):
+ from utilities.transaction_base import validate_item_fetch
+ validate_item_fetch(args, item)
+
+ # validate if purchase item or subcontracted item
+ if item.is_purchase_item != "Yes":
+ msgprint(_("Item") + (" %s: " % item.name) + _("not a purchase item"),
+ raise_exception=True)
+
+ if args.is_subcontracted == "Yes" and item.is_sub_contracted_item != "Yes":
+ msgprint(_("Item") + (" %s: " % item.name) +
+ _("not a sub-contracted item.") +
+ _("Please select a sub-contracted item or do not sub-contract the transaction."),
+ raise_exception=True)
def get_last_purchase_details(item_code, doc_name, conversion_rate=1.0):
"""returns last purchase details in stock uom"""
diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py
index 04e4bbd..1499e0a 100644
--- a/controllers/accounts_controller.py
+++ b/controllers/accounts_controller.py
@@ -16,14 +16,254 @@
from __future__ import unicode_literals
import webnotes
-from webnotes.utils import flt
-
-from utilities.transaction_base import TransactionBase
+from webnotes import _, msgprint
+from webnotes.utils import flt, cint
+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):
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.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):
"""this method populates the common properties of a gl entry record"""
@@ -97,4 +337,4 @@
if not hasattr(self, "_abbr"):
self._abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr")
- return self._abbr
\ No newline at end of file
+ return self._abbr
diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py
index 3deda02..8313b54 100644
--- a/controllers/buying_controller.py
+++ b/controllers/buying_controller.py
@@ -17,35 +17,45 @@
from __future__ import unicode_literals
import webnotes
from webnotes import _, msgprint
-from webnotes.utils import flt, cint
-import json
+from webnotes.utils import flt
from buying.utils import get_item_details
from setup.utils import get_company_currency
-from webnotes.model.utils import round_floats_in_doc
from controllers.stock_controller import StockController
class WrongWarehouseCompany(Exception): pass
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):
super(BuyingController, self).validate()
self.validate_stock_or_nonstock_items()
self.validate_warehouse_belongs_to_company()
- if self.meta.get_field("currency"):
- self.company_currency = get_company_currency(self.doc.company)
- self.validate_conversion_rate("currency", "conversion_rate")
-
- if self.doc.price_list_name and self.doc.price_list_currency:
- self.validate_conversion_rate("price_list_currency", "plc_conversion_rate")
-
- # IMPORTANT: enable this only when client side code is similar to this one
- # self.calculate_taxes_and_totals()
+
+ def set_missing_values(self, for_validate=False):
+ # set contact and address details for supplier, if they are not mentioned
+ if self.doc.supplier and not (self.doc.contact_person and self.doc.supplier_address):
+ 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
+
+ self.set_missing_item_details(get_item_details)
+
+ def set_supplier_defaults(self):
+ self.get_default_supplier_address()
- # set total in words
- self.set_total_in_words()
-
+ 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):
for warehouse, company in webnotes.conn.get_values("Warehouse",
self.doclist.get_distinct_values("warehouse"), "company").items():
@@ -71,46 +81,6 @@
webnotes.msgprint(_("""Tax Category can not be 'Valuation' or 'Valuation and Total'
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 validate_conversion_rate(self, currency_field, conversion_rate_field):
- """common validation for currency and price list currency"""
-
- currency = self.doc.fields.get(currency_field)
- conversion_rate = flt(self.doc.fields.get(conversion_rate_field))
- conversion_rate_label = self.meta.get_label(conversion_rate_field)
-
- if conversion_rate == 0:
- msgprint(conversion_rate_label + _(' cannot be 0'), raise_exception=True)
-
- # parenthesis for 'OR' are necessary as we want it to evaluate as
- # mandatory valid condition and (1st optional valid condition
- # or 2nd optional valid condition)
- valid_conversion_rate = (conversion_rate and
- ((currency == self.company_currency and conversion_rate == 1.00)
- or (currency != self.company_currency and conversion_rate != 1.00)))
-
- if not valid_conversion_rate:
- msgprint(_('Please enter valid ') + conversion_rate_label + (': ')
- + ("1 %s = [?] %s" % (currency, self.company_currency)),
- raise_exception=True)
-
def set_total_in_words(self):
from webnotes.utils import money_in_words
company_currency = get_company_currency(self.doc.company)
@@ -121,154 +91,54 @@
self.doc.currency)
def calculate_taxes_and_totals(self):
- self.doc.conversion_rate = flt(self.doc.conversion_rate)
- self.item_doclist = self.doclist.get({"parentfield": self.fname})
- 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.other_fname = "purchase_tax_details"
+ super(BuyingController, self).calculate_taxes_and_totals()
self.calculate_outstanding_amount()
- self._cleanup()
-
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.item[print_field]) * self.doc.conversion_rate),
- self.precision.item[base_field])
-
- for item in self.item_doclist:
- round_floats_in_doc(item, self.precision.item)
+ # hack! - cleaned up in _cleanup()
+ if self.doc.doctype != "Purchase Invoice":
+ df = self.meta.get_field("purchase_rate", parentfield=self.fname)
+ df.fieldname = "rate"
+ for item in self.item_doclist:
# hack! - cleaned up in _cleanup()
if self.doc.doctype != "Purchase Invoice":
item.rate = item.purchase_rate
- self.precision.item.rate = self.precision.item.purchase_rate
- item.discount = item.discount_rate
- self.precision.item.discount = self.precision.item.discount_rate
+ self.round_floats_in(item)
- if item.discount == 100:
- if not item.import_ref_rate:
- item.import_ref_rate = item.import_rate
- item.import_rate = 0
- else:
- if item.import_ref_rate:
- item.import_rate = flt(item.import_ref_rate *
- (1.0 - (item.discount_rate / 100.0)),
- self.precision.item.import_rate)
- else:
- # assume that print rate and discount are specified
- item.import_ref_rate = flt(item.import_rate /
- (1.0 - (item.discount_rate / 100.0)),
- self.precision.item.import_ref_rate)
+ if item.discount_rate == 100.0:
+ item.import_rate = 0.0
+ elif item.import_ref_rate:
+ item.import_rate = flt(item.import_ref_rate * (1.0 - (item.discount_rate / 100.0)),
+ self.precision("import_rate", item))
item.import_amount = flt(item.import_rate * item.qty,
- self.precision.item.import_amount)
+ self.precision("import_amount", item))
+ item.item_tax_amount = 0.0;
- _set_base(item, "import_ref_rate", "purchase_ref_rate")
- _set_base(item, "import_rate", "rate")
- _set_base(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
+ self._set_in_company_currency(item, "import_ref_rate", "purchase_ref_rate")
+ self._set_in_company_currency(item, "import_rate", "rate")
+ self._set_in_company_currency(item, "import_amount", "amount")
- # 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)
-
- round_floats_in_doc(tax, self.precision.tax)
-
def calculate_net_total(self):
- self.doc.net_total = 0
- self.doc.net_total_import = 0
+ self.doc.net_total = self.doc.net_total_import = 0.0
for item in self.item_doclist:
self.doc.net_total += item.amount
self.doc.net_total_import += item.import_amount
- self.doc.net_total = flt(self.doc.net_total, self.precision.main.net_total)
- self.doc.net_total_import = flt(self.doc.net_total_import,
- self.precision.main.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.tax_amount)
- 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.tax.total)
-
- else:
- tax.grand_total_for_current_item = \
- flt(self.tax_doclist[i-1].grand_total_for_current_item +
- current_tax_amount, self.precision.tax.total)
-
- # 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
+ self.round_floats_in(self.doc, ["net_total", "net_total_import"])
def calculate_totals(self):
- if self.tax_doclist:
- self.doc.grand_total = flt(self.tax_doclist[-1].total,
- self.precision.main.grand_total)
- self.doc.grand_total_import = flt(
- self.doc.grand_total / self.doc.conversion_rate,
- self.precision.main.grand_total_import)
- else:
- self.doc.grand_total = flt(self.doc.net_total,
- self.precision.main.grand_total)
- self.doc.grand_total_import = flt(
- self.doc.grand_total / self.doc.conversion_rate,
- self.precision.main.grand_total_import)
+ self.doc.grand_total = flt(self.tax_doclist and \
+ self.tax_doclist[-1].total or 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.doc.total_tax = \
- flt(self.doc.grand_total - self.doc.net_total,
- self.precision.main.total_tax)
+ self.doc.total_tax = flt(self.doc.grand_total - self.doc.net_total,
+ self.precision("total_tax"))
if self.meta.get_field("rounded_total"):
self.doc.rounded_total = round(self.doc.grand_total)
@@ -277,75 +147,27 @@
self.doc.rounded_total_import = round(self.doc.grand_total_import)
def calculate_outstanding_amount(self):
- if self.doc.doctype == "Purchase Invoice" and self.doc.docstatus == 0:
+ if self.doc.doctype == "Purchase Invoice" and self.doc.docstatus < 2:
self.doc.total_advance = flt(self.doc.total_advance,
- self.precision.main.total_advance)
+ self.precision("total_advance"))
self.doc.total_amount_to_pay = flt(self.doc.grand_total - flt(self.doc.write_off_amount,
- self.precision.main.write_off_amount), self.precision.main.total_amount_to_pay)
+ self.precision("write_off_amount")), self.precision("total_amount_to_pay"))
self.doc.outstanding_amount = flt(self.doc.total_amount_to_pay - self.doc.total_advance,
- self.precision.main.outstanding_amount)
+ self.precision("outstanding_amount"))
def _cleanup(self):
- for tax in self.tax_doclist:
- 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
+ super(BuyingController, self)._cleanup()
+
+ # except in purchase invoice, rate field is purchase_rate
+ # reset fieldname of rate
if self.doc.doctype != "Purchase Invoice":
+ df = self.meta.get_field("rate", parentfield=self.fname)
+ df.fieldname = "purchase_rate"
+
for item in self.item_doclist:
item.purchase_rate = item.rate
del item.fields["rate"]
- item.discount_rate = item.discount
- del item.fields["discount"]
-
- 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.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.tax_amount)
- 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.tax_amount)
-
- 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.tax.rate)
- else:
- return tax.rate
-
def set_item_tax_amount(self, item, tax, current_tax_amount):
"""
item_tax_amount is the total tax amount applied on that item
@@ -353,29 +175,28 @@
TODO: rename item_tax_amount to valuation_tax_amount
"""
- if tax.category in ["Valuation", "Valuation and Total"] and \
- item.item_code in self.stock_items:
- item.item_tax_amount += flt(current_tax_amount,
- self.precision.item.item_tax_amount)
+ if tax.category in ["Valuation", "Valuation and Total"]:
+ item.item_tax_amount += flt(current_tax_amount, self.precision("item_tax_amount", item))
# update valuation rate
def update_valuation_rate(self, parentfield):
- for d in self.doclist.get({"parentfield": parentfield}):
- d.conversion_factor = d.conversion_factor or flt(webnotes.conn.get_value(
- "UOM Conversion Detail", {"parent": d.item_code, "uom": d.uom},
+ for item in self.doclist.get({"parentfield": parentfield}):
+ item.conversion_factor = item.conversion_factor or flt(webnotes.conn.get_value(
+ "UOM Conversion Detail", {"parent": item.item_code, "uom": item.uom},
"conversion_factor")) or 1
- if d.item_code and d.qty:
+
+ if item.item_code and item.qty:
+ self.round_floats_in(item)
+
+ purchase_rate = item.rate if self.doc.doctype == "Purchase Invoice" else item.purchase_rate
+
# if no item code, which is sometimes the case in purchase invoice,
# then it is not possible to track valuation against it
- d.valuation_rate = flt(((flt(d.purchase_rate, self.precision.item.purchase_rate) or
- flt(d.rate, self.precision.item.rate)) +
- (flt(d.item_tax_amount, self.precision.item.item_tax_amount) +
- flt(d.rm_supp_cost, self.precision.item.rm_supp_cost)) /
- flt(d.qty, self.precision.item.qty)) /
- flt(d.conversion_factor, self.precision.item.conversion_factor),
- self.precision.item.valuation_rate)
+ item.valuation_rate = flt((purchase_rate +
+ (item.item_tax_amount + item.rm_supp_cost) / item.qty) / item.conversion_factor,
+ self.precision("valuation_rate", item))
else:
- d.valuation_rate = 0.0
+ item.valuation_rate = 0.0
def validate_for_subcontracting(self):
if not self.doc.is_subcontracted and self.sub_contracted_items:
@@ -437,18 +258,6 @@
return bom_items
-
- @property
- def precision(self):
- if not hasattr(self, "_precision"):
- self._precision = webnotes._dict()
- self._precision.main = self.meta.get_precision_map()
- self._precision.item = self.meta.get_precision_map(parentfield = self.fname)
- if self.meta.get_field("purchase_tax_details"):
- self._precision.tax = self.meta.get_precision_map(parentfield = \
- "purchase_tax_details")
- return self._precision
-
@property
def sub_contracted_items(self):
if not hasattr(self, "_sub_contracted_items"):
diff --git a/controllers/selling_controller.py b/controllers/selling_controller.py
index 80af337..de90fa7 100644
--- a/controllers/selling_controller.py
+++ b/controllers/selling_controller.py
@@ -16,16 +16,37 @@
from __future__ import unicode_literals
import webnotes
-from webnotes.utils import cint
+from webnotes.utils import cint, flt, comma_or
from setup.utils import get_company_currency
+from selling.utils import get_item_details
from webnotes import msgprint, _
from controllers.stock_controller import StockController
class SellingController(StockController):
- def validate(self):
- super(SellingController, self).validate()
- self.set_total_in_words()
+ def onload_post_render(self):
+ self.set_price_list_currency("selling")
+
+ # contact, address, item details and pos details (if applicable)
+ self.set_missing_values()
+
+ self.set_taxes("Sales Taxes and Charges", "other_charges", "charge")
+
+ def set_missing_values(self, for_validate=False):
+ # set contact and address details for customer, if they are not mentioned
+ if self.doc.customer and not (self.doc.contact_person and self.doc.customer_address):
+ for fieldname, val in self.get_default_address_and_contact("customer").items():
+ if not self.doc.fields.get(fieldname) and self.meta.get_field(fieldname):
+ self.doc.fields[fieldname] = val
+
+ self.set_missing_item_details(get_item_details)
+
+ def get_other_charges(self):
+ self.doclist = self.doc.clear_table(self.doclist, "other_charges")
+ self.set_taxes("Sales Taxes and Charges", "other_charges", "charge")
+
+ def set_customer_defaults(self):
+ self.get_default_customer_address()
def set_total_in_words(self):
from webnotes.utils import money_in_words
@@ -71,4 +92,142 @@
if item.buying_amount and not item.cost_center:
msgprint(_("""Cost Center is mandatory for item: """) + item.item_code,
- raise_exception=1)
\ No newline at end of file
+ raise_exception=1)
+
+ def calculate_taxes_and_totals(self):
+ self.other_fname = "other_charges"
+
+ super(SellingController, self).calculate_taxes_and_totals()
+
+ self.calculate_commission()
+ self.calculate_contribution()
+ # self.calculate_outstanding_amount()
+
+ def determine_exclusive_rate(self):
+ if not any((cint(tax.included_in_print_rate) for tax in self.tax_doclist)):
+ # no inclusive tax
+ return
+
+ for item in self.item_doclist:
+ item_tax_map = self._load_item_tax_rate(item.item_tax_rate)
+ cumulated_tax_fraction = 0
+ for i, tax in enumerate(self.tax_doclist):
+ tax.tax_fraction_for_current_item = self.get_current_tax_fraction(tax, item_tax_map)
+
+ if i==0:
+ tax.grand_total_fraction_for_current_item = 1 + tax.tax_fraction_for_current_item
+ else:
+ tax.grand_total_fraction_for_current_item = \
+ self.tax_doclist[i-1].grand_total_fraction_for_current_item \
+ + tax.tax_fraction_for_current_item
+
+ cumulated_tax_fraction += tax.tax_fraction_for_current_item
+
+ if cumulated_tax_fraction:
+ item.basic_rate = flt((item.export_rate * self.doc.conversion_rate) /
+ (1 + cumulated_tax_fraction), self.precision("basic_rate", item))
+
+ item.amount = flt(item.basic_rate * item.qty, self.precision("amount", item))
+
+ if item.adj_rate == 100:
+ item.base_ref_rate = item.basic_rate
+ item.basic_rate = 0.0
+ else:
+ item.base_ref_rate = flt(item.basic_rate / (1 - (item.adj_rate / 100.0)),
+ self.precision("base_ref_rate", item))
+
+ def get_current_tax_fraction(self, tax, item_tax_map):
+ """
+ Get tax fraction for calculating tax exclusive amount
+ from tax inclusive amount
+ """
+ current_tax_fraction = 0
+
+ if cint(tax.included_in_print_rate):
+ tax_rate = self._get_tax_rate(tax, item_tax_map)
+
+ if tax.charge_type == "On Net Total":
+ current_tax_fraction = tax_rate / 100.0
+
+ elif tax.charge_type == "On Previous Row Amount":
+ current_tax_fraction = (tax_rate / 100.0) * \
+ self.tax_doclist[cint(tax.row_id) - 1].tax_fraction_for_current_item
+
+ elif tax.charge_type == "On Previous Row Total":
+ current_tax_fraction = (tax_rate / 100.0) * \
+ self.tax_doclist[cint(tax.row_id) - 1].grand_total_fraction_for_current_item
+
+ return current_tax_fraction
+
+ def calculate_item_values(self):
+ for item in self.item_doclist:
+ self.round_floats_in(item)
+
+ if item.adj_rate == 100:
+ item.export_rate = 0
+ elif item.ref_rate:
+ item.export_rate = flt(item.ref_rate * (1.0 - (item.adj_rate / 100.0)),
+ self.precision("export_rate", item))
+
+ item.export_amount = flt(item.export_rate * item.qty,
+ self.precision("export_amount", item))
+
+ self._set_in_company_currency(item, "ref_rate", "base_ref_rate")
+ self._set_in_company_currency(item, "export_rate", "basic_rate")
+ self._set_in_company_currency(item, "export_amount", "amount")
+
+ def calculate_net_total(self):
+ self.doc.net_total = self.doc.net_total_export = 0.0
+
+ for item in self.item_doclist:
+ self.doc.net_total += item.amount
+ self.doc.net_total_export += item.export_amount
+
+ self.round_floats_in(self.doc, ["net_total", "net_total_export"])
+
+ def calculate_totals(self):
+ self.doc.grand_total = flt(self.tax_doclist and \
+ self.tax_doclist[-1].total or self.doc.net_total, self.precision("grand_total"))
+ self.doc.grand_total_export = flt(self.doc.grand_total / self.doc.conversion_rate,
+ self.precision("grand_total_export"))
+
+ self.doc.other_charges_total = flt(self.doc.grand_total - self.doc.net_total,
+ self.precision("other_charges_total"))
+ self.doc.other_charges_total_export = flt(self.doc.grand_total_export - self.doc.net_total_export,
+ self.precision("other_charges_total_export"))
+
+ self.doc.rounded_total = round(self.doc.grand_total)
+ self.doc.rounded_total_export = round(self.doc.grand_total_export)
+
+ def calculate_commission(self):
+ self.round_floats_in(self.doc, ["net_total", "commission_rate"])
+ if self.doc.commission_rate > 100.0:
+ msgprint(_(self.meta.get_label("commission_rate")) + " " +
+ _("cannot be greater than 100"), raise_exception=True)
+
+ self.doc.total_commission = flt(self.doc.net_total * self.doc.commission_rate / 100.0,
+ self.precision("total_commission"))
+
+ def calculate_contribution(self):
+ total = 0.0
+ sales_team = self.doclist.get({"parentfield": "sales_team"})
+ for sales_person in sales_team:
+ self.round_floats_in(sales_person)
+
+ sales_person.allocated_amount = flt(
+ self.doc.net_total * sales_person.allocated_percentage / 100.0,
+ self.precision("allocated_amount", sales_person))
+
+ total += sales_person.allocated_percentage
+
+ if sales_team and total != 100.0:
+ msgprint(_("Total") + " " +
+ _(self.meta.get_label("allocated_percentage", parentfield="sales_team")) +
+ " " + _("should be 100%"), raise_exception=True)
+
+ def validate_order_type(self):
+ valid_types = ["Sales", "Maintenance"]
+ if self.doc.order_type not in valid_types:
+ msgprint(_(self.meta.get_label("order_type")) + " " +
+ _("must be one of") + ": " + comma_or(valid_types),
+ raise_exception=True)
diff --git a/patches/april_2013/p05_update_file_data.py b/patches/april_2013/p05_update_file_data.py
index 39449a6..0168de6 100644
--- a/patches/april_2013/p05_update_file_data.py
+++ b/patches/april_2013/p05_update_file_data.py
@@ -1,5 +1,4 @@
import webnotes, webnotes.utils, os
-from webnotes.modules.export_file import export_to_files
def execute():
webnotes.reload_doc("core", "doctype", "file_data")
@@ -71,4 +70,4 @@
pass
else:
webnotes.conn.sql("""delete from `tabFile Data` where name=%s""",
- fileid)
\ No newline at end of file
+ fileid)
diff --git a/patches/april_2013/p06_default_cost_center.py b/patches/april_2013/p06_default_cost_center.py
index 4f80d95..4aaa7d5 100644
--- a/patches/april_2013/p06_default_cost_center.py
+++ b/patches/april_2013/p06_default_cost_center.py
@@ -1,10 +1,10 @@
import webnotes
def execute():
- for dt, fieldname in \
- (("Journal Voucher Detail", "cost_center"),
- ("Sales Taxes and Charges", "cost_center_other_charges"),
- ("Purchase Taxes and Charges", "cost_center"), ("Delivery Note Item", "cost_center"),
- ("Purchase Invoice Item", "cost_center"), ("Sales Invoice Item", "cost_center")):
- webnotes.conn.sql_ddl("""alter table `tab%s` alter `%s` drop default""" % (dt, fieldname))
+ webnotes.reload_doc("Stock", "DocType", "Delivery Note Item")
+ for dt in ("Journal Voucher Detail", "Sales Taxes and Charges",
+ "Purchase Taxes and Charges", "Delivery Note Item",
+ "Purchase Invoice Item", "Sales Invoice Item"):
+ webnotes.conn.sql_ddl("""alter table `tab%s` alter `cost_center` drop default""" \
+ % (dt,))
webnotes.reload_doc(webnotes.conn.get_value("DocType", dt, "module"), "DocType", dt)
diff --git a/patches/april_2013/p07_rename_cost_center_other_charges.py b/patches/april_2013/p07_rename_cost_center_other_charges.py
new file mode 100644
index 0000000..c3c9491
--- /dev/null
+++ b/patches/april_2013/p07_rename_cost_center_other_charges.py
@@ -0,0 +1,9 @@
+import webnotes
+
+def execute():
+ webnotes.reload_doc("Accounts", "DocType", "Sales Taxes and Charges")
+ webnotes.conn.sql("""update `tabSales Taxes and Charges`
+ set cost_center = cost_center_other_charges""")
+ webnotes.conn.sql_ddl("""alter table `tabSales Taxes and Charges`
+ drop column cost_center_other_charges""")
+
\ No newline at end of file
diff --git a/patches/may_2013/p01_selling_net_total_export.py b/patches/may_2013/p01_selling_net_total_export.py
new file mode 100644
index 0000000..7d4e346
--- /dev/null
+++ b/patches/may_2013/p01_selling_net_total_export.py
@@ -0,0 +1,29 @@
+from __future__ import unicode_literals
+import webnotes
+from webnotes.utils import cint
+
+def execute():
+ for module, doctype in (("Accounts", "Sales Invoice"), ("Selling", "Sales Order"), ("Selling", "Quotation"),
+ ("Stock", "Delivery Note")):
+ webnotes.reload_doc(module, "DocType", doctype)
+ webnotes.conn.sql("""update `tab%s`
+ set net_total_export = round(net_total / if(conversion_rate=0, 1, ifnull(conversion_rate, 1)), 2),
+ other_charges_total_export = round(grand_total_export - net_total_export, 2)""" %
+ (doctype,))
+
+ for module, doctype in (("Accounts", "Sales Invoice Item"), ("Selling", "Sales Order Item"), ("Selling", "Quotation Item"),
+ ("Stock", "Delivery Note Item")):
+ if cint(webnotes.conn.get_value("DocField", {"parent": doctype, "fieldname": "ref_rate"}, "read_only")) == 0 and \
+ not webnotes.conn.sql("""select name from `tabProperty Setter` where doc_type=%s and doctype_or_field='DocField'
+ and field_name='ref_rate' and property='read_only'""", doctype):
+ webnotes.bean({
+ "doctype": "Property Setter",
+ "doc_type": doctype,
+ "doctype_or_field": "DocField",
+ "field_name": "ref_rate",
+ "property": "read_only",
+ "property_type": "Check",
+ "value": "0"
+ }).insert()
+
+ webnotes.reload_doc(module, "DocType", doctype)
\ No newline at end of file
diff --git a/patches/patch_list.py b/patches/patch_list.py
index ea61a04..b3ed12c 100644
--- a/patches/patch_list.py
+++ b/patches/patch_list.py
@@ -240,12 +240,13 @@
"patches.april_2013.p06_update_file_size",
"patches.april_2013.p05_fixes_in_reverse_modules",
"execute:webnotes.delete_doc('DocType Mapper', 'Delivery Note-Packing Slip')",
- "execute:webnotes.reload_doc('Stock', 'DocType', 'Delivery Note Item')",
+ "patches.april_2013.p07_rename_cost_center_other_charges",
"patches.april_2013.p06_default_cost_center",
"execute:webnotes.reset_perms('File Data')",
"patches.april_2013.p07_update_file_data_2",
"patches.april_2013.rebuild_sales_browser",
"patches.april_2013.p08_price_list_country",
+ "patches.may_2013.p01_selling_net_total_export",
"patches.may_2013.repost_stock_for_no_posting_time",
"patches.may_2013.p01_conversion_factor_and_aii",
"patches.may_2013.p02_update_valuation_rate",
diff --git a/public/js/transaction.js b/public/js/transaction.js
new file mode 100644
index 0000000..34e10f6
--- /dev/null
+++ b/public/js/transaction.js
@@ -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));
+ },
+});
\ No newline at end of file
diff --git a/public/js/utils.js b/public/js/utils.js
index 4df9555..0284670 100644
--- a/public/js/utils.js
+++ b/public/js/utils.js
@@ -13,8 +13,7 @@
//
// 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.utils');
+wn.provide("erpnext.utils");
erpnext.get_currency = function(company) {
if(!company && cur_frm)
@@ -23,4 +22,4 @@
return wn.model.get(":Company", company).default_currency || wn.boot.sysdefaults.currency;
else
return wn.boot.sysdefaults.currency;
-}
\ No newline at end of file
+}
diff --git a/selling/doctype/quotation/quotation.js b/selling/doctype/quotation/quotation.js
index 078baf1..a7c5421 100644
--- a/selling/doctype/quotation/quotation.js
+++ b/selling/doctype/quotation/quotation.js
@@ -53,14 +53,6 @@
}
}
-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..
// =======================================================================================================================
cur_frm.cscript.lead_cust_show = function(doc,cdt,cdn){
diff --git a/selling/doctype/quotation/quotation.py b/selling/doctype/quotation/quotation.py
index c154a6a..f4c30fc 100644
--- a/selling/doctype/quotation/quotation.py
+++ b/selling/doctype/quotation/quotation.py
@@ -95,17 +95,6 @@
def get_rate(self,arg):
return get_obj('Sales Common').get_rate(arg)
- # Load Default Charges
- # ----------------------------------------------------------
- def load_default_taxes(self):
- self.doclist = get_obj('Sales Common').load_default_taxes(self)
-
- # Pull details from other charges master (Get Sales Taxes and Charges Master)
- # ----------------------------------------------------------
- def get_other_charges(self):
- self.doclist = get_obj('Sales Common').get_other_charges(self)
-
-
# GET TERMS AND CONDITIONS
# ====================================================================================
def get_tc_details(self):
@@ -142,6 +131,8 @@
#do not allow sales item in maintenance quotation and service item in sales quotation
#-----------------------------------------------------------------------------------------------
def validate_order_type(self):
+ super(DocType, self).validate_order_type()
+
if self.doc.order_type in ['Maintenance', 'Service']:
for d in getlist(self.doclist, 'quotation_details'):
is_service_item = sql("select is_service_item from `tabItem` where name=%s", d.item_code)
diff --git a/selling/doctype/quotation/quotation.txt b/selling/doctype/quotation/quotation.txt
index 4115be8..3ea87e1 100644
--- a/selling/doctype/quotation/quotation.txt
+++ b/selling/doctype/quotation/quotation.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-05-22 12:10:46",
"docstatus": 0,
- "modified": "2013-05-22 16:54:07",
+ "modified": "2013-05-22 16:55:07",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -214,6 +214,7 @@
"oldfieldtype": "Table",
"options": "Quotation Item",
"read_only": 0,
+ "reqd": 1,
"width": "40px"
},
{
@@ -239,13 +240,21 @@
"oldfieldname": "net_total",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
- "print_hide": 0,
+ "print_hide": 1,
"read_only": 1,
"reqd": 0,
"width": "100px"
},
{
"doctype": "DocField",
+ "fieldname": "net_total_export",
+ "fieldtype": "Currency",
+ "label": "Net Total (Export)",
+ "options": "currency",
+ "read_only": 1
+ },
+ {
+ "doctype": "DocField",
"fieldname": "recalculate_values",
"fieldtype": "Button",
"label": "Re-Calculate Values",
@@ -423,7 +432,7 @@
"doctype": "DocField",
"fieldname": "other_charges_total",
"fieldtype": "Currency",
- "label": "Taxes and Charges Total*",
+ "label": "Taxes and Charges Total",
"oldfieldname": "other_charges_total",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
@@ -432,6 +441,15 @@
},
{
"doctype": "DocField",
+ "fieldname": "other_charges_total_export",
+ "fieldtype": "Currency",
+ "label": "Taxes and Charges Total (Export)",
+ "options": "currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "doctype": "DocField",
"fieldname": "other_charges_calculation",
"fieldtype": "HTML",
"label": "Taxes and Charges Calculation",
diff --git a/selling/doctype/quotation_item/quotation_item.txt b/selling/doctype/quotation_item/quotation_item.txt
index bcb9281..11ac1ba 100644
--- a/selling/doctype/quotation_item/quotation_item.txt
+++ b/selling/doctype/quotation_item/quotation_item.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-03-07 11:42:57",
"docstatus": 0,
- "modified": "2013-05-22 12:08:32",
+ "modified": "2013-05-22 12:10:32",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -119,7 +119,7 @@
"options": "currency",
"print_hide": 1,
"print_width": "100px",
- "read_only": 0,
+ "read_only": 1,
"reqd": 0,
"width": "100px"
},
@@ -195,7 +195,7 @@
"options": "Company:company:default_currency",
"print_hide": 1,
"print_width": "100px",
- "read_only": 0,
+ "read_only": 1,
"reqd": 0,
"search_index": 0,
"width": "100px"
diff --git a/selling/doctype/sales_common/sales_common.js b/selling/doctype/sales_common/sales_common.js
index 8a8d8d0..4d97034 100644
--- a/selling/doctype/sales_common/sales_common.js
+++ b/selling/doctype/sales_common/sales_common.js
@@ -21,118 +21,450 @@
// cur_frm.cscript.other_fname - wn.require('app/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js'); fieldname
// cur_frm.cscript.sales_team_fname - Sales Team fieldname
-// ============== Load Default Taxes ===================
-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.customer || getchildren('Sales Taxes and Charges', doc.name, 'other_charges', doc.doctype).length) {
- if(callback) {
- callback(doc, cdt, cdn);
+wn.provide("erpnext.selling");
+wn.require("app/js/transaction.js");
+
+erpnext.selling.SellingController = erpnext.TransactionController.extend({
+ setup: function() {
+ this.frm.add_fetch("sales_partner", "commission_rate", "commission_rate");
+ },
+
+ // 1
+ onload: function() {
+ this._super();
+ this.toggle_rounded_total();
+
+ // TODO set depends_on for customer related fields
+ },
+
+ validate: function() {
+ this.calculate_taxes_and_totals();
+
+ // 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();
+ }
+ }
+ });
+ }
}
- } else if(doc.charge) {
- cur_frm.cscript.get_charges(doc, cdt, cdn, callback);
- } else {
- $c_obj(make_doclist(doc.doctype, doc.name),'load_default_taxes','',function(r,rt){
- refresh_field('other_charges');
- if(callback) callback(doc, cdt, cdn);
+
+ // TODO hide/unhide related fields
+ },
+
+ barcode: function(doc, cdt, cdn) {
+ this.item_code(doc, cdt, cdn);
+ },
+
+ item_code: function(doc, cdt, cdn) {
+ var me = this;
+ var item = wn.model.get_doc(cdt, cdn);
+ if(item.item_code || item.barcode) {
+ if(!this.validate_company_and_party("customer")) {
+ item.item_code = null;
+ refresh_field("item_code", item.name, item.parentfield);
+ } else {
+ this.frm.call({
+ method: "selling.utils.get_item_details",
+ child: item,
+ args: {
+ args: {
+ item_code: item.item_code,
+ barcode: item.barcode,
+ warehouse: item.warehouse,
+ doctype: me.frm.doc.doctype,
+ customer: me.frm.doc.customer,
+ currency: me.frm.doc.currency,
+ conversion_rate: me.frm.doc.conversion_rate,
+ price_list_name: me.frm.doc.price_list_name,
+ price_list_currency: me.frm.doc.price_list_currency,
+ plc_conversion_rate: me.frm.doc.plc_conversion_rate,
+ company: me.frm.doc.company,
+ order_type: me.frm.doc.order_type,
+ is_pos: cint(me.frm.doc.is_pos),
+ update_stock: cint(me.frm.doc.update_stock),
+ }
+ },
+ callback: function(r) {
+ if(!r.exc) {
+ me.ref_rate(me.frm.doc, cdt, cdn);
+ }
+ }
+ });
+ }
+ }
+ },
+
+ price_list_name: function() {
+ this._super("selling");
+ },
+
+ ref_rate: function(doc, cdt, cdn) {
+ var item = wn.model.get_doc(cdt, cdn);
+ wn.model.round_floats_in(item, ["ref_rate", "adj_rate"]);
+
+ item.export_rate = flt(item.ref_rate * (1 - item.adj_rate / 100.0),
+ precision("export_rate", item));
+
+ this.calculate_taxes_and_totals();
+ },
+
+ adj_rate: function(doc, cdt, cdn) {
+ this.ref_rate(doc, cdt, cdn);
+ },
+
+ export_rate: function(doc, cdt, cdn) {
+ var item = wn.model.get_doc(cdt, cdn);
+ wn.model.round_floats_in(item, ["export_rate", "ref_rate"]);
+
+ if(item.ref_rate) {
+ item.adj_rate = flt((1 - item.export_rate / item.ref_rate) * 100.0,
+ precision("adj_rate", item));
+ } else {
+ item.adj_rate = 0.0;
+ }
+
+ this.calculate_taxes_and_totals();
+ },
+
+ commission_rate: function() {
+ this.calculate_commission();
+ refresh_field("total_commission");
+ },
+
+ total_commission: function() {
+ if(this.frm.doc.net_total) {
+ wn.model.round_floats_in(this.frm.doc, ["net_total", "total_commission"]);
+
+ if(this.frm.doc.net_total < this.frm.doc.total_commission) {
+ var msg = (wn._("[Error]") + " " +
+ wn._(wn.meta.get_label(this.frm.doc.doctype, "total_commission",
+ this.frm.doc.name)) + " > " +
+ wn._(wn.meta.get_label(this.frm.doc.doctype, "net_total", this.frm.doc.name)));
+ msgprint(msg);
+ throw msg;
+ }
+
+ this.frm.set_value("commission_rate",
+ flt(this.frm.doc.total_commission * 100.0 / this.frm.doc.net_total));
+ }
+ },
+
+ allocated_percentage: function(doc, cdt, cdn) {
+ var sales_person = wn.model.get_doc(cdt, cdn);
+
+ if(sales_person.allocated_percentage) {
+ sales_person.allocated_percentage = flt(sales_person.allocated_percentage,
+ precision("allocated_percentage", sales_person));
+ sales_person.allocated_amount = flt(this.frm.doc.net_total *
+ sales_person.allocated_percentage / 100.0,
+ precision("allocated_amount", sales_person));
+
+ refresh_field(["allocated_percentage", "allocated_amount"], sales_person.name,
+ sales_person.parentfield);
+ }
+ },
+
+ toggle_rounded_total: function() {
+ var me = this;
+ if(cint(wn.defaults.get_global_default("disable_rounded_total"))) {
+ $.each(["rounded_total", "rounded_total_export"], function(i, fieldname) {
+ me.frm.set_df_property(fieldname, "print_hide", 1);
+ me.frm.toggle_display(fieldname, false);
+ });
+ }
+ },
+
+ calculate_taxes_and_totals: function() {
+ this._super();
+ this.calculate_commission();
+ this.calculate_contribution();
+
+ // TODO
+ // outstanding amount
+
+ // check for custom_recalc in custom scripts of server
+
+ this.frm.refresh_fields();
+ },
+
+ calculate_item_values: function() {
+ var me = this;
+ $.each(this.frm.item_doclist, function(i, item) {
+ wn.model.round_floats_in(item);
+ item.export_amount = flt(item.export_rate * item.qty, precision("export_amount", item));
+
+ me._set_in_company_currency(item, "ref_rate", "base_ref_rate");
+ me._set_in_company_currency(item, "export_rate", "basic_rate");
+ me._set_in_company_currency(item, "export_amount", "amount");
});
- }
-}
-
-
-// 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);
-}
-
-
-// Update existing item details
-cur_frm.cscript.update_item_details = function(doc, dt, dn, callback) {
- doc = locals[doc.doctype][doc.name];
- if(!cur_frm.doc.__islocal) return;
- var children = getchildren(cur_frm.cscript.tname, doc.name, cur_frm.cscript.fname);
- if(children.length) {
- $c_obj(make_doclist(doc.doctype, doc.name), 'get_item_details', '',
- function(r, rt) {
- if(!r.exc) {
- refresh_field(cur_frm.cscript.fname);
- doc = locals[doc.doctype][doc.name];
- cur_frm.cscript.load_defaults(doc, dt, dn, callback);
+
+ },
+
+ determine_exclusive_rate: function() {
+ var me = this;
+ $.each(me.frm.item_doclist, function(n, item) {
+ var item_tax_map = me._load_item_tax_rate(item.item_tax_rate);
+ var cumulated_tax_fraction = 0.0;
+
+ $.each(me.frm.tax_doclist, function(i, tax) {
+ tax.tax_fraction_for_current_item = me.get_current_tax_fraction(tax, item_tax_map);
+
+ if(i==0) {
+ tax.grand_total_fraction_for_current_item = 1 + tax.tax_fraction_for_current_item;
+ } else {
+ tax.grand_total_fraction_for_current_item =
+ me.frm.tax_doclist[i-1].grand_total_fraction_for_current_item +
+ tax.tax_fraction_for_current_item;
+ }
+
+ cumulated_tax_fraction += tax.tax_fraction_for_current_item;
+ });
+
+ if(cumulated_tax_fraction) {
+ item.basic_rate = flt(
+ (item.export_rate * me.frm.doc.conversion_rate) / (1 + cumulated_tax_fraction),
+ precision("basic_rate", item));
+
+ item.amount = flt(item.basic_rate * item.qty, precision("amount", item));
+
+ if(item.adj_rate == 100) {
+ item.base_ref_rate = item.basic_rate;
+ item.basic_rate = 0.0;
+ } else {
+ item.base_ref_rate = flt(item.basic_rate / (1 - item.adj_rate / 100.0),
+ precision("base_ref_rate", item));
+ }
}
});
- } else {
- cur_frm.cscript.load_taxes(doc, dt, dn, callback);
- }
-}
-
-
-var set_dynamic_label_par = function(doc, cdt, cdn, base_curr) {
- //parent flds
- par_cols_base = {'net_total': 'Net Total', 'other_charges_total': 'Taxes and Charges Total',
- 'grand_total': 'Grand Total', 'rounded_total': 'Rounded Total', 'in_words': 'In Words'}
- par_cols_export = {'grand_total_export': 'Grand Total', 'rounded_total_export': 'Rounded Total', 'in_words_export': 'In Words'};
-
- for (d in par_cols_base) cur_frm.fields_dict[d].label_span.innerHTML = par_cols_base[d]+' (' + base_curr + ')';
- for (d in par_cols_export) cur_frm.fields_dict[d].label_span.innerHTML = par_cols_export[d]+' (' + doc.currency + ')';
- cur_frm.fields_dict['conversion_rate'].label_span.innerHTML = "Conversion Rate (" + doc.currency +' -> '+ base_curr + ')';
- cur_frm.fields_dict['plc_conversion_rate'].label_span.innerHTML = 'Price List Currency Conversion Rate (' + doc.price_list_currency +' -> '+ base_curr + ')';
-
- if (doc.doctype == 'Sales Invoice') {
- si_cols = {'total_advance': 'Total Advance', 'outstanding_amount': 'Outstanding Amount', 'paid_amount': 'Paid Amount', 'write_off_amount': 'Write Off Amount'}
- for (d in si_cols) cur_frm.fields_dict[d].label_span.innerHTML = si_cols[d] + ' (' + base_curr + ')';
- }
-}
-
-
-var set_dynamic_label_child = function(doc, cdt, cdn, base_curr) {
- // item table flds
- item_cols_base = {'basic_rate': 'Basic Rate', 'base_ref_rate': 'Price List Rate', 'amount': 'Amount'};
- item_cols_export = {'export_rate': 'Basic Rate', 'ref_rate': 'Price List Rate', 'export_amount': 'Amount'};
+ },
+
+ get_current_tax_fraction: function(tax, item_tax_map) {
+ // Get tax fraction for calculating tax exclusive amount
+ // from tax inclusive amount
+ var current_tax_fraction = 0.0;
- for (d in item_cols_base) $('[data-grid-fieldname="'+cur_frm.cscript.tname+'-'+d+'"]').html(item_cols_base[d]+' ('+base_curr+')');
- for (d in item_cols_export) $('[data-grid-fieldname="'+cur_frm.cscript.tname+'-'+d+'"]').html(item_cols_export[d]+' ('+doc.currency+')');
-
- var hide = (doc.currency == sys_defaults['currency']) ? false : true;
- for (f in item_cols_base) {
- cur_frm.fields_dict[cur_frm.cscript.fname].grid.set_column_disp(f, hide);
- }
-
- //tax table flds
- tax_cols = {'tax_amount': 'Amount', 'total': 'Total'};
- for (d in tax_cols) $('[data-grid-fieldname="Sales Taxes and Charges-'+d+'"]').html(tax_cols[d]+' ('+base_curr+')');
+ if(cint(tax.included_in_print_rate)) {
+ var tax_rate = this._get_tax_rate(tax, item_tax_map);
+
+ if(tax.charge_type == "On Net Total") {
+ current_tax_fraction = (tax_rate / 100.0);
+
+ } else if(tax.charge_type == "On Previous Row Amount") {
+ current_tax_fraction = (tax_rate / 100.0) *
+ this.frm.tax_doclist[cint(tax.row_id) - 1].tax_fraction_for_current_item;
+
+ } else if(tax.charge_type == "On Previous Row Total") {
+ current_tax_fraction = (tax_rate / 100.0) *
+ this.frm.tax_doclist[cint(tax.row_id) - 1].grand_total_fraction_for_current_item;
+ }
+ }
- if (doc.doctype == 'Sales Invoice') {
- // advance table flds
- adv_cols = {'advance_amount': 'Advance Amount', 'allocated_amount': 'Allocated Amount'}
- for (d in adv_cols) $('[data-grid-fieldname="Sales Invoice Advance-'+d+'"]').html(adv_cols[d]+' ('+base_curr+')');
- }
-}
+ return current_tax_fraction;
+ },
+
+ calculate_net_total: function() {
+ var me = this;
-// Change label dynamically based on currency
-//------------------------------------------------------------------
+ this.frm.doc.net_total = this.frm.doc.net_total_export = 0.0;
+ $.each(this.frm.item_doclist, function(i, item) {
+ me.frm.doc.net_total += item.amount;
+ me.frm.doc.net_total_export += item.export_amount;
+ });
+
+ wn.model.round_floats_in(this.frm.doc, ["net_total", "net_total_export"]);
+ },
+
+ 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_export = flt(this.frm.doc.grand_total / this.frm.doc.conversion_rate,
+ precision("grand_total_export"));
+
+ this.frm.doc.other_charges_total = flt(this.frm.doc.grand_total - this.frm.doc.net_total,
+ precision("other_charges_total"));
+ this.frm.doc.other_charges_total_export = flt(
+ this.frm.doc.grand_total_export - this.frm.doc.net_total_export,
+ precision("other_charges_total_export"));
+
+ this.frm.doc.rounded_total = Math.round(this.frm.doc.grand_total);
+ this.frm.doc.rounded_total_export = Math.round(this.frm.doc.grand_total_export);
+ },
+
+ calculate_commission: function() {
+ if(this.frm.doc.commission_rate > 100) {
+ var msg = wn._(wn.meta.get_label(this.frm.doc.doctype, "commission_rate", this.frm.doc.name)) +
+ " " + wn._("cannot be greater than 100");
+ msgprint(msg);
+ throw msg;
+ }
+
+ this.frm.doc.total_commission = flt(this.frm.doc.net_total * this.frm.doc.commission_rate / 100.0,
+ precision("total_commission"));
+ },
+
+ calculate_contribution: function() {
+ var me = this;
+ $.each(wn.model.get_doclist(this.frm.doc.doctype, this.frm.doc.name,
+ {parentfield: "sales_team"}), function(i, sales_person) {
+ wn.model.round_floats_in(sales_person);
+ if(sales_person.allocated_percentage) {
+ sales_person.allocated_amount = flt(
+ me.frm.doc.net_total * sales_person.allocated_percentage / 100.0,
+ precision("allocated_amount", sales_person));
+ }
+ });
+ },
+
+ _cleanup: function() {
+ this._super();
+ this.frm.doc.in_words = this.frm.doc.in_words_export = "";
+ },
-cur_frm.cscript.dynamic_label = function(doc, cdt, cdn, base_curr, callback) {
- cur_frm.cscript.base_currency = base_curr;
- set_dynamic_label_par(doc, cdt, cdn, base_curr);
- set_dynamic_label_child(doc, cdt, cdn, base_curr);
- set_sales_bom_help(doc);
+ show_item_wise_taxes: function() {
+ $(this.get_item_wise_taxes_html())
+ .appendTo($(this.frm.fields_dict.other_charges_calculation.wrapper).empty());
+ },
+
+ get_charges: function() {
+ var me = this;
+ if(this.frm.doc.charge) {
+ this.frm.call({
+ doc: this.frm.doc,
+ method: "get_other_charges",
+ callback: function(r) {
+ if(!r.exc) {
+ me.calculate_taxes_and_totals();
+ }
+ }
+ });
+ }
+ },
+
+ set_dynamic_labels: function() {
+ var company_currency = this.get_company_currency();
+
+ this.change_form_labels(company_currency);
+ this.change_grid_labels(company_currency);
+ },
+
+ change_form_labels: function(company_currency) {
+ var me = this;
+ var field_label_map = {};
+
+ var setup_field_label_map = function(fields_list, currency) {
+ $.each(fields_list, function(i, fname) {
+ var docfield = wn.meta.get_docfield(me.frm.doc.doctype, fname);
+ if(docfield) {
+ var label = wn._((docfield.label || "")).replace(/\([^\)]*\)/g, "");
+ field_label_map[fname] = label.trim() + " (" + currency + ")";
+ }
+ });
+ };
+
+ setup_field_label_map(["net_total", "other_charges_total", "grand_total",
+ "rounded_total", "in_words",
+ "outstanding_amount", "total_advance", "paid_amount", "write_off_amount"],
+ company_currency);
+
+ setup_field_label_map(["net_total_export", "other_charges_total_export", "grand_total_export",
+ "rounded_total_export", "in_words_export"], this.frm.doc.currency);
+
+ setup_field_label_map(["conversion_rate"], "1 " + this.frm.doc.currency
+ + " = [?] " + company_currency);
+
+ if(this.frm.doc.price_list_currency && this.frm.doc.price_list_currency!=company_currency) {
+ setup_field_label_map(["plc_conversion_rate"], "1 " + this.frm.doc.price_list_currency
+ + " = [?] " + company_currency);
+ }
+
+ // toggle fields
+ this.frm.toggle_display(["conversion_rate", "net_total", "other_charges_total",
+ "grand_total", "rounded_total", "in_words"],
+ this.frm.doc.currency != company_currency);
+
+ this.frm.toggle_display(["plc_conversion_rate"],
+ this.frm.doc.price_list_currency != company_currency);
+
+ // set labels
+ $.each(field_label_map, function(fname, label) {
+ me.frm.fields_dict[fname].set_label(label);
+ });
+ },
+
+ change_grid_labels: function(company_currency) {
+ var me = this;
+ var field_label_map = {};
+
+ var setup_field_label_map = function(fields_list, currency, parentfield) {
+ var grid_doctype = me.frm.fields_dict[parentfield].grid.doctype;
+ $.each(fields_list, function(i, fname) {
+ var docfield = wn.meta.get_docfield(grid_doctype, fname);
+ if(docfield) {
+ var label = wn._((docfield.label || "")).replace(/\([^\)]*\)/g, "");
+ field_label_map[grid_doctype + "-" + fname] =
+ label.trim() + " (" + currency + ")";
+ }
+ });
+ }
+
+ setup_field_label_map(["basic_rate", "base_ref_rate", "amount"],
+ company_currency, this.fname);
+
+ setup_field_label_map(["export_rate", "ref_rate", "export_amount"],
+ this.frm.doc.currency, this.fname);
+
+ setup_field_label_map(["tax_amount", "total"], company_currency, "other_charges");
+
+ if(this.frm.fields_dict["advance_allocation_details"]) {
+ setup_field_label_map(["advance_amount", "allocated_amount"], company_currency,
+ "advance_allocation_details");
+ }
+
+ // toggle columns
+ var item_grid = this.frm.fields_dict[this.fname].grid;
+ var show = this.frm.doc.currency != company_currency;
+ $.each(["basic_rate", "base_ref_rate", "amount"], function(i, fname) {
+ if(wn.meta.get_docfield(item_grid.doctype, fname))
+ item_grid.set_column_disp(fname, show);
+ });
+
+ // set labels
+ var $wrapper = $(this.frm.wrapper);
+ $.each(field_label_map, function(fname, label) {
+ $wrapper.find('[data-grid-fieldname="'+fname+'"]').text(label);
+ });
+ },
+
+});
- if (callback) callback(doc, cdt, cdn);
-}
+// to save previous state of cur_frm.cscript
+var prev_cscript = {};
+$.extend(prev_cscript, cur_frm.cscript);
+
+cur_frm.cscript = new erpnext.selling.SellingController({frm: cur_frm});
+
+// for backward compatibility: combine new and previous states
+$.extend(cur_frm.cscript, prev_cscript);
// Help for Sales BOM items
var set_sales_bom_help = function(doc) {
@@ -158,113 +490,8 @@
refresh_field('sales_bom_help');
}
-
-// hide / unhide price list currency based on availability of price list in customer's currency
-//---------------------------------------------------------------------------------------------------
-
-cur_frm.cscript.hide_price_list_currency = function(doc, cdt, cdn, callback1) {
- if (doc.price_list_name && doc.currency) {
- wn.call({
- method: 'selling.doctype.sales_common.sales_common.get_price_list_currency',
- args: {'price_list':doc.price_list_name, 'company': doc.company},
- callback: function(r, rt) {
- pl_currency = r.message[0]?r.message[0]:[];
- unhide_field(['price_list_currency', 'plc_conversion_rate']);
-
- if (pl_currency.length==1) {
- if (doc.price_list_currency != pl_currency[0])
- set_multiple(cdt, cdn, {price_list_currency:pl_currency[0]});
- if (pl_currency[0] == doc.currency) {
- if(doc.plc_conversion_rate != doc.conversion_rate)
- set_multiple(cdt, cdn, {plc_conversion_rate:doc.conversion_rate});
- hide_field(['price_list_currency', 'plc_conversion_rate']);
- } else if (pl_currency[0] == r.message[1]) {
- if (doc.plc_conversion_rate != 1)
- set_multiple(cdt, cdn, {plc_conversion_rate:1})
- hide_field(['price_list_currency', 'plc_conversion_rate']);
- }
- }
-
- if (r.message[1] == doc.currency) {
- if (doc.conversion_rate != 1)
- set_multiple(cdt, cdn, {conversion_rate:1});
- hide_field(['conversion_rate', 'grand_total_export', 'in_words_export', 'rounded_total_export']);
- } else {
- unhide_field(['conversion_rate', 'grand_total_export', 'in_words_export']);
- if(!cint(sys_defaults.disable_rounded_total))
- unhide_field("rounded_total_export");
- }
- if (r.message[1] == doc.price_list_currency) {
- if (doc.plc_conversion_rate != 1)
- set_multiple(cdt, cdn, {plc_conversion_rate:1});
- hide_field('plc_conversion_rate');
- } else unhide_field('plc_conversion_rate');
- cur_frm.cscript.dynamic_label(doc, cdt, cdn, r.message[1], callback1);
- }
- })
- }
-}
-
-cur_frm.cscript.manage_rounded_total = function() {
- if(cint(sys_defaults.disable_rounded_total)) {
- cur_frm.set_df_property("rounded_total", "print_hide", 1);
- cur_frm.set_df_property("rounded_total_export", "print_hide", 1);
- hide_field(["rounded_total", "rounded_total_export"]);
- }
-}
-
-// TRIGGERS FOR CALCULATIONS
-// =====================================================================================================
-
-// ********************* CURRENCY ******************************
-cur_frm.cscript.currency = function(doc, cdt, cdn) {
- cur_frm.cscript.price_list_name(doc, cdt, cdn);
-}
-
-cur_frm.cscript.price_list_currency = cur_frm.cscript.currency;
-cur_frm.cscript.conversion_rate = cur_frm.cscript.currency;
-cur_frm.cscript.plc_conversion_rate = cur_frm.cscript.currency;
-
-cur_frm.cscript.company = function(doc, cdt, cdn) {
- wn.call({
- method: 'selling.doctype.sales_common.sales_common.get_comp_base_currency',
- args: {company:doc.company},
- callback: function(r, rt) {
- var doc = locals[cdt][cdn];
- set_multiple(doc.doctype, doc.name, {
- currency:r.message,
- price_list_currency:r.message
- });
- cur_frm.cscript.currency(doc, cdt, cdn);
- }
- });
-}
-
-
-
-// ******************** PRICE LIST ******************************
-cur_frm.cscript.price_list_name = function(doc, cdt, cdn) {
- var callback = function() {
- var fname = cur_frm.cscript.fname;
- var cl = getchildren(cur_frm.cscript.tname, doc.name, cur_frm.cscript.fname);
- if(doc.price_list_name && doc.currency && doc.price_list_currency && doc.conversion_rate && doc.plc_conversion_rate) {
- $c_obj(make_doclist(doc.doctype, doc.name), 'get_adj_percent', '',
- function(r, rt) {
- refresh_field(fname);
- var doc = locals[cdt][cdn];
- cur_frm.cscript.recalc(doc,3); //this is to re-calculate BASIC RATE and AMOUNT on basis of changed REF RATE
- }
- );
- }
- }
- cur_frm.cscript.hide_price_list_currency(doc, cdt, cdn, callback);
-}
-
-
-
-// ******************** ITEM CODE ********************************
cur_frm.fields_dict[cur_frm.cscript.fname].grid.get_field("item_code").get_query = function(doc, cdt, cdn) {
- if (inList(['Maintenance', 'Service'], doc.order_type)) {
+ if (doc.order_type == "Maintenance") {
return erpnext.queries.item({
'ifnull(tabItem.is_service_item, "No")': 'Yes'
});
@@ -275,47 +502,6 @@
}
}
-
-cur_frm.cscript.item_code = function(doc, cdt, cdn) {
- var fname = cur_frm.cscript.fname;
- var d = locals[cdt][cdn];
- if (d.item_code) {
- if (!doc.company) {
- msgprint("Please select company to proceed");
- d.item_code = '';
- refresh_field('item_code', d.name, fname);
- } else {
- var callback = function(r, rt){
- cur_frm.cscript.recalc(doc, 1);
- }
- var args = {
- 'item_code':d.item_code,
- 'income_account':d.income_account,
- 'cost_center': d.cost_center,
- 'warehouse': d.warehouse
- };
- get_server_fields('get_item_details',JSON.stringify(args),
- fname,doc,cdt,cdn,1,callback);
- }
- }
- if(cur_frm.cscript.custom_item_code){
- cur_frm.cscript.custom_item_code(doc, cdt, cdn);
- }
-}
-
-//Barcode
-//
-cur_frm.cscript.barcode = function(doc, cdt, cdn) {
- var d = locals[cdt][cdn];
- var callback = function(r, rt) {
- cur_frm.cscript.item_code(doc, cdt, cdn);
- }
- if(d.barcode) {
- get_server_fields('get_barcode_details', d.barcode, cur_frm.cscript.fname,
- doc, cdt, cdn, 1, callback);
- }
-}
-
cur_frm.fields_dict[cur_frm.cscript.fname].grid.get_field('batch_no').get_query =
function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
@@ -360,66 +546,6 @@
'" AND docstatus != 2 AND %(key)s LIKE "%s" ORDER BY name ASC LIMIT 50';
}
-// *********************** QUANTITY ***************************
-cur_frm.cscript.qty = function(doc, cdt, cdn) { cur_frm.cscript.recalc(doc, 1); }
-
-// ************************ DISCOUNT (%) ***********************
-cur_frm.cscript.adj_rate = function(doc, cdt, cdn) { cur_frm.cscript.recalc(doc, 1); }
-
-// ************************ REF RATE ****************************
-cur_frm.cscript.ref_rate = function(doc, cdt, cdn){
- var d = locals[cdt][cdn];
- var consider_incl_rate = cur_frm.cscript.consider_incl_rate(doc, cur_frm.cscript.other_fname);
- if(!consider_incl_rate) {
- set_multiple(cur_frm.cscript.tname, d.name, {'export_rate': flt(d.ref_rate) * (100 - flt(d.adj_rate)) / 100}, cur_frm.cscript.fname);
- }
- cur_frm.cscript.recalc(doc, 1);
-}
-
-// *********************** BASIC RATE **************************
-cur_frm.cscript.basic_rate = function(doc, cdt, cdn) {
- var fname = cur_frm.cscript.fname;
- var d = locals[cdt][cdn];
- if(!d.qty) {
- d.qty = 1;
- refresh_field('qty', d.name, fname);
- }
- var consider_incl_rate = cur_frm.cscript.consider_incl_rate(doc, cur_frm.cscript.other_fname);
- if(!consider_incl_rate) {
- cur_frm.cscript.recalc(doc, 2);
- } else {
- var basic_rate = cur_frm.cscript.back_calc_basic_rate(
- doc, cur_frm.cscript.tname, fname, d, cur_frm.cscript.other_fname
- );
- // TODO: remove roundNumber for basic_rate comparison
- if (d.basic_rate != roundNumber(basic_rate, 2)) {
- d.basic_rate = basic_rate;
- refresh_field('basic_rate', d.name, fname);
- msgprint("You cannot change Basic Rate* (Base Currency) when \
- considering rates inclusive of taxes.<br /> \
- Please either <br /> \
- * Specify Basic Rate (i.e. Rate which will be displayed in print) <br /> \
- -- or -- <br />\
- * Uncheck 'Is this Tax included in Basic Rate?' in the tax entries of Taxes section.");
- }
- }
-}
-
-// ************************ EXPORT RATE *************************
-cur_frm.cscript.export_rate = function(doc,cdt,cdn) {
- var cur_rec = locals[cdt][cdn];
- var fname = cur_frm.cscript.fname;
- var tname = cur_frm.cscript.tname;
- if(flt(cur_rec.ref_rate)>0 && flt(cur_rec.export_rate)>0) {
- var adj_rate = 100 * (1 - (flt(cur_rec.export_rate) / flt(cur_rec.ref_rate)));
- set_multiple(tname, cur_rec.name, { 'adj_rate': adj_rate }, fname);
- }
- doc = locals[doc.doctype][doc.name];
- cur_frm.cscript.recalc(doc, 1);
-}
-
-
-
// ************* GET OTHER CHARGES BASED ON COMPANY *************
cur_frm.fields_dict.charge.get_query = function(doc) {
return 'SELECT DISTINCT `tabSales Taxes and Charges Master`.name FROM \
@@ -430,492 +556,4 @@
ORDER BY `tabSales Taxes and Charges Master`.name LIMIT 50';
}
-// ********************* Get Charges ****************************
-cur_frm.cscript.get_charges = function(doc, cdt, cdn, callback) {
- $c_obj(make_doclist(doc.doctype,doc.name),
- 'get_other_charges',
- '',
- function(r, rt) {
- cur_frm.cscript.calculate_charges(doc, cdt, cdn);
- if(callback) callback(doc, cdt, cdn);
- }, null,null,cur_frm.fields_dict.get_charges.input);
-}
-
-
-// CALCULATION OF TOTAL AMOUNTS
-// ========================================================================================================
-cur_frm.cscript.recalc = function(doc, n) {
- if(!n)n=0;
- doc = locals[doc.doctype][doc.name];
- var tname = cur_frm.cscript.tname;
- var fname = cur_frm.cscript.fname;
- var sales_team = cur_frm.cscript.sales_team_fname;
- var other_fname = cur_frm.cscript.other_fname;
-
- if(!flt(doc.conversion_rate)) {
- doc.conversion_rate = 1;
- refresh_field('conversion_rate');
- }
- if(!flt(doc.plc_conversion_rate)) {
- doc.plc_conversion_rate = 1;
- refresh_field('plc_conversion_rate');
- }
-
- if(n > 0) cur_frm.cscript.update_fname_table(doc , tname , fname , n, other_fname); // updates all values in table (i.e. amount, export amount, net total etc.)
-
- if(flt(doc.net_total) > 0) {
- var cl = getchildren('Sales Taxes and Charges', doc.name, other_fname,doc.doctype);
- for(var i = 0; i<cl.length; i++){
- cl[i].total_tax_amount = 0;
- cl[i].total_amount = 0;
- cl[i].tax_amount = 0; // this is done to calculate other charges
- cl[i].total = 0;
- cl[i].item_wise_tax_detail = "";
- if(in_list(['On Previous Row Amount','On Previous Row Total'],cl[i].charge_type) && !cl[i].row_id){
- alert("Please Enter Row on which amount needs to be calculated for row : "+cl[i].idx);
- validated = false;
- }
- }
- cur_frm.cscript.calc_other_charges(doc , tname , fname , other_fname); // calculate other charges
- }
- cur_frm.cscript.calc_doc_values(doc, null, null, tname, fname, other_fname); // calculates total amounts
-
- // ******************* calculate allocated amount of sales person ************************
- cl = getchildren('Sales Team', doc.name, sales_team);
- for(var i=0;i<cl.length;i++) {
- if (cl[i].allocated_percentage) {
- cl[i].allocated_amount = flt(flt(doc.net_total)*flt(cl[i].allocated_percentage)/100);
- refresh_field('allocated_amount', cl[i].name, sales_team);
- }
- }
- doc.in_words = '';
- doc.in_words_export = '';
- refresh_many(['total_discount_rate','total_discount','net_total','total_commission','grand_total','rounded_total','grand_total_export','rounded_total_export','in_words','in_words_export','other_charges','other_charges_total']);
- if(cur_frm.cscript.custom_recalc)cur_frm.cscript.custom_recalc(doc);
-}
-
-// ******* Calculation of total amounts of document (item amount + other charges)****************
-cur_frm.cscript.calc_doc_values = function(doc, cdt, cdn, tname, fname, other_fname) {
- doc = locals[doc.doctype][doc.name];
- var net_total = 0; var other_charges_total = 0;
- var net_total_incl = 0
- var cl = getchildren(tname, doc.name, fname);
- for(var i = 0; i<cl.length; i++){
- //net_total += flt(cl[i].basic_rate) * flt(cl[i].qty);
- net_total += flt(cl[i].amount);
- net_total_incl += flt(cl[i].export_amount);
- }
-
- var inclusive_rate = 0
- var d = getchildren('Sales Taxes and Charges', doc.name, other_fname,doc.doctype);
- for(var j = 0; j<d.length; j++){
- other_charges_total += flt(d[j].tax_amount);
- if(d[j].included_in_print_rate) {
- inclusive_rate = 1;
- }
- }
-
- if(flt(doc.conversion_rate)>1) {
- net_total_incl *= flt(doc.conversion_rate);
- }
-
- doc.net_total = inclusive_rate ? flt(net_total_incl) : flt(net_total);
- doc.other_charges_total = roundNumber(flt(other_charges_total), 2);
- doc.grand_total = roundNumber((flt(net_total) + flt(other_charges_total)), 2);
- doc.rounded_total = Math.round(doc.grand_total);
- doc.grand_total_export = roundNumber((flt(doc.grand_total) / flt(doc.conversion_rate)), 2);
- doc.rounded_total_export = Math.round(doc.grand_total_export);
- doc.total_commission = flt(flt(net_total) * flt(doc.commission_rate) / 100);
-}
-
-// ******************************* OTHER CHARGES *************************************
-cur_frm.cscript.calc_other_charges = function(doc , tname , fname , other_fname) {
- doc = locals[doc.doctype][doc.name];
-
- // Make Display Area
- cur_frm.fields_dict['other_charges_calculation'].disp_area.innerHTML =
- '<b style="padding: 8px 0px;">Calculation Details for Taxes and Charges:</b>';
-
- var cl = getchildren(tname, doc.name, fname);
- var tax = getchildren('Sales Taxes and Charges', doc.name, other_fname,doc.doctype);
-
- // Make display table
- var otc = make_table(cur_frm.fields_dict['other_charges_calculation'].disp_area,
- cl.length + 1, tax.length + 1, '90%', [], { border:'1px solid #AAA', padding:'2px' });
- $y(otc,{marginTop:'8px'});
-
- var tax_desc = {}; var tax_desc_rates = []; var net_total = 0;
-
- for(var i=0;i<cl.length;i++) {
- net_total += flt(flt(cl[i].qty) * flt(cl[i].basic_rate));
- var prev_total = flt(cl[i].amount);
- if(cl[i].item_tax_rate) {
- try {
- var check_tax = JSON.parse(cl[i].item_tax_rate); //to get in dictionary
- } catch(exception) {
- var check_tax = eval('var a='+cl[i].item_tax_rate+';a'); //to get in dictionary
- }
- }
-
- // Add Item Code in new Row
- $td(otc,i+1,0).innerHTML = cl[i].item_code ? cl[i].item_code : cl[i].description;
-
- //var tax = getchildren('Sales Taxes and Charges', doc.name, other_fname,doc.doctype);
- var total = net_total;
-
-
- for(var t=0;t<tax.length;t++){
- var account = tax[t].account_head;
- $td(otc,0,t+1).innerHTML = account?account:'';
- //Check For Rate
- if(cl[i].item_tax_rate && check_tax[account]!=null) {
- var rate = flt(check_tax[account]);
- } else {
- // if particular item doesn't have particular rate it will take other charges rate
- var rate = flt(tax[t].rate);
- }
-
- //Check For Rate and get tax amount
- var tax_amount = cur_frm.cscript.check_charge_type_and_get_tax_amount(doc,tax,t, cl[i], rate);
-
- //enter item_wise_tax_detail i.e. tax rate on each item
- var item_wise_tax_detail = cur_frm.cscript.get_item_wise_tax_detail(doc, rate, cl, i, tax, t);
- if(tax[t].charge_type != "Actual") tax[t].item_wise_tax_detail += item_wise_tax_detail;
- tax[t].total_amount = flt(tax_amount); //stores actual tax amount in virtual field
- tax[t].total_tax_amount = flt(prev_total); //stores total amount in virtual field
- tax[t].tax_amount += flt(tax_amount);
- var total_amount = flt(tax[t].tax_amount);
- total_tax_amount = flt(tax[t].total_tax_amount) + flt(total_amount);
- set_multiple('Sales Taxes and Charges', tax[t].name, { 'item_wise_tax_detail':tax[t].item_wise_tax_detail, 'amount':roundNumber(flt(total_amount), 2), 'total':roundNumber(flt(total)+flt(tax[t].tax_amount), 2)}, other_fname);
- prev_total += flt(tax[t].total_amount); // for previous row total
- total += flt(tax[t].tax_amount); // for adding total to previous amount
-
- if(tax[t].charge_type == 'Actual')
- $td(otc,i+1,t+1).innerHTML = format_currency(tax[t].total_amount, erpnext.get_currency(doc.company));
- else
- $td(otc,i+1,t+1).innerHTML = '('+format_number(rate) + '%) ' +format_currency(tax[t].total_amount, erpnext.get_currency(doc.company));
-
- }
- }
-
- for(var t=0;t<tax.length;t++){
- tax[t].tax_amount = roundNumber(tax[t].tax_amount, 2);
- }
-}
-cur_frm.cscript.check_charge_type_and_get_tax_amount = function( doc, tax, t, cl, rate, print_amt) {
- doc = locals[doc.doctype][doc.name];
- if (! print_amt) print_amt = 0;
- var tax_amount = 0;
- if(tax[t].charge_type == 'Actual') {
- var value = flt(tax[t].rate) / flt(doc.net_total); // this give the ratio in which all items are divided
- return tax_amount = flt(value) * flt(cl.amount);
- }
- else if(tax[t].charge_type == 'On Net Total') {
- if (flt(print_amt) == 1) {
- doc.excise_rate = flt(rate);
- doc.total_excise_rate += flt(rate);
- refresh_field('excise_rate');
- refresh_field('total_excise_rate');
- return
- }
- return tax_amount = (flt(rate) * flt(cl.amount) / 100);
- }
- else if(tax[t].charge_type == 'On Previous Row Amount'){
- if(flt(print_amt) == 1) {
- doc.total_excise_rate += flt(flt(doc.excise_rate) * 0.01 * flt(rate));
- refresh_field('total_excise_rate');
- return
- }
- var row_no = (tax[t].row_id).toString();
- var row = (row_no).split("+"); // splits the values and stores in an array
- for(var r = 0;r<row.length;r++){
- var id = cint(row[r].replace(/^\s+|\s+$/g,""));
- tax_amount += (flt(rate) * flt(tax[id-1].total_amount) / 100);
- }
- var row_id = row_no.indexOf("/");
- if(row_id != -1) {
- rate = '';
- var row = (row_no).split("/"); // splits the values and stores in an array
- if(row.length>2) alert("You cannot enter more than 2 nos. for division");
- var id1 = cint(row[0].replace(/^\s+|\s+$/g,""));
- var id2 = cint(row[1].replace(/^\s+|\s+$/g,""));
- tax_amount = flt(tax[id1-1].total_amount) / flt(tax[id2-1].total_amount);
- }
- return tax_amount
- }
- else if(tax[t].charge_type == 'On Previous Row Total') {
- if(flt(print_amt) == 1) {
- doc.sales_tax_rate += flt(rate);
- refresh_field('sales_tax_rate');
- return
- }
- var row = cint(tax[t].row_id);
- return tax_amount = flt(rate) * (flt(tax[row-1].total_tax_amount)+flt(tax[row-1].total_amount)) / 100;
- }
-}
-
-// ********************** Functions for inclusive value calc ******************************
-cur_frm.cscript.consider_incl_rate = function(doc, other_fname) {
- var tax_list = getchildren('Sales Taxes and Charges', doc.name, other_fname, doc.doctype);
- for(var i=0; i<tax_list.length; i++) {
- if(tax_list[i].included_in_print_rate) {
- return true;
- }
- }
- return false;
-}
-
-cur_frm.cscript.back_calc_basic_rate = function(doc, tname, fname, child, other_fname) {
- var get_item_tax_rate = function(item, tax) {
- if(item.item_tax_rate) {
- try {
- var item_tax = JSON.parse(item.item_tax_rate);
- } catch(exception) {
- var item_tax = eval('var a='+item.item_tax_rate+';a');
- }
- if(item_tax[tax.account_head]!=null) {
- return flt(item_tax[tax.account_head]);
- }
- }
- };
-
- var tax_list = getchildren('Sales Taxes and Charges', doc.name, other_fname, doc.doctype);
- var total = 1;
- var temp_tax_list = [];
- var amt = 0;
- var item_tax_rate = 0;
- var rate = 0;
- for(var i=0; i<tax_list.length; i++) {
- amt = 0;
- item_tax_rate = get_item_tax_rate(child, tax_list[i]);
- rate = item_tax_rate ? item_tax_rate : flt(tax_list[i].rate);
- if(tax_list[i].included_in_print_rate) {
- if(tax_list[i].charge_type=='On Net Total') {
- amt = flt(rate / 100);
- } else if(tax_list[i].charge_type=='On Previous Row Total') {
- amt = flt((rate * temp_tax_list[tax_list[i].row_id-1]['total']) / 100);
- } else if(tax_list[i].charge_type=='On Previous Row Amount') {
- amt = flt((rate * temp_tax_list[tax_list[i].row_id-1]['amt']) / 100);
- }
- }
- total += flt(amt);
- temp_tax_list[i] = {
- amt: amt,
- total: total
- };
- }
- var basic_rate = (child.export_rate * flt(doc.conversion_rate)) / total;
- //console.log(temp_tax_list);
- //console.log('in basic rate back calc');
- //console.log(basic_rate);
- return basic_rate;
-}
-
-cur_frm.cscript.included_in_print_rate = function(doc, cdt, cdn) {
- var tax = locals[cdt][cdn];
- if(tax.included_in_print_rate==1) {
- if(!inList(['On Net Total', 'On Previous Row Total', 'On Previous Row Amount'], tax.charge_type)) {
- msgprint("'Is this Tax included in Basic Rate?' (i.e. Inclusive Price) is only valid for charges of type: <br /> \
- * On Net Total <br /> \
- * On Previous Row Amount <br /> \
- * On Previous Row Total");
- tax.included_in_print_rate = 0;
- refresh_field('included_in_print_rate', tax.name, cur_frm.cscript.other_fname);
- }
- var tax_list = getchildren('Sales Taxes and Charges', doc.name, cur_frm.cscript.other_fname, doc.doctype);
- cur_frm.cscript.validate_print_rate_option(doc, tax_list, tax.idx-1);
- }
-}
-
-// ********************** Update values in table ******************************
-cur_frm.cscript.update_fname_table = function(doc , tname , fname , n, other_fname) {
- doc = locals[doc.doctype][doc.name]
- var net_total = 0
- var cl = getchildren(tname, doc.name, fname);
- var consider_incl_rate = cur_frm.cscript.consider_incl_rate(doc, other_fname);
- for(var i=0;i<cl.length;i++) {
- if(n == 1){
- if(!consider_incl_rate) {
- if(flt(cl[i].ref_rate) > 0) {
- set_multiple(tname, cl[i].name, {
- 'export_rate': flt(flt(cl[i].ref_rate) * (100 - flt(cl[i].adj_rate)) / 100)
- }, fname);
- }
- set_multiple(tname, cl[i].name, {
- 'export_amount': flt(flt(cl[i].qty) * flt(cl[i].export_rate)),
- 'basic_rate': flt(flt(cl[i].export_rate) * flt(doc.conversion_rate)),
- 'amount': roundNumber(flt((flt(cl[i].export_rate) * flt(doc.conversion_rate)) * flt(cl[i].qty)), 2)
- }, fname);
- //var base_ref_rate = flt(cl[i].basic_rate) + flt(flt(cl[i].basic_rate) * flt(cl[i].adj_rate) / 100);
- //set_multiple(tname, cl[i].name, {
- // 'base_ref_rate': flt(base_ref_rate)
- //}, fname);
-
- } else if(consider_incl_rate) {
- if(flt(cl[i].export_rate) > 0) {
- // calculate basic rate based on taxes
- // then calculate and set basic_rate, base_ref_rate, ref_rate, amount, export_amount
- var ref_rate = flt(cl[i].adj_rate)!=flt(100) ?
- flt((100 * flt(cl[i].export_rate))/flt(100 - flt(cl[i].adj_rate))) :
- flt(0)
- set_multiple(tname, cl[i].name, { 'ref_rate': ref_rate }, fname);
- } else if((flt(cl[i].ref_rate) > 0) && (flt(cl[i].adj_rate) > 0)) {
- var export_rate = flt(cl[i].ref_rate) * flt(1 - flt(cl[i].adj_rate / 100));
- set_multiple(tname, cl[i].name, { 'export_rate': flt(export_rate) }, fname);
- }
- //console.log("export_rate: " + cl[i].export_rate);
-
- var basic_rate = cur_frm.cscript.back_calc_basic_rate(doc, tname, fname, cl[i], other_fname);
- var base_ref_rate = basic_rate + flt(basic_rate * flt(cl[i].adj_rate) / 100);
- set_multiple(tname, cl[i].name, {
- 'basic_rate': flt(basic_rate),
- 'amount': roundNumber(flt(basic_rate * flt(cl[i].qty)), 2),
- 'export_amount': flt(flt(cl[i].qty) * flt(cl[i].export_rate)),
- 'base_ref_rate': flt(base_ref_rate)
- }, fname);
- }
- }
- else if(n == 2){
- if(flt(cl[i].ref_rate) > 0)
- set_multiple(tname, cl[i].name, {'adj_rate': 100 - flt(flt(cl[i].basic_rate) * 100 / (flt(cl[i].ref_rate) * flt(doc.conversion_rate)))}, fname);
- set_multiple(tname, cl[i].name, {'amount': flt(flt(cl[i].qty) * flt(cl[i].basic_rate)), 'export_rate': flt(flt(cl[i].basic_rate) / flt(doc.conversion_rate)), 'export_amount': flt((flt(cl[i].basic_rate) / flt(doc.conversion_rate)) * flt(cl[i].qty)) }, fname);
- }
- /*else if(n == 3){
- set_multiple(tname, cl[i].name, {'basic_rate': flt(flt(cl[i].export_rate) * flt(doc.conversion_rate))}, fname);
- set_multiple(tname, cl[i].name, {'amount' : flt(flt(cl[i].basic_rate) * flt(cl[i].qty)), 'export_amount': flt(flt(cl[i].export_rate) * flt(cl[i].qty))}, fname);
- if(cl[i].ref_rate > 0)
- set_multiple(tname, cl[i].name, {'adj_rate': 100 - flt(flt(cl[i].export_rate) * 100 / flt(cl[i].ref_rate)), 'base_ref_rate': flt(flt(cl[i].ref_rate) * flt(doc.conversion_rate)) }, fname);
- }*/
- net_total += flt(flt(cl[i].qty) * flt(cl[i].basic_rate));
- }
- doc.net_total = net_total;
- refresh_field('net_total');
-}
-
-cur_frm.cscript.get_item_wise_tax_detail = function( doc, rate, cl, i, tax, t) {
- doc = locals[doc.doctype][doc.name];
- var detail = '';
- detail = cl[i].item_code + " : " + cstr(rate) + NEWLINE;
- return detail;
-}
-
-// **************** RE-CALCULATE VALUES ***************************
-
-cur_frm.cscript.recalculate_values = function(doc, cdt, cdn) {
- cur_frm.cscript.calculate_charges(doc,cdt,cdn);
-}
-
-cur_frm.cscript.validate_print_rate_option = function(doc, taxes, i) {
- if(in_list(['On Previous Row Amount','On Previous Row Total'], taxes[i].charge_type)) {
- if(!taxes[i].row_id){
- alert("Please Enter Row on which amount needs to be calculated for row : "+taxes[i].idx);
- validated = false;
- } else if(taxes[i].included_in_print_rate && taxes[taxes[i].row_id-1].charge_type=='Actual') {
- msgprint("Row of type 'Actual' cannot be depended on for type '" + taxes[i].charge_type + "'\
- when using tax inclusive prices.<br />\
- This will lead to incorrect values.<br /><br /> \
- <b>Please specify correct value in 'Enter Row' column of <span style='color:red'>Row: "
- + taxes[i].idx + "</span> in Taxes table</b>");
- validated = false;
- taxes[i].included_in_print_rate = 0;
- refresh_field('included_in_print_rate', taxes[i].name, other_fname);
- } else if ((taxes[i].included_in_print_rate && !taxes[taxes[i].row_id-1].included_in_print_rate) ||
- (!taxes[i].included_in_print_rate && taxes[taxes[i].row_id-1].included_in_print_rate)) {
- msgprint("If any row in the tax table depends on 'Previous Row Amount/Total', <br />\
- 'Is this Tax included in Basic Rate?' column should be same for both row <br />\
- i.e for that row and the previous row. <br /><br />\
- The same is violated for row #"+(i+1)+" and row #"+taxes[i].row_id
- );
- validated = false;
- }
- }
-}
-
-cur_frm.cscript.calculate_charges = function(doc, cdt, cdn) {
- var other_fname = cur_frm.cscript.other_fname;
-
- var cl = getchildren('Sales Taxes and Charges', doc.name, other_fname, doc.doctype);
- for(var i = 0; i<cl.length; i++){
- cl[i].total_tax_amount = 0;
- cl[i].total_amount = 0;
- cl[i].tax_amount = 0; // this is done to calculate other charges
- cl[i].total = 0;
- cur_frm.cscript.validate_print_rate_option(doc, cl, i);
- }
- cur_frm.cscript.recalc(doc, 1);
-}
-
-// Get Sales Partner Commission
-// =================================================================================
-cur_frm.cscript.sales_partner = function(doc, cdt, cdn){
- if(doc.sales_partner){
-
- get_server_fields('get_comm_rate', doc.sales_partner, '', doc, cdt, cdn, 1);
- }
-}
-
-// *******Commission Rate Trigger (calculates total commission amount)*********
-cur_frm.cscript.commission_rate = function(doc, cdt, cdn) {
- if(doc.commission_rate > 100){
- alert("Commision rate cannot be greater than 100.");
- doc.total_commission = 0;
- doc.commission_rate = 0;
- } else {
- doc.total_commission = doc.net_total * doc.commission_rate / 100;
- }
- refresh_many(['total_commission','commission_rate']);
-
-}
-
-// *******Total Commission Trigger (calculates commission rate)*********
-cur_frm.cscript.total_commission = function(doc, cdt, cdn) {
- if(doc.net_total){
- if(doc.net_total < doc.total_commission){
- alert("Total commission cannot be greater than net total.");
- doc.total_commission = 0;
- doc.commission_rate = 0;
- } else {
- doc.commission_rate = doc.total_commission * 100 / doc.net_total;
- }
- refresh_many(['total_commission','commission_rate']);
- }
-}
-// Sales Person Allocated % trigger
-// ==============================================================================
-cur_frm.cscript.allocated_percentage = function(doc, cdt, cdn) {
- var fname = cur_frm.cscript.sales_team_fname;
- var d = locals[cdt][cdn];
- if (d.allocated_percentage) {
- d.allocated_amount = flt(flt(doc.net_total)*flt(d.allocated_percentage)/100);
- refresh_field('allocated_amount', d.name, fname);
- }
-}
-
-// Client Side Validation
-// =================================================================================
-cur_frm.cscript.validate = function(doc, cdt, cdn) {
- cur_frm.cscript.validate_items(doc);
- var cl = getchildren('Sales Taxes and Charges Master', doc.name, 'other_charges');
- for(var i =0;i<cl.length;i++) {
- if(!cl[i].amount) {
- alert("Please Enter Amount in Row no. "+cl[i].idx+" in Taxes and Charges table");
- validated = false;
- }
- }
- cur_frm.cscript.calculate_charges (doc, cdt, cdn);
-
- if (doc.docstatus == 0 && cur_frm.cscript.calc_adjustment_amount)
- cur_frm.cscript.calc_adjustment_amount(doc);
-}
-
-
-// ************** Atleast one item in document ****************
-cur_frm.cscript.validate_items = function(doc) {
- var cl = getchildren(cur_frm.cscript.tname, doc.name, cur_frm.cscript.fname);
- if(!cl.length){
- alert("Please enter Items for " + doc.doctype);
- validated = false;
- }
-}
-
cur_frm.fields_dict.customer.get_query = erpnext.utils.customer_query;
\ No newline at end of file
diff --git a/selling/doctype/sales_common/sales_common.py b/selling/doctype/sales_common/sales_common.py
index 78f8422..0ac8031 100644
--- a/selling/doctype/sales_common/sales_common.py
+++ b/selling/doctype/sales_common/sales_common.py
@@ -28,23 +28,6 @@
from utilities.transaction_base import TransactionBase
-
-@webnotes.whitelist()
-def get_comp_base_currency(arg=None):
- """ get default currency of company"""
- res = webnotes.conn.sql("""select default_currency from `tabCompany`
- where name = %s""", webnotes.form_dict.get('company'))
- return res and res[0][0] or None
-
-@webnotes.whitelist()
-def get_price_list_currency(arg=None):
- """ Get all currency in which price list is maintained"""
- plc = webnotes.conn.sql("select distinct ref_currency from `tabItem Price` where price_list_name = %s", webnotes.form_dict['price_list'])
- plc = [d[0] for d in plc]
- base_currency = get_comp_base_currency(webnotes.form_dict['company'])
- return plc, base_currency
-
-
class DocType(TransactionBase):
def __init__(self,d,dl):
self.doc, self.doclist = d,dl
@@ -122,67 +105,67 @@
# Get Item Details
# ===============================================================
- def get_item_details(self, args, obj):
- import json
- if not obj.doc.price_list_name:
- msgprint("Please Select Price List before selecting Items", raise_exception=True)
- item = webnotes.conn.sql("""select description, item_name, brand, item_group, stock_uom,
- default_warehouse, default_income_account, default_sales_cost_center,
- purchase_account, description_html, barcode from `tabItem`
- where name = %s and (ifnull(end_of_life,'')='' or end_of_life > now()
- or end_of_life = '0000-00-00') and (is_sales_item = 'Yes'
- or is_service_item = 'Yes')""", args['item_code'], as_dict=1)
- tax = webnotes.conn.sql("""select tax_type, tax_rate from `tabItem Tax`
- where parent = %s""", args['item_code'])
- t = {}
- for x in tax: t[x[0]] = flt(x[1])
- ret = {
- 'description': item and item[0]['description_html'] or \
- item[0]['description'],
- 'barcode': item and item[0]['barcode'] or '',
- 'item_group': item and item[0]['item_group'] or '',
- 'item_name': item and item[0]['item_name'] or '',
- 'brand': item and item[0]['brand'] or '',
- 'stock_uom': item and item[0]['stock_uom'] or '',
- 'reserved_warehouse': item and item[0]['default_warehouse'] or '',
- 'warehouse': item and item[0]['default_warehouse'] or \
- args.get('warehouse'),
- 'income_account': item and item[0]['default_income_account'] or \
- args.get('income_account'),
- 'expense_account': item and item[0]['purchase_account'] or \
- args.get('expense_account'),
- 'cost_center': item and item[0]['default_sales_cost_center'] or \
- args.get('cost_center'),
- # this is done coz if item once fetched is fetched again than its qty shld be reset to 1
- 'qty': 1.00,
- 'adj_rate': 0,
- 'amount': 0,
- 'export_amount': 0,
- 'item_tax_rate': json.dumps(t),
- 'batch_no': ''
- }
- if(obj.doc.price_list_name and item): #this is done to fetch the changed BASIC RATE and REF RATE based on PRICE LIST
- base_ref_rate = self.get_ref_rate(args['item_code'], obj.doc.price_list_name, obj.doc.price_list_currency, obj.doc.plc_conversion_rate)
- ret['ref_rate'] = flt(base_ref_rate)/flt(obj.doc.conversion_rate)
- ret['export_rate'] = flt(base_ref_rate)/flt(obj.doc.conversion_rate)
- ret['base_ref_rate'] = flt(base_ref_rate)
- ret['basic_rate'] = flt(base_ref_rate)
-
- if ret['warehouse'] or ret['reserved_warehouse']:
- av_qty = self.get_available_qty({'item_code': args['item_code'], 'warehouse': ret['warehouse'] or ret['reserved_warehouse']})
- ret.update(av_qty)
-
- # get customer code for given item from Item Customer Detail
- customer_item_code_row = webnotes.conn.sql("""\
- select ref_code from `tabItem Customer Detail`
- where parent = %s and customer_name = %s""",
- (args['item_code'], obj.doc.customer))
- if customer_item_code_row and customer_item_code_row[0][0]:
- ret['customer_item_code'] = customer_item_code_row[0][0]
-
- return ret
+ # def get_item_details(self, args, obj):
+ # import json
+ # if not obj.doc.price_list_name:
+ # msgprint("Please Select Price List before selecting Items", raise_exception=True)
+ # item = webnotes.conn.sql("""select description, item_name, brand, item_group, stock_uom,
+ # default_warehouse, default_income_account, default_sales_cost_center,
+ # purchase_account, description_html, barcode from `tabItem`
+ # where name = %s and (ifnull(end_of_life,'')='' or end_of_life > now()
+ # or end_of_life = '0000-00-00') and (is_sales_item = 'Yes'
+ # or is_service_item = 'Yes')""", args['item_code'], as_dict=1)
+ # tax = webnotes.conn.sql("""select tax_type, tax_rate from `tabItem Tax`
+ # where parent = %s""", args['item_code'])
+ # t = {}
+ # for x in tax: t[x[0]] = flt(x[1])
+ # ret = {
+ # 'description': item and item[0]['description_html'] or \
+ # item[0]['description'],
+ # 'barcode': item and item[0]['barcode'] or '',
+ # 'item_group': item and item[0]['item_group'] or '',
+ # 'item_name': item and item[0]['item_name'] or '',
+ # 'brand': item and item[0]['brand'] or '',
+ # 'stock_uom': item and item[0]['stock_uom'] or '',
+ # 'reserved_warehouse': item and item[0]['default_warehouse'] or '',
+ # 'warehouse': item and item[0]['default_warehouse'] or \
+ # args.get('warehouse'),
+ # 'income_account': item and item[0]['default_income_account'] or \
+ # args.get('income_account'),
+ # 'expense_account': item and item[0]['purchase_account'] or \
+ # args.get('expense_account'),
+ # 'cost_center': item and item[0]['default_sales_cost_center'] or \
+ # args.get('cost_center'),
+ # # this is done coz if item once fetched is fetched again than its qty shld be reset to 1
+ # 'qty': 1.00,
+ # 'adj_rate': 0,
+ # 'amount': 0,
+ # 'export_amount': 0,
+ # 'item_tax_rate': json.dumps(t),
+ # 'batch_no': ''
+ # }
+ # if(obj.doc.price_list_name and item): #this is done to fetch the changed BASIC RATE and REF RATE based on PRICE LIST
+ # base_ref_rate = self.get_ref_rate(args['item_code'], obj.doc.price_list_name, obj.doc.price_list_currency, obj.doc.plc_conversion_rate)
+ # ret['ref_rate'] = flt(base_ref_rate)/flt(obj.doc.conversion_rate)
+ # ret['export_rate'] = flt(base_ref_rate)/flt(obj.doc.conversion_rate)
+ # ret['base_ref_rate'] = flt(base_ref_rate)
+ # ret['basic_rate'] = flt(base_ref_rate)
+ #
+ # if ret['warehouse'] or ret['reserved_warehouse']:
+ # av_qty = self.get_available_qty({'item_code': args['item_code'], 'warehouse': ret['warehouse'] or ret['reserved_warehouse']})
+ # ret.update(av_qty)
+ #
+ # # get customer code for given item from Item Customer Detail
+ # customer_item_code_row = webnotes.conn.sql("""\
+ # select ref_code from `tabItem Customer Detail`
+ # where parent = %s and customer_name = %s""",
+ # (args['item_code'], obj.doc.customer))
+ # if customer_item_code_row and customer_item_code_row[0][0]:
+ # ret['customer_item_code'] = customer_item_code_row[0][0]
+ #
+ # return ret
-
+ # TODO: deprecate it
def get_item_defaults(self, args):
item = webnotes.conn.sql("""select default_warehouse, default_income_account,
default_sales_cost_center, purchase_account from `tabItem` where name = %s
@@ -200,97 +183,78 @@
return ret
- def get_available_qty(self,args):
- tot_avail_qty = webnotes.conn.sql("select projected_qty, actual_qty from `tabBin` where item_code = '%s' and warehouse = '%s'" % (args['item_code'], args['warehouse']), as_dict=1)
- ret = {
- 'projected_qty' : tot_avail_qty and flt(tot_avail_qty[0]['projected_qty']) or 0,
- 'actual_qty' : tot_avail_qty and flt(tot_avail_qty[0]['actual_qty']) or 0
- }
- return ret
+ # def get_available_qty(self,args):
+# tot_avail_qty = webnotes.conn.sql("select projected_qty, actual_qty from `tabBin` where item_code = '%s' and warehouse = '%s'" % (args['item_code'], args['warehouse']), as_dict=1)
+# ret = {
+# 'projected_qty' : tot_avail_qty and flt(tot_avail_qty[0]['projected_qty']) or 0,
+# 'actual_qty' : tot_avail_qty and flt(tot_avail_qty[0]['actual_qty']) or 0
+# }
+# return ret
# ***************** Get Ref rate as entered in Item Master ********************
- def get_ref_rate(self, item_code, price_list_name, price_list_currency, plc_conv_rate):
- ref_rate = webnotes.conn.sql("select ref_rate from `tabItem Price` where parent = %s and price_list_name = %s and ref_currency = %s and selling=1",
- (item_code, price_list_name, price_list_currency))
- base_ref_rate = ref_rate and flt(ref_rate[0][0]) * flt(plc_conv_rate) or 0
- return base_ref_rate
+ # def get_ref_rate(self, item_code, price_list_name, price_list_currency, plc_conv_rate):
+ # ref_rate = webnotes.conn.sql("select ref_rate from `tabItem Price` where parent = %s and price_list_name = %s and ref_currency = %s and selling=1",
+ # (item_code, price_list_name, price_list_currency))
+ # base_ref_rate = ref_rate and flt(ref_rate[0][0]) * flt(plc_conv_rate) or 0
+ # return base_ref_rate
- def get_barcode_details(self, barcode):
- item = webnotes.conn.sql("select name, end_of_life, is_sales_item, is_service_item \
- from `tabItem` where barcode = %s", barcode, as_dict=1)
- ret = {}
- if not item:
- msgprint("""No item found for this barcode: %s.
- May be barcode not updated in item master. Please check""" % barcode)
- elif item[0]['end_of_life'] and getdate(cstr(item[0]['end_of_life'])) < nowdate():
- msgprint("Item: %s has been expired. Please check 'End of Life' field in item master" % item[0]['name'])
- elif item[0]['is_sales_item'] == 'No' and item[0]['is_service_item'] == 'No':
- msgprint("Item: %s is not a sales or service item" % item[0]['name'])
- elif len(item) > 1:
- msgprint("There are multiple item for this barcode. \nPlease select item code manually")
- else:
- ret = {'item_code': item and item[0]['name'] or ''}
-
- return ret
-
-
# ****** Re-cancellculates Basic Rate & amount based on Price List Selected ******
- def get_adj_percent(self, obj):
- for d in getlist(obj.doclist, obj.fname):
- base_ref_rate = self.get_ref_rate(d.item_code, obj.doc.price_list_name, obj.doc.price_list_currency, obj.doc.plc_conversion_rate)
- d.adj_rate = 0
- d.ref_rate = flt(base_ref_rate)/flt(obj.doc.conversion_rate)
- d.basic_rate = flt(base_ref_rate)
- d.base_ref_rate = flt(base_ref_rate)
- d.export_rate = flt(base_ref_rate)/flt(obj.doc.conversion_rate)
- d.amount = flt(d.qty)*flt(base_ref_rate)
- d.export_amount = flt(d.qty)*flt(base_ref_rate)/flt(obj.doc.conversion_rate)
+ # def get_adj_percent(self, obj):
+ # for d in getlist(obj.doclist, obj.fname):
+ # base_ref_rate = self.get_ref_rate(d.item_code, obj.doc.price_list_name, obj.doc.price_list_currency, obj.doc.plc_conversion_rate)
+ # d.adj_rate = 0
+ # d.ref_rate = flt(base_ref_rate)/flt(obj.doc.conversion_rate)
+ # d.basic_rate = flt(base_ref_rate)
+ # d.base_ref_rate = flt(base_ref_rate)
+ # d.export_rate = flt(base_ref_rate)/flt(obj.doc.conversion_rate)
+ # d.amount = flt(d.qty)*flt(base_ref_rate)
+ # d.export_amount = flt(d.qty)*flt(base_ref_rate)/flt(obj.doc.conversion_rate)
- # Load Default Taxes
- # ====================
- def load_default_taxes(self, obj):
- if cstr(obj.doc.charge):
- return self.get_other_charges(obj)
- else:
- return self.get_other_charges(obj, 1)
-
-
- # Get other charges from Master
- # =================================================================================
- def get_other_charges(self,obj, default=0):
- obj.doclist = obj.doc.clear_table(obj.doclist, 'other_charges')
- if not getlist(obj.doclist, 'other_charges'):
- if default: add_cond = 'ifnull(t2.is_default,0) = 1'
- else: add_cond = 't1.parent = "'+cstr(obj.doc.charge)+'"'
- idx = 0
- other_charge = webnotes.conn.sql("""\
- select t1.*
- from
- `tabSales Taxes and Charges` t1,
- `tabSales Taxes and Charges Master` t2
- where
- t1.parent = t2.name and
- t2.company = '%s' and
- %s
- order by t1.idx""" % (obj.doc.company, add_cond), as_dict=1)
- from webnotes.model import default_fields
- for other in other_charge:
- # remove default fields like parent, parenttype etc.
- # from query results
- for field in default_fields:
- if field in other: del other[field]
-
- d = addchild(obj.doc, 'other_charges', 'Sales Taxes and Charges',
- obj.doclist)
- d.fields.update(other)
- d.rate = flt(d.rate)
- d.tax_amount = flt(d.tax_rate)
- d.included_in_print_rate = cint(d.included_in_print_rate)
- d.idx = idx
- idx += 1
- return obj.doclist
+ # # Load Default Taxes
+ # # ====================
+ # def load_default_taxes(self, obj):
+ # if cstr(obj.doc.charge):
+ # return self.get_other_charges(obj)
+ # else:
+ # return self.get_other_charges(obj, 1)
+ #
+ #
+ # # Get other charges from Master
+ # # =================================================================================
+ # def get_other_charges(self,obj, default=0):
+ # obj.doclist = obj.doc.clear_table(obj.doclist, 'other_charges')
+ # if not getlist(obj.doclist, 'other_charges'):
+ # if default: add_cond = 'ifnull(t2.is_default,0) = 1'
+ # else: add_cond = 't1.parent = "'+cstr(obj.doc.charge)+'"'
+ # idx = 0
+ # other_charge = webnotes.conn.sql("""\
+ # select t1.*
+ # from
+ # `tabSales Taxes and Charges` t1,
+ # `tabSales Taxes and Charges Master` t2
+ # where
+ # t1.parent = t2.name and
+ # t2.company = '%s' and
+ # %s
+ # order by t1.idx""" % (obj.doc.company, add_cond), as_dict=1)
+ # from webnotes.model import default_fields
+ # for other in other_charge:
+ # # remove default fields like parent, parenttype etc.
+ # # from query results
+ # for field in default_fields:
+ # if field in other: del other[field]
+ #
+ # d = addchild(obj.doc, 'other_charges', 'Sales Taxes and Charges',
+ # obj.doclist)
+ # d.fields.update(other)
+ # d.rate = flt(d.rate)
+ # d.tax_amount = flt(d.tax_rate)
+ # d.included_in_print_rate = cint(d.included_in_print_rate)
+ # d.idx = idx
+ # idx += 1
+ # return obj.doclist
# Get TERMS AND CONDITIONS
# =======================================================================================
@@ -327,23 +291,6 @@
}
return ret
- # Get Commission rate
- # =======================================================================
- def get_comm_rate(self, sales_partner, obj):
-
- comm_rate = webnotes.conn.sql("select commission_rate from `tabSales Partner` where name = '%s' and docstatus != 2" %(sales_partner), as_dict=1)
- if comm_rate:
- total_comm = flt(comm_rate[0]['commission_rate']) * flt(obj.doc.net_total) / 100
- ret = {
- 'commission_rate' : comm_rate and flt(comm_rate[0]['commission_rate']) or 0,
- 'total_commission' : flt(total_comm)
- }
- return ret
- else:
- msgprint("Business Associate : %s does not exist in the system." % (sales_partner))
- raise Exception
-
-
# To verify whether rate entered in details table does not exceed max discount %
# =======================================================================================
def validate_max_discount(self,obj, detail_table):
@@ -352,16 +299,6 @@
if discount and discount[0]['max_discount'] and (flt(d.adj_rate)>flt(discount[0]['max_discount'])):
msgprint("You cannot give more than " + cstr(discount[0]['max_discount']) + " % discount on Item Code : "+cstr(d.item_code))
raise Exception
-
-
- # Get sum of allocated % of sales person (it should be 100%)
- # ========================================================================
- # it indicates % contribution of sales person in sales
- def get_allocated_sum(self,obj):
- sales_team_list = obj.doclist.get({"parentfield": "sales_team"})
- total_allocation = sum([flt(d.allocated_percentage) for d in sales_team_list])
- if sales_team_list and total_allocation != 100.0:
- msgprint("Total Allocated % of Sales Persons should be 100%", raise_exception=True)
# Check Conversion Rate (i.e. it will not allow conversion rate to be 1 for Currency other than default currency set in Global Defaults)
# ===========================================================================
diff --git a/selling/doctype/sales_order/sales_order.js b/selling/doctype/sales_order/sales_order.js
index b792754..79f20bc 100644
--- a/selling/doctype/sales_order/sales_order.js
+++ b/selling/doctype/sales_order/sales_order.js
@@ -28,7 +28,7 @@
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.transaction_date) set_multiple(cdt,cdn,{transaction_date:get_today()});
@@ -42,25 +42,10 @@
}
}
-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.clear_custom_buttons();
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);
if(doc.docstatus==1) {
diff --git a/selling/doctype/sales_order/sales_order.py b/selling/doctype/sales_order/sales_order.py
index c8db1f9..4b5408d 100644
--- a/selling/doctype/sales_order/sales_order.py
+++ b/selling/doctype/sales_order/sales_order.py
@@ -83,12 +83,6 @@
def get_rate(self,arg):
return get_obj('Sales Common').get_rate(arg)
- def load_default_taxes(self):
- self.doclist = get_obj('Sales Common').load_default_taxes(self)
-
- def get_other_charges(self):
- self.doclist = get_obj('Sales Common').get_other_charges(self)
-
def get_tc_details(self):
return get_obj('Sales Common').get_tc_details(self)
@@ -194,6 +188,8 @@
and current Sales Order""" % (self.doc.order_type, d.prevdoc_docname))
def validate_order_type(self):
+ super(DocType, self).validate_order_type()
+
#validate delivery date
if self.doc.order_type == 'Sales' and not self.doc.delivery_date:
msgprint("Please enter 'Expected Delivery Date'")
@@ -226,7 +222,6 @@
sales_com_obj.check_conversion_rate(self)
sales_com_obj.validate_max_discount(self,'sales_order_details')
- sales_com_obj.get_allocated_sum(self)
self.doclist = sales_com_obj.make_packing_list(self,'sales_order_details')
if not self.doc.status:
diff --git a/selling/doctype/sales_order/sales_order.txt b/selling/doctype/sales_order/sales_order.txt
index ba0b1de..fdf60a2 100644
--- a/selling/doctype/sales_order/sales_order.txt
+++ b/selling/doctype/sales_order/sales_order.txt
@@ -1,8 +1,8 @@
[
{
- "creation": "2013-03-07 14:48:34",
+ "creation": "2013-05-21 16:16:41",
"docstatus": 0,
- "modified": "2013-01-29 17:14:58",
+ "modified": "2013-05-21 18:30:14",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -230,7 +230,8 @@
"oldfieldname": "sales_order_details",
"oldfieldtype": "Table",
"options": "Sales Order Item",
- "print_hide": 0
+ "print_hide": 0,
+ "reqd": 1
},
{
"doctype": "DocField",
@@ -251,13 +252,21 @@
"oldfieldname": "net_total",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
- "print_hide": 0,
+ "print_hide": 1,
"read_only": 1,
"reqd": 0,
"width": "150px"
},
{
"doctype": "DocField",
+ "fieldname": "net_total_export",
+ "fieldtype": "Currency",
+ "label": "Net Total (Export)",
+ "options": "currency",
+ "read_only": 1
+ },
+ {
+ "doctype": "DocField",
"fieldname": "recalculate_values",
"fieldtype": "Button",
"label": "Re-Calculate Values",
@@ -426,7 +435,7 @@
"doctype": "DocField",
"fieldname": "other_charges_total",
"fieldtype": "Currency",
- "label": "Taxes and Charges Total*",
+ "label": "Taxes and Charges Total",
"oldfieldname": "other_charges_total",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
@@ -436,6 +445,15 @@
},
{
"doctype": "DocField",
+ "fieldname": "other_charges_total_export",
+ "fieldtype": "Currency",
+ "label": "Taxes and Charges Total (Export)",
+ "options": "company",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "doctype": "DocField",
"fieldname": "other_charges_calculation",
"fieldtype": "HTML",
"label": "Taxes and Charges Calculation",
@@ -955,7 +973,6 @@
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
- "match": "",
"permlevel": 1,
"report": 0,
"role": "Sales Manager",
@@ -978,7 +995,6 @@
"cancel": 1,
"create": 1,
"doctype": "DocPerm",
- "match": "",
"permlevel": 0,
"report": 1,
"role": "Sales User",
@@ -990,7 +1006,6 @@
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
- "match": "",
"permlevel": 1,
"report": 0,
"role": "Sales User",
@@ -1013,7 +1028,6 @@
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
- "match": "",
"permlevel": 1,
"role": "Maintenance Manager",
"submit": 0
@@ -1034,7 +1048,6 @@
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
- "match": "",
"permlevel": 1,
"role": "Maintenance User",
"submit": 0
diff --git a/selling/doctype/sales_order_item/sales_order_item.txt b/selling/doctype/sales_order_item/sales_order_item.txt
index c65ac0d..7276fc3 100644
--- a/selling/doctype/sales_order_item/sales_order_item.txt
+++ b/selling/doctype/sales_order_item/sales_order_item.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-03-07 11:42:58",
"docstatus": 0,
- "modified": "2013-05-22 12:09:03",
+ "modified": "2013-05-22 12:10:03",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -113,7 +113,7 @@
"options": "currency",
"print_hide": 1,
"print_width": "70px",
- "read_only": 0,
+ "read_only": 1,
"reqd": 0,
"width": "70px"
},
@@ -183,7 +183,7 @@
"options": "Company:company:default_currency",
"print_hide": 1,
"print_width": "100px",
- "read_only": 0,
+ "read_only": 1,
"reqd": 0,
"width": "100px"
},
diff --git a/selling/doctype/sales_team/sales_team.txt b/selling/doctype/sales_team/sales_team.txt
index add466c..29a951e 100644
--- a/selling/doctype/sales_team/sales_team.txt
+++ b/selling/doctype/sales_team/sales_team.txt
@@ -1,8 +1,8 @@
[
{
- "creation": "2013-02-22 01:27:53",
+ "creation": "2013-04-19 13:30:51",
"docstatus": 0,
- "modified": "2013-03-07 07:03:31",
+ "modified": "2013-05-21 17:04:45",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -42,6 +42,7 @@
"doctype": "DocField",
"fieldname": "sales_designation",
"fieldtype": "Data",
+ "hidden": 0,
"label": "Designation",
"oldfieldname": "sales_designation",
"oldfieldtype": "Data",
@@ -63,7 +64,7 @@
"doctype": "DocField",
"fieldname": "allocated_percentage",
"fieldtype": "Float",
- "label": "Allocated (%)",
+ "label": "Contribution (%)",
"oldfieldname": "allocated_percentage",
"oldfieldtype": "Currency",
"print_width": "100px",
@@ -74,11 +75,12 @@
"doctype": "DocField",
"fieldname": "allocated_amount",
"fieldtype": "Currency",
- "label": "Allocated Amount",
+ "label": "Contribution to Net Total",
"oldfieldname": "allocated_amount",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"print_width": "120px",
+ "read_only": 1,
"reqd": 0,
"width": "120px"
},
diff --git a/selling/utils.py b/selling/utils.py
index 21e94f7..5e986ee 100644
--- a/selling/utils.py
+++ b/selling/utils.py
@@ -16,6 +16,9 @@
from __future__ import unicode_literals
import webnotes
+from webnotes import msgprint, _
+from webnotes.utils import flt, cint, comma_and
+import json
def get_customer_list(doctype, txt, searchfield, start, page_len, filters):
if webnotes.conn.get_default("cust_master_name") == "Customer Name":
@@ -29,4 +32,147 @@
case when customer_name like %s then 0 else 1 end,
name, customer_name limit %s, %s""" %
(", ".join(fields), searchfield, "%s", "%s", "%s", "%s", "%s", "%s"),
- ("%%%s%%" % txt, "%%%s%%" % txt, "%%%s%%" % txt, "%%%s%%" % txt, start, page_len))
\ No newline at end of file
+ ("%%%s%%" % txt, "%%%s%%" % txt, "%%%s%%" % txt, "%%%s%%" % txt, start, page_len))
+
+@webnotes.whitelist()
+def get_item_details(args):
+ """
+ args = {
+ "item_code": "",
+ "warehouse": None,
+ "customer": "",
+ "conversion_rate": 1.0,
+ "price_list_name": None,
+ "price_list_currency": None,
+ "plc_conversion_rate": 1.0
+ }
+ """
+ if isinstance(args, basestring):
+ args = json.loads(args)
+ args = webnotes._dict(args)
+
+ if args.barcode:
+ args.item_code = _get_item_code(args.barcode)
+
+ item_bean = webnotes.bean("Item", args.item_code)
+
+ _validate_item_details(args, item_bean.doc)
+
+ out = _get_basic_details(args, item_bean)
+
+ meta = webnotes.get_doctype(args.doctype)
+ if meta.get_field("currency"):
+ out.base_ref_rate = out.basic_rate = out.ref_rate = out.export_rate = 0.0
+
+ if args.price_list_name and args.price_list_currency:
+ out.update(_get_price_list_rate(args, item_bean, meta))
+
+ if out.warehouse or out.reserved_warehouse:
+ out.update(_get_available_qty(args, out.warehouse or out.reserved_warehouse))
+
+ out.customer_item_code = _get_customer_item_code(args, item_bean)
+
+ if cint(args.is_pos):
+ pos_settings = get_pos_settings(args.company)
+ out.update(apply_pos_settings(pos_settings, out))
+
+ return out
+
+def _get_item_code(barcode):
+ item_code = webnotes.conn.sql_list("""select name from `tabItem` where barcode=%s""", barcode)
+
+ if not item_code:
+ msgprint(_("No Item found with Barcode") + ": %s" % barcode, raise_exception=True)
+
+ elif len(item_code) > 1:
+ msgprint(_("Items") + " %s " % comma_and(item_code) +
+ _("have the same Barcode") + " %s" % barcode, raise_exception=True)
+
+ return item_code[0]
+
+def _validate_item_details(args, item):
+ from utilities.transaction_base import validate_item_fetch
+ validate_item_fetch(args, item)
+
+ # validate if sales item or service item
+ if args.order_type == "Maintenance":
+ if item.is_service_item != "Yes":
+ msgprint(_("Item") + (" %s: " % item.name) +
+ _("not a service item.") +
+ _("Please select a service item or change the order type to Sales."),
+ raise_exception=True)
+
+ elif item.is_sales_item != "Yes":
+ msgprint(_("Item") + (" %s: " % item.name) + _("not a sales item"),
+ raise_exception=True)
+
+def _get_basic_details(args, item_bean):
+ item = item_bean.doc
+ out = webnotes._dict({
+ "description": item.description_html or item.description,
+ "reserved_warehouse": item.default_warehouse,
+ "warehouse": item.default_warehouse or args.warehouse,
+ "income_account": item.default_income_account or args.income_account,
+ "expense_account": item.purchase_account or args.expense_account,
+ "cost_center": item.default_sales_cost_center or args.cost_center,
+ "qty": 1.0,
+ "adj_rate": 0.0,
+ "export_amount": 0.0,
+ "amount": 0.0,
+ "batch_no": None,
+ "item_tax_rate": json.dumps(dict(([d.tax_type, d.tax_rate] for d in
+ item_bean.doclist.get({"parentfield": "item_tax"})))),
+ })
+
+ for fieldname in ("item_name", "item_group", "barcode", "brand", "stock_uom"):
+ out[fieldname] = item.fields.get(fieldname)
+
+ return out
+
+def _get_price_list_rate(args, item_bean, meta=None):
+ base_ref_rate = item_bean.doclist.get({
+ "parentfield": "ref_rate_details",
+ "price_list_name": args.price_list_name,
+ "price_list_currency": args.price_list_currency,
+ "selling": 1})
+
+ if not base_ref_rate:
+ return {}
+
+ # found price list rate - now we can validate
+ from utilities.transaction_base import validate_currency
+ validate_currency(args, item_bean.doc, meta)
+
+ return {"base_ref_rate": flt(base_ref_rate[0].ref_rate / args.plc_conversion_rate)}
+
+def _get_available_qty(args, warehouse):
+ return webnotes.conn.get_value("Bin", {"item_code": args.item_code, "warehouse": warehouse},
+ ["projected_qty", "actual_qty"], as_dict=True) or {}
+
+def _get_customer_item_code(args, item_bean):
+ customer_item_code = item_bean.doclist.get({"parentfield": "item_customer_details",
+ "customer_name": args.customer})
+
+ return customer_item_code and customer_item_code[0].ref_code or None
+
+def get_pos_settings(company):
+ pos_settings = webnotes.conn.sql("""select * from `tabPOS Setting` where user = %s
+ and company = %s""", (webnotes.session['user'], company), as_dict=1)
+
+ if not pos_settings:
+ pos_settings = webnotes.conn.sql("""select * from `tabPOS Setting`
+ where ifnull(user,'') = '' and company = %s""", company, as_dict=1)
+
+ return pos_settings and pos_settings[0] or None
+
+def apply_pos_settings(pos_settings, opts):
+ out = {}
+
+ for fieldname in ("income_account", "cost_center", "warehouse", "expense_account"):
+ if not opts.get(fieldname):
+ out[fieldname] = pos_settings.get(fieldname)
+
+ if out.get("warehouse"):
+ out["actual_qty"] = _get_available_qty(opts, out.get("warehouse")).get("actual_qty")
+
+ return out
diff --git a/setup/utils.py b/setup/utils.py
index 1a86921..33fa3e2 100644
--- a/setup/utils.py
+++ b/setup/utils.py
@@ -46,4 +46,4 @@
if result and len(result)==1:
return {"price_list_currency": result[0][0]}
else:
- return {}
\ No newline at end of file
+ return {}
diff --git a/startup/boot.py b/startup/boot.py
index 9ed20ff..b202d17 100644
--- a/startup/boot.py
+++ b/startup/boot.py
@@ -36,9 +36,8 @@
for key in ['max_users', 'expires_on', 'max_space', 'status', 'developer_mode']:
if hasattr(conf, key): bootinfo[key] = getattr(conf, key)
- bootinfo['docs'] += webnotes.conn.sql("""select name, default_currency, cost_center,
- cost_center as 'cost_center_other_charges' from `tabCompany`""",
- as_dict=1, update={"doctype":":Company"})
+ bootinfo['docs'] += webnotes.conn.sql("""select name, default_currency, cost_center
+ from `tabCompany`""", as_dict=1, update={"doctype":":Company"})
def get_letter_heads():
"""load letter heads with startup"""
diff --git a/stock/doctype/delivery_note/delivery_note.js b/stock/doctype/delivery_note/delivery_note.js
index 0a31dfe..df5e761 100644
--- a/stock/doctype/delivery_note/delivery_note.js
+++ b/stock/doctype/delivery_note/delivery_note.js
@@ -43,15 +43,6 @@
}
}
-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
// ================================================================================================
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
diff --git a/stock/doctype/delivery_note/delivery_note.py b/stock/doctype/delivery_note/delivery_note.py
index 6ffd960..363fb39 100644
--- a/stock/doctype/delivery_note/delivery_note.py
+++ b/stock/doctype/delivery_note/delivery_note.py
@@ -114,16 +114,6 @@
def get_rate(self,arg):
return get_obj('Sales Common').get_rate(arg)
-
- def load_default_taxes(self):
- self.doclist = get_obj('Sales Common').load_default_taxes(self)
-
-
- def get_other_charges(self):
- """Pull details from Sales Taxes and Charges Master"""
- self.doclist = get_obj('Sales Common').get_other_charges(self)
-
-
def so_required(self):
"""check in manage account if sales order required or not"""
if webnotes.conn.get_value('Global Defaults', 'Global Defaults', 'so_required') == 'Yes':
@@ -152,7 +142,6 @@
self.validate_warehouse()
sales_com_obj.validate_max_discount(self, 'delivery_note_details')
- sales_com_obj.get_allocated_sum(self)
sales_com_obj.check_conversion_rate(self)
# Set actual qty for each item in selected warehouse
@@ -419,4 +408,4 @@
if gl_entries:
from accounts.general_ledger import make_gl_entries
- make_gl_entries(gl_entries, cancel=(self.doc.docstatus == 2))
\ No newline at end of file
+ make_gl_entries(gl_entries, cancel=(self.doc.docstatus == 2))
diff --git a/stock/doctype/delivery_note/delivery_note.txt b/stock/doctype/delivery_note/delivery_note.txt
index 36c2789..72c6f47 100644
--- a/stock/doctype/delivery_note/delivery_note.txt
+++ b/stock/doctype/delivery_note/delivery_note.txt
@@ -1,8 +1,8 @@
[
{
- "creation": "2013-04-02 10:50:50",
+ "creation": "2013-05-21 16:16:31",
"docstatus": 0,
- "modified": "2013-02-02 19:18:38",
+ "modified": "2013-05-21 18:30:32",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -223,7 +223,8 @@
"oldfieldtype": "Table",
"options": "Delivery Note Item",
"print_hide": 0,
- "read_only": 0
+ "read_only": 0,
+ "reqd": 1
},
{
"doctype": "DocField",
@@ -255,7 +256,7 @@
"oldfieldname": "net_total",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
- "print_hide": 0,
+ "print_hide": 1,
"print_width": "150px",
"read_only": 1,
"reqd": 0,
@@ -263,6 +264,14 @@
},
{
"doctype": "DocField",
+ "fieldname": "net_total_export",
+ "fieldtype": "Currency",
+ "label": "Net Total (Export)",
+ "options": "currency",
+ "read_only": 1
+ },
+ {
+ "doctype": "DocField",
"fieldname": "recalculate_values",
"fieldtype": "Button",
"label": "Re-Calculate Values",
@@ -437,6 +446,15 @@
},
{
"doctype": "DocField",
+ "fieldname": "other_charges_total_export",
+ "fieldtype": "Currency",
+ "label": "Taxes and Charges Total (Export)",
+ "options": "company",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "doctype": "DocField",
"fieldname": "calculate_charges",
"fieldtype": "Button",
"label": "Calculate Charges",
@@ -1136,7 +1154,6 @@
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
- "match": "",
"permlevel": 1,
"report": 0,
"role": "Material User",
@@ -1159,7 +1176,6 @@
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
- "match": "",
"permlevel": 1,
"report": 0,
"role": "Material Manager",
@@ -1171,7 +1187,6 @@
"cancel": 1,
"create": 1,
"doctype": "DocPerm",
- "match": "",
"permlevel": 0,
"report": 1,
"role": "Sales User",
@@ -1183,7 +1198,6 @@
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
- "match": "",
"permlevel": 1,
"report": 0,
"role": "Sales User",
@@ -1205,7 +1219,6 @@
"cancel": 0,
"create": 0,
"doctype": "DocPerm",
- "match": "",
"permlevel": 1,
"role": "Accounts User",
"submit": 0
diff --git a/stock/doctype/delivery_note_item/delivery_note_item.txt b/stock/doctype/delivery_note_item/delivery_note_item.txt
index f90ba69..a8eda20 100644
--- a/stock/doctype/delivery_note_item/delivery_note_item.txt
+++ b/stock/doctype/delivery_note_item/delivery_note_item.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-04-22 13:15:44",
"docstatus": 0,
- "modified": "2013-05-22 12:05:32",
+ "modified": "2013-05-22 12:15:32",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -120,7 +120,7 @@
"options": "currency",
"print_hide": 1,
"print_width": "100px",
- "read_only": 0,
+ "read_only": 1,
"reqd": 0,
"width": "100px"
},
@@ -189,7 +189,7 @@
"options": "Company:company:default_currency",
"print_hide": 1,
"print_width": "150px",
- "read_only": 0,
+ "read_only": 1,
"reqd": 0,
"width": "150px"
},
diff --git a/stock/doctype/item/item.txt b/stock/doctype/item/item.txt
index 9e0a2fb..611ae5e 100644
--- a/stock/doctype/item/item.txt
+++ b/stock/doctype/item/item.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-05-03 10:45:46",
"docstatus": 0,
- "modified": "2013-05-22 15:48:27",
+ "modified": "2013-05-22 15:49:27",
"modified_by": "Administrator",
"owner": "Administrator"
},
diff --git a/stock/doctype/material_request/material_request.js b/stock/doctype/material_request/material_request.js
index 21bc141..3d4eed4 100644
--- a/stock/doctype/material_request/material_request.js
+++ b/stock/doctype/material_request/material_request.js
@@ -57,14 +57,6 @@
$.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) {
// second call
if(doc.__islocal){
@@ -79,12 +71,6 @@
}
};
-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) {
var d = locals[cdt][cdn];
if (flt(d.qty) < flt(d.min_order_qty))
diff --git a/stock/doctype/material_request/material_request.py b/stock/doctype/material_request/material_request.py
index 8a899b3..9f19a5b 100644
--- a/stock/doctype/material_request/material_request.py
+++ b/stock/doctype/material_request/material_request.py
@@ -17,9 +17,6 @@
self.tname = 'Material Request Item'
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
def get_bin_details(self, arg = ''):
return get_obj(dt='Purchase Common').get_bin_details(arg)
@@ -30,22 +27,12 @@
self.check_if_already_pulled()
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']]")
- self.get_item_defaults()
else:
msgprint("Please select Sales Order whose details need to pull")
def check_if_already_pulled(self):
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
# ----------------------------
def validate_qty_against_so(self):
diff --git a/stock/doctype/purchase_receipt/purchase_receipt.js b/stock/doctype/purchase_receipt/purchase_receipt.js
index 82e494c..20740e7 100644
--- a/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -38,20 +38,6 @@
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});
diff --git a/stock/doctype/stock_entry/test_stock_entry.py b/stock/doctype/stock_entry/test_stock_entry.py
index c3ce2d7..a9281cd 100644
--- a/stock/doctype/stock_entry/test_stock_entry.py
+++ b/stock/doctype/stock_entry/test_stock_entry.py
@@ -450,6 +450,7 @@
for d in pi.doclist.get({"parentfield": "entries"}):
d.expense_head = "_Test Account Cost for Goods Sold - _TC"
d.cost_center = "_Test Cost Center - _TC"
+
for d in pi.doclist.get({"parentfield": "purchase_tax_details"}):
d.cost_center = "_Test Cost Center - _TC"
diff --git a/utilities/transaction_base.py b/utilities/transaction_base.py
index 5d7d1a8..d4c61f5 100644
--- a/utilities/transaction_base.py
+++ b/utilities/transaction_base.py
@@ -16,6 +16,7 @@
from __future__ import unicode_literals
import webnotes
+from webnotes import msgprint, _
from webnotes.utils import load_json, cstr, flt, now_datetime
from webnotes.model.doc import addchild
@@ -268,4 +269,45 @@
def validate_posting_time(self):
if not self.doc.posting_time:
self.doc.posting_time = now_datetime().strftime('%H:%M:%S')
-
\ No newline at end of file
+
+def validate_conversion_rate(currency, conversion_rate, conversion_rate_label, company):
+ """common validation for currency and price list currency"""
+ if conversion_rate == 0:
+ msgprint(conversion_rate_label + _(' cannot be 0'), raise_exception=True)
+
+ company_currency = webnotes.conn.get_value("Company", company, "default_currency")
+
+ # parenthesis for 'OR' are necessary as we want it to evaluate as
+ # mandatory valid condition and (1st optional valid condition
+ # or 2nd optional valid condition)
+ valid_conversion_rate = (conversion_rate and
+ ((currency == company_currency and conversion_rate == 1.00)
+ or (currency != company_currency and conversion_rate != 1.00)))
+
+ if not valid_conversion_rate:
+ msgprint(_('Please enter valid ') + conversion_rate_label + (': ')
+ + ("1 %s = [?] %s" % (currency, company_currency)),
+ raise_exception=True)
+
+def validate_item_fetch(args, item):
+ from stock.utils import validate_end_of_life
+ validate_end_of_life(item.name, item.end_of_life)
+
+ # validate company
+ if not args.company:
+ msgprint(_("Please specify Company"), raise_exception=True)
+
+def validate_currency(args, item, meta=None):
+ if not meta:
+ meta = webnotes.get_doctype(args.doctype)
+
+ # validate conversion rate
+ if meta.get_field("currency"):
+ validate_conversion_rate(args.currency, args.conversion_rate,
+ meta.get_label("conversion_rate"), args.company)
+
+ # validate price list conversion rate
+ if meta.get_field("price_list_currency") and args.price_list_name and \
+ args.price_list_currency:
+ validate_conversion_rate(args.price_list_currency, args.plc_conversion_rate,
+ meta.get_label("plc_conversion_rate"), args.company)
\ No newline at end of file