// 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 frappe.provide("erpnext.selling"); frappe.require("assets/erpnext/js/transaction.js"); {% include "public/js/controllers/accounts.js" %} erpnext.selling.SellingController = erpnext.TransactionController.extend({ onload: function() { this._super(); this.setup_queries(); }, onload_post_render: function() { cur_frm.get_field(this.fname).grid.set_multiple_add("item_code", "qty"); }, 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.taxes_and_charges) { this.frm.set_query("taxes_and_charges", 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: { selling: 1 } }; }); } 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 = frappe.get_doc(cdt, cdn); if(!item.item_code) { frappe.throw(__("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 : "erpnext.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.doc.packing_details || []).length; this.frm.toggle_display("packing_list", packing_list_exists ? true : false); } this.toggle_editable_price_list_rate(); }, customer: function() { var me = this; erpnext.utils.get_party_details(this.frm, null, null, function(){me.apply_pricing_rule()}); }, customer_address: function() { erpnext.utils.get_address_display(this.frm, "customer_address"); }, shipping_address_name: function() { erpnext.utils.get_address_display(this.frm, "shipping_address_name", "shipping_address"); }, contact_person: function() { erpnext.utils.get_contact_details(this.frm); }, sales_partner: function() { this.apply_pricing_rule(); }, campaign: function() { this.apply_pricing_rule(); }, barcode: function(doc, cdt, cdn) { this.item_code(doc, cdt, cdn); }, selling_price_list: function() { this.apply_price_list(); }, price_list_rate: function(doc, cdt, cdn) { var item = frappe.get_doc(cdt, cdn); frappe.model.round_floats_in(item, ["price_list_rate", "discount_percentage"]); item.rate = flt(item.price_list_rate * (1 - item.discount_percentage / 100.0), precision("rate", item)); this.calculate_taxes_and_totals(); }, discount_percentage: function(doc, cdt, cdn) { var item = frappe.get_doc(cdt, cdn); if(!item.price_list_rate) { item.discount_percentage = 0.0; } else { this.price_list_rate(doc, cdt, cdn); } }, rate: function(doc, cdt, cdn) { var item = frappe.get_doc(cdt, cdn); frappe.model.round_floats_in(item, ["rate", "price_list_rate"]); if(item.price_list_rate) { item.discount_percentage = flt((1 - item.rate / item.price_list_rate) * 100.0, precision("discount_percentage", item)); } else { item.discount_percentage = 0.0; } this.calculate_taxes_and_totals(); }, discount_amount: function() { this.calculate_taxes_and_totals(); }, commission_rate: function() { this.calculate_commission(); refresh_field("total_commission"); }, total_commission: function() { if(this.frm.doc.net_total) { frappe.model.round_floats_in(this.frm.doc, ["net_total", "total_commission"]); if(this.frm.doc.net_total < this.frm.doc.total_commission) { var msg = (__("[Error]") + " " + __(frappe.meta.get_label(this.frm.doc.doctype, "total_commission", this.frm.doc.name)) + " > " + __(frappe.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 = frappe.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 me = this; this.batch_no(doc, cdt, cdn); var item = frappe.get_doc(cdt, cdn); if(item.item_code && item.warehouse) { return this.frm.call({ method: "erpnext.stock.get_item_details.get_available_qty", child: item, args: { item_code: item.item_code, warehouse: item.warehouse, }, }); } }, toggle_editable_price_list_rate: function() { var df = frappe.meta.get_docfield(this.tname, "price_list_rate", this.frm.doc.name); var editable_price_list_rate = cint(frappe.defaults.get_default("editable_price_list_rate")); if(df && editable_price_list_rate) { df.read_only = 0; } }, calculate_taxes_and_totals: function(update_paid_amount) { this._super(); this.calculate_total_advance("Sales Invoice", "advance_adjustment_details", update_paid_amount); 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; if (!this.discount_amount_applied) { $.each(this.frm.item_doclist, function(i, item) { frappe.model.round_floats_in(item); item.amount = flt(item.rate * item.qty, precision("amount", item)); me._set_in_company_currency(item, "price_list_rate", "base_price_list_rate"); me._set_in_company_currency(item, "rate", "base_rate"); me._set_in_company_currency(item, "amount", "base_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 && !me.discount_amount_applied) { item.base_amount = flt( (item.amount * me.frm.doc.conversion_rate) / (1 + cumulated_tax_fraction), precision("base_amount", item)); item.base_rate = flt(item.base_amount / item.qty, precision("base_rate", item)); if(item.discount_percentage == 100) { item.base_price_list_rate = item.base_rate; item.base_rate = 0.0; } else { item.base_price_list_rate = flt(item.base_rate / (1 - item.discount_percentage / 100.0), precision("base_price_list_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.base_amount; me.frm.doc.net_total_export += item.amount; }); frappe.model.round_floats_in(this.frm.doc, ["net_total", "net_total_export"]); }, calculate_totals: function() { var me = this; 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); this.frm.doc.other_charges_total = flt(this.frm.doc.grand_total - this.frm.doc.net_total, precision("other_charges_total")); this.frm.doc.grand_total_export = (this.frm.doc.other_charges_total || this.frm.doc.discount_amount) ? flt(this.frm.doc.grand_total / this.frm.doc.conversion_rate) : this.frm.doc.net_total_export; this.frm.doc.other_charges_total_export = flt(this.frm.doc.grand_total_export - this.frm.doc.net_total_export + flt(this.frm.doc.discount_amount), precision("other_charges_total_export")); this.frm.doc.grand_total = flt(this.frm.doc.grand_total, precision("grand_total")); this.frm.doc.grand_total_export = flt(this.frm.doc.grand_total_export, precision("grand_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); }, apply_discount_amount: function() { var me = this; var distributed_amount = 0.0; if (this.frm.doc.discount_amount) { this.frm.set_value("base_discount_amount", flt(this.frm.doc.discount_amount * this.frm.doc.conversion_rate, precision("base_discount_amount"))) var grand_total_for_discount_amount = this.get_grand_total_for_discount_amount(); // calculate item amount after Discount Amount if (grand_total_for_discount_amount) { $.each(this.frm.item_doclist, function(i, item) { distributed_amount = flt(me.frm.doc.base_discount_amount) * item.base_amount / grand_total_for_discount_amount; item.base_amount = flt(item.base_amount - distributed_amount, precision("base_amount", item)); }); this.discount_amount_applied = true; this._calculate_taxes_and_totals(); } } else { this.frm.set_value("base_discount_amount", 0); } }, get_grand_total_for_discount_amount: function() { var me = this; var total_actual_tax = 0.0; var actual_taxes_dict = {}; $.each(this.frm.tax_doclist, function(i, tax) { if (tax.charge_type == "Actual") actual_taxes_dict[tax.idx] = tax.tax_amount; else if (actual_taxes_dict[tax.row_id] !== null) { actual_tax_amount = flt(actual_taxes_dict[tax.row_id]) * flt(tax.rate) / 100; actual_taxes_dict[tax.idx] = actual_tax_amount; } }); $.each(actual_taxes_dict, function(key, value) { if (value) total_actual_tax += value; }); grand_total_for_discount_amount = flt(this.frm.doc.grand_total - total_actual_tax, precision("grand_total")); return grand_total_for_discount_amount; }, calculate_outstanding_amount: function(update_paid_amount) { // 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) { frappe.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; if(this.frm.doc.is_pos) { if(!this.frm.doc.paid_amount || update_paid_amount===undefined || update_paid_amount) { this.frm.doc.paid_amount = flt(total_amount_to_pay); } } else { this.frm.doc.paid_amount = 0 } this.frm.set_value("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 = __(frappe.meta.get_label(this.frm.doc.doctype, "commission_rate", this.frm.doc.name)) + " " + __("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(this.frm.doc.doctype.sales_team || [], function(i, sales_person) { frappe.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)); } }); }, manipulate_grand_total_for_inclusive_tax: function() { // if fully inclusive taxes and diff if (this.frm.tax_doclist.length) { var all_inclusive = frappe.utils.all(this.frm.tax_doclist.map(function(d) { return cint(d.included_in_print_rate); })); if (all_inclusive) { var last_tax = this.frm.tax_doclist.slice(-1)[0]; var diff = this.frm.doc.net_total_export - flt(last_tax.total / this.frm.doc.conversion_rate, precision("grand_total_export")); if ( diff && Math.abs(diff) <= (2.0 / Math.pow(10, precision("tax_amount", last_tax))) ) { var adjustment_amount = flt(diff * this.frm.doc.conversion_rate, precision("tax_amount", last_tax)); last_tax.tax_amount += adjustment_amount; last_tax.tax_amount_after_discount += adjustment_amount; last_tax.total += adjustment_amount; } } } }, _cleanup: function() { this._super(); this.frm.doc.in_words = this.frm.doc.in_words_export = ""; }, 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(); } } }) } }, batch_no: function(doc, cdt, cdn) { var me = this; var item = frappe.get_doc(cdt, cdn); if(item.warehouse && item.item_code && item.batch_no) { return this.frm.call({ method: "erpnext.stock.get_item_details.get_batch_qty", child: item, args: { "batch_no": item.batch_no, "warehouse": item.warehouse, "item_code": item.item_code }, "fieldname": "actual_batch_qty" }); } }, set_dynamic_labels: function() { this._super(); this.set_sales_bom_help(this.frm.doc); }, set_sales_bom_help: function(doc) { if(!cur_frm.fields_dict.packing_list) return; if ((doc.packing_details || []).length) { $(cur_frm.fields_dict.packing_list.row.wrapper).toggle(true); if (inList(['Delivery Note', 'Sales Invoice'], doc.doctype)) { help_msg = "