// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt cur_frm.cscript.tax_table = "Sales Taxes and Charges"; {% include 'erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.js' %} cur_frm.email_field = "contact_email"; frappe.provide("erpnext.selling"); erpnext.selling.SellingController = class SellingController extends erpnext.TransactionController { setup() { super.setup(); this.frm.add_fetch("sales_partner", "commission_rate", "commission_rate"); this.frm.add_fetch("sales_person", "commission_rate", "commission_rate"); } onload() { super.onload(); this.setup_queries(); this.frm.set_query('shipping_rule', function() { return { filters: { "shipping_rule_type": "Selling" } }; }); } setup_queries() { var me = this; $.each([["customer", "customer"], ["lead", "lead"]], function(i, opts) { if(me.frm.fields_dict[opts[0]]) me.frm.set_query(opts[0], erpnext.queries[opts[1]]); }); me.frm.set_query('contact_person', erpnext.queries.contact_query); me.frm.set_query('customer_address', erpnext.queries.address_query); me.frm.set_query('shipping_address_name', erpnext.queries.address_query); me.frm.set_query('dispatch_address_name', erpnext.queries.dispatch_address_query); if(this.frm.fields_dict.selling_price_list) { this.frm.set_query("selling_price_list", function() { return { filters: { selling: 1 } }; }); } if(this.frm.fields_dict.tc_name) { this.frm.set_query("tc_name", function() { return { filters: { selling: 1 } }; }); } if(!this.frm.fields_dict["items"]) { return; } if(this.frm.fields_dict["items"].grid.get_field('item_code')) { this.frm.set_query("item_code", "items", function() { return { query: "erpnext.controllers.queries.item_query", filters: {'is_sales_item': 1, 'customer': cur_frm.doc.customer, 'has_variants': 0} } }); } if(this.frm.fields_dict["packed_items"] && this.frm.fields_dict["packed_items"].grid.get_field('batch_no')) { this.frm.set_query("batch_no", "packed_items", function(doc, cdt, cdn) { return me.set_query_for_batch(doc, cdt, cdn) }); } if(this.frm.fields_dict["items"].grid.get_field('item_code')) { this.frm.set_query("item_tax_template", "items", function(doc, cdt, cdn) { return me.set_query_for_item_tax_template(doc, cdt, cdn) }); } } refresh() { super.refresh(); frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer'} this.frm.toggle_display("customer_name", (this.frm.doc.customer_name && this.frm.doc.customer_name!==this.frm.doc.customer)); this.toggle_editable_price_list_rate(); } customer() { var me = this; erpnext.utils.get_party_details(this.frm, null, null, function() { me.apply_price_list(); }); } customer_address() { erpnext.utils.get_address_display(this.frm, "customer_address"); erpnext.utils.set_taxes_from_address(this.frm, "customer_address", "customer_address", "shipping_address_name"); } shipping_address_name() { erpnext.utils.get_address_display(this.frm, "shipping_address_name", "shipping_address"); erpnext.utils.set_taxes_from_address(this.frm, "shipping_address_name", "customer_address", "shipping_address_name"); } dispatch_address_name() { erpnext.utils.get_address_display(this.frm, "dispatch_address_name", "dispatch_address"); } sales_partner() { this.apply_pricing_rule(); } campaign() { this.apply_pricing_rule(); } selling_price_list() { this.apply_price_list(); this.set_dynamic_labels(); } discount_percentage(doc, cdt, cdn) { var item = frappe.get_doc(cdt, cdn); item.discount_amount = 0.0; this.apply_discount_on_item(doc, cdt, cdn, 'discount_percentage'); } discount_amount(doc, cdt, cdn) { if(doc.name === cdn) { return; } var item = frappe.get_doc(cdt, cdn); item.discount_percentage = 0.0; this.apply_discount_on_item(doc, cdt, cdn, 'discount_amount'); } apply_discount_on_item(doc, cdt, cdn, field) { var item = frappe.get_doc(cdt, cdn); if(!item.price_list_rate) { item[field] = 0.0; } else { this.price_list_rate(doc, cdt, cdn); } this.set_gross_profit(item); } commission_rate() { this.calculate_commission(); } total_commission() { frappe.model.round_floats_in(this.frm.doc, ["amount_eligible_for_commission", "total_commission"]); const { amount_eligible_for_commission } = this.frm.doc; if(!amount_eligible_for_commission) return; this.frm.set_value( "commission_rate", flt( this.frm.doc.total_commission * 100.0 / amount_eligible_for_commission ) ); } allocated_percentage(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.amount_eligible_for_commission * sales_person.allocated_percentage / 100.0, precision("allocated_amount", sales_person)); refresh_field(["allocated_amount"], sales_person); this.calculate_incentive(sales_person); refresh_field(["allocated_percentage", "allocated_amount", "commission_rate","incentives"], sales_person.name, sales_person.parentfield); } } sales_person(doc, cdt, cdn) { var row = frappe.get_doc(cdt, cdn); this.calculate_incentive(row); refresh_field("incentives",row.name,row.parentfield); } warehouse(doc, cdt, cdn) { var me = this; var item = frappe.get_doc(cdt, cdn); // check if serial nos entered are as much as qty in row if (item.serial_no) { let serial_nos = item.serial_no.split(`\n`).filter(sn => sn.trim()); // filter out whitespaces if (item.qty === serial_nos.length) return; } if (item.serial_no && !item.batch_no) { item.serial_no = null; } var has_batch_no; frappe.db.get_value('Item', {'item_code': item.item_code}, 'has_batch_no', (r) => { has_batch_no = r && r.has_batch_no; if(item.item_code && item.warehouse) { return this.frm.call({ method: "erpnext.stock.get_item_details.get_bin_details_and_serial_nos", child: item, args: { item_code: item.item_code, warehouse: item.warehouse, has_batch_no: has_batch_no || 0, stock_qty: item.stock_qty, serial_no: item.serial_no || "", }, callback:function(r){ if (in_list(['Delivery Note', 'Sales Invoice'], doc.doctype)) { if (doc.doctype === 'Sales Invoice' && (!doc.update_stock)) return; if (has_batch_no) { me.set_batch_number(cdt, cdn); me.batch_no(doc, cdt, cdn); } } } }); } }) } toggle_editable_price_list_rate() { var df = frappe.meta.get_docfield(this.frm.doc.doctype + " Item", "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) { const parent_field = frappe.meta.get_parentfield(this.frm.doc.doctype, this.frm.doc.doctype + " Item"); if (!this.frm.fields_dict[parent_field]) return; this.frm.fields_dict[parent_field].grid.update_docfield_property( 'price_list_rate', 'read_only', 0 ); } } calculate_commission() { if(!this.frm.fields_dict.commission_rate) return; if(this.frm.doc.commission_rate > 100) { this.frm.set_value("commission_rate", 100); frappe.throw(`${__(frappe.meta.get_label( this.frm.doc.doctype, "commission_rate", this.frm.doc.name ))} ${__("cannot be greater than 100")}`); } this.frm.doc.amount_eligible_for_commission = this.frm.doc.items.reduce( (sum, item) => item.grant_commission ? sum + item.base_net_amount : sum, 0 ) this.frm.doc.total_commission = flt( this.frm.doc.amount_eligible_for_commission * this.frm.doc.commission_rate / 100.0, precision("total_commission") ); refresh_field(["amount_eligible_for_commission", "total_commission"]); } calculate_contribution() { 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) return; sales_person.allocated_amount = flt( me.frm.doc.amount_eligible_for_commission * sales_person.allocated_percentage / 100.0, precision("allocated_amount", sales_person) ); }); } calculate_incentive(row) { if(row.allocated_amount) { row.incentives = flt( row.allocated_amount * row.commission_rate / 100.0, precision("incentives", row)); } } batch_no(doc, cdt, cdn) { var me = this; var item = frappe.get_doc(cdt, cdn); if (item.serial_no) { return; } item.serial_no = null; var has_serial_no; frappe.db.get_value('Item', {'item_code': item.item_code}, 'has_serial_no', (r) => { has_serial_no = r && r.has_serial_no; if(item.warehouse && item.item_code && item.batch_no) { return this.frm.call({ method: "erpnext.stock.get_item_details.get_batch_qty_and_serial_no", child: item, args: { "batch_no": item.batch_no, "stock_qty": item.stock_qty || item.qty, //if stock_qty field is not available fetch qty (in case of Packed Items table) "warehouse": item.warehouse, "item_code": item.item_code, "has_serial_no": has_serial_no }, "fieldname": "actual_batch_qty" }); } }) } set_dynamic_labels() { super.set_dynamic_labels(); this.set_product_bundle_help(this.frm.doc); } set_product_bundle_help(doc) { if(!cur_frm.fields_dict.packing_list) return; if ((doc.packed_items || []).length) { $(cur_frm.fields_dict.packing_list.row.wrapper).toggle(true); if (in_list(['Delivery Note', 'Sales Invoice'], doc.doctype)) { var help_msg = "