From 7f2a54d95bba8f686e4fc3c439a8f37c170b3688 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Tue, 19 Mar 2024 12:03:36 +0100 Subject: [PATCH 01/19] refactor: usage of in_list (cherry picked from commit d238751e6ba0666b4098f1db9be38e9bd8163770) # Conflicts: # erpnext/accounts/doctype/payment_entry/payment_entry.js # erpnext/buying/doctype/purchase_order/purchase_order.js # erpnext/public/js/controllers/accounts.js # erpnext/public/js/controllers/buying.js # erpnext/public/js/controllers/transaction.js # erpnext/public/js/utils/sales_common.js # erpnext/templates/form_grid/item_grid.html --- .../doctype/journal_entry/journal_entry.js | 6 +- .../doctype/payment_entry/payment_entry.js | 50 ++ .../payment_request/payment_request.js | 2 +- erpnext/assets/doctype/asset/asset.js | 6 +- .../doctype/purchase_order/purchase_order.js | 15 + erpnext/manufacturing/doctype/bom/bom.js | 2 +- .../production_plan/production_plan.js | 2 +- .../doctype/work_order/work_order.js | 4 +- erpnext/public/js/communication.js | 2 +- erpnext/public/js/controllers/accounts.js | 53 ++ erpnext/public/js/controllers/buying.js | 399 ++++++++++++++ .../public/js/controllers/taxes_and_totals.js | 22 +- erpnext/public/js/controllers/transaction.js | 61 ++- erpnext/public/js/payment/payments.js | 2 +- erpnext/public/js/sms_manager.js | 4 +- erpnext/public/js/utils/party.js | 4 +- erpnext/public/js/utils/sales_common.js | 510 ++++++++++++++++++ .../import_supplier_invoice.js | 2 +- .../point_of_sale/pos_past_order_summary.js | 2 +- .../closing_stock_balance.js | 2 +- .../delivery_trip/delivery_trip_list.js | 4 +- erpnext/templates/form_grid/item_grid.html | 5 + 22 files changed, 1120 insertions(+), 39 deletions(-) create mode 100644 erpnext/public/js/utils/sales_common.js diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js index a2f5455f2f74..5bbdd84d3f4d 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.js +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js @@ -171,7 +171,7 @@ frappe.ui.form.on("Journal Entry", { !(frm.doc.accounts || []).length || ((frm.doc.accounts || []).length === 1 && !frm.doc.accounts[0].account) ) { - if (in_list(["Bank Entry", "Cash Entry"], frm.doc.voucher_type)) { + if (["Bank Entry", "Cash Entry"].includes(frm.doc.voucher_type)) { return frappe.call({ type: "GET", method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_default_bank_cash_account", @@ -283,7 +283,7 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro filters: [[jvd.reference_type, "docstatus", "=", 1]], }; - if (in_list(["Sales Invoice", "Purchase Invoice"], jvd.reference_type)) { + if (["Sales Invoice", "Purchase Invoice"].includes(jvd.reference_type)) { out.filters.push([jvd.reference_type, "outstanding_amount", "!=", 0]); // Filter by cost center if (jvd.cost_center) { @@ -295,7 +295,7 @@ erpnext.accounts.JournalEntry = class JournalEntry extends frappe.ui.form.Contro out.filters.push([jvd.reference_type, party_account_field, "=", jvd.account]); } - if (in_list(["Sales Order", "Purchase Order"], jvd.reference_type)) { + if (["Sales Order", "Purchase Order"].includes(jvd.reference_type)) { // party_type and party mandatory frappe.model.validate_missing(jvd, "party_type"); frappe.model.validate_missing(jvd, "party"); diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index 309141fe4c27..8ad31e1e7915 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -21,8 +21,14 @@ frappe.ui.form.on('Payment Entry', { frm.set_query("paid_from", function() { frm.events.validate_company(frm); +<<<<<<< HEAD var account_types = in_list(["Pay", "Internal Transfer"], frm.doc.payment_type) ? ["Bank", "Cash"] : [frappe.boot.party_account_types[frm.doc.party_type]]; +======= + var account_types = ["Pay", "Internal Transfer"].includes(frm.doc.payment_type) + ? ["Bank", "Cash"] + : [frappe.boot.party_account_types[frm.doc.party_type]]; +>>>>>>> d238751e6b (refactor: usage of in_list) return { filters: { "account_type": ["in", account_types], @@ -75,8 +81,14 @@ frappe.ui.form.on('Payment Entry', { frm.set_query("paid_to", function() { frm.events.validate_company(frm); +<<<<<<< HEAD var account_types = in_list(["Receive", "Internal Transfer"], frm.doc.payment_type) ? ["Bank", "Cash"] : [frappe.boot.party_account_types[frm.doc.party_type]]; +======= + var account_types = ["Receive", "Internal Transfer"].includes(frm.doc.payment_type) + ? ["Bank", "Cash"] + : [frappe.boot.party_account_types[frm.doc.party_type]]; +>>>>>>> d238751e6b (refactor: usage of in_list) return { filters: { "account_type": ["in", account_types], @@ -121,7 +133,14 @@ frappe.ui.form.on('Payment Entry', { frm.set_query('payment_term', 'references', function(frm, cdt, cdn) { const child = locals[cdt][cdn]; +<<<<<<< HEAD if (in_list(['Purchase Invoice', 'Sales Invoice'], child.reference_doctype) && child.reference_name) { +======= + if ( + ["Purchase Invoice", "Sales Invoice"].includes(child.reference_doctype) && + child.reference_name + ) { +>>>>>>> d238751e6b (refactor: usage of in_list) return { query: "erpnext.controllers.queries.get_payment_terms_for_references", filters: { @@ -484,8 +503,13 @@ frappe.ui.form.on('Payment Entry', { if (frm.doc.paid_from_account_currency == company_currency) { frm.set_value("source_exchange_rate", 1); +<<<<<<< HEAD } else if (frm.doc.paid_from){ if (in_list(["Internal Transfer", "Pay"], frm.doc.payment_type)) { +======= + } else if (frm.doc.paid_from) { + if (["Internal Transfer", "Pay"].includes(frm.doc.payment_type)) { +>>>>>>> d238751e6b (refactor: usage of in_list) let company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency; frappe.call({ method: "erpnext.setup.utils.get_exchange_rate", @@ -852,11 +876,19 @@ frappe.ui.form.on('Payment Entry', { total_negative_outstanding : remaining_outstanding; } +<<<<<<< HEAD var allocated_positive_outstanding = paid_amount + allocated_negative_outstanding; } else if (in_list(["Customer", "Supplier"], frm.doc.party_type)) { total_negative_outstanding = flt(total_negative_outstanding, precision("outstanding_amount")) if(paid_amount > total_negative_outstanding) { if(total_negative_outstanding == 0) { +======= + var allocated_positive_outstanding = paid_amount + allocated_negative_outstanding; + } else if (["Customer", "Supplier"].includes(frm.doc.party_type)) { + total_negative_outstanding = flt(total_negative_outstanding, precision("outstanding_amount")); + if (paid_amount > total_negative_outstanding) { + if (total_negative_outstanding == 0) { +>>>>>>> d238751e6b (refactor: usage of in_list) frappe.msgprint( __("Cannot {0} {1} {2} without any negative outstanding invoice", [frm.doc.payment_type, (frm.doc.party_type=="Customer" ? "to" : "from"), frm.doc.party_type]) @@ -987,16 +1019,28 @@ frappe.ui.form.on('Payment Entry', { return; } +<<<<<<< HEAD if(frm.doc.party_type=="Customer" && !in_list(["Sales Order", "Sales Invoice", "Journal Entry", "Dunning"], row.reference_doctype) +======= + if ( + frm.doc.party_type == "Customer" && + !["Sales Order", "Sales Invoice", "Journal Entry", "Dunning"].includes(row.reference_doctype) +>>>>>>> d238751e6b (refactor: usage of in_list) ) { frappe.model.set_value(row.doctype, row.name, "reference_doctype", null); frappe.msgprint(__("Row #{0}: Reference Document Type must be one of Sales Order, Sales Invoice, Journal Entry or Dunning", [row.idx])); return false; } +<<<<<<< HEAD if(frm.doc.party_type=="Supplier" && !in_list(["Purchase Order", "Purchase Invoice", "Journal Entry"], row.reference_doctype) +======= + if ( + frm.doc.party_type == "Supplier" && + !["Purchase Order", "Purchase Invoice", "Journal Entry"].includes(row.reference_doctype) +>>>>>>> d238751e6b (refactor: usage of in_list) ) { frappe.model.set_value(row.doctype, row.name, "against_voucher_type", null); frappe.msgprint(__("Row #{0}: Reference Document Type must be one of Purchase Order, Purchase Invoice or Journal Entry", [row.idx])); @@ -1078,9 +1122,15 @@ frappe.ui.form.on('Payment Entry', { } }, +<<<<<<< HEAD bank_account: function(frm) { const field = frm.doc.payment_type == "Pay" ? "paid_from":"paid_to"; if (frm.doc.bank_account && in_list(['Pay', 'Receive'], frm.doc.payment_type)) { +======= + bank_account: function (frm) { + const field = frm.doc.payment_type == "Pay" ? "paid_from" : "paid_to"; + if (frm.doc.bank_account && ["Pay", "Receive"].includes(frm.doc.payment_type)) { +>>>>>>> d238751e6b (refactor: usage of in_list) frappe.call({ method: "erpnext.accounts.doctype.bank_account.bank_account.get_bank_account_details", args: { diff --git a/erpnext/accounts/doctype/payment_request/payment_request.js b/erpnext/accounts/doctype/payment_request/payment_request.js index e5a6040c735e..e45aa512fe80 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.js +++ b/erpnext/accounts/doctype/payment_request/payment_request.js @@ -28,7 +28,7 @@ frappe.ui.form.on("Payment Request", "refresh", function (frm) { if ( frm.doc.payment_request_type == "Inward" && frm.doc.payment_channel !== "Phone" && - !in_list(["Initiated", "Paid"], frm.doc.status) && + !["Initiated", "Paid"].includes(frm.doc.status) && !frm.doc.__islocal && frm.doc.docstatus == 1 ) { diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js index 49c0b24e4cbc..b6afe11e4ff2 100644 --- a/erpnext/assets/doctype/asset/asset.js +++ b/erpnext/assets/doctype/asset/asset.js @@ -78,7 +78,7 @@ frappe.ui.form.on("Asset", { frm.events.make_schedules_editable(frm); if (frm.doc.docstatus == 1) { - if (in_list(["Submitted", "Partially Depreciated", "Fully Depreciated"], frm.doc.status)) { + if (["Submitted", "Partially Depreciated", "Fully Depreciated"].includes(frm.doc.status)) { frm.add_custom_button( __("Transfer Asset"), function () { @@ -280,7 +280,7 @@ frappe.ui.form.on("Asset", { if (v.journal_entry) { asset_values.push(asset_value); } else { - if (in_list(["Scrapped", "Sold"], frm.doc.status)) { + if (["Scrapped", "Sold"].includes(frm.doc.status)) { asset_values.push(null); } else { asset_values.push(asset_value); @@ -312,7 +312,7 @@ frappe.ui.form.on("Asset", { }); } - if (in_list(["Scrapped", "Sold"], frm.doc.status)) { + if (["Scrapped", "Sold"].includes(frm.doc.status)) { x_intervals.push(frappe.format(frm.doc.disposal_date, { fieldtype: "Date" })); asset_values.push(0); } diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index 52a0f4ac2a28..a1a06489957f 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -180,11 +180,22 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends e this.frm.fields_dict.items_section.wrapper.removeClass("hide-border"); } +<<<<<<< HEAD if(!in_list(["Closed", "Delivered"], doc.status)) { if(this.frm.doc.status !== 'Closed' && flt(this.frm.doc.per_received) < 100 && flt(this.frm.doc.per_billed) < 100) { // Don't add Update Items button if the PO is following the new subcontracting flow. if (!(this.frm.doc.is_subcontracted && !this.frm.doc.is_old_subcontracting_flow)) { this.frm.add_custom_button(__('Update Items'), () => { +======= + if (!["Closed", "Delivered"].includes(doc.status)) { + if ( + this.frm.doc.status !== "Closed" && + flt(this.frm.doc.per_received, 2) < 100 && + flt(this.frm.doc.per_billed, 2) < 100 + ) { + if (!this.frm.doc.__onload || this.frm.doc.__onload.can_update_items) { + this.frm.add_custom_button(__("Update Items"), () => { +>>>>>>> d238751e6b (refactor: usage of in_list) erpnext.utils.update_child_items({ frm: this.frm, child_docname: "items", @@ -211,7 +222,11 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends e this.frm.page.set_inner_btn_group_as_primary(__("Status")); } +<<<<<<< HEAD } else if(in_list(["Closed", "Delivered"], doc.status)) { +======= + } else if (["Closed", "Delivered"].includes(doc.status)) { +>>>>>>> d238751e6b (refactor: usage of in_list) if (this.frm.has_perm("submit")) { this.frm.add_custom_button(__('Re-open'), () => this.unclose_purchase_order(), __("Status")); } diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js index b7ab6ef38728..bf8cb05d8ce6 100644 --- a/erpnext/manufacturing/doctype/bom/bom.js +++ b/erpnext/manufacturing/doctype/bom/bom.js @@ -400,7 +400,7 @@ frappe.ui.form.on("BOM", { }, rm_cost_as_per(frm) { - if (in_list(["Valuation Rate", "Last Purchase Rate"], frm.doc.rm_cost_as_per)) { + if (["Valuation Rate", "Last Purchase Rate"].includes(frm.doc.rm_cost_as_per)) { frm.set_value("plc_conversion_rate", 1.0); } }, diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.js b/erpnext/manufacturing/doctype/production_plan/production_plan.js index 54d1414c8145..6db901c71a41 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.js +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.js @@ -129,7 +129,7 @@ frappe.ui.form.on("Production Plan", { if ( frm.doc.mr_items && frm.doc.mr_items.length && - !in_list(["Material Requested", "Closed"], frm.doc.status) + !["Material Requested", "Closed"].includes(frm.doc.status) ) { frm.add_custom_button( __("Material Request"), diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js index 5e3860355146..ea86d0a939c6 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.js +++ b/erpnext/manufacturing/doctype/work_order/work_order.js @@ -194,7 +194,7 @@ frappe.ui.form.on("Work Order", { }, add_custom_button_to_return_components: function (frm) { - if (frm.doc.docstatus === 1 && in_list(["Closed", "Completed"], frm.doc.status)) { + if (frm.doc.docstatus === 1 && ["Closed", "Completed"].includes(frm.doc.status)) { let non_consumed_items = frm.doc.required_items.filter((d) => { return flt(d.consumed_qty) < flt(d.transferred_qty - d.returned_qty); }); @@ -594,7 +594,7 @@ erpnext.work_order = { ); } - if (doc.docstatus === 1 && !in_list(["Closed", "Completed"], doc.status)) { + if (doc.docstatus === 1 && !["Closed", "Completed"].includes(doc.status)) { if (doc.status != "Stopped" && doc.status != "Completed") { frm.add_custom_button( __("Stop"), diff --git a/erpnext/public/js/communication.js b/erpnext/public/js/communication.js index d9187f8b6788..c8905e14af29 100644 --- a/erpnext/public/js/communication.js +++ b/erpnext/public/js/communication.js @@ -20,7 +20,7 @@ frappe.ui.form.on("Communication", { ); } - if (!in_list(["Lead", "Opportunity"], frm.doc.reference_doctype)) { + if (!["Lead", "Opportunity"].includes(frm.doc.reference_doctype)) { frm.add_custom_button( __("Lead"), () => { diff --git a/erpnext/public/js/controllers/accounts.js b/erpnext/public/js/controllers/accounts.js index 72845b207420..830034182660 100644 --- a/erpnext/public/js/controllers/accounts.js +++ b/erpnext/public/js/controllers/accounts.js @@ -5,6 +5,7 @@ frappe.provide("erpnext.taxes"); frappe.provide("erpnext.taxes.flags"); +<<<<<<< HEAD frappe.ui.form.on(cur_frm.doctype, { setup: function(frm) { // set conditional display for rate column in taxes @@ -12,6 +13,58 @@ frappe.ui.form.on(cur_frm.doctype, { if(in_list(['Sales Taxes and Charges', 'Purchase Taxes and Charges'], grid_row.doc.doctype)) { erpnext.taxes.set_conditional_mandatory_rate_or_amount(grid_row); } +======= +erpnext.accounts.taxes = { + setup_tax_validations: function(doctype) { + let me = this; + frappe.ui.form.on(doctype, { + setup: function(frm) { + // set conditional display for rate column in taxes + $(frm.wrapper).on('grid-row-render', function(e, grid_row) { + if(['Sales Taxes and Charges', 'Purchase Taxes and Charges'].includes(grid_row.doc.doctype)) { + me.set_conditional_mandatory_rate_or_amount(grid_row); + } + }); + }, + onload: function(frm) { + if(frm.get_field("taxes")) { + frm.set_query("account_head", "taxes", function(doc) { + if(frm.cscript.tax_table == "Sales Taxes and Charges") { + var account_type = ["Tax", "Chargeable", "Expense Account"]; + } else { + var account_type = ["Tax", "Chargeable", "Income Account", "Expenses Included In Valuation"]; + } + + return { + query: "erpnext.controllers.queries.tax_account_query", + filters: { + "account_type": account_type, + "company": doc.company, + } + } + }); + frm.set_query("cost_center", "taxes", function(doc) { + return { + filters: { + "company": doc.company, + "is_group": 0 + } + }; + }); + } + }, + validate: function(frm) { + // neither is absolutely mandatory + if(frm.get_docfield("taxes")) { + frm.get_docfield("taxes", "rate").reqd = 0; + frm.get_docfield("taxes", "tax_amount").reqd = 0; + } + + }, + taxes_on_form_rendered: function(frm) { + me.set_conditional_mandatory_rate_or_amount(frm.open_grid_row()); + }, +>>>>>>> d238751e6b (refactor: usage of in_list) }); }, onload: function(frm) { diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js index b0e08cc6f265..ab2a476a1d4b 100644 --- a/erpnext/public/js/controllers/buying.js +++ b/erpnext/public/js/controllers/buying.js @@ -9,9 +9,408 @@ cur_frm.cscript.tax_table = "Purchase Taxes and Charges"; cur_frm.email_field = "contact_email"; +<<<<<<< HEAD erpnext.buying.BuyingController = class BuyingController extends erpnext.TransactionController { setup() { super.setup(); +======= + if (this.frm.doc.__islocal + && frappe.meta.has_field(this.frm.doc.doctype, "disable_rounded_total")) { + + var df = frappe.meta.get_docfield(this.frm.doc.doctype, "disable_rounded_total"); + var disable = cint(df.default) || cint(frappe.sys_defaults.disable_rounded_total); + this.frm.set_value("disable_rounded_total", disable); + } + + + // no idea where me is coming from + if(this.frm.get_field('shipping_address')) { + this.frm.set_query("shipping_address", () => { + if(this.frm.doc.customer) { + return { + query: 'frappe.contacts.doctype.address.address.address_query', + filters: { link_doctype: 'Customer', link_name: this.frm.doc.customer } + }; + } else + return erpnext.queries.company_address_query(this.frm.doc) + }); + } + } + + setup_queries(doc, cdt, cdn) { + var me = this; + + if(this.frm.fields_dict.buying_price_list) { + this.frm.set_query("buying_price_list", function() { + return{ + filters: { 'buying': 1 } + } + }); + } + + if(this.frm.fields_dict.tc_name) { + this.frm.set_query("tc_name", function() { + return{ + filters: { 'buying': 1 } + } + }); + } + + me.frm.set_query('supplier', erpnext.queries.supplier); + me.frm.set_query('contact_person', erpnext.queries.contact_query); + me.frm.set_query('supplier_address', erpnext.queries.address_query); + + me.frm.set_query('billing_address', erpnext.queries.company_address_query); + erpnext.accounts.dimensions.setup_dimension_filters(me.frm, me.frm.doctype); + + this.frm.set_query("item_code", "items", function() { + if (me.frm.doc.is_subcontracted) { + var filters = {'supplier': me.frm.doc.supplier}; + if (me.frm.doc.is_old_subcontracting_flow) { + filters["is_sub_contracted_item"] = 1; + } + else { + filters["is_stock_item"] = 0; + } + + return{ + query: "erpnext.controllers.queries.item_query", + filters: filters + } + } + else { + return{ + query: "erpnext.controllers.queries.item_query", + filters: { 'supplier': me.frm.doc.supplier, 'is_purchase_item': 1, 'has_variants': 0} + } + } + }); + + + this.frm.set_query("manufacturer", "items", function(doc, cdt, cdn) { + const row = locals[cdt][cdn]; + return { + query: "erpnext.controllers.queries.item_manufacturer_query", + filters:{ 'item_code': row.item_code } + } + }); + + 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(doc) { + frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'supplier', doctype: 'Supplier'}; + + this.frm.toggle_display("supplier_name", + (this.frm.doc.supplier_name && this.frm.doc.supplier_name!==this.frm.doc.supplier)); + + if(this.frm.doc.docstatus==0 && + (this.frm.doctype==="Purchase Order" || this.frm.doctype==="Material Request")) { + this.set_from_product_bundle(); + } + + this.toggle_subcontracting_fields(); + super.refresh(); + } + + toggle_subcontracting_fields() { + if (['Purchase Receipt', 'Purchase Invoice'].includes(this.frm.doc.doctype)) { + this.frm.fields_dict.supplied_items.grid.update_docfield_property('consumed_qty', + 'read_only', this.frm.doc.__onload && this.frm.doc.__onload.backflush_based_on === 'BOM'); + + this.frm.set_df_property('supplied_items', 'cannot_add_rows', 1); + this.frm.set_df_property('supplied_items', 'cannot_delete_rows', 1); + } + } + + supplier() { + var me = this; + erpnext.utils.get_party_details(this.frm, null, null, function(){ + me.apply_price_list(); + }); + } + + supplier_address() { + erpnext.utils.get_address_display(this.frm); + erpnext.utils.set_taxes_from_address(this.frm, "supplier_address", "supplier_address", "supplier_address"); + } + + buying_price_list() { + this.apply_price_list(); + } + + discount_percentage(doc, cdt, cdn) { + var item = frappe.get_doc(cdt, cdn); + item.discount_amount = 0.0; + this.price_list_rate(doc, cdt, cdn); + } + + discount_amount(doc, cdt, cdn) { + var item = frappe.get_doc(cdt, cdn); + item.discount_percentage = 0.0; + this.price_list_rate(doc, cdt, cdn); + } + + qty(doc, cdt, cdn) { + if ((doc.doctype == "Purchase Receipt") || (doc.doctype == "Purchase Invoice" && (doc.update_stock || doc.is_return))) { + this.calculate_received_qty(doc, cdt, cdn) + } + super.qty(doc, cdt, cdn); + } + + rejected_qty(doc, cdt, cdn) { + this.calculate_received_qty(doc, cdt, cdn) + } + + calculate_received_qty(doc, cdt, cdn){ + var item = frappe.get_doc(cdt, cdn); + frappe.model.round_floats_in(item, ["qty", "rejected_qty"]); + + if(!doc.is_return && this.validate_negative_quantity(cdt, cdn, item, ["qty", "rejected_qty"])){ return } + + let received_qty = flt(item.qty + item.rejected_qty, precision("received_qty", item)); + let received_stock_qty = flt(item.conversion_factor, precision("conversion_factor", item)) * flt(received_qty); + + frappe.model.set_value(cdt, cdn, "received_qty", received_qty); + frappe.model.set_value(cdt, cdn, "received_stock_qty", received_stock_qty); + } + + batch_no(doc, cdt, cdn) { + super.batch_no(doc, cdt, cdn); + } + + validate_negative_quantity(cdt, cdn, item, fieldnames){ + if(!item || !fieldnames) { return } + + var is_negative_qty = false; + for(var i = 0; i{0} is invalid", [row.manufacturer_part_no]), + title: __("Invalid Part Number") + } + frappe.throw(msg); + } + } + ); + } + } + + add_serial_batch_bundle(doc, cdt, cdn) { + let item = locals[cdt][cdn]; + let me = this; + let path = "assets/erpnext/js/utils/serial_no_batch_selector.js"; + + frappe.db.get_value("Item", item.item_code, ["has_batch_no", "has_serial_no"]) + .then((r) => { + if (r.message && (r.message.has_batch_no || r.message.has_serial_no)) { + item.has_serial_no = r.message.has_serial_no; + item.has_batch_no = r.message.has_batch_no; + item.type_of_transaction = item.qty > 0 ? "Inward" : "Outward"; + item.is_rejected = false; + + frappe.require(path, function() { + new erpnext.SerialBatchPackageSelector( + me.frm, item, (r) => { + if (r) { + let qty = Math.abs(r.total_qty); + if (doc.is_return) { + qty = qty * -1; + } + + let update_values = { + "serial_and_batch_bundle": r.name, + "use_serial_batch_fields": 0, + "qty": qty / flt(item.conversion_factor || 1, precision("conversion_factor", item)) + } + + if (r.warehouse) { + update_values["warehouse"] = r.warehouse; + } + + frappe.model.set_value(item.doctype, item.name, update_values); + } + } + ); + }); + } + }); + } + + add_serial_batch_for_rejected_qty(doc, cdt, cdn) { + let item = locals[cdt][cdn]; + let me = this; + let path = "assets/erpnext/js/utils/serial_no_batch_selector.js"; + + frappe.db.get_value("Item", item.item_code, ["has_batch_no", "has_serial_no"]) + .then((r) => { + if (r.message && (r.message.has_batch_no || r.message.has_serial_no)) { + item.has_serial_no = r.message.has_serial_no; + item.has_batch_no = r.message.has_batch_no; + item.type_of_transaction = item.qty > 0 ? "Inward" : "Outward"; + item.is_rejected = true; + + frappe.require(path, function() { + new erpnext.SerialBatchPackageSelector( + me.frm, item, (r) => { + if (r) { + let qty = Math.abs(r.total_qty); + if (doc.is_return) { + qty = qty * -1; + } + + let update_values = { + "serial_and_batch_bundle": r.name, + "use_serial_batch_fields": 0, + "rejected_qty": qty / flt(item.conversion_factor || 1, precision("conversion_factor", item)) + } + + if (r.warehouse) { + update_values["rejected_warehouse"] = r.warehouse; + } + + frappe.model.set_value(item.doctype, item.name, update_values); + } + } + ); + }); + } + }); + } + }; +>>>>>>> d238751e6b (refactor: usage of in_list) } onload(doc, cdt, cdn) { diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js index 186c342a75e1..670cf35bb118 100644 --- a/erpnext/public/js/controllers/taxes_and_totals.js +++ b/erpnext/public/js/controllers/taxes_and_totals.js @@ -9,7 +9,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { apply_pricing_rule_on_item(item) { let effective_item_rate = item.price_list_rate; let item_rate = item.rate; - if (in_list(["Sales Order", "Quotation"], item.parenttype) && item.blanket_order_rate) { + if (["Sales Order", "Quotation"].includes(item.parenttype) && item.blanket_order_rate) { effective_item_rate = item.blanket_order_rate; } if (item.margin_type == "Percentage") { @@ -52,7 +52,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { // Advance calculation applicable to Sales/Purchase Invoice if ( - in_list(["Sales Invoice", "POS Invoice", "Purchase Invoice"], this.frm.doc.doctype) + ["Sales Invoice", "POS Invoice", "Purchase Invoice"].includes(this.frm.doc.doctype) && this.frm.doc.docstatus < 2 && !this.frm.doc.is_return ) { @@ -60,7 +60,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { } if ( - in_list(["Sales Invoice", "POS Invoice"], this.frm.doc.doctype) + ["Sales Invoice", "POS Invoice"].includes(this.frm.doc.doctype) && this.frm.doc.is_pos && this.frm.doc.is_return ) { @@ -69,7 +69,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { } // Sales person's commission - if (in_list(["Quotation", "Sales Order", "Delivery Note", "Sales Invoice"], this.frm.doc.doctype)) { + if (["Quotation", "Sales Order", "Delivery Note", "Sales Invoice"].includes(this.frm.doc.doctype)) { this.calculate_commission(); this.calculate_contribution(); } @@ -547,7 +547,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { ? this.frm.doc["taxes"][tax_count - 1].total + flt(this.frm.doc.rounding_adjustment) : this.frm.doc.net_total); - if(in_list(["Quotation", "Sales Order", "Delivery Note", "Sales Invoice", "POS Invoice"], this.frm.doc.doctype)) { + if(["Quotation", "Sales Order", "Delivery Note", "Sales Invoice", "POS Invoice"].includes(this.frm.doc.doctype)) { this.frm.doc.base_grand_total = (this.frm.doc.total_taxes_and_charges) ? flt(this.frm.doc.grand_total * this.frm.doc.conversion_rate) : this.frm.doc.base_net_total; } else { @@ -555,7 +555,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { this.frm.doc.taxes_and_charges_added = this.frm.doc.taxes_and_charges_deducted = 0.0; if(tax_count) { $.each(this.frm.doc["taxes"] || [], function(i, tax) { - if (in_list(["Valuation and Total", "Total"], tax.category)) { + if (["Valuation and Total", "Total"].includes(tax.category)) { if(tax.add_deduct_tax == "Add") { me.frm.doc.taxes_and_charges_added += flt(tax.tax_amount_after_discount_amount); } else { @@ -702,7 +702,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { var actual_taxes_dict = {}; $.each(this.frm.doc["taxes"] || [], function(i, tax) { - if (in_list(["Actual", "On Item Quantity"], tax.charge_type)) { + if (["Actual", "On Item Quantity"].includes(tax.charge_type)) { var tax_amount = (tax.category == "Valuation") ? 0.0 : tax.tax_amount; tax_amount *= (tax.add_deduct_tax == "Deduct") ? -1.0 : 1.0; actual_taxes_dict[tax.idx] = tax_amount; @@ -747,7 +747,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { // NOTE: // paid_amount and write_off_amount is only for POS/Loyalty Point Redemption Invoice // total_advance is only for non POS Invoice - if(in_list(["Sales Invoice", "POS Invoice"], this.frm.doc.doctype) && this.frm.doc.is_return){ + if(["Sales Invoice", "POS Invoice"].includes(this.frm.doc.doctype) && this.frm.doc.is_return){ this.calculate_paid_amount(); } @@ -755,7 +755,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { frappe.model.round_floats_in(this.frm.doc, ["grand_total", "total_advance", "write_off_amount"]); - if(in_list(["Sales Invoice", "POS Invoice", "Purchase Invoice"], this.frm.doc.doctype)) { + if(["Sales Invoice", "POS Invoice", "Purchase Invoice"].includes(this.frm.doc.doctype)) { let grand_total = this.frm.doc.rounded_total || this.frm.doc.grand_total; let base_grand_total = this.frm.doc.base_rounded_total || this.frm.doc.base_grand_total; @@ -778,7 +778,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { this.frm.refresh_field("base_paid_amount"); } - if(in_list(["Sales Invoice", "POS Invoice"], this.frm.doc.doctype)) { + if(["Sales Invoice", "POS Invoice"].includes(this.frm.doc.doctype)) { let total_amount_for_payment = (this.frm.doc.redeem_loyalty_points && this.frm.doc.loyalty_amount) ? flt(total_amount_to_pay - this.frm.doc.loyalty_amount, precision("base_grand_total")) : total_amount_to_pay; @@ -882,7 +882,7 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments { calculate_change_amount(){ this.frm.doc.change_amount = 0.0; this.frm.doc.base_change_amount = 0.0; - if(in_list(["Sales Invoice", "POS Invoice"], this.frm.doc.doctype) + if(["Sales Invoice", "POS Invoice"].includes(this.frm.doc.doctype) && this.frm.doc.paid_amount > this.frm.doc.grand_total && !this.frm.doc.is_return) { var payment_types = $.map(this.frm.doc.payments, function(d) { return d.type; }); diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 66ac9582b2dd..2d836ad1e2f3 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -260,7 +260,11 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe } setup_quality_inspection() { +<<<<<<< HEAD if(!in_list(["Delivery Note", "Sales Invoice", "Purchase Receipt", "Purchase Invoice"], this.frm.doc.doctype)) { +======= + if(!["Delivery Note", "Sales Invoice", "Purchase Receipt", "Purchase Invoice", "Subcontracting Receipt"].includes(this.frm.doc.doctype)) { +>>>>>>> d238751e6b (refactor: usage of in_list) return; } @@ -272,7 +276,11 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe this.frm.page.set_inner_btn_group_as_primary(__('Create')); } +<<<<<<< HEAD const inspection_type = in_list(["Purchase Receipt", "Purchase Invoice"], this.frm.doc.doctype) +======= + const inspection_type = ["Purchase Receipt", "Purchase Invoice", "Subcontracting Receipt"].includes(this.frm.doc.doctype) +>>>>>>> d238751e6b (refactor: usage of in_list) ? "Incoming" : "Outgoing"; let quality_inspection_field = this.frm.get_docfield("items", "quality_inspection"); @@ -304,7 +312,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe make_payment_request() { let me = this; - const payment_request_type = (in_list(['Sales Order', 'Sales Invoice'], this.frm.doc.doctype)) + const payment_request_type = (['Sales Order', 'Sales Invoice'].includes(this.frm.doc.doctype)) ? "Inward" : "Outward"; frappe.call({ @@ -417,7 +425,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe setup_sms() { var me = this; let blacklist = ['Purchase Invoice', 'BOM']; - if(this.frm.doc.docstatus===1 && !in_list(["Lost", "Stopped", "Closed"], this.frm.doc.status) + if(this.frm.doc.docstatus===1 && !["Lost", "Stopped", "Closed"].includes(this.frm.doc.status) && !blacklist.includes(this.frm.doctype)) { this.frm.page.add_menu_item(__('Send SMS'), function() { me.send_sms(); }); } @@ -691,6 +699,24 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe } } +<<<<<<< HEAD +======= + on_submit() { + if (["Purchase Invoice", "Sales Invoice"].includes(this.frm.doc.doctype) + && !this.frm.doc.update_stock) { + return; + } + + this.refresh_serial_batch_bundle_field(); + } + + refresh_serial_batch_bundle_field() { + frappe.route_hooks.after_submit = (frm_obj) => { + frm_obj.reload_doc(); + } + } + +>>>>>>> d238751e6b (refactor: usage of in_list) update_qty(cdt, cdn) { var valid_serial_nos = []; var serialnos = []; @@ -780,7 +806,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe } var set_party_account = function(set_pricing) { - if (in_list(["Sales Invoice", "Purchase Invoice"], me.frm.doc.doctype)) { + if (["Sales Invoice", "Purchase Invoice"].includes(me.frm.doc.doctype)) { if(me.frm.doc.doctype=="Sales Invoice") { var party_type = "Customer"; var party_account_field = 'debit_to'; @@ -815,7 +841,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe } if (frappe.meta.get_docfield(this.frm.doctype, "shipping_address") && - in_list(['Purchase Order', 'Purchase Receipt', 'Purchase Invoice'], this.frm.doctype)) { + ['Purchase Order', 'Purchase Receipt', 'Purchase Invoice'].includes(this.frm.doctype)) { erpnext.utils.get_shipping_address(this.frm, function() { set_party_account(set_pricing); }); @@ -1482,7 +1508,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe "doctype": me.frm.doc.doctype, "name": me.frm.doc.name, "is_return": cint(me.frm.doc.is_return), - "update_stock": in_list(['Sales Invoice', 'Purchase Invoice'], me.frm.doc.doctype) ? cint(me.frm.doc.update_stock) : 0, + "update_stock": ['Sales Invoice', 'Purchase Invoice'].includes(me.frm.doc.doctype) ? cint(me.frm.doc.update_stock) : 0, "conversion_factor": me.frm.doc.conversion_factor, "pos_profile": me.frm.doc.doctype == 'Sales Invoice' ? me.frm.doc.pos_profile : '', "coupon_code": me.frm.doc.coupon_code @@ -2126,7 +2152,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe get_method_for_payment() { var method = "erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry"; if(cur_frm.doc.__onload && cur_frm.doc.__onload.make_payment_via_journal_entry){ - if(in_list(['Sales Invoice', 'Purchase Invoice'], cur_frm.doc.doctype)){ + if(['Sales Invoice', 'Purchase Invoice'].includes( cur_frm.doc.doctype)){ method = "erpnext.accounts.doctype.journal_entry.journal_entry.get_payment_entry_against_invoice"; }else { method= "erpnext.accounts.doctype.journal_entry.journal_entry.get_payment_entry_against_order"; @@ -2351,6 +2377,7 @@ erpnext.show_serial_batch_selector = function (frm, d, callback, on_close, show_ } frappe.require("assets/erpnext/js/utils/serial_no_batch_selector.js", function() { +<<<<<<< HEAD new erpnext.SerialNoBatchSelector({ frm: frm, item: d, @@ -2361,6 +2388,28 @@ erpnext.show_serial_batch_selector = function (frm, d, callback, on_close, show_ callback: callback, on_close: on_close }, show_dialog); +======= + if (["Sales Invoice", "Delivery Note"].includes(frm.doc.doctype)) { + item_row.type_of_transaction = frm.doc.is_return ? "Inward" : "Outward"; + } else { + item_row.type_of_transaction = frm.doc.is_return ? "Outward" : "Inward"; + } + + new erpnext.SerialBatchPackageSelector(frm, item_row, (r) => { + if (r) { + let update_values = { + "serial_and_batch_bundle": r.name, + "qty": Math.abs(r.total_qty) + } + + if (r.warehouse) { + update_values[warehouse_field] = r.warehouse; + } + + frappe.model.set_value(item_row.doctype, item_row.name, update_values); + } + }); +>>>>>>> d238751e6b (refactor: usage of in_list) }); } diff --git a/erpnext/public/js/payment/payments.js b/erpnext/public/js/payment/payments.js index 0e5842053962..c91bb046a52f 100644 --- a/erpnext/public/js/payment/payments.js +++ b/erpnext/public/js/payment/payments.js @@ -218,7 +218,7 @@ erpnext.payments = class payments extends erpnext.stock.StockController { update_paid_amount(update_write_off) { var me = this; - if (in_list(["change_amount", "write_off_amount"], this.idx)) { + if (["change_amount", "write_off_amount"].includes(this.idx)) { var value = me.selected_mode.val(); if (me.idx == "change_amount") { me.change_amount(value); diff --git a/erpnext/public/js/sms_manager.js b/erpnext/public/js/sms_manager.js index d3147bb46002..63833da5af3f 100644 --- a/erpnext/public/js/sms_manager.js +++ b/erpnext/public/js/sms_manager.js @@ -28,11 +28,11 @@ erpnext.SMSManager = function SMSManager(doc) { "Purchase Receipt": "Items has been received against purchase receipt: " + doc.name, }; - if (in_list(["Sales Order", "Delivery Note", "Sales Invoice"], doc.doctype)) + if (["Sales Order", "Delivery Note", "Sales Invoice"].includes(doc.doctype)) this.show(doc.contact_person, "Customer", doc.customer, "", default_msg[doc.doctype]); else if (doc.doctype === "Quotation") this.show(doc.contact_person, "Customer", doc.party_name, "", default_msg[doc.doctype]); - else if (in_list(["Purchase Order", "Purchase Receipt"], doc.doctype)) + else if (["Purchase Order", "Purchase Receipt"].includes(doc.doctype)) this.show(doc.contact_person, "Supplier", doc.supplier, "", default_msg[doc.doctype]); else if (doc.doctype == "Lead") this.show("", "", "", doc.mobile_no, default_msg[doc.doctype]); else if (doc.doctype == "Opportunity") diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js index 801376b2ed7d..623941755d1b 100644 --- a/erpnext/public/js/utils/party.js +++ b/erpnext/public/js/utils/party.js @@ -14,10 +14,10 @@ erpnext.utils.get_party_details = function (frm, method, args, callback) { if (!args) { if ( (frm.doctype != "Purchase Order" && frm.doc.customer) || - (frm.doc.party_name && in_list(["Quotation", "Opportunity"], frm.doc.doctype)) + (frm.doc.party_name && ["Quotation", "Opportunity"].includes(frm.doc.doctype)) ) { let party_type = "Customer"; - if (frm.doc.quotation_to && in_list(["Lead", "Prospect"], frm.doc.quotation_to)) { + if (frm.doc.quotation_to && ["Lead", "Prospect"].includes(frm.doc.quotation_to)) { party_type = frm.doc.quotation_to; } diff --git a/erpnext/public/js/utils/sales_common.js b/erpnext/public/js/utils/sales_common.js new file mode 100644 index 000000000000..00df1c5c191a --- /dev/null +++ b/erpnext/public/js/utils/sales_common.js @@ -0,0 +1,510 @@ +// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +// License: GNU General Public License v3. See license.txt + +frappe.provide("erpnext.selling"); + +erpnext.sales_common = { + setup_selling_controller: function () { + erpnext.selling.SellingController = class SellingController extends erpnext.TransactionController { + setup() { + super.setup(); + this.toggle_enable_for_stock_uom("allow_to_edit_stock_uom_qty_for_sales"); + this.frm.email_field = "contact_email"; + } + + onload() { + super.onload(); + this.setup_queries(); + this.frm.set_query("shipping_rule", function () { + return { + filters: { + shipping_rule_type: "Selling", + }, + }; + }); + + this.frm.set_query("project", function (doc) { + return { + query: "erpnext.controllers.queries.get_project_name", + filters: { + customer: doc.customer, + }, + }; + }); + } + + 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); + + erpnext.accounts.dimensions.setup_dimension_filters(me.frm, me.frm.doctype); + + 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: me.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"); + } + + 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) { + if (doc.docstatus === 0 && doc.is_return && !doc.return_against) { + frappe.model.set_value(cdt, cdn, "incoming_rate", 0.0); + } + } + + 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 || this.frm.doc.docstatus === 1) 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) + ); + } + } + + set_dynamic_labels() { + super.set_dynamic_labels(); + this.set_product_bundle_help(this.frm.doc); + } + + set_product_bundle_help(doc) { + if (!this.frm.fields_dict.packing_list) return; + if ((doc.packed_items || []).length) { + $(this.frm.fields_dict.packing_list.row.wrapper).toggle(true); + + if (["Delivery Note", "Sales Invoice"].includes(doc.doctype)) { + var help_msg = + "
" + + __( + "For 'Product Bundle' 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 'Product Bundle' item, those values can be entered in the main Item table, values will be copied to 'Packing List' table." + ) + + "
"; + frappe.meta.get_docfield(doc.doctype, "product_bundle_help", doc.name).options = + help_msg; + } + } else { + $(this.frm.fields_dict.packing_list.row.wrapper).toggle(false); + if (["Delivery Note", "Sales Invoice"].includes(doc.doctype)) { + frappe.meta.get_docfield(doc.doctype, "product_bundle_help", doc.name).options = ""; + } + } + refresh_field("product_bundle_help"); + } + + company_address() { + var me = this; + if (this.frm.doc.company_address) { + frappe.call({ + method: "frappe.contacts.doctype.address.address.get_address_display", + args: { address_dict: this.frm.doc.company_address }, + callback: function (r) { + if (r.message) { + me.frm.set_value("company_address_display", r.message); + } + }, + }); + } else { + this.frm.set_value("company_address_display", ""); + } + } + + conversion_factor(doc, cdt, cdn, dont_fetch_price_list_rate) { + super.conversion_factor(doc, cdt, cdn, dont_fetch_price_list_rate); + } + + qty(doc, cdt, cdn) { + super.qty(doc, cdt, cdn); + } + + pick_serial_and_batch(doc, cdt, cdn) { + let item = locals[cdt][cdn]; + let me = this; + let path = "assets/erpnext/js/utils/serial_no_batch_selector.js"; + + frappe.db.get_value("Item", item.item_code, ["has_batch_no", "has_serial_no"]).then((r) => { + if (r.message && (r.message.has_batch_no || r.message.has_serial_no)) { + item.has_serial_no = r.message.has_serial_no; + item.has_batch_no = r.message.has_batch_no; + item.type_of_transaction = item.qty > 0 ? "Outward" : "Inward"; + + item.title = item.has_serial_no ? __("Select Serial No") : __("Select Batch No"); + + if (item.has_serial_no && item.has_batch_no) { + item.title = __("Select Serial and Batch"); + } + + frappe.require(path, function () { + new erpnext.SerialBatchPackageSelector(me.frm, item, (r) => { + if (r) { + let qty = Math.abs(r.total_qty); + if (doc.is_return) { + qty = qty * -1; + } + + frappe.model.set_value(item.doctype, item.name, { + serial_and_batch_bundle: r.name, + use_serial_batch_fields: 0, + qty: + qty / + flt( + item.conversion_factor || 1, + precision("conversion_factor", item) + ), + }); + } + }); + }); + } + }); + } + + update_auto_repeat_reference(doc) { + if (doc.auto_repeat) { + frappe.call({ + method: "frappe.automation.doctype.auto_repeat.auto_repeat.update_reference", + args: { + docname: doc.auto_repeat, + reference: doc.name, + }, + callback: function (r) { + if (r.message == "success") { + frappe.show_alert({ + message: __("Auto repeat document updated"), + indicator: "green", + }); + } else { + frappe.show_alert({ + message: __("An error occurred during the update process"), + indicator: "red", + }); + } + }, + }); + } + } + + project() { + let me = this; + if (["Delivery Note", "Sales Invoice", "Sales Order"].includes(this.frm.doc.doctype)) { + if (this.frm.doc.project) { + frappe.call({ + method: "erpnext.projects.doctype.project.project.get_cost_center_name", + args: { project: this.frm.doc.project }, + callback: function (r, rt) { + if (!r.exc) { + $.each(me.frm.doc["items"] || [], function (i, row) { + if (r.message) { + frappe.model.set_value( + row.doctype, + row.name, + "cost_center", + r.message + ); + frappe.msgprint( + __( + "Cost Center For Item with Item Code {0} has been Changed to {1}", + [row.item_name, r.message] + ) + ); + } + }); + } + }, + }); + } + } + } + + coupon_code() { + this.frm.set_value("discount_amount", 0); + this.frm.set_value("additional_discount_percentage", 0); + } + }; + }, +}; + +erpnext.pre_sales = { + set_as_lost: function (doctype) { + frappe.ui.form.on(doctype, { + set_as_lost_dialog: function (frm) { + var dialog = new frappe.ui.Dialog({ + title: __("Set as Lost"), + fields: [ + { + fieldtype: "Table MultiSelect", + label: __("Lost Reasons"), + fieldname: "lost_reason", + options: + frm.doctype === "Opportunity" + ? "Opportunity Lost Reason Detail" + : "Quotation Lost Reason Detail", + reqd: 1, + }, + { + fieldtype: "Table MultiSelect", + label: __("Competitors"), + fieldname: "competitors", + options: "Competitor Detail", + }, + { + fieldtype: "Small Text", + label: __("Detailed Reason"), + fieldname: "detailed_reason", + }, + ], + primary_action: function () { + let values = dialog.get_values(); + + frm.call({ + doc: frm.doc, + method: "declare_enquiry_lost", + args: { + lost_reasons_list: values.lost_reason, + competitors: values.competitors ? values.competitors : [], + detailed_reason: values.detailed_reason, + }, + callback: function (r) { + dialog.hide(); + frm.reload_doc(); + }, + }); + }, + primary_action_label: __("Declare Lost"), + }); + + dialog.show(); + }, + }); + }, +}; diff --git a/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.js b/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.js index 5fbb5cb7e010..7aa8012f0b6f 100644 --- a/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.js +++ b/erpnext/regional/doctype/import_supplier_invoice/import_supplier_invoice.js @@ -34,7 +34,7 @@ frappe.ui.form.on("Import Supplier Invoice", { }, toggle_read_only_fields: function (frm) { - if (in_list(["File Import Completed", "Processing File Data"], frm.doc.status)) { + if (["File Import Completed", "Processing File Data"].includes(frm.doc.status)) { cur_frm.set_read_only(); cur_frm.refresh_fields(); frm.set_df_property("import_invoices", "hidden", 1); diff --git a/erpnext/selling/page/point_of_sale/pos_past_order_summary.js b/erpnext/selling/page/point_of_sale/pos_past_order_summary.js index 53fedbf56cf3..a408417c1194 100644 --- a/erpnext/selling/page/point_of_sale/pos_past_order_summary.js +++ b/erpnext/selling/page/point_of_sale/pos_past_order_summary.js @@ -73,7 +73,7 @@ erpnext.PointOfSale.PastOrderSummary = class { const { status } = doc; let indicator_color = ""; - in_list(["Paid", "Consolidated"], status) && (indicator_color = "green"); + ["Paid", "Consolidated"].includes(status) && (indicator_color = "green"); status === "Draft" && (indicator_color = "red"); status === "Return" && (indicator_color = "grey"); diff --git a/erpnext/stock/doctype/closing_stock_balance/closing_stock_balance.js b/erpnext/stock/doctype/closing_stock_balance/closing_stock_balance.js index 0f0221fa5623..aec752aec77b 100644 --- a/erpnext/stock/doctype/closing_stock_balance/closing_stock_balance.js +++ b/erpnext/stock/doctype/closing_stock_balance/closing_stock_balance.js @@ -8,7 +8,7 @@ frappe.ui.form.on("Closing Stock Balance", { }, generate_closing_balance(frm) { - if (in_list(["Queued", "Failed"], frm.doc.status)) { + if (["Queued", "Failed"].includes(frm.doc.status)) { frm.add_custom_button(__("Generate Closing Stock Balance"), () => { frm.call({ method: "enqueue_job", diff --git a/erpnext/stock/doctype/delivery_trip/delivery_trip_list.js b/erpnext/stock/doctype/delivery_trip/delivery_trip_list.js index 230107caadbb..65a1be332241 100644 --- a/erpnext/stock/doctype/delivery_trip/delivery_trip_list.js +++ b/erpnext/stock/doctype/delivery_trip/delivery_trip_list.js @@ -1,9 +1,9 @@ frappe.listview_settings["Delivery Trip"] = { add_fields: ["status"], get_indicator: function (doc) { - if (in_list(["Cancelled", "Draft"], doc.status)) { + if (["Cancelled", "Draft"].includes(doc.status)) { return [__(doc.status), "red", "status,=," + doc.status]; - } else if (in_list(["In Transit", "Scheduled"], doc.status)) { + } else if (["In Transit", "Scheduled"].includes(doc.status)) { return [__(doc.status), "orange", "status,=," + doc.status]; } else if (doc.status === "Completed") { return [__(doc.status), "green", "status,=," + doc.status]; diff --git a/erpnext/templates/form_grid/item_grid.html b/erpnext/templates/form_grid/item_grid.html index c596890aa32a..e78b42d66197 100644 --- a/erpnext/templates/form_grid/item_grid.html +++ b/erpnext/templates/form_grid/item_grid.html @@ -17,8 +17,13 @@ title = "Warehouse", actual_qty = (frm.doc.doctype==="Sales Order" ? doc.projected_qty : doc.actual_qty); +<<<<<<< HEAD if(flt(frm.doc.per_delivered) < 100 && in_list(["Sales Order Item", "Delivery Note Item"], doc.doctype)) { +======= + if(flt(frm.doc.per_delivered, 2) < 100 + && ["Sales Order Item", "Delivery Note Item"].includes(doc.doctype)) { +>>>>>>> d238751e6b (refactor: usage of in_list) if(actual_qty != undefined) { if(actual_qty >= doc.qty) { var color = "green"; From 3b2044dcd768ad290907a524d8b021a468f35164 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Tue, 19 Mar 2024 12:46:14 +0100 Subject: [PATCH 02/19] chore: resolve conflicts --- .../doctype/payment_entry/payment_entry.js | 60 +-- .../doctype/sales_invoice/sales_invoice.js | 2 +- .../doctype/purchase_order/purchase_order.js | 19 +- erpnext/public/js/account_tree_grid.js | 2 +- erpnext/public/js/controllers/accounts.js | 55 +-- erpnext/public/js/controllers/buying.js | 401 +----------------- erpnext/public/js/controllers/transaction.js | 53 +-- erpnext/selling/sales_common.js | 12 +- .../stock/doctype/stock_entry/stock_entry.js | 2 +- erpnext/templates/form_grid/item_grid.html | 5 - 10 files changed, 20 insertions(+), 591 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index 8ad31e1e7915..33478a54e396 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -21,14 +21,8 @@ frappe.ui.form.on('Payment Entry', { frm.set_query("paid_from", function() { frm.events.validate_company(frm); -<<<<<<< HEAD - var account_types = in_list(["Pay", "Internal Transfer"], frm.doc.payment_type) ? + var account_types = ["Pay", "Internal Transfer"].includes(frm.doc.payment_type) ? ["Bank", "Cash"] : [frappe.boot.party_account_types[frm.doc.party_type]]; -======= - var account_types = ["Pay", "Internal Transfer"].includes(frm.doc.payment_type) - ? ["Bank", "Cash"] - : [frappe.boot.party_account_types[frm.doc.party_type]]; ->>>>>>> d238751e6b (refactor: usage of in_list) return { filters: { "account_type": ["in", account_types], @@ -81,14 +75,8 @@ frappe.ui.form.on('Payment Entry', { frm.set_query("paid_to", function() { frm.events.validate_company(frm); -<<<<<<< HEAD - var account_types = in_list(["Receive", "Internal Transfer"], frm.doc.payment_type) ? + var account_types = ["Receive", "Internal Transfer"].includes(frm.doc.payment_type) ? ["Bank", "Cash"] : [frappe.boot.party_account_types[frm.doc.party_type]]; -======= - var account_types = ["Receive", "Internal Transfer"].includes(frm.doc.payment_type) - ? ["Bank", "Cash"] - : [frappe.boot.party_account_types[frm.doc.party_type]]; ->>>>>>> d238751e6b (refactor: usage of in_list) return { filters: { "account_type": ["in", account_types], @@ -133,14 +121,7 @@ frappe.ui.form.on('Payment Entry', { frm.set_query('payment_term', 'references', function(frm, cdt, cdn) { const child = locals[cdt][cdn]; -<<<<<<< HEAD - if (in_list(['Purchase Invoice', 'Sales Invoice'], child.reference_doctype) && child.reference_name) { -======= - if ( - ["Purchase Invoice", "Sales Invoice"].includes(child.reference_doctype) && - child.reference_name - ) { ->>>>>>> d238751e6b (refactor: usage of in_list) + if (['Purchase Invoice', 'Sales Invoice'].includes(child.reference_doctype) && child.reference_name) { return { query: "erpnext.controllers.queries.get_payment_terms_for_references", filters: { @@ -503,13 +484,8 @@ frappe.ui.form.on('Payment Entry', { if (frm.doc.paid_from_account_currency == company_currency) { frm.set_value("source_exchange_rate", 1); -<<<<<<< HEAD } else if (frm.doc.paid_from){ - if (in_list(["Internal Transfer", "Pay"], frm.doc.payment_type)) { -======= - } else if (frm.doc.paid_from) { if (["Internal Transfer", "Pay"].includes(frm.doc.payment_type)) { ->>>>>>> d238751e6b (refactor: usage of in_list) let company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency; frappe.call({ method: "erpnext.setup.utils.get_exchange_rate", @@ -876,19 +852,11 @@ frappe.ui.form.on('Payment Entry', { total_negative_outstanding : remaining_outstanding; } -<<<<<<< HEAD var allocated_positive_outstanding = paid_amount + allocated_negative_outstanding; - } else if (in_list(["Customer", "Supplier"], frm.doc.party_type)) { + } else if (["Customer", "Supplier"].includes(frm.doc.party_type)) { total_negative_outstanding = flt(total_negative_outstanding, precision("outstanding_amount")) if(paid_amount > total_negative_outstanding) { if(total_negative_outstanding == 0) { -======= - var allocated_positive_outstanding = paid_amount + allocated_negative_outstanding; - } else if (["Customer", "Supplier"].includes(frm.doc.party_type)) { - total_negative_outstanding = flt(total_negative_outstanding, precision("outstanding_amount")); - if (paid_amount > total_negative_outstanding) { - if (total_negative_outstanding == 0) { ->>>>>>> d238751e6b (refactor: usage of in_list) frappe.msgprint( __("Cannot {0} {1} {2} without any negative outstanding invoice", [frm.doc.payment_type, (frm.doc.party_type=="Customer" ? "to" : "from"), frm.doc.party_type]) @@ -1019,28 +987,16 @@ frappe.ui.form.on('Payment Entry', { return; } -<<<<<<< HEAD if(frm.doc.party_type=="Customer" && - !in_list(["Sales Order", "Sales Invoice", "Journal Entry", "Dunning"], row.reference_doctype) -======= - if ( - frm.doc.party_type == "Customer" && !["Sales Order", "Sales Invoice", "Journal Entry", "Dunning"].includes(row.reference_doctype) ->>>>>>> d238751e6b (refactor: usage of in_list) ) { frappe.model.set_value(row.doctype, row.name, "reference_doctype", null); frappe.msgprint(__("Row #{0}: Reference Document Type must be one of Sales Order, Sales Invoice, Journal Entry or Dunning", [row.idx])); return false; } -<<<<<<< HEAD if(frm.doc.party_type=="Supplier" && - !in_list(["Purchase Order", "Purchase Invoice", "Journal Entry"], row.reference_doctype) -======= - if ( - frm.doc.party_type == "Supplier" && !["Purchase Order", "Purchase Invoice", "Journal Entry"].includes(row.reference_doctype) ->>>>>>> d238751e6b (refactor: usage of in_list) ) { frappe.model.set_value(row.doctype, row.name, "against_voucher_type", null); frappe.msgprint(__("Row #{0}: Reference Document Type must be one of Purchase Order, Purchase Invoice or Journal Entry", [row.idx])); @@ -1122,15 +1078,9 @@ frappe.ui.form.on('Payment Entry', { } }, -<<<<<<< HEAD bank_account: function(frm) { const field = frm.doc.payment_type == "Pay" ? "paid_from":"paid_to"; - if (frm.doc.bank_account && in_list(['Pay', 'Receive'], frm.doc.payment_type)) { -======= - bank_account: function (frm) { - const field = frm.doc.payment_type == "Pay" ? "paid_from" : "paid_to"; - if (frm.doc.bank_account && ["Pay", "Receive"].includes(frm.doc.payment_type)) { ->>>>>>> d238751e6b (refactor: usage of in_list) + if (frm.doc.bank_account && ['Pay', 'Receive'].includes(frm.doc.payment_type)) { frappe.call({ method: "erpnext.accounts.doctype.bank_account.bank_account.get_bank_account_details", args: { diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index b2672424af9c..ad8578401470 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -200,7 +200,7 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends e if(cur_frm.meta._default_print_format) { cur_frm.meta.default_print_format = cur_frm.meta._default_print_format; cur_frm.meta._default_print_format = null; - } else if(in_list([cur_frm.pos_print_format, cur_frm.return_print_format], cur_frm.meta.default_print_format)) { + } else if([cur_frm.pos_print_format, cur_frm.return_print_format].includes(cur_frm.meta.default_print_format)) { cur_frm.meta.default_print_format = null; cur_frm.meta._default_print_format = null; } diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index a1a06489957f..2a96035f4b56 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -180,22 +180,11 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends e this.frm.fields_dict.items_section.wrapper.removeClass("hide-border"); } -<<<<<<< HEAD - if(!in_list(["Closed", "Delivered"], doc.status)) { + if(!["Closed", "Delivered"].includes(doc.status)) { if(this.frm.doc.status !== 'Closed' && flt(this.frm.doc.per_received) < 100 && flt(this.frm.doc.per_billed) < 100) { // Don't add Update Items button if the PO is following the new subcontracting flow. if (!(this.frm.doc.is_subcontracted && !this.frm.doc.is_old_subcontracting_flow)) { this.frm.add_custom_button(__('Update Items'), () => { -======= - if (!["Closed", "Delivered"].includes(doc.status)) { - if ( - this.frm.doc.status !== "Closed" && - flt(this.frm.doc.per_received, 2) < 100 && - flt(this.frm.doc.per_billed, 2) < 100 - ) { - if (!this.frm.doc.__onload || this.frm.doc.__onload.can_update_items) { - this.frm.add_custom_button(__("Update Items"), () => { ->>>>>>> d238751e6b (refactor: usage of in_list) erpnext.utils.update_child_items({ frm: this.frm, child_docname: "items", @@ -222,11 +211,7 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends e this.frm.page.set_inner_btn_group_as_primary(__("Status")); } -<<<<<<< HEAD - } else if(in_list(["Closed", "Delivered"], doc.status)) { -======= - } else if (["Closed", "Delivered"].includes(doc.status)) { ->>>>>>> d238751e6b (refactor: usage of in_list) + } else if(["Closed", "Delivered"].includes(doc.status)) { if (this.frm.has_perm("submit")) { this.frm.add_custom_button(__('Re-open'), () => this.unclose_purchase_order(), __("Status")); } diff --git a/erpnext/public/js/account_tree_grid.js b/erpnext/public/js/account_tree_grid.js index 6b4cdf1177a3..1d4596ba1a41 100644 --- a/erpnext/public/js/account_tree_grid.js +++ b/erpnext/public/js/account_tree_grid.js @@ -240,7 +240,7 @@ erpnext.AccountTreeGrid = class AccountTreeGrid extends frappe.views.TreeGridRep flt(account.closing_dr) - flt(account.closing_cr); me.set_debit_or_credit(parent_account, "closing", bal); - } else if (in_list(["debit", "credit"], col.field)) { + } else if (["debit", "credit"].includes(col.field)) { parent_account[col.field] = flt(parent_account[col.field]) + flt(account[col.field]); } diff --git a/erpnext/public/js/controllers/accounts.js b/erpnext/public/js/controllers/accounts.js index 830034182660..1ba941ab6f7d 100644 --- a/erpnext/public/js/controllers/accounts.js +++ b/erpnext/public/js/controllers/accounts.js @@ -5,66 +5,13 @@ frappe.provide("erpnext.taxes"); frappe.provide("erpnext.taxes.flags"); -<<<<<<< HEAD frappe.ui.form.on(cur_frm.doctype, { setup: function(frm) { // set conditional display for rate column in taxes $(frm.wrapper).on('grid-row-render', function(e, grid_row) { - if(in_list(['Sales Taxes and Charges', 'Purchase Taxes and Charges'], grid_row.doc.doctype)) { + if(['Sales Taxes and Charges', 'Purchase Taxes and Charges'].includes(grid_row.doc.doctype)) { erpnext.taxes.set_conditional_mandatory_rate_or_amount(grid_row); } -======= -erpnext.accounts.taxes = { - setup_tax_validations: function(doctype) { - let me = this; - frappe.ui.form.on(doctype, { - setup: function(frm) { - // set conditional display for rate column in taxes - $(frm.wrapper).on('grid-row-render', function(e, grid_row) { - if(['Sales Taxes and Charges', 'Purchase Taxes and Charges'].includes(grid_row.doc.doctype)) { - me.set_conditional_mandatory_rate_or_amount(grid_row); - } - }); - }, - onload: function(frm) { - if(frm.get_field("taxes")) { - frm.set_query("account_head", "taxes", function(doc) { - if(frm.cscript.tax_table == "Sales Taxes and Charges") { - var account_type = ["Tax", "Chargeable", "Expense Account"]; - } else { - var account_type = ["Tax", "Chargeable", "Income Account", "Expenses Included In Valuation"]; - } - - return { - query: "erpnext.controllers.queries.tax_account_query", - filters: { - "account_type": account_type, - "company": doc.company, - } - } - }); - frm.set_query("cost_center", "taxes", function(doc) { - return { - filters: { - "company": doc.company, - "is_group": 0 - } - }; - }); - } - }, - validate: function(frm) { - // neither is absolutely mandatory - if(frm.get_docfield("taxes")) { - frm.get_docfield("taxes", "rate").reqd = 0; - frm.get_docfield("taxes", "tax_amount").reqd = 0; - } - - }, - taxes_on_form_rendered: function(frm) { - me.set_conditional_mandatory_rate_or_amount(frm.open_grid_row()); - }, ->>>>>>> d238751e6b (refactor: usage of in_list) }); }, onload: function(frm) { diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js index ab2a476a1d4b..aa7dfbd90d68 100644 --- a/erpnext/public/js/controllers/buying.js +++ b/erpnext/public/js/controllers/buying.js @@ -9,408 +9,9 @@ cur_frm.cscript.tax_table = "Purchase Taxes and Charges"; cur_frm.email_field = "contact_email"; -<<<<<<< HEAD erpnext.buying.BuyingController = class BuyingController extends erpnext.TransactionController { setup() { super.setup(); -======= - if (this.frm.doc.__islocal - && frappe.meta.has_field(this.frm.doc.doctype, "disable_rounded_total")) { - - var df = frappe.meta.get_docfield(this.frm.doc.doctype, "disable_rounded_total"); - var disable = cint(df.default) || cint(frappe.sys_defaults.disable_rounded_total); - this.frm.set_value("disable_rounded_total", disable); - } - - - // no idea where me is coming from - if(this.frm.get_field('shipping_address')) { - this.frm.set_query("shipping_address", () => { - if(this.frm.doc.customer) { - return { - query: 'frappe.contacts.doctype.address.address.address_query', - filters: { link_doctype: 'Customer', link_name: this.frm.doc.customer } - }; - } else - return erpnext.queries.company_address_query(this.frm.doc) - }); - } - } - - setup_queries(doc, cdt, cdn) { - var me = this; - - if(this.frm.fields_dict.buying_price_list) { - this.frm.set_query("buying_price_list", function() { - return{ - filters: { 'buying': 1 } - } - }); - } - - if(this.frm.fields_dict.tc_name) { - this.frm.set_query("tc_name", function() { - return{ - filters: { 'buying': 1 } - } - }); - } - - me.frm.set_query('supplier', erpnext.queries.supplier); - me.frm.set_query('contact_person', erpnext.queries.contact_query); - me.frm.set_query('supplier_address', erpnext.queries.address_query); - - me.frm.set_query('billing_address', erpnext.queries.company_address_query); - erpnext.accounts.dimensions.setup_dimension_filters(me.frm, me.frm.doctype); - - this.frm.set_query("item_code", "items", function() { - if (me.frm.doc.is_subcontracted) { - var filters = {'supplier': me.frm.doc.supplier}; - if (me.frm.doc.is_old_subcontracting_flow) { - filters["is_sub_contracted_item"] = 1; - } - else { - filters["is_stock_item"] = 0; - } - - return{ - query: "erpnext.controllers.queries.item_query", - filters: filters - } - } - else { - return{ - query: "erpnext.controllers.queries.item_query", - filters: { 'supplier': me.frm.doc.supplier, 'is_purchase_item': 1, 'has_variants': 0} - } - } - }); - - - this.frm.set_query("manufacturer", "items", function(doc, cdt, cdn) { - const row = locals[cdt][cdn]; - return { - query: "erpnext.controllers.queries.item_manufacturer_query", - filters:{ 'item_code': row.item_code } - } - }); - - 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(doc) { - frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'supplier', doctype: 'Supplier'}; - - this.frm.toggle_display("supplier_name", - (this.frm.doc.supplier_name && this.frm.doc.supplier_name!==this.frm.doc.supplier)); - - if(this.frm.doc.docstatus==0 && - (this.frm.doctype==="Purchase Order" || this.frm.doctype==="Material Request")) { - this.set_from_product_bundle(); - } - - this.toggle_subcontracting_fields(); - super.refresh(); - } - - toggle_subcontracting_fields() { - if (['Purchase Receipt', 'Purchase Invoice'].includes(this.frm.doc.doctype)) { - this.frm.fields_dict.supplied_items.grid.update_docfield_property('consumed_qty', - 'read_only', this.frm.doc.__onload && this.frm.doc.__onload.backflush_based_on === 'BOM'); - - this.frm.set_df_property('supplied_items', 'cannot_add_rows', 1); - this.frm.set_df_property('supplied_items', 'cannot_delete_rows', 1); - } - } - - supplier() { - var me = this; - erpnext.utils.get_party_details(this.frm, null, null, function(){ - me.apply_price_list(); - }); - } - - supplier_address() { - erpnext.utils.get_address_display(this.frm); - erpnext.utils.set_taxes_from_address(this.frm, "supplier_address", "supplier_address", "supplier_address"); - } - - buying_price_list() { - this.apply_price_list(); - } - - discount_percentage(doc, cdt, cdn) { - var item = frappe.get_doc(cdt, cdn); - item.discount_amount = 0.0; - this.price_list_rate(doc, cdt, cdn); - } - - discount_amount(doc, cdt, cdn) { - var item = frappe.get_doc(cdt, cdn); - item.discount_percentage = 0.0; - this.price_list_rate(doc, cdt, cdn); - } - - qty(doc, cdt, cdn) { - if ((doc.doctype == "Purchase Receipt") || (doc.doctype == "Purchase Invoice" && (doc.update_stock || doc.is_return))) { - this.calculate_received_qty(doc, cdt, cdn) - } - super.qty(doc, cdt, cdn); - } - - rejected_qty(doc, cdt, cdn) { - this.calculate_received_qty(doc, cdt, cdn) - } - - calculate_received_qty(doc, cdt, cdn){ - var item = frappe.get_doc(cdt, cdn); - frappe.model.round_floats_in(item, ["qty", "rejected_qty"]); - - if(!doc.is_return && this.validate_negative_quantity(cdt, cdn, item, ["qty", "rejected_qty"])){ return } - - let received_qty = flt(item.qty + item.rejected_qty, precision("received_qty", item)); - let received_stock_qty = flt(item.conversion_factor, precision("conversion_factor", item)) * flt(received_qty); - - frappe.model.set_value(cdt, cdn, "received_qty", received_qty); - frappe.model.set_value(cdt, cdn, "received_stock_qty", received_stock_qty); - } - - batch_no(doc, cdt, cdn) { - super.batch_no(doc, cdt, cdn); - } - - validate_negative_quantity(cdt, cdn, item, fieldnames){ - if(!item || !fieldnames) { return } - - var is_negative_qty = false; - for(var i = 0; i{0} is invalid", [row.manufacturer_part_no]), - title: __("Invalid Part Number") - } - frappe.throw(msg); - } - } - ); - } - } - - add_serial_batch_bundle(doc, cdt, cdn) { - let item = locals[cdt][cdn]; - let me = this; - let path = "assets/erpnext/js/utils/serial_no_batch_selector.js"; - - frappe.db.get_value("Item", item.item_code, ["has_batch_no", "has_serial_no"]) - .then((r) => { - if (r.message && (r.message.has_batch_no || r.message.has_serial_no)) { - item.has_serial_no = r.message.has_serial_no; - item.has_batch_no = r.message.has_batch_no; - item.type_of_transaction = item.qty > 0 ? "Inward" : "Outward"; - item.is_rejected = false; - - frappe.require(path, function() { - new erpnext.SerialBatchPackageSelector( - me.frm, item, (r) => { - if (r) { - let qty = Math.abs(r.total_qty); - if (doc.is_return) { - qty = qty * -1; - } - - let update_values = { - "serial_and_batch_bundle": r.name, - "use_serial_batch_fields": 0, - "qty": qty / flt(item.conversion_factor || 1, precision("conversion_factor", item)) - } - - if (r.warehouse) { - update_values["warehouse"] = r.warehouse; - } - - frappe.model.set_value(item.doctype, item.name, update_values); - } - } - ); - }); - } - }); - } - - add_serial_batch_for_rejected_qty(doc, cdt, cdn) { - let item = locals[cdt][cdn]; - let me = this; - let path = "assets/erpnext/js/utils/serial_no_batch_selector.js"; - - frappe.db.get_value("Item", item.item_code, ["has_batch_no", "has_serial_no"]) - .then((r) => { - if (r.message && (r.message.has_batch_no || r.message.has_serial_no)) { - item.has_serial_no = r.message.has_serial_no; - item.has_batch_no = r.message.has_batch_no; - item.type_of_transaction = item.qty > 0 ? "Inward" : "Outward"; - item.is_rejected = true; - - frappe.require(path, function() { - new erpnext.SerialBatchPackageSelector( - me.frm, item, (r) => { - if (r) { - let qty = Math.abs(r.total_qty); - if (doc.is_return) { - qty = qty * -1; - } - - let update_values = { - "serial_and_batch_bundle": r.name, - "use_serial_batch_fields": 0, - "rejected_qty": qty / flt(item.conversion_factor || 1, precision("conversion_factor", item)) - } - - if (r.warehouse) { - update_values["rejected_warehouse"] = r.warehouse; - } - - frappe.model.set_value(item.doctype, item.name, update_values); - } - } - ); - }); - } - }); - } - }; ->>>>>>> d238751e6b (refactor: usage of in_list) } onload(doc, cdt, cdn) { @@ -535,7 +136,7 @@ erpnext.buying.BuyingController = class BuyingController extends erpnext.Transac } toggle_subcontracting_fields() { - if (in_list(['Purchase Receipt', 'Purchase Invoice'], this.frm.doc.doctype)) { + if (['Purchase Receipt', 'Purchase Invoice'].includes(this.frm.doc.doctype)) { this.frm.fields_dict.supplied_items.grid.update_docfield_property('consumed_qty', 'read_only', this.frm.doc.__onload && this.frm.doc.__onload.backflush_based_on === 'BOM'); diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 2d836ad1e2f3..e3e25499b846 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -260,11 +260,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe } setup_quality_inspection() { -<<<<<<< HEAD - if(!in_list(["Delivery Note", "Sales Invoice", "Purchase Receipt", "Purchase Invoice"], this.frm.doc.doctype)) { -======= - if(!["Delivery Note", "Sales Invoice", "Purchase Receipt", "Purchase Invoice", "Subcontracting Receipt"].includes(this.frm.doc.doctype)) { ->>>>>>> d238751e6b (refactor: usage of in_list) + if(!["Delivery Note", "Sales Invoice", "Purchase Receipt", "Purchase Invoice"].includes(this.frm.doc.doctype)) { return; } @@ -276,11 +272,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe this.frm.page.set_inner_btn_group_as_primary(__('Create')); } -<<<<<<< HEAD - const inspection_type = in_list(["Purchase Receipt", "Purchase Invoice"], this.frm.doc.doctype) -======= - const inspection_type = ["Purchase Receipt", "Purchase Invoice", "Subcontracting Receipt"].includes(this.frm.doc.doctype) ->>>>>>> d238751e6b (refactor: usage of in_list) + const inspection_type = ["Purchase Receipt", "Purchase Invoice"].includes(this.frm.doc.doctype) ? "Incoming" : "Outgoing"; let quality_inspection_field = this.frm.get_docfield("items", "quality_inspection"); @@ -699,24 +691,6 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe } } -<<<<<<< HEAD -======= - on_submit() { - if (["Purchase Invoice", "Sales Invoice"].includes(this.frm.doc.doctype) - && !this.frm.doc.update_stock) { - return; - } - - this.refresh_serial_batch_bundle_field(); - } - - refresh_serial_batch_bundle_field() { - frappe.route_hooks.after_submit = (frm_obj) => { - frm_obj.reload_doc(); - } - } - ->>>>>>> d238751e6b (refactor: usage of in_list) update_qty(cdt, cdn) { var valid_serial_nos = []; var serialnos = []; @@ -2377,7 +2351,6 @@ erpnext.show_serial_batch_selector = function (frm, d, callback, on_close, show_ } frappe.require("assets/erpnext/js/utils/serial_no_batch_selector.js", function() { -<<<<<<< HEAD new erpnext.SerialNoBatchSelector({ frm: frm, item: d, @@ -2388,28 +2361,6 @@ erpnext.show_serial_batch_selector = function (frm, d, callback, on_close, show_ callback: callback, on_close: on_close }, show_dialog); -======= - if (["Sales Invoice", "Delivery Note"].includes(frm.doc.doctype)) { - item_row.type_of_transaction = frm.doc.is_return ? "Inward" : "Outward"; - } else { - item_row.type_of_transaction = frm.doc.is_return ? "Outward" : "Inward"; - } - - new erpnext.SerialBatchPackageSelector(frm, item_row, (r) => { - if (r) { - let update_values = { - "serial_and_batch_bundle": r.name, - "qty": Math.abs(r.total_qty) - } - - if (r.warehouse) { - update_values[warehouse_field] = r.warehouse; - } - - frappe.model.set_value(item_row.doctype, item_row.name, update_values); - } - }); ->>>>>>> d238751e6b (refactor: usage of in_list) }); } diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js index b2a64a5d4611..ad2f1e5f282b 100644 --- a/erpnext/selling/sales_common.js +++ b/erpnext/selling/sales_common.js @@ -219,7 +219,7 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran serial_no: item.serial_no || "", }, callback:function(r){ - if (in_list(['Delivery Note', 'Sales Invoice'], doc.doctype)) { + if (['Delivery Note', 'Sales Invoice'].includes(doc.doctype)) { if (doc.doctype === 'Sales Invoice' && (!doc.update_stock)) return; if (has_batch_no) { me.set_batch_number(cdt, cdn); @@ -332,7 +332,7 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran if ((doc.packed_items || []).length) { $(cur_frm.fields_dict.packing_list.row.wrapper).toggle(true); - if (in_list(['Delivery Note', 'Sales Invoice'], doc.doctype)) { + if (['Delivery Note', 'Sales Invoice'].includes(doc.doctype)) { var help_msg = "
" + __("For 'Product Bundle' 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 'Product Bundle' item, those values can be entered in the main Item table, values will be copied to 'Packing List' table.")+ "
"; @@ -340,7 +340,7 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran } } else { $(cur_frm.fields_dict.packing_list.row.wrapper).toggle(false); - if (in_list(['Delivery Note', 'Sales Invoice'], doc.doctype)) { + if (['Delivery Note', 'Sales Invoice'].includes(doc.doctype)) { frappe.meta.get_docfield(doc.doctype, 'product_bundle_help', doc.name).options = ''; } } @@ -367,7 +367,7 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran conversion_factor(doc, cdt, cdn, dont_fetch_price_list_rate) { super.conversion_factor(doc, cdt, cdn, dont_fetch_price_list_rate); if(frappe.meta.get_docfield(cdt, "stock_qty", cdn) && - in_list(['Delivery Note', 'Sales Invoice'], doc.doctype)) { + ['Delivery Note', 'Sales Invoice'].includes(doc.doctype)) { if (doc.doctype === 'Sales Invoice' && (!doc.update_stock)) return; this.set_batch_number(cdt, cdn); } @@ -376,7 +376,7 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran qty(doc, cdt, cdn) { super.qty(doc, cdt, cdn); - if(in_list(['Delivery Note', 'Sales Invoice'], doc.doctype)) { + if(['Delivery Note', 'Sales Invoice'].includes(doc.doctype)) { if (doc.doctype === 'Sales Invoice' && (!doc.update_stock)) return; this.set_batch_number(cdt, cdn); } @@ -440,7 +440,7 @@ erpnext.selling.SellingController = class SellingController extends erpnext.Tran }; frappe.ui.form.on(cur_frm.doctype,"project", function(frm) { - if(in_list(["Delivery Note", "Sales Invoice"], frm.doc.doctype)) { + if(["Delivery Note", "Sales Invoice"].includes(frm.doc.doctype)) { if(frm.doc.project) { frappe.call({ method:'erpnext.projects.doctype.project.project.get_cost_center_name' , diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index b6459ba1e28e..d58361b2d3b3 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -77,7 +77,7 @@ frappe.ui.form.on('Stock Entry', { if(!item.item_code) { frappe.throw(__("Please enter Item Code to get Batch Number")); } else { - if (in_list(["Material Transfer for Manufacture", "Manufacture", "Repack", "Send to Subcontractor"], doc.purpose)) { + if (["Material Transfer for Manufacture", "Manufacture", "Repack", "Send to Subcontractor"].includes(doc.purpose)) { var filters = { 'item_code': item.item_code, 'posting_date': frm.doc.posting_date || frappe.datetime.nowdate() diff --git a/erpnext/templates/form_grid/item_grid.html b/erpnext/templates/form_grid/item_grid.html index e78b42d66197..449edd14e15e 100644 --- a/erpnext/templates/form_grid/item_grid.html +++ b/erpnext/templates/form_grid/item_grid.html @@ -17,13 +17,8 @@ title = "Warehouse", actual_qty = (frm.doc.doctype==="Sales Order" ? doc.projected_qty : doc.actual_qty); -<<<<<<< HEAD if(flt(frm.doc.per_delivered) < 100 - && in_list(["Sales Order Item", "Delivery Note Item"], doc.doctype)) { -======= - if(flt(frm.doc.per_delivered, 2) < 100 && ["Sales Order Item", "Delivery Note Item"].includes(doc.doctype)) { ->>>>>>> d238751e6b (refactor: usage of in_list) if(actual_qty != undefined) { if(actual_qty >= doc.qty) { var color = "green"; From d0a0a35d72f5cb809c793853fa7d125135a85e44 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Tue, 19 Mar 2024 12:53:20 +0100 Subject: [PATCH 03/19] chore: remove accidentally added file --- erpnext/public/js/utils/sales_common.js | 510 ------------------------ 1 file changed, 510 deletions(-) delete mode 100644 erpnext/public/js/utils/sales_common.js diff --git a/erpnext/public/js/utils/sales_common.js b/erpnext/public/js/utils/sales_common.js deleted file mode 100644 index 00df1c5c191a..000000000000 --- a/erpnext/public/js/utils/sales_common.js +++ /dev/null @@ -1,510 +0,0 @@ -// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -// License: GNU General Public License v3. See license.txt - -frappe.provide("erpnext.selling"); - -erpnext.sales_common = { - setup_selling_controller: function () { - erpnext.selling.SellingController = class SellingController extends erpnext.TransactionController { - setup() { - super.setup(); - this.toggle_enable_for_stock_uom("allow_to_edit_stock_uom_qty_for_sales"); - this.frm.email_field = "contact_email"; - } - - onload() { - super.onload(); - this.setup_queries(); - this.frm.set_query("shipping_rule", function () { - return { - filters: { - shipping_rule_type: "Selling", - }, - }; - }); - - this.frm.set_query("project", function (doc) { - return { - query: "erpnext.controllers.queries.get_project_name", - filters: { - customer: doc.customer, - }, - }; - }); - } - - 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); - - erpnext.accounts.dimensions.setup_dimension_filters(me.frm, me.frm.doctype); - - 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: me.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"); - } - - 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) { - if (doc.docstatus === 0 && doc.is_return && !doc.return_against) { - frappe.model.set_value(cdt, cdn, "incoming_rate", 0.0); - } - } - - 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 || this.frm.doc.docstatus === 1) 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) - ); - } - } - - set_dynamic_labels() { - super.set_dynamic_labels(); - this.set_product_bundle_help(this.frm.doc); - } - - set_product_bundle_help(doc) { - if (!this.frm.fields_dict.packing_list) return; - if ((doc.packed_items || []).length) { - $(this.frm.fields_dict.packing_list.row.wrapper).toggle(true); - - if (["Delivery Note", "Sales Invoice"].includes(doc.doctype)) { - var help_msg = - "
" + - __( - "For 'Product Bundle' 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 'Product Bundle' item, those values can be entered in the main Item table, values will be copied to 'Packing List' table." - ) + - "
"; - frappe.meta.get_docfield(doc.doctype, "product_bundle_help", doc.name).options = - help_msg; - } - } else { - $(this.frm.fields_dict.packing_list.row.wrapper).toggle(false); - if (["Delivery Note", "Sales Invoice"].includes(doc.doctype)) { - frappe.meta.get_docfield(doc.doctype, "product_bundle_help", doc.name).options = ""; - } - } - refresh_field("product_bundle_help"); - } - - company_address() { - var me = this; - if (this.frm.doc.company_address) { - frappe.call({ - method: "frappe.contacts.doctype.address.address.get_address_display", - args: { address_dict: this.frm.doc.company_address }, - callback: function (r) { - if (r.message) { - me.frm.set_value("company_address_display", r.message); - } - }, - }); - } else { - this.frm.set_value("company_address_display", ""); - } - } - - conversion_factor(doc, cdt, cdn, dont_fetch_price_list_rate) { - super.conversion_factor(doc, cdt, cdn, dont_fetch_price_list_rate); - } - - qty(doc, cdt, cdn) { - super.qty(doc, cdt, cdn); - } - - pick_serial_and_batch(doc, cdt, cdn) { - let item = locals[cdt][cdn]; - let me = this; - let path = "assets/erpnext/js/utils/serial_no_batch_selector.js"; - - frappe.db.get_value("Item", item.item_code, ["has_batch_no", "has_serial_no"]).then((r) => { - if (r.message && (r.message.has_batch_no || r.message.has_serial_no)) { - item.has_serial_no = r.message.has_serial_no; - item.has_batch_no = r.message.has_batch_no; - item.type_of_transaction = item.qty > 0 ? "Outward" : "Inward"; - - item.title = item.has_serial_no ? __("Select Serial No") : __("Select Batch No"); - - if (item.has_serial_no && item.has_batch_no) { - item.title = __("Select Serial and Batch"); - } - - frappe.require(path, function () { - new erpnext.SerialBatchPackageSelector(me.frm, item, (r) => { - if (r) { - let qty = Math.abs(r.total_qty); - if (doc.is_return) { - qty = qty * -1; - } - - frappe.model.set_value(item.doctype, item.name, { - serial_and_batch_bundle: r.name, - use_serial_batch_fields: 0, - qty: - qty / - flt( - item.conversion_factor || 1, - precision("conversion_factor", item) - ), - }); - } - }); - }); - } - }); - } - - update_auto_repeat_reference(doc) { - if (doc.auto_repeat) { - frappe.call({ - method: "frappe.automation.doctype.auto_repeat.auto_repeat.update_reference", - args: { - docname: doc.auto_repeat, - reference: doc.name, - }, - callback: function (r) { - if (r.message == "success") { - frappe.show_alert({ - message: __("Auto repeat document updated"), - indicator: "green", - }); - } else { - frappe.show_alert({ - message: __("An error occurred during the update process"), - indicator: "red", - }); - } - }, - }); - } - } - - project() { - let me = this; - if (["Delivery Note", "Sales Invoice", "Sales Order"].includes(this.frm.doc.doctype)) { - if (this.frm.doc.project) { - frappe.call({ - method: "erpnext.projects.doctype.project.project.get_cost_center_name", - args: { project: this.frm.doc.project }, - callback: function (r, rt) { - if (!r.exc) { - $.each(me.frm.doc["items"] || [], function (i, row) { - if (r.message) { - frappe.model.set_value( - row.doctype, - row.name, - "cost_center", - r.message - ); - frappe.msgprint( - __( - "Cost Center For Item with Item Code {0} has been Changed to {1}", - [row.item_name, r.message] - ) - ); - } - }); - } - }, - }); - } - } - } - - coupon_code() { - this.frm.set_value("discount_amount", 0); - this.frm.set_value("additional_discount_percentage", 0); - } - }; - }, -}; - -erpnext.pre_sales = { - set_as_lost: function (doctype) { - frappe.ui.form.on(doctype, { - set_as_lost_dialog: function (frm) { - var dialog = new frappe.ui.Dialog({ - title: __("Set as Lost"), - fields: [ - { - fieldtype: "Table MultiSelect", - label: __("Lost Reasons"), - fieldname: "lost_reason", - options: - frm.doctype === "Opportunity" - ? "Opportunity Lost Reason Detail" - : "Quotation Lost Reason Detail", - reqd: 1, - }, - { - fieldtype: "Table MultiSelect", - label: __("Competitors"), - fieldname: "competitors", - options: "Competitor Detail", - }, - { - fieldtype: "Small Text", - label: __("Detailed Reason"), - fieldname: "detailed_reason", - }, - ], - primary_action: function () { - let values = dialog.get_values(); - - frm.call({ - doc: frm.doc, - method: "declare_enquiry_lost", - args: { - lost_reasons_list: values.lost_reason, - competitors: values.competitors ? values.competitors : [], - detailed_reason: values.detailed_reason, - }, - callback: function (r) { - dialog.hide(); - frm.reload_doc(); - }, - }); - }, - primary_action_label: __("Declare Lost"), - }); - - dialog.show(); - }, - }); - }, -}; From 18b6d50a31207f1b7e089fe621f48214b4792b11 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Mon, 27 May 2024 17:39:46 +0200 Subject: [PATCH 04/19] fix: allow Auditor to select a company (cherry picked from commit 06401cc84fd0ffe8ab7e1cf7dec68544af72a3aa) # Conflicts: # erpnext/setup/doctype/company/company.json --- erpnext/setup/doctype/company/company.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json index 349c328c06c8..7b300d57195f 100644 --- a/erpnext/setup/doctype/company/company.json +++ b/erpnext/setup/doctype/company/company.json @@ -712,7 +712,11 @@ "image_field": "company_logo", "is_tree": 1, "links": [], +<<<<<<< HEAD "modified": "2023-10-23 10:19:24.322898", +======= + "modified": "2024-05-27 17:32:49.057386", +>>>>>>> 06401cc84f (fix: allow Auditor to select a company) "modified_by": "Administrator", "module": "Setup", "name": "Company", @@ -768,6 +772,10 @@ "role": "Accounts Manager", "share": 1, "write": 1 + }, + { + "role": "Auditor", + "select": 1 } ], "show_name_in_global_search": 1, From b1a911aa9ce2e339aa7b8054c4fd6eb6e4b24e4e Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Mon, 27 May 2024 17:40:08 +0200 Subject: [PATCH 05/19] fix: allow Auditor to read a Fiscal Year (cherry picked from commit eaa4efbc457678155efe710b1fc6bd12516dcb62) # Conflicts: # erpnext/accounts/doctype/fiscal_year/fiscal_year.json --- erpnext/accounts/doctype/fiscal_year/fiscal_year.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/erpnext/accounts/doctype/fiscal_year/fiscal_year.json b/erpnext/accounts/doctype/fiscal_year/fiscal_year.json index ff4ac50850f3..24962f2088e2 100644 --- a/erpnext/accounts/doctype/fiscal_year/fiscal_year.json +++ b/erpnext/accounts/doctype/fiscal_year/fiscal_year.json @@ -82,7 +82,11 @@ "icon": "fa fa-calendar", "idx": 1, "links": [], +<<<<<<< HEAD "modified": "2020-11-05 12:16:53.081573", +======= + "modified": "2024-05-27 17:29:55.560840", +>>>>>>> eaa4efbc45 (fix: allow Auditor to read a Fiscal Year) "modified_by": "Administrator", "module": "Accounts", "name": "Fiscal Year", @@ -126,6 +130,10 @@ { "read": 1, "role": "Stock Manager" + }, + { + "read": 1, + "role": "Auditor" } ], "show_name_in_global_search": 1, From a53a80f01d79d0d998405155edccbecbd8133a7b Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Mon, 27 May 2024 18:54:17 +0200 Subject: [PATCH 06/19] chore: resolve conflicts --- erpnext/accounts/doctype/fiscal_year/fiscal_year.json | 4 ---- erpnext/setup/doctype/company/company.json | 4 ---- 2 files changed, 8 deletions(-) diff --git a/erpnext/accounts/doctype/fiscal_year/fiscal_year.json b/erpnext/accounts/doctype/fiscal_year/fiscal_year.json index 24962f2088e2..496dd44ad86d 100644 --- a/erpnext/accounts/doctype/fiscal_year/fiscal_year.json +++ b/erpnext/accounts/doctype/fiscal_year/fiscal_year.json @@ -82,11 +82,7 @@ "icon": "fa fa-calendar", "idx": 1, "links": [], -<<<<<<< HEAD - "modified": "2020-11-05 12:16:53.081573", -======= "modified": "2024-05-27 17:29:55.560840", ->>>>>>> eaa4efbc45 (fix: allow Auditor to read a Fiscal Year) "modified_by": "Administrator", "module": "Accounts", "name": "Fiscal Year", diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json index 7b300d57195f..70a0872a2c4f 100644 --- a/erpnext/setup/doctype/company/company.json +++ b/erpnext/setup/doctype/company/company.json @@ -712,11 +712,7 @@ "image_field": "company_logo", "is_tree": 1, "links": [], -<<<<<<< HEAD - "modified": "2023-10-23 10:19:24.322898", -======= "modified": "2024-05-27 17:32:49.057386", ->>>>>>> 06401cc84f (fix: allow Auditor to select a company) "modified_by": "Administrator", "module": "Setup", "name": "Company", From 245c6d86720cc56c7068dc36634d981ab263f13a Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 12 Jun 2024 17:19:16 +0530 Subject: [PATCH 07/19] fix: allow Employee role to select Department (backport #41877) (#41880) * fix: allow Employee role to select Department (#41877) (cherry picked from commit 56082f5a2911f8f1766b504ff3b34f3ea949cf97) # Conflicts: # erpnext/setup/doctype/department/department.json * chore: fix conflicts --------- Co-authored-by: Rucha Mahabal --- erpnext/setup/doctype/department/department.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/erpnext/setup/doctype/department/department.json b/erpnext/setup/doctype/department/department.json index 99deca5c19d4..fa6b9ad4a552 100644 --- a/erpnext/setup/doctype/department/department.json +++ b/erpnext/setup/doctype/department/department.json @@ -90,7 +90,7 @@ "idx": 1, "is_tree": 1, "links": [], - "modified": "2023-08-28 17:26:46.826501", + "modified": "2024-06-12 16:10:31.451257", "modified_by": "Administrator", "module": "Setup", "name": "Department", @@ -132,6 +132,10 @@ "role": "HR Manager", "share": 1, "write": 1 + }, + { + "role": "Employee", + "select": 1 } ], "show_name_in_global_search": 1, From 6441bc78629d29d033b4038428b19a0a1b4dbf33 Mon Sep 17 00:00:00 2001 From: ljain112 Date: Mon, 10 Jun 2024 20:06:05 +0530 Subject: [PATCH 08/19] fix: regional overide for updating item valution (cherry picked from commit 1a10f0bcbd0d9d19e9267a0715b3a5e69c77f2c3) --- erpnext/controllers/buying_controller.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 89226453b7ff..364aadc8eae9 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -8,6 +8,7 @@ from frappe.utils import cint, cstr, flt, getdate from frappe.utils.data import nowtime +import erpnext from erpnext.accounts.doctype.budget.budget import validate_expense_against_budget from erpnext.accounts.party import get_party_details from erpnext.buying.utils import update_last_purchase_rate, validate_for_items @@ -305,6 +306,8 @@ def update_valuation_rate(self, reset_outgoing_rate=True): else: item.valuation_rate = 0.0 + update_regional_item_valuation_rate(self) + def set_incoming_rate(self): if self.doctype not in ("Purchase Receipt", "Purchase Invoice", "Purchase Order"): return @@ -894,3 +897,8 @@ def validate_item_type(doc, fieldname, message): ).format(items, message) frappe.throw(error_message) + + +@erpnext.allow_regional +def update_regional_item_valuation_rate(doc): + pass From 20b8ee1e904e7bffecf68bdbebec9638610da11d Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Thu, 29 Feb 2024 09:04:24 +0530 Subject: [PATCH 09/19] fix: add LCV flag to determine negative expenses (cherry picked from commit baa3fee1bf9ce814a889ecf264fb6bac4ebaf93c) # Conflicts: # erpnext/controllers/stock_controller.py --- erpnext/controllers/stock_controller.py | 32 ++++++++++++++++++- .../landed_cost_voucher.py | 2 +- .../purchase_receipt/purchase_receipt.py | 27 ++++++++-------- 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 410851817204..1fcde1119daa 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -51,7 +51,37 @@ def validate(self): self.validate_internal_transfer() self.validate_putaway_capacity() +<<<<<<< HEAD def make_gl_entries(self, gl_entries=None, from_repost=False): +======= + def validate_duplicate_serial_and_batch_bundle(self): + if sbb_list := [ + item.get("serial_and_batch_bundle") + for item in self.items + if item.get("serial_and_batch_bundle") + ]: + SLE = frappe.qb.DocType("Stock Ledger Entry") + data = ( + frappe.qb.from_(SLE) + .select(SLE.voucher_type, SLE.voucher_no, SLE.serial_and_batch_bundle) + .where( + (SLE.docstatus == 1) + & (SLE.serial_and_batch_bundle.notnull()) + & (SLE.serial_and_batch_bundle.isin(sbb_list)) + ) + .limit(1) + ).run(as_dict=True) + + if data: + data = data[0] + frappe.throw( + _("Serial and Batch Bundle {0} is already used in {1} {2}.").format( + frappe.bold(data.serial_and_batch_bundle), data.voucher_type, data.voucher_no + ) + ) + + def make_gl_entries(self, gl_entries=None, from_repost=False, via_landed_cost_voucher=False): +>>>>>>> baa3fee1bf (fix: add LCV flag to determine negative expenses) if self.docstatus == 2: make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name) @@ -72,7 +102,7 @@ def make_gl_entries(self, gl_entries=None, from_repost=False): if self.docstatus == 1: if not gl_entries: - gl_entries = self.get_gl_entries(warehouse_account) + gl_entries = self.get_gl_entries(warehouse_account, via_landed_cost_voucher) make_gl_entries(gl_entries, from_repost=from_repost) def validate_serialized_batch(self): diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py index f6b7e0d84353..77f3d2ba2b35 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py @@ -224,7 +224,7 @@ def update_landed_cost(self): # update stock & gl entries for submit state of PR doc.docstatus = 1 doc.update_stock_ledger(allow_negative_stock=True, via_landed_cost_voucher=True) - doc.make_gl_entries() + doc.make_gl_entries(via_landed_cost_voucher=True) doc.repost_future_sle_and_gle() def validate_asset_qty_and_status(self, receipt_document_type, receipt_document): diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index a6fd929ea349..7bbe7b9ff756 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -307,13 +307,13 @@ def on_cancel(self): self.delete_auto_created_batches() self.set_consumed_qty_in_subcontract_order() - def get_gl_entries(self, warehouse_account=None): + def get_gl_entries(self, warehouse_account=None, via_landed_cost_voucher=False): from erpnext.accounts.general_ledger import process_gl_map gl_entries = [] self.make_item_gl_entries(gl_entries, warehouse_account=warehouse_account) - self.make_tax_gl_entries(gl_entries) + self.make_tax_gl_entries(gl_entries, via_landed_cost_voucher) update_regional_gl_entries(gl_entries, self) return process_gl_map(gl_entries) @@ -661,7 +661,7 @@ def add_provisional_gl_entry( posting_date=posting_date, ) - def make_tax_gl_entries(self, gl_entries): + def make_tax_gl_entries(self, gl_entries, via_landed_cost_voucher=False): negative_expense_to_be_booked = sum([flt(d.item_tax_amount) for d in self.get("items")]) is_asset_pr = any(d.is_fixed_asset for d in self.get("items")) # Cost center-wise amount breakup for other charges included for valuation @@ -696,18 +696,17 @@ def make_tax_gl_entries(self, gl_entries): i = 1 for tax in self.get("taxes"): if valuation_tax.get(tax.name): - negative_expense_booked_in_pi = frappe.db.sql( - """select name from `tabPurchase Invoice Item` pi - where docstatus = 1 and purchase_receipt=%s - and exists(select name from `tabGL Entry` where voucher_type='Purchase Invoice' - and voucher_no=pi.parent and account=%s)""", - (self.name, tax.account_head), - ) - - if negative_expense_booked_in_pi: - account = stock_rbnb - else: + if via_landed_cost_voucher: account = tax.account_head + else: + negative_expense_booked_in_pi = frappe.db.sql( + """select name from `tabPurchase Invoice Item` pi + where docstatus = 1 and purchase_receipt=%s + and exists(select name from `tabGL Entry` where voucher_type='Purchase Invoice' + and voucher_no=pi.parent and account=%s)""", + (self.name, tax.account_head), + ) + account = stock_rbnb if negative_expense_booked_in_pi else tax.account_head if i == len(valuation_tax): applicable_amount = amount_including_divisional_loss From 7c699c8a385af20c0471071456aca5d2228bfc1e Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Thu, 29 Feb 2024 11:26:31 +0530 Subject: [PATCH 10/19] test: LCV entries after billing (cherry picked from commit 53642e7417c54197ba526625902d2671a7a564c2) # Conflicts: # erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py --- erpnext/controllers/stock_controller.py | 6 +- .../purchase_receipt/test_purchase_receipt.py | 133 +++++++++++++++++- 2 files changed, 131 insertions(+), 8 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 1fcde1119daa..e0c41ff1dfa8 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -102,7 +102,11 @@ def make_gl_entries(self, gl_entries=None, from_repost=False, via_landed_cost_vo if self.docstatus == 1: if not gl_entries: - gl_entries = self.get_gl_entries(warehouse_account, via_landed_cost_voucher) + gl_entries = ( + self.get_gl_entries(warehouse_account, via_landed_cost_voucher) + if self.doctype == "Purchase Receipt" + else self.get_gl_entries(warehouse_account) + ) make_gl_entries(gl_entries, from_repost=from_repost) def validate_serialized_batch(self): diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index b185fd471f92..e2639ac0815c 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -2301,6 +2301,115 @@ def test_sle_qty_after_transaction(self): for index, d in enumerate(data): self.assertEqual(d.qty_after_transaction, 11 + index) +<<<<<<< HEAD +======= + def test_auto_set_batch_based_on_bundle(self): + item_code = make_item( + "_Test Auto Set Batch Based on Bundle", + properties={ + "has_batch_no": 1, + "batch_number_series": "BATCH-BNU-TASBBB-.#####", + "create_new_batch": 1, + }, + ).name + + frappe.db.set_single_value( + "Stock Settings", "do_not_update_serial_batch_on_creation_of_auto_bundle", 0 + ) + + pr = make_purchase_receipt( + item_code=item_code, + qty=5, + rate=100, + ) + + self.assertTrue(pr.items[0].batch_no) + batch_no = get_batch_from_bundle(pr.items[0].serial_and_batch_bundle) + self.assertEqual(pr.items[0].batch_no, batch_no) + + frappe.db.set_single_value( + "Stock Settings", "do_not_update_serial_batch_on_creation_of_auto_bundle", 1 + ) + + def test_pr_billed_amount_against_return_entry(self): + from erpnext.accounts.doctype.purchase_invoice.purchase_invoice import make_debit_note + from erpnext.stock.doctype.purchase_receipt.purchase_receipt import ( + make_purchase_invoice as make_pi_from_pr, + ) + + # Create a Purchase Receipt and Fully Bill it + pr = make_purchase_receipt(qty=10) + pi = make_pi_from_pr(pr.name) + pi.insert() + pi.submit() + + # Debit Note - 50% Qty & enable updating PR billed amount + pi_return = make_debit_note(pi.name) + pi_return.items[0].qty = -5 + pi_return.update_billed_amount_in_purchase_receipt = 1 + pi_return.submit() + + # Check if the billed amount reduced + pr.reload() + self.assertEqual(pr.per_billed, 50) + + pi_return.reload() + pi_return.cancel() + + # Debit Note - 50% Qty & disable updating PR billed amount + pi_return = make_debit_note(pi.name) + pi_return.items[0].qty = -5 + pi_return.update_billed_amount_in_purchase_receipt = 0 + pi_return.submit() + + # Check if the billed amount stayed the same + pr.reload() + self.assertEqual(pr.per_billed, 100) + + def test_valuation_taxes_lcv_repost_after_billing(self): + from erpnext.stock.doctype.landed_cost_voucher.test_landed_cost_voucher import ( + make_landed_cost_voucher, + ) + + company = frappe.get_doc("Company", "_Test Company") + company.enable_perpetual_inventory = 1 + company.default_inventory_account = "Stock In Hand - _TC" + company.stock_received_but_not_billed = "Stock Received But Not Billed - _TC" + company.save() + + pr = make_purchase_receipt(qty=10, rate=1000, do_not_submit=1) + pr.append( + "taxes", + { + "category": "Valuation and Total", + "charge_type": "Actual", + "account_head": "Freight and Forwarding Charges - _TC", + "tax_amount": 2000, + "description": "Test", + }, + ) + pr.submit() + pi = make_purchase_invoice(pr.name) + pi.submit() + lcv = make_landed_cost_voucher( + company=pr.company, + receipt_document_type="Purchase Receipt", + receipt_document=pr.name, + charges=2000, + distribute_charges_based_on="Qty", + expense_account="Expenses Included In Valuation - _TC", + ) + + gl_entries = get_gl_entries("Purchase Receipt", pr.name, skip_cancelled=True, as_dict=False) + expected_gle = ( + ("Stock Received But Not Billed - _TC", 0, 10000, "Main - _TC"), + ("Stock In Hand - _TC", 14000, 0, "Main - _TC"), + ("Freight and Forwarding Charges - _TC", 0, 2000, "Main - _TC"), + ("Expenses Included In Valuation - _TC", 0, 2000, "Main - _TC"), + ) + self.assertSequenceEqual(expected_gle, gl_entries) + +>>>>>>> 53642e7417 (test: LCV entries after billing) def prepare_data_for_internal_transfer(): from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier @@ -2347,14 +2456,24 @@ def get_sl_entries(voucher_type, voucher_no): ) -def get_gl_entries(voucher_type, voucher_no): - return frappe.db.sql( - """select account, debit, credit, cost_center, is_cancelled - from `tabGL Entry` where voucher_type=%s and voucher_no=%s - order by account desc""", - (voucher_type, voucher_no), - as_dict=1, +def get_gl_entries(voucher_type, voucher_no, skip_cancelled=False, as_dict=True): + gl = frappe.qb.DocType("GL Entry") + gl_query = ( + frappe.qb.from_(gl) + .select( + gl.account, + gl.debit, + gl.credit, + gl.cost_center, + ) + .where((gl.voucher_type == voucher_type) & (gl.voucher_no == voucher_no)) + .orderby(gl.account, order=frappe.qb.desc) ) + if skip_cancelled: + gl_query = gl_query.where(gl.is_cancelled == 0) + else: + gl_query = gl_query.select(gl.is_cancelled) + return gl_query.run(as_dict=as_dict) def get_taxes(**args): From d48455393eef57570c5804012ee58d8604683982 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Thu, 29 Feb 2024 11:58:14 +0530 Subject: [PATCH 11/19] fix: parameters for PI references (cherry picked from commit 8b3d46610eacd27edbceaefff6452efb68a83365) --- .../stock/doctype/landed_cost_voucher/landed_cost_voucher.py | 5 ++++- .../stock/doctype/purchase_receipt/test_purchase_receipt.py | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py index 77f3d2ba2b35..81dea899f390 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py @@ -224,7 +224,10 @@ def update_landed_cost(self): # update stock & gl entries for submit state of PR doc.docstatus = 1 doc.update_stock_ledger(allow_negative_stock=True, via_landed_cost_voucher=True) - doc.make_gl_entries(via_landed_cost_voucher=True) + if d.receipt_document_type == "Purchase Receipt": + doc.make_gl_entries(via_landed_cost_voucher=True) + else: + doc.make_gl_entries() doc.repost_future_sle_and_gle() def validate_asset_qty_and_status(self, receipt_document_type, receipt_document): diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index e2639ac0815c..b1678aff7be4 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -2408,6 +2408,7 @@ def test_valuation_taxes_lcv_repost_after_billing(self): ("Expenses Included In Valuation - _TC", 0, 2000, "Main - _TC"), ) self.assertSequenceEqual(expected_gle, gl_entries) + frappe.db.rollback() >>>>>>> 53642e7417 (test: LCV entries after billing) From eae5f27ec814f143c1d19a37bc5773a7b0d7a7df Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Thu, 29 Feb 2024 13:04:01 +0530 Subject: [PATCH 12/19] fix: reset perpetual inventory flag after test (cherry picked from commit 0b36cbe307fec68f72ddfdfdeee401134887a884) --- .../purchase_receipt/test_purchase_receipt.py | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index b1678aff7be4..1379715b7b99 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -9,6 +9,7 @@ import erpnext from erpnext.accounts.doctype.account.test_account import get_inventory_account from erpnext.controllers.buying_controller import QtyMismatchError +from erpnext.stock import get_warehouse_account_map from erpnext.stock.doctype.item.test_item import create_item, make_item from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos @@ -1640,7 +1641,6 @@ def test_validate_received_qty_for_internal_pr(self): frappe.db.set_single_value("Stock Settings", "over_delivery_receipt_allowance", 0) def test_internal_pr_gl_entries(self): - from erpnext.stock import get_warehouse_account_map from erpnext.stock.doctype.delivery_note.delivery_note import make_inter_company_purchase_receipt from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry @@ -2371,11 +2371,14 @@ def test_valuation_taxes_lcv_repost_after_billing(self): make_landed_cost_voucher, ) - company = frappe.get_doc("Company", "_Test Company") - company.enable_perpetual_inventory = 1 - company.default_inventory_account = "Stock In Hand - _TC" - company.stock_received_but_not_billed = "Stock Received But Not Billed - _TC" - company.save() + old_perpetual_inventory = erpnext.is_perpetual_inventory_enabled("_Test Company") + frappe.local.enable_perpetual_inventory["_Test Company"] = 1 + frappe.db.set_value( + "Company", + "_Test Company", + "stock_received_but_not_billed", + "Stock Received But Not Billed - _TC", + ) pr = make_purchase_receipt(qty=10, rate=1000, do_not_submit=1) pr.append( @@ -2391,7 +2394,7 @@ def test_valuation_taxes_lcv_repost_after_billing(self): pr.submit() pi = make_purchase_invoice(pr.name) pi.submit() - lcv = make_landed_cost_voucher( + make_landed_cost_voucher( company=pr.company, receipt_document_type="Purchase Receipt", receipt_document=pr.name, @@ -2401,14 +2404,15 @@ def test_valuation_taxes_lcv_repost_after_billing(self): ) gl_entries = get_gl_entries("Purchase Receipt", pr.name, skip_cancelled=True, as_dict=False) + warehouse_account = get_warehouse_account_map("_Test Company") expected_gle = ( ("Stock Received But Not Billed - _TC", 0, 10000, "Main - _TC"), - ("Stock In Hand - _TC", 14000, 0, "Main - _TC"), ("Freight and Forwarding Charges - _TC", 0, 2000, "Main - _TC"), ("Expenses Included In Valuation - _TC", 0, 2000, "Main - _TC"), + (warehouse_account[pr.items[0].warehouse]["account"], 14000, 0, "Main - _TC"), ) self.assertSequenceEqual(expected_gle, gl_entries) - frappe.db.rollback() + frappe.local.enable_perpetual_inventory["_Test Company"] = old_perpetual_inventory >>>>>>> 53642e7417 (test: LCV entries after billing) From e8f5c45751aa6b1a1bf7251d123df5ceaff74d1f Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Sun, 21 Apr 2024 19:07:08 +0530 Subject: [PATCH 13/19] chore: resolve conflicts (cherry picked from commit 54a58e9205af43f4aabe1668e8d8cf925a226536) --- .../stock/doctype/landed_cost_voucher/landed_cost_voucher.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py index 81dea899f390..abfa604e2f3e 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py @@ -228,7 +228,7 @@ def update_landed_cost(self): doc.make_gl_entries(via_landed_cost_voucher=True) else: doc.make_gl_entries() - doc.repost_future_sle_and_gle() + doc.repost_future_sle_and_gle(via_landed_cost_voucher=True) def validate_asset_qty_and_status(self, receipt_document_type, receipt_document): for item in self.get("items"): From b050110544de6adf73bb02861fd63b6399b62efc Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Sun, 16 Jun 2024 20:37:05 +0530 Subject: [PATCH 14/19] chore: resolve conflicts --- erpnext/controllers/stock_controller.py | 30 --------- .../landed_cost_voucher.py | 2 +- .../purchase_receipt/test_purchase_receipt.py | 66 ------------------- 3 files changed, 1 insertion(+), 97 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index e0c41ff1dfa8..a4d8e3efee16 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -51,37 +51,7 @@ def validate(self): self.validate_internal_transfer() self.validate_putaway_capacity() -<<<<<<< HEAD - def make_gl_entries(self, gl_entries=None, from_repost=False): -======= - def validate_duplicate_serial_and_batch_bundle(self): - if sbb_list := [ - item.get("serial_and_batch_bundle") - for item in self.items - if item.get("serial_and_batch_bundle") - ]: - SLE = frappe.qb.DocType("Stock Ledger Entry") - data = ( - frappe.qb.from_(SLE) - .select(SLE.voucher_type, SLE.voucher_no, SLE.serial_and_batch_bundle) - .where( - (SLE.docstatus == 1) - & (SLE.serial_and_batch_bundle.notnull()) - & (SLE.serial_and_batch_bundle.isin(sbb_list)) - ) - .limit(1) - ).run(as_dict=True) - - if data: - data = data[0] - frappe.throw( - _("Serial and Batch Bundle {0} is already used in {1} {2}.").format( - frappe.bold(data.serial_and_batch_bundle), data.voucher_type, data.voucher_no - ) - ) - def make_gl_entries(self, gl_entries=None, from_repost=False, via_landed_cost_voucher=False): ->>>>>>> baa3fee1bf (fix: add LCV flag to determine negative expenses) if self.docstatus == 2: make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name) diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py index abfa604e2f3e..81dea899f390 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py @@ -228,7 +228,7 @@ def update_landed_cost(self): doc.make_gl_entries(via_landed_cost_voucher=True) else: doc.make_gl_entries() - doc.repost_future_sle_and_gle(via_landed_cost_voucher=True) + doc.repost_future_sle_and_gle() def validate_asset_qty_and_status(self, receipt_document_type, receipt_document): for item in self.get("items"): diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 1379715b7b99..52dd85767f87 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -2301,71 +2301,6 @@ def test_sle_qty_after_transaction(self): for index, d in enumerate(data): self.assertEqual(d.qty_after_transaction, 11 + index) -<<<<<<< HEAD -======= - def test_auto_set_batch_based_on_bundle(self): - item_code = make_item( - "_Test Auto Set Batch Based on Bundle", - properties={ - "has_batch_no": 1, - "batch_number_series": "BATCH-BNU-TASBBB-.#####", - "create_new_batch": 1, - }, - ).name - - frappe.db.set_single_value( - "Stock Settings", "do_not_update_serial_batch_on_creation_of_auto_bundle", 0 - ) - - pr = make_purchase_receipt( - item_code=item_code, - qty=5, - rate=100, - ) - - self.assertTrue(pr.items[0].batch_no) - batch_no = get_batch_from_bundle(pr.items[0].serial_and_batch_bundle) - self.assertEqual(pr.items[0].batch_no, batch_no) - - frappe.db.set_single_value( - "Stock Settings", "do_not_update_serial_batch_on_creation_of_auto_bundle", 1 - ) - - def test_pr_billed_amount_against_return_entry(self): - from erpnext.accounts.doctype.purchase_invoice.purchase_invoice import make_debit_note - from erpnext.stock.doctype.purchase_receipt.purchase_receipt import ( - make_purchase_invoice as make_pi_from_pr, - ) - - # Create a Purchase Receipt and Fully Bill it - pr = make_purchase_receipt(qty=10) - pi = make_pi_from_pr(pr.name) - pi.insert() - pi.submit() - - # Debit Note - 50% Qty & enable updating PR billed amount - pi_return = make_debit_note(pi.name) - pi_return.items[0].qty = -5 - pi_return.update_billed_amount_in_purchase_receipt = 1 - pi_return.submit() - - # Check if the billed amount reduced - pr.reload() - self.assertEqual(pr.per_billed, 50) - - pi_return.reload() - pi_return.cancel() - - # Debit Note - 50% Qty & disable updating PR billed amount - pi_return = make_debit_note(pi.name) - pi_return.items[0].qty = -5 - pi_return.update_billed_amount_in_purchase_receipt = 0 - pi_return.submit() - - # Check if the billed amount stayed the same - pr.reload() - self.assertEqual(pr.per_billed, 100) - def test_valuation_taxes_lcv_repost_after_billing(self): from erpnext.stock.doctype.landed_cost_voucher.test_landed_cost_voucher import ( make_landed_cost_voucher, @@ -2414,7 +2349,6 @@ def test_valuation_taxes_lcv_repost_after_billing(self): self.assertSequenceEqual(expected_gle, gl_entries) frappe.local.enable_perpetual_inventory["_Test Company"] = old_perpetual_inventory ->>>>>>> 53642e7417 (test: LCV entries after billing) def prepare_data_for_internal_transfer(): from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier From bcfc83d8d5ea45d9e01f75fb21ea05e4500289d6 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 17 Jun 2024 16:51:46 +0530 Subject: [PATCH 15/19] fix: reposting validation related PCV (cherry picked from commit 194f1dc67431c4b823289c9603de51d78a40dda8) --- .../repost_item_valuation.py | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py index e47c1f8aba7e..60a7707228d7 100644 --- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py +++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py @@ -45,7 +45,7 @@ def validate(self): def validate_period_closing_voucher(self): # Period Closing Voucher - year_end_date = self.get_max_year_end_date(self.company) + year_end_date = self.get_max_period_closing_date(self.company) if year_end_date and getdate(self.posting_date) <= getdate(year_end_date): date = frappe.format(year_end_date, "Date") msg = f"Due to period closing, you cannot repost item valuation before {date}" @@ -88,24 +88,16 @@ def get_closing_stock_balance(self): return frappe.get_all("Closing Stock Balance", fields=["name", "to_date"], filters=filters) @staticmethod - def get_max_year_end_date(company): - data = frappe.get_all( - "Period Closing Voucher", fields=["fiscal_year"], filters={"docstatus": 1, "company": company} - ) - - if not data: - return - - fiscal_years = [d.fiscal_year for d in data] - table = frappe.qb.DocType("Fiscal Year") + def get_max_period_closing_date(company): + table = frappe.qb.DocType("Period Closing Voucher") query = ( frappe.qb.from_(table) - .select(Max(table.year_end_date)) - .where((table.name.isin(fiscal_years)) & (table.disabled == 0)) + .select(Max(table.posting_date)) + .where((table.company == company) & (table.docstatus == 1)) ).run() - return query[0][0] if query else None + return query[0][0] if query and query[0][0] else None def validate_accounts_freeze(self): acc_settings = frappe.db.get_value( From f833923f2fcc5ce18847a93fe741db7e59a4d349 Mon Sep 17 00:00:00 2001 From: ljain112 Date: Fri, 14 Jun 2024 13:13:11 +0530 Subject: [PATCH 16/19] refactor: ignore unreconcile doc for PO and SO on cancel/delete (cherry picked from commit b618d685c62837657fe808d6c30dc3582a12d0ec) # Conflicts: # erpnext/buying/doctype/purchase_order/purchase_order.js # erpnext/selling/doctype/sales_order/sales_order.js --- erpnext/buying/doctype/purchase_order/purchase_order.js | 5 +++++ erpnext/buying/doctype/purchase_order/purchase_order.py | 8 +++++++- erpnext/selling/doctype/sales_order/sales_order.js | 8 ++++++++ erpnext/selling/doctype/sales_order/sales_order.py | 8 +++++++- 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index 52a0f4ac2a28..ced0b5fb4a11 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -6,8 +6,13 @@ frappe.provide("erpnext.accounts.dimensions"); {% include 'erpnext/public/js/controllers/buying.js' %}; frappe.ui.form.on("Purchase Order", { +<<<<<<< HEAD setup: function(frm) { +======= + setup: function (frm) { + frm.ignore_doctypes_on_cancel_all = ["Unreconcile Payment", "Unreconcile Payment Entries"]; +>>>>>>> b618d685c6 (refactor: ignore unreconcile doc for PO and SO on cancel/delete) if (frm.doc.is_old_subcontracting_flow) { frm.set_query("reserve_warehouse", "supplied_items", function() { return { diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 58d7440211ce..705e8fd6dd87 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -345,7 +345,13 @@ def on_submit(self): update_linked_doc(self.doctype, self.name, self.inter_company_order_reference) def on_cancel(self): - self.ignore_linked_doctypes = ("GL Entry", "Payment Ledger Entry") + self.ignore_linked_doctypes = ( + "GL Entry", + "Payment Ledger Entry", + "Unreconcile Payment", + "Unreconcile Payment Entries", + ) + super().on_cancel() if self.is_against_so(): diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index 2995a1e99bce..d0f85790553e 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -150,7 +150,15 @@ frappe.ui.form.on("Sales Order", { frm.set_value("advance_paid", 0) } +<<<<<<< HEAD frm.ignore_doctypes_on_cancel_all = ['Purchase Order']; +======= + frm.ignore_doctypes_on_cancel_all = [ + "Purchase Order", + "Unreconcile Payment", + "Unreconcile Payment Entries", + ]; +>>>>>>> b618d685c6 (refactor: ignore unreconcile doc for PO and SO on cancel/delete) }, delivery_date: function(frm) { diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 52b5e4051bb0..5b4597125fbe 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -269,7 +269,13 @@ def on_submit(self): update_coupon_code_count(self.coupon_code, "used") def on_cancel(self): - self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry", "Payment Ledger Entry") + self.ignore_linked_doctypes = ( + "GL Entry", + "Stock Ledger Entry", + "Payment Ledger Entry", + "Unreconcile Payment", + "Unreconcile Payment Entries", + ) super().on_cancel() # Cannot cancel closed SO From 2fabcb0c50c8b76e8b13a4b50497b19ef8bad308 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 18 Jun 2024 10:43:07 +0530 Subject: [PATCH 17/19] chore: resolve conflicts --- erpnext/buying/doctype/purchase_order/purchase_order.js | 5 ----- erpnext/selling/doctype/sales_order/sales_order.js | 4 ---- 2 files changed, 9 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index ced0b5fb4a11..1abd10ec3f80 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -6,13 +6,8 @@ frappe.provide("erpnext.accounts.dimensions"); {% include 'erpnext/public/js/controllers/buying.js' %}; frappe.ui.form.on("Purchase Order", { -<<<<<<< HEAD - setup: function(frm) { - -======= setup: function (frm) { frm.ignore_doctypes_on_cancel_all = ["Unreconcile Payment", "Unreconcile Payment Entries"]; ->>>>>>> b618d685c6 (refactor: ignore unreconcile doc for PO and SO on cancel/delete) if (frm.doc.is_old_subcontracting_flow) { frm.set_query("reserve_warehouse", "supplied_items", function() { return { diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index d0f85790553e..db3d6c2ca542 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -150,15 +150,11 @@ frappe.ui.form.on("Sales Order", { frm.set_value("advance_paid", 0) } -<<<<<<< HEAD - frm.ignore_doctypes_on_cancel_all = ['Purchase Order']; -======= frm.ignore_doctypes_on_cancel_all = [ "Purchase Order", "Unreconcile Payment", "Unreconcile Payment Entries", ]; ->>>>>>> b618d685c6 (refactor: ignore unreconcile doc for PO and SO on cancel/delete) }, delivery_date: function(frm) { From 8f5278e3d47347c82c6102c7bbd2afa2130e0461 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Sun, 12 May 2024 23:01:19 +0200 Subject: [PATCH 18/19] fix: migrate lead notes (cherry picked from commit 382d0ff45300fe6e92d1c535b8e6126d5e4057c3) --- .../migrate_existing_lead_notes_as_per_the_new_format.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/erpnext/patches/v14_0/migrate_existing_lead_notes_as_per_the_new_format.py b/erpnext/patches/v14_0/migrate_existing_lead_notes_as_per_the_new_format.py index ec72527552c0..d740a5b9c8ed 100644 --- a/erpnext/patches/v14_0/migrate_existing_lead_notes_as_per_the_new_format.py +++ b/erpnext/patches/v14_0/migrate_existing_lead_notes_as_per_the_new_format.py @@ -9,15 +9,13 @@ def execute(): dt = frappe.qb.DocType(doctype) records = ( - frappe.qb.from_(dt) - .select(dt.name, dt.notes, dt.modified_by, dt.modified) - .where(dt.notes.isnotnull() & dt.notes != "") + frappe.qb.from_(dt).select(dt.name, dt.notes).where(dt.notes.isnotnull() & dt.notes != "") ).run(as_dict=True) for d in records: if strip_html(cstr(d.notes)).strip(): doc = frappe.get_doc(doctype, d.name) - doc.append("notes", {"note": d.notes, "added_by": d.modified_by, "added_on": d.modified}) + doc.append("notes", {"note": d.notes}) doc.update_child_table("notes") frappe.db.sql_ddl(f"alter table `tab{doctype}` drop column `notes`") From 598c581623f509abe0ca7aa4bb6126a8dec457fe Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Fri, 14 Jun 2024 17:47:02 +0200 Subject: [PATCH 19/19] fix: only show user and date if available (cherry picked from commit 895aede5907cd949ae4d93521705e3144e31dfd5) --- erpnext/public/js/templates/crm_notes.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/public/js/templates/crm_notes.html b/erpnext/public/js/templates/crm_notes.html index 53df93307840..a20e6c2723c5 100644 --- a/erpnext/public/js/templates/crm_notes.html +++ b/erpnext/public/js/templates/crm_notes.html @@ -12,6 +12,7 @@ {% for(var i=0, l=notes.length; i
+ {% if (notes[i].added_by && notes[i].added_on) %}
{{ frappe.avatar(notes[i].added_by) }} @@ -25,6 +26,7 @@
+ {% } %}
{{ notes[i].note }}