| // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors |
| // License: GNU General Public License v3. See license.txt |
| |
| // Preset |
| // ------ |
| // cur_frm.cscript.tname - Details table name |
| // cur_frm.cscript.fname - Details fieldname |
| // cur_frm.cscript.other_fname - fieldname |
| // cur_frm.cscript.sales_team_fname - Sales Team fieldname |
| |
| wn.provide("erpnext.selling"); |
| wn.require("assets/erpnext/js/transaction.js"); |
| {% include "public/js/controllers/accounts.js" %} |
| |
| erpnext.selling.SellingController = erpnext.TransactionController.extend({ |
| onload: function() { |
| this._super(); |
| this.toggle_rounded_total(); |
| this.setup_queries(); |
| this.toggle_editable_price_list_rate(); |
| }, |
| |
| setup_queries: function() { |
| var me = this; |
| |
| this.frm.add_fetch("sales_partner", "commission_rate", "commission_rate"); |
| |
| $.each([["customer_address", "customer_filter"], |
| ["shipping_address_name", "customer_filter"], |
| ["contact_person", "customer_filter"], |
| ["customer", "customer"], |
| ["lead", "lead"]], |
| function(i, opts) { |
| if(me.frm.fields_dict[opts[0]]) |
| me.frm.set_query(opts[0], erpnext.queries[opts[1]]); |
| }); |
| |
| if(this.frm.fields_dict.charge) { |
| this.frm.set_query("charge", function() { |
| return { |
| filters: [ |
| ['Sales Taxes and Charges Master', 'company', '=', me.frm.doc.company], |
| ['Sales Taxes and Charges Master', 'docstatus', '!=', 2] |
| ] |
| } |
| }); |
| } |
| |
| if(this.frm.fields_dict.selling_price_list) { |
| this.frm.set_query("selling_price_list", function() { |
| return { filters: { buying_or_selling: "Selling" } }; |
| }); |
| } |
| |
| if(!this.fname) { |
| return; |
| } |
| |
| if(this.frm.fields_dict[this.fname].grid.get_field('item_code')) { |
| this.frm.set_query("item_code", this.fname, function() { |
| return { |
| query: "erpnext.controllers.queries.item_query", |
| filters: (me.frm.doc.order_type === "Maintenance" ? |
| {'is_service_item': 'Yes'}: |
| {'is_sales_item': 'Yes' }) |
| } |
| }); |
| } |
| |
| if(this.frm.fields_dict[this.fname].grid.get_field('batch_no')) { |
| this.frm.set_query("batch_no", this.fname, function(doc, cdt, cdn) { |
| var item = wn.model.get_doc(cdt, cdn); |
| if(!item.item_code) { |
| wn.throw(wn._("Please enter Item Code to get batch no")); |
| } else { |
| filters = { |
| 'item_code': item.item_code, |
| 'posting_date': me.frm.doc.posting_date, |
| } |
| if(item.warehouse) filters["warehouse"] = item.warehouse |
| |
| return { |
| query : "controllers.queries.get_batch_no", |
| filters: filters |
| } |
| } |
| }); |
| } |
| |
| if(this.frm.fields_dict.sales_team && this.frm.fields_dict.sales_team.grid.get_field("sales_person")) { |
| this.frm.set_query("sales_person", "sales_team", erpnext.queries.not_a_group_filter); |
| } |
| }, |
| |
| refresh: function() { |
| this._super(); |
| this.frm.toggle_display("customer_name", |
| (this.frm.doc.customer_name && this.frm.doc.customer_name!==this.frm.doc.customer)); |
| if(this.frm.fields_dict.packing_details) { |
| var packing_list_exists = this.frm.get_doclist({parentfield: "packing_details"}).length; |
| this.frm.toggle_display("packing_list", packing_list_exists ? true : false); |
| } |
| }, |
| |
| customer: function() { |
| var me = this; |
| 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 selling_price_list = this.frm.doc.selling_price_list; |
| return this.frm.call({ |
| doc: this.frm.doc, |
| method: "set_customer_defaults", |
| freeze: true, |
| callback: function(r) { |
| if(!r.exc) { |
| (me.frm.doc.selling_price_list !== selling_price_list) ? |
| me.selling_price_list() : |
| me.price_list_currency(); |
| } |
| } |
| }); |
| } |
| } |
| }, |
| |
| customer_address: function() { |
| var me = this; |
| if(this.frm.doc.customer) { |
| return this.frm.call({ |
| doc: this.frm.doc, |
| args: { |
| customer: this.frm.doc.customer, |
| address: this.frm.doc.customer_address, |
| contact: this.frm.doc.contact_person |
| }, |
| method: "set_customer_address", |
| freeze: true, |
| }); |
| } |
| }, |
| |
| contact_person: function() { |
| this.customer_address(); |
| }, |
| |
| 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 || item.serial_no) { |
| if(!this.validate_company_and_party("customer")) { |
| cur_frm.fields_dict[me.frm.cscript.fname].grid.grid_rows[item.idx - 1].remove(); |
| } else { |
| return this.frm.call({ |
| method: "erpnext.selling.utils.get_item_details", |
| child: item, |
| args: { |
| args: { |
| item_code: item.item_code, |
| barcode: item.barcode, |
| serial_no: item.serial_no, |
| warehouse: item.warehouse, |
| doctype: me.frm.doc.doctype, |
| parentfield: item.parentfield, |
| customer: me.frm.doc.customer, |
| currency: me.frm.doc.currency, |
| conversion_rate: me.frm.doc.conversion_rate, |
| selling_price_list: me.frm.doc.selling_price_list, |
| 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), |
| } |
| }, |
| callback: function(r) { |
| if(!r.exc) { |
| me.frm.script_manager.trigger("ref_rate", cdt, cdn); |
| } |
| } |
| }); |
| } |
| } |
| }, |
| |
| selling_price_list: function() { |
| this.get_price_list_currency("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) { |
| var item = wn.model.get_doc(cdt, cdn); |
| if(!item.ref_rate) { |
| item.adj_rate = 0.0; |
| } else { |
| 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); |
| } |
| }, |
| |
| warehouse: function(doc, cdt, cdn) { |
| var item = wn.model.get_doc(cdt, cdn); |
| if(item.item_code && item.warehouse) { |
| return this.frm.call({ |
| method: "erpnext.selling.utils.get_available_qty", |
| child: item, |
| args: { |
| item_code: item.item_code, |
| warehouse: item.warehouse, |
| }, |
| }); |
| } |
| }, |
| |
| 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); |
| }); |
| } |
| }, |
| |
| toggle_editable_price_list_rate: function() { |
| var df = wn.meta.get_docfield(this.tname, "ref_rate", this.frm.doc.name); |
| var editable_price_list_rate = cint(wn.defaults.get_default("editable_price_list_rate")); |
| |
| if(df && editable_price_list_rate) { |
| df.read_only = 0; |
| } |
| }, |
| |
| calculate_taxes_and_totals: function() { |
| this._super(); |
| this.calculate_total_advance("Sales Invoice", "advance_adjustment_details"); |
| this.calculate_commission(); |
| this.calculate_contribution(); |
| |
| // TODO 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"); |
| }); |
| |
| }, |
| |
| 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.amount = flt( |
| (item.export_amount * me.frm.doc.conversion_rate) / (1 + cumulated_tax_fraction), |
| precision("amount", item)); |
| |
| item.basic_rate = flt(item.amount / item.qty, precision("basic_rate", 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)); |
| } |
| } |
| }); |
| }, |
| |
| 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; |
| |
| 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; |
| } |
| } |
| |
| return current_tax_fraction; |
| }, |
| |
| calculate_net_total: function() { |
| var me = this; |
| |
| 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_outstanding_amount: function() { |
| // NOTE: |
| // paid_amount and write_off_amount is only for POS Invoice |
| // total_advance is only for non POS Invoice |
| if(this.frm.doc.doctype == "Sales Invoice" && this.frm.doc.docstatus==0) { |
| wn.model.round_floats_in(this.frm.doc, ["grand_total", "total_advance", "write_off_amount", |
| "paid_amount"]); |
| var total_amount_to_pay = this.frm.doc.grand_total - this.frm.doc.write_off_amount - this.frm.doc.total_advance; |
| this.frm.doc.paid_amount = this.frm.doc.is_pos? flt(total_amount_to_pay): 0.0; |
| |
| this.frm.doc.outstanding_amount = flt(total_amount_to_pay - this.frm.doc.paid_amount, |
| precision("outstanding_amount")); |
| } |
| }, |
| |
| calculate_commission: function() { |
| if(this.frm.fields_dict.commission_rate) { |
| 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 = ""; |
| }, |
| |
| show_item_wise_taxes: function() { |
| if(this.frm.fields_dict.other_charges_calculation) { |
| $(this.get_item_wise_taxes_html()) |
| .appendTo($(this.frm.fields_dict.other_charges_calculation.wrapper).empty()); |
| } |
| }, |
| |
| charge: function() { |
| var me = this; |
| if(this.frm.doc.charge) { |
| return this.frm.call({ |
| doc: this.frm.doc, |
| method: "get_other_charges", |
| callback: function(r) { |
| if(!r.exc) { |
| me.calculate_taxes_and_totals(); |
| } |
| } |
| }); |
| } |
| }, |
| |
| shipping_rule: function() { |
| var me = this; |
| if(this.frm.doc.shipping_rule) { |
| return this.frm.call({ |
| doc: this.frm.doc, |
| method: "apply_shipping_rule", |
| callback: function(r) { |
| if(!r.exc) { |
| me.calculate_taxes_and_totals(); |
| } |
| } |
| }) |
| } |
| }, |
| |
| set_dynamic_labels: function() { |
| this._super(); |
| set_sales_bom_help(this.frm.doc); |
| }, |
| |
| 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.docfield_map[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); |
| |
| cur_frm.set_df_property("conversion_rate", "description", "1 " + this.frm.doc.currency |
| + " = [?] " + company_currency) |
| |
| if(this.frm.doc.price_list_currency && this.frm.doc.price_list_currency!=company_currency) { |
| cur_frm.set_df_property("plc_conversion_rate", "description", "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", "price_list_currency"], |
| 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.docfield_map[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) || |
| (wn.model.get_doclist(cur_frm.doctype, cur_frm.docname, |
| {parentfield: "other_charges", included_in_print_rate: 1}).length); |
| |
| $.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) { |
| fname = fname.split("-"); |
| var df = wn.meta.get_docfield(fname[0], fname[1], me.frm.doc.name); |
| if(df) df.label = label; |
| }); |
| }, |
| |
| shipping_address_name: function () { |
| var me = this; |
| if(this.frm.doc.shipping_address_name) { |
| wn.model.with_doc("Address", this.frm.doc.shipping_address_name, function(name) { |
| var address = wn.model.get_doc("Address", name); |
| |
| var out = $.map(["address_line1", "address_line2", "city"], |
| function(f) { return address[f]; }); |
| |
| var state_pincode = $.map(["state", "pincode"], function(f) { return address[f]; }).join(" "); |
| if(state_pincode) out.push(state_pincode); |
| |
| if(address["country"]) out.push(address["country"]); |
| |
| out.concat($.map([["Phone:", address["phone"]], ["Fax:", address["fax"]]], |
| function(val) { return val[1] ? val.join(" ") : null; })); |
| |
| me.frm.set_value("shipping_address", out.join("\n")); |
| }); |
| } |
| } |
| }); |
| |
| // Help for Sales BOM items |
| var set_sales_bom_help = function(doc) { |
| if(!cur_frm.fields_dict.packing_list) return; |
| if (getchildren('Packed Item', doc.name, 'packing_details').length) { |
| $(cur_frm.fields_dict.packing_list.row.wrapper).toggle(true); |
| |
| if (inList(['Delivery Note', 'Sales Invoice'], doc.doctype)) { |
| help_msg = "<div class='alert alert-warning'>" + |
| wn._("For 'Sales BOM' items, warehouse, serial no and batch no \ |
| will be considered from the 'Packing List' table. \ |
| If warehouse and batch no are same for all packing items for any 'Sales BOM' item, \ |
| those values can be entered in the main item table, values will be copied to 'Packing List' table.")+ |
| "</div>"; |
| wn.meta.get_docfield(doc.doctype, 'sales_bom_help', doc.name).options = help_msg; |
| } |
| } else { |
| $(cur_frm.fields_dict.packing_list.row.wrapper).toggle(false); |
| if (inList(['Delivery Note', 'Sales Invoice'], doc.doctype)) { |
| wn.meta.get_docfield(doc.doctype, 'sales_bom_help', doc.name).options = ''; |
| } |
| } |
| refresh_field('sales_bom_help'); |
| } |