From 819ced4cb3feca1535182cde98b7a8ae3aeee131 Mon Sep 17 00:00:00 2001 From: "Nihantra C. Patel" <141945075+Nihantra-Patel@users.noreply.github.com> Date: Tue, 5 Mar 2024 17:24:17 +0530 Subject: [PATCH 01/67] fix: Add to Cart button width for Mobile/Tablet --- erpnext/public/scss/shopping_cart.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/public/scss/shopping_cart.scss b/erpnext/public/scss/shopping_cart.scss index 6ae464d2c21..36e2cf9cd0a 100644 --- a/erpnext/public/scss/shopping_cart.scss +++ b/erpnext/public/scss/shopping_cart.scss @@ -444,7 +444,7 @@ body.product-page { width: 30%; @media (max-width: 992px) { - width: 40%; + width: 50%; } } } @@ -1378,4 +1378,4 @@ body.product-page { .mt-minus-1 { margin-top: -1rem; -} \ No newline at end of file +} 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 02/67] 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 a2f5455f2f7..5bbdd84d3f4 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 309141fe4c2..8ad31e1e791 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 e5a6040c735..e45aa512fe8 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 49c0b24e4cb..b6afe11e4ff 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 52a0f4ac2a2..a1a06489957 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 b7ab6ef3872..bf8cb05d8ce 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 54d1414c814..6db901c71a4 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 5e386035514..ea86d0a939c 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 d9187f8b678..c8905e14af2 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 72845b20742..83003418266 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 b0e08cc6f26..ab2a476a1d4 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 186c342a75e..670cf35bb11 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 66ac9582b2d..2d836ad1e2f 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 0e584205396..c91bb046a52 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 d3147bb4600..63833da5af3 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 801376b2ed7..623941755d1 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 00000000000..00df1c5c191 --- /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 5fbb5cb7e01..7aa8012f0b6 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 53fedbf56cf..a408417c119 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 0f0221fa562..aec752aec77 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 230107caadb..65a1be33224 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 c596890aa32..e78b42d6619 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 03/67] 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 8ad31e1e791..33478a54e39 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 b2672424af9..ad857840147 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 a1a06489957..2a96035f4b5 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 6b4cdf1177a..1d4596ba1a4 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 83003418266..1ba941ab6f7 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 ab2a476a1d4..aa7dfbd90d6 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 2d836ad1e2f..e3e25499b84 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 b2a64a5d461..ad2f1e5f282 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 b6459ba1e28..d58361b2d3b 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 e78b42d6619..449edd14e15 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 04/67] 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 00df1c5c191..00000000000 --- 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 c3244f009bc5bcafa3befa3751a603aa9cf7ebb4 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 24 Apr 2024 16:59:51 +0530 Subject: [PATCH 05/67] fix: Default dates in report --- .../asset_depreciations_and_balances.js | 4 ++-- .../bank_clearance_summary.js | 2 +- .../dimension_wise_accounts_balance_report.js | 4 ++-- .../report/gross_profit/gross_profit.js | 4 ++-- .../payment_period_based_on_invoice_date.js | 2 +- .../profitability_analysis.js | 4 ++-- .../report/trial_balance/trial_balance.js | 4 ++-- .../trial_balance_for_party.js | 4 ++-- .../procurement_tracker.js | 4 ++-- .../purchase_analytics/purchase_analytics.js | 4 ++-- .../campaign_efficiency.js | 4 ++-- .../lead_owner_efficiency.js | 4 ++-- .../job_card_summary/job_card_summary.js | 4 ++-- .../production_analytics.js | 4 ++-- erpnext/public/js/utils.js | 21 ++++++++++++------- .../customer_acquisition_and_loyalty.js | 4 ++-- .../report/sales_analytics/sales_analytics.js | 4 ++-- .../sales_person_commission_summary.js | 2 +- .../sales_person_wise_transaction_summary.js | 2 +- .../incorrect_serial_no_valuation.js | 4 ++-- 20 files changed, 47 insertions(+), 42 deletions(-) diff --git a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.js b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.js index 1da35cd95bf..5f78b779342 100644 --- a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.js +++ b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.js @@ -15,14 +15,14 @@ frappe.query_reports["Asset Depreciations and Balances"] = { "fieldname":"from_date", "label": __("From Date"), "fieldtype": "Date", - "default": frappe.defaults.get_user_default("year_start_date"), + "default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1], "reqd": 1 }, { "fieldname":"to_date", "label": __("To Date"), "fieldtype": "Date", - "default": frappe.defaults.get_user_default("year_end_date"), + "default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2], "reqd": 1 }, { diff --git a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.js b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.js index f0b6c6b20ac..8a7d071a474 100644 --- a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.js +++ b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.js @@ -7,7 +7,7 @@ frappe.query_reports["Bank Clearance Summary"] = { "fieldname":"from_date", "label": __("From Date"), "fieldtype": "Date", - "default": frappe.defaults.get_user_default("year_start_date"), + "default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1], "width": "80" }, { diff --git a/erpnext/accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.js b/erpnext/accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.js index 9d416db4fdd..33d51066dac 100644 --- a/erpnext/accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.js +++ b/erpnext/accounts/report/dimension_wise_accounts_balance_report/dimension_wise_accounts_balance_report.js @@ -38,14 +38,14 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() { "fieldname": "from_date", "label": __("From Date"), "fieldtype": "Date", - "default": frappe.defaults.get_user_default("year_start_date"), + "default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1], "reqd": 1 }, { "fieldname": "to_date", "label": __("To Date"), "fieldtype": "Date", - "default": frappe.defaults.get_user_default("year_end_date"), + "default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2], "reqd": 1 }, { diff --git a/erpnext/accounts/report/gross_profit/gross_profit.js b/erpnext/accounts/report/gross_profit/gross_profit.js index cf4ccef2433..8e05cf86061 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.js +++ b/erpnext/accounts/report/gross_profit/gross_profit.js @@ -15,14 +15,14 @@ frappe.query_reports["Gross Profit"] = { "fieldname": "from_date", "label": __("From Date"), "fieldtype": "Date", - "default": frappe.defaults.get_user_default("year_start_date"), + "default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1], "reqd": 1 }, { "fieldname": "to_date", "label": __("To Date"), "fieldtype": "Date", - "default": frappe.defaults.get_user_default("year_end_date"), + "default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2], "reqd": 1 }, { diff --git a/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.js b/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.js index 2343eaa8461..5ec2c9880c3 100644 --- a/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.js +++ b/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.js @@ -15,7 +15,7 @@ frappe.query_reports["Payment Period Based On Invoice Date"] = { fieldname: "from_date", label: __("From Date"), fieldtype: "Date", - default: frappe.defaults.get_user_default("year_start_date"), + default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1], }, { fieldname:"to_date", diff --git a/erpnext/accounts/report/profitability_analysis/profitability_analysis.js b/erpnext/accounts/report/profitability_analysis/profitability_analysis.js index c4054a977a8..b3b32c08c4c 100644 --- a/erpnext/accounts/report/profitability_analysis/profitability_analysis.js +++ b/erpnext/accounts/report/profitability_analysis/profitability_analysis.js @@ -59,13 +59,13 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() { "fieldname": "from_date", "label": __("From Date"), "fieldtype": "Date", - "default": frappe.defaults.get_user_default("year_start_date"), + "default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1], }, { "fieldname": "to_date", "label": __("To Date"), "fieldtype": "Date", - "default": frappe.defaults.get_user_default("year_end_date"), + "default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2], }, { "fieldname": "show_zero_values", diff --git a/erpnext/accounts/report/trial_balance/trial_balance.js b/erpnext/accounts/report/trial_balance/trial_balance.js index ffb2931e902..ee1d5e3dba0 100644 --- a/erpnext/accounts/report/trial_balance/trial_balance.js +++ b/erpnext/accounts/report/trial_balance/trial_balance.js @@ -37,13 +37,13 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() { "fieldname": "from_date", "label": __("From Date"), "fieldtype": "Date", - "default": frappe.defaults.get_user_default("year_start_date"), + "default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1], }, { "fieldname": "to_date", "label": __("To Date"), "fieldtype": "Date", - "default": frappe.defaults.get_user_default("year_end_date"), + "default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2], }, { "fieldname": "cost_center", diff --git a/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.js b/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.js index 0f7578cdc17..33c644adcb9 100644 --- a/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.js +++ b/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.js @@ -36,13 +36,13 @@ frappe.query_reports["Trial Balance for Party"] = { "fieldname": "from_date", "label": __("From Date"), "fieldtype": "Date", - "default": frappe.defaults.get_user_default("year_start_date"), + "default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1], }, { "fieldname": "to_date", "label": __("To Date"), "fieldtype": "Date", - "default": frappe.defaults.get_user_default("year_end_date"), + "default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2], }, { "fieldname":"party_type", diff --git a/erpnext/buying/report/procurement_tracker/procurement_tracker.js b/erpnext/buying/report/procurement_tracker/procurement_tracker.js index 283d56c9469..4d119a5cd75 100644 --- a/erpnext/buying/report/procurement_tracker/procurement_tracker.js +++ b/erpnext/buying/report/procurement_tracker/procurement_tracker.js @@ -27,13 +27,13 @@ frappe.query_reports["Procurement Tracker"] = { fieldname: "from_date", label: __("From Date"), fieldtype: "Date", - default: frappe.defaults.get_user_default("year_start_date"), + default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1], }, { fieldname:"to_date", label: __("To Date"), fieldtype: "Date", - default: frappe.defaults.get_user_default("year_end_date"), + default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2], }, ] } diff --git a/erpnext/buying/report/purchase_analytics/purchase_analytics.js b/erpnext/buying/report/purchase_analytics/purchase_analytics.js index a884f06d2c2..fe3bbc9bd89 100644 --- a/erpnext/buying/report/purchase_analytics/purchase_analytics.js +++ b/erpnext/buying/report/purchase_analytics/purchase_analytics.js @@ -35,14 +35,14 @@ frappe.query_reports["Purchase Analytics"] = { fieldname: "from_date", label: __("From Date"), fieldtype: "Date", - default: frappe.defaults.get_user_default("year_start_date"), + default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1], reqd: 1 }, { fieldname:"to_date", label: __("To Date"), fieldtype: "Date", - default: frappe.defaults.get_user_default("year_end_date"), + default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2], reqd: 1 }, { diff --git a/erpnext/crm/report/campaign_efficiency/campaign_efficiency.js b/erpnext/crm/report/campaign_efficiency/campaign_efficiency.js index f29c2c64e14..0c4e7f2dabe 100644 --- a/erpnext/crm/report/campaign_efficiency/campaign_efficiency.js +++ b/erpnext/crm/report/campaign_efficiency/campaign_efficiency.js @@ -6,13 +6,13 @@ frappe.query_reports["Campaign Efficiency"] = { "fieldname": "from_date", "label": __("From Date"), "fieldtype": "Date", - "default": frappe.defaults.get_user_default("year_start_date"), + "default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1], }, { "fieldname": "to_date", "label": __("To Date"), "fieldtype": "Date", - "default": frappe.defaults.get_user_default("year_end_date"), + "default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2], } ] }; diff --git a/erpnext/crm/report/lead_owner_efficiency/lead_owner_efficiency.js b/erpnext/crm/report/lead_owner_efficiency/lead_owner_efficiency.js index bbfd6ac9ff7..6fc52a1afc9 100644 --- a/erpnext/crm/report/lead_owner_efficiency/lead_owner_efficiency.js +++ b/erpnext/crm/report/lead_owner_efficiency/lead_owner_efficiency.js @@ -6,12 +6,12 @@ "fieldname": "from_date", "label": __("From Date"), "fieldtype": "Date", - "default": frappe.defaults.get_user_default("year_start_date"), + "default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1], }, { "fieldname": "to_date", "label": __("To Date"), "fieldtype": "Date", - "default": frappe.defaults.get_user_default("year_end_date"), + "default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2], } ]}; diff --git a/erpnext/manufacturing/report/job_card_summary/job_card_summary.js b/erpnext/manufacturing/report/job_card_summary/job_card_summary.js index a874f224820..9f1098d46fc 100644 --- a/erpnext/manufacturing/report/job_card_summary/job_card_summary.js +++ b/erpnext/manufacturing/report/job_card_summary/job_card_summary.js @@ -37,14 +37,14 @@ frappe.query_reports["Job Card Summary"] = { label: __("From Posting Date"), fieldname:"from_date", fieldtype: "Date", - default: frappe.defaults.get_user_default("year_start_date"), + default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1], reqd: 1 }, { label: __("To Posting Date"), fieldname:"to_date", fieldtype: "Date", - default: frappe.defaults.get_user_default("year_end_date"), + default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2], reqd: 1, }, { diff --git a/erpnext/manufacturing/report/production_analytics/production_analytics.js b/erpnext/manufacturing/report/production_analytics/production_analytics.js index 99f9b1260a2..7c71b2eac65 100644 --- a/erpnext/manufacturing/report/production_analytics/production_analytics.js +++ b/erpnext/manufacturing/report/production_analytics/production_analytics.js @@ -16,14 +16,14 @@ frappe.query_reports["Production Analytics"] = { fieldname: "from_date", label: __("From Date"), fieldtype: "Date", - default: frappe.defaults.get_user_default("year_start_date"), + default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1], reqd: 1 }, { fieldname:"to_date", label: __("To Date"), fieldtype: "Date", - default: frappe.defaults.get_user_default("year_end_date"), + default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2], reqd: 1 }, { diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js index 4c7b2534fcc..fef55942e46 100755 --- a/erpnext/public/js/utils.js +++ b/erpnext/public/js/utils.js @@ -351,26 +351,31 @@ $.extend(erpnext.utils, { }, - get_fiscal_year: function(date) { - if(!date) { + get_fiscal_year: function (date, with_dates = false, boolean = false) { + if (!frappe.boot.setup_complete) { + return; + } + if (!date) { date = frappe.datetime.get_today(); } - let fiscal_year = ''; + let fiscal_year = ""; frappe.call({ method: "erpnext.accounts.utils.get_fiscal_year", args: { - date: date + date: date, + boolean: boolean, }, async: false, - callback: function(r) { + callback: function (r) { if (r.message) { - fiscal_year = r.message[0]; + if (with_dates) fiscal_year = r.message; + else fiscal_year = r.message[0]; } - } + }, }); return fiscal_year; - } + }, }); erpnext.utils.select_alternate_items = function(opts) { diff --git a/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.js b/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.js index 1b931e12de3..744b5d982b5 100644 --- a/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.js +++ b/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.js @@ -23,14 +23,14 @@ frappe.query_reports["Customer Acquisition and Loyalty"] = { "fieldname":"from_date", "label": __("From Date"), "fieldtype": "Date", - "default": frappe.defaults.get_user_default("year_start_date"), + "default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1], "reqd": 1 }, { "fieldname":"to_date", "label": __("To Date"), "fieldtype": "Date", - "default": frappe.defaults.get_user_default("year_end_date"), + "default": erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2], "reqd": 1 } ], diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.js b/erpnext/selling/report/sales_analytics/sales_analytics.js index 87dd02f9915..e56fe8b5732 100644 --- a/erpnext/selling/report/sales_analytics/sales_analytics.js +++ b/erpnext/selling/report/sales_analytics/sales_analytics.js @@ -35,14 +35,14 @@ frappe.query_reports["Sales Analytics"] = { fieldname: "from_date", label: __("From Date"), fieldtype: "Date", - default: frappe.defaults.get_user_default("year_start_date"), + default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1], reqd: 1 }, { fieldname:"to_date", label: __("To Date"), fieldtype: "Date", - default: frappe.defaults.get_user_default("year_end_date"), + default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2], reqd: 1 }, { diff --git a/erpnext/selling/report/sales_person_commission_summary/sales_person_commission_summary.js b/erpnext/selling/report/sales_person_commission_summary/sales_person_commission_summary.js index ba6ee784b91..2044ff8c289 100644 --- a/erpnext/selling/report/sales_person_commission_summary/sales_person_commission_summary.js +++ b/erpnext/selling/report/sales_person_commission_summary/sales_person_commission_summary.js @@ -22,7 +22,7 @@ frappe.query_reports["Sales Person Commission Summary"] = { fieldname: "from_date", label: __("From Date"), fieldtype: "Date", - default: frappe.defaults.get_user_default("year_start_date"), + default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1], }, { fieldname:"to_date", diff --git a/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.js b/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.js index e269f02d0ce..80c7b5f59d7 100644 --- a/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.js +++ b/erpnext/selling/report/sales_person_wise_transaction_summary/sales_person_wise_transaction_summary.js @@ -20,7 +20,7 @@ frappe.query_reports["Sales Person-wise Transaction Summary"] = { fieldname: "from_date", label: __("From Date"), fieldtype: "Date", - default: frappe.defaults.get_user_default("year_start_date"), + default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1], }, { fieldname:"to_date", diff --git a/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.js b/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.js index c62d48081c2..ff27fb32cd8 100644 --- a/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.js +++ b/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.js @@ -22,14 +22,14 @@ frappe.query_reports["Incorrect Serial No Valuation"] = { fieldtype: 'Date', fieldname: 'from_date', reqd: 1, - default: frappe.defaults.get_user_default("year_start_date") + default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[1] }, { label: __('To Date'), fieldtype: 'Date', fieldname: 'to_date', reqd: 1, - default: frappe.defaults.get_user_default("year_end_date") + default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2] } ] }; From 7a380f584d9be2f6a78bfdb5e5711002ccb945b4 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 11 May 2024 17:51:53 +0530 Subject: [PATCH 06/67] fix: default fiscal year --- erpnext/accounts/utils.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index d966074b2ae..57ecc9e9275 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -55,6 +55,9 @@ GL_REPOSTING_CHUNK = 100 def get_fiscal_year( date=None, fiscal_year=None, label="Date", verbose=1, company=None, as_dict=False, boolean=False ): + if isinstance(boolean, str): + boolean = frappe.json.loads(boolean) + fiscal_years = get_fiscal_years( date, fiscal_year, label, verbose, company, as_dict=as_dict, boolean=boolean ) From 7b28d7d2b8cc2f71a175af1793ed28636faa2f5e Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 21:37:13 +0530 Subject: [PATCH 07/67] feat: allow to pick manually qty / batches / serial nos (backport #40723) (#41435) * feat: allow to pick manually qty / batches / serial nos (cherry picked from commit 50dd9fa8a32b8cd29b50d1c6181dfd8f6f5d27b6) # Conflicts: # erpnext/stock/doctype/pick_list/pick_list.json # erpnext/stock/doctype/pick_list/pick_list.py * chore: fix conflicts * chore: fix conflicts --------- Co-authored-by: Rohit Waghchaure --- erpnext/stock/doctype/pick_list/pick_list.json | 12 ++++++++++-- erpnext/stock/doctype/pick_list/pick_list.py | 3 ++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/doctype/pick_list/pick_list.json b/erpnext/stock/doctype/pick_list/pick_list.json index 948011cce69..b4aadbd7987 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.json +++ b/erpnext/stock/doctype/pick_list/pick_list.json @@ -18,6 +18,7 @@ "parent_warehouse", "consider_rejected_warehouses", "get_item_locations", + "pick_manually", "section_break_6", "scan_barcode", "column_break_13", @@ -192,11 +193,18 @@ "fieldname": "consider_rejected_warehouses", "fieldtype": "Check", "label": "Consider Rejected Warehouses" + }, + { + "default": "0", + "description": "If enabled then system won't override the picked qty / batches / serial numbers.", + "fieldname": "pick_manually", + "fieldtype": "Check", + "label": "Pick Manually" } ], "is_submittable": 1, "links": [], - "modified": "2024-01-24 17:05:20.317180", + "modified": "2024-03-27 22:49:16.954637", "modified_by": "Administrator", "module": "Stock", "name": "Pick List", @@ -268,4 +276,4 @@ "sort_order": "DESC", "states": [], "track_changes": 1 -} \ No newline at end of file +} diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py index ef7dc710b13..99858835fed 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.py +++ b/erpnext/stock/doctype/pick_list/pick_list.py @@ -29,7 +29,8 @@ class PickList(Document): def before_save(self): self.update_status() - self.set_item_locations() + if not self.pick_manually: + self.set_item_locations() if self.get("locations"): self.validate_sales_order_percentage() From a8be5f078956a4269bb5fa6e87950d359bc38b9a Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 11 May 2024 19:35:52 +0530 Subject: [PATCH 08/67] fix: Duplicate party name column in AR/AP report (cherry picked from commit 7501fe8ebd9c0735fcdb62529f275d970a86cca5) --- .../accounts_receivable/accounts_receivable.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 25143e555d3..be42da8423f 100644 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -1028,20 +1028,6 @@ class ReceivablePayableReport: fieldtype="Link", options="Contact", ) - if self.filters.party_type == "Customer": - self.add_column( - _("Customer Name"), - fieldname="customer_name", - fieldtype="Link", - options="Customer", - ) - elif self.filters.party_type == "Supplier": - self.add_column( - _("Supplier Name"), - fieldname="supplier_name", - fieldtype="Link", - options="Supplier", - ) self.add_column(label=_("Cost Center"), fieldname="cost_center", fieldtype="Data") self.add_column(label=_("Voucher Type"), fieldname="voucher_type", fieldtype="Data") From e69e5404d3da90a17462fd2ec87cab94f0c47a1c Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 30 Apr 2024 12:50:21 +0530 Subject: [PATCH 09/67] fix: PSOA ageing (cherry picked from commit fed2d1190581449d78cb160b214e0b47130f5169) --- .../process_statement_of_accounts.py | 2 +- ...cess_statement_of_accounts_accounts_receivable.html | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py index 0c266ce7947..a602e0d7df3 100644 --- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py +++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py @@ -104,7 +104,7 @@ def set_ageing(doc, entry): ageing_filters = frappe._dict( { "company": doc.company, - "report_date": doc.to_date, + "report_date": doc.posting_date, "ageing_based_on": doc.ageing_based_on, "range1": 30, "range2": 60, diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html index 647600a9fea..bf8de073853 100644 --- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html +++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts_accounts_receivable.html @@ -340,10 +340,11 @@ - - - - + + + + + @@ -352,6 +353,7 @@ +
30 Days60 Days90 Days120 Days0 - 30 Days30 - 60 Days60 - 90 Days90 - 120 DaysAbove 120 Days
{{ frappe.utils.fmt_money(ageing.range2, currency=data[0]["currency"]) }} {{ frappe.utils.fmt_money(ageing.range3, currency=data[0]["currency"]) }} {{ frappe.utils.fmt_money(ageing.range4, currency=data[0]["currency"]) }}{{ frappe.utils.fmt_money(ageing.range5, currency=filters.presentation_currency) }}
From 26595351cc2123c731b59b76dcedc25144b2c215 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 15 May 2024 15:15:41 +0530 Subject: [PATCH 10/67] fix: validate reorder group warehouse (backport #41478) (#41479) fix: validate reorder group warehouse (#41478) (cherry picked from commit 0363afcfd0906cd790779e93dd73646b937be3b5) Co-authored-by: rohitwaghchaure --- erpnext/stock/doctype/item/item.py | 29 ++++++++++++++++++++++++- erpnext/stock/doctype/item/test_item.py | 21 ++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index b2b06e05871..3543e42e217 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -5,7 +5,7 @@ import copy import json import frappe -from frappe import _ +from frappe import _, bold from frappe.model.document import Document from frappe.utils import ( cint, @@ -397,6 +397,13 @@ class Item(Document): def validate_warehouse_for_reorder(self): """Validate Reorder level table for duplicate and conditional mandatory""" warehouse_material_request_type: list[tuple[str, str]] = [] + + _warehouse_before_save = frappe._dict() + if not self.is_new() and self._doc_before_save: + _warehouse_before_save = { + d.name: d.warehouse for d in self._doc_before_save.get("reorder_levels") or [] + } + for d in self.get("reorder_levels"): if not d.warehouse_group: d.warehouse_group = d.warehouse @@ -413,6 +420,19 @@ class Item(Document): if d.warehouse_reorder_level and not d.warehouse_reorder_qty: frappe.throw(_("Row #{0}: Please set reorder quantity").format(d.idx)) + if d.warehouse_group and d.warehouse: + if _warehouse_before_save.get(d.name) == d.warehouse: + continue + + child_warehouses = get_child_warehouses(d.warehouse_group) + if d.warehouse not in child_warehouses: + frappe.throw( + _( + "Row #{0}: The warehouse {1} is not a child warehouse of a group warehouse {2}" + ).format(d.idx, bold(d.warehouse), bold(d.warehouse_group)), + title=_("Incorrect Check in (group) Warehouse for Reorder"), + ) + def stock_ledger_created(self): if not hasattr(self, "_stock_ledger_created"): self._stock_ledger_created = len( @@ -1318,3 +1338,10 @@ def get_asset_naming_series(): from erpnext.assets.doctype.asset.asset import get_asset_naming_series return get_asset_naming_series() + + +@frappe.request_cache +def get_child_warehouses(warehouse): + from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses + + return get_child_warehouses(warehouse) diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index d486e972771..827261d6540 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -848,6 +848,27 @@ class TestItem(FrappeTestCase): self.assertEqual(data[0].description, item.description) self.assertTrue("description" in data[0]) + def test_group_warehouse_for_reorder_item(self): + from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse + + item_doc = make_item("_Test Group Warehouse For Reorder Item", {"is_stock_item": 1}) + warehouse = create_warehouse("_Test Warehouse - _TC") + warehouse_doc = frappe.get_doc("Warehouse", warehouse) + warehouse_doc.db_set("parent_warehouse", "") + + item_doc.append( + "reorder_levels", + { + "warehouse": warehouse, + "warehouse_reorder_level": 10, + "warehouse_reorder_qty": 100, + "material_request_type": "Purchase", + "warehouse_group": "_Test Warehouse Group - _TC", + }, + ) + + self.assertRaises(frappe.ValidationError, item_doc.save) + def set_item_variant_settings(fields): doc = frappe.get_doc("Item Variant Settings") From 89d507e07e738f1979f526be8b04defea904ae57 Mon Sep 17 00:00:00 2001 From: "Nihantra C. Patel" <141945075+Nihantra-Patel@users.noreply.github.com> Date: Fri, 23 Feb 2024 16:37:11 +0530 Subject: [PATCH 11/67] fix: print format bold for field "total" (cherry picked from commit 3c9640df27a0a3fac7f90d829997652c8f235916) --- erpnext/templates/print_formats/includes/total.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/templates/print_formats/includes/total.html b/erpnext/templates/print_formats/includes/total.html index 879203bbf25..f964047bd08 100644 --- a/erpnext/templates/print_formats/includes/total.html +++ b/erpnext/templates/print_formats/includes/total.html @@ -1,14 +1,14 @@ -
+
{% if doc.flags.show_inclusive_tax_in_print %}
-
+
{{ doc.get_formatted("net_total", doc) }}
{% else %}
-
+
{{ doc.get_formatted("total", doc) }}
{% endif %} From 0cbf049608f8d2e3b86947e433bd33eee6343752 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 17 May 2024 09:37:03 +0530 Subject: [PATCH 12/67] chore(BOM Explorer): display items in the same order as in the BOM (backport #41496) (#41510) chore(BOM Explorer): display items in the same order as in the BOM (#41496) (cherry picked from commit bd381cc0c607b2fc44ebbd854689686d37d67c7a) Co-authored-by: Samuel Danieli <23150094+scdanieli@users.noreply.github.com> --- erpnext/manufacturing/report/bom_explorer/bom_explorer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/manufacturing/report/bom_explorer/bom_explorer.py b/erpnext/manufacturing/report/bom_explorer/bom_explorer.py index 2aa31be0f0e..97c85502c98 100644 --- a/erpnext/manufacturing/report/bom_explorer/bom_explorer.py +++ b/erpnext/manufacturing/report/bom_explorer/bom_explorer.py @@ -21,7 +21,8 @@ def get_exploded_items(bom, data, indent=0, qty=1): exploded_items = frappe.get_all( "BOM Item", filters={"parent": bom}, - fields=["qty", "bom_no", "qty", "item_code", "item_name", "description", "uom"], + fields=["qty", "bom_no", "qty", "item_code", "item_name", "description", "uom", "idx"], + order_by="idx ASC", ) for item in exploded_items: From dfb4c4708959b89b368333378bd46979e858190d Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 17 May 2024 10:37:07 +0530 Subject: [PATCH 13/67] fix: possible sql error on General Ledger (cherry picked from commit 76131f8e1084a95fe05a14f496d4cbf755a570c8) --- erpnext/accounts/report/general_ledger/general_ledger.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py index f70aec743d2..0c4e1eca3f9 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.py +++ b/erpnext/accounts/report/general_ledger/general_ledger.py @@ -211,7 +211,8 @@ def get_conditions(filters): if filters.get("account"): filters.account = get_accounts_with_children(filters.account) - conditions.append("account in %(account)s") + if filters.account: + conditions.append("account in %(account)s") if filters.get("cost_center"): filters.cost_center = get_cost_centers_with_children(filters.cost_center) @@ -316,7 +317,7 @@ def get_accounts_with_children(accounts): else: frappe.throw(_("Account: {0} does not exist").format(d)) - return list(set(all_accounts)) + return list(set(all_accounts)) if all_accounts else None def get_data_with_opening_closing(filters, account_details, accounting_dimensions, gl_entries): From 331a743d6938eeab577e4bc8c99f72c2acad8e1b Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 17 May 2024 14:41:17 +0530 Subject: [PATCH 14/67] fix: typerror on hide_fields (cherry picked from commit deb9766f2ac1e28b2f7d1e9ec6657b123c16cd68) --- .../accounts/doctype/purchase_invoice/purchase_invoice.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js index 665fc6edcc9..c29ec5fd12f 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js @@ -440,8 +440,12 @@ function hide_fields(doc) { var item_fields_stock = ['warehouse_section', 'received_qty', 'rejected_qty']; - cur_frm.fields_dict['items'].grid.set_column_disp(item_fields_stock, - (cint(doc.update_stock)==1 || cint(doc.is_return)==1 ? true : false)); + if (cur_frm.fields_dict["items"]) { + cur_frm.fields_dict["items"].grid.set_column_disp( + item_fields_stock, + cint(doc.update_stock) == 1 || cint(doc.is_return) == 1 ? true : false + ); + } cur_frm.refresh_fields(); } From 82d206b709ada758c277bc5a266dbc6ec10d00c8 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 17 May 2024 17:06:39 +0530 Subject: [PATCH 15/67] fix: minor Dr and Cr between Purchase Receipt and Purchase Invoice This applies for Provisional Accounting for Non-stock items (cherry picked from commit 1c0a24424a1f585c4b3a736fe92b419567b9da1e) --- .../accounts/doctype/purchase_invoice/purchase_invoice.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index b53627a682f..77f879a1f42 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -982,7 +982,7 @@ class PurchaseInvoice(BuyingController): pr_items = frappe.get_all( "Purchase Receipt Item", filters={"parent": ("in", linked_purchase_receipts)}, - fields=["name", "provisional_expense_account", "qty", "base_rate"], + fields=["name", "provisional_expense_account", "qty", "base_rate", "rate"], ) default_provisional_account = self.get_company_default("default_provisional_account") provisional_accounts = set( @@ -1010,6 +1010,7 @@ class PurchaseInvoice(BuyingController): "provisional_account": item.provisional_expense_account or default_provisional_account, "qty": item.qty, "base_rate": item.base_rate, + "rate": item.rate, "has_provisional_entry": item.name in rows_with_provisional_entries, } @@ -1026,7 +1027,10 @@ class PurchaseInvoice(BuyingController): self.posting_date, pr_item.get("provisional_account"), reverse=1, - item_amount=(min(item.qty, pr_item.get("qty")) * pr_item.get("base_rate")), + item_amount=( + (min(item.qty, pr_item.get("qty")) * pr_item.get("rate")) + * purchase_receipt_doc.get("conversion_rate") + ), ) def update_gross_purchase_amount_for_linked_assets(self, item): From 97fdda8a7cf0eaee30e7e652a48a8d19df70dbd6 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 20 May 2024 13:39:39 +0530 Subject: [PATCH 16/67] fix: priority not working for multiple pricing rules (backport #41516) (#41524) * fix: priority not working for multiple pricing rules (#41516) (cherry picked from commit 5cf5b18aea34f825cd024194e8e02cb7c0704230) # Conflicts: # erpnext/accounts/doctype/pricing_rule/pricing_rule.json # erpnext/accounts/doctype/pricing_rule/pricing_rule.py # erpnext/patches.txt * chore: fix conflicts * chore: fix conflicts * chore: fix conflicts --------- Co-authored-by: rohitwaghchaure --- .../doctype/pricing_rule/pricing_rule.json | 53 ++++++++++++++--- .../doctype/pricing_rule/pricing_rule.py | 6 ++ .../doctype/pricing_rule/test_pricing_rule.py | 57 +++++++++++++++++++ .../accounts/doctype/pricing_rule/utils.py | 3 + erpnext/patches.txt | 3 +- .../enable_set_priority_for_pricing_rules.py | 10 ++++ 6 files changed, 124 insertions(+), 8 deletions(-) create mode 100644 erpnext/patches/v14_0/enable_set_priority_for_pricing_rules.py diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json index e8e80449292..6f191c106c9 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json @@ -74,15 +74,21 @@ "discount_amount", "discount_percentage", "for_price_list", - "section_break_13", - "threshold_percentage", - "priority", + "dynamic_condition_tab", "condition", - "column_break_66", + "section_break_13", "apply_multiple_pricing_rules", "apply_discount_on_rate", + "column_break_66", + "threshold_percentage", + "validate_pricing_rule_section", "validate_applied_rule", + "column_break_texp", "rule_description", + "priority_section", + "has_priority", + "column_break_sayg", + "priority", "help_section", "pricing_rule_help", "reference_section", @@ -477,7 +483,7 @@ { "collapsible": 1, "fieldname": "section_break_13", - "fieldtype": "Section Break", + "fieldtype": "Tab Break", "label": "Advanced Settings" }, { @@ -487,6 +493,7 @@ "label": "Threshold for Suggestion (In Percentage)" }, { + "depends_on": "has_priority", "description": "Higher the number, higher the priority", "fieldname": "priority", "fieldtype": "Select", @@ -513,6 +520,7 @@ { "default": "0", "depends_on": "eval:doc.price_or_product_discount == 'Price'", + "description": "If enabled, then system will only validate the pricing rule and not apply automatically. User has to manually set the discount percentage / margin / free items to validate the pricing rule", "fieldname": "validate_applied_rule", "fieldtype": "Check", "label": "Validate Applied Rule" @@ -525,7 +533,8 @@ }, { "fieldname": "help_section", - "fieldtype": "Section Break", + "fieldtype": "Tab Break", + "label": "Help Article", "options": "Simple" }, { @@ -603,12 +612,42 @@ "fieldname": "apply_recursion_over", "fieldtype": "Float", "label": "Apply Recursion Over (As Per Transaction UOM)" + }, + { + "fieldname": "priority_section", + "fieldtype": "Section Break", + "label": "Priority" + }, + { + "fieldname": "dynamic_condition_tab", + "fieldtype": "Tab Break", + "label": "Dynamic Condition" + }, + { + "fieldname": "validate_pricing_rule_section", + "fieldtype": "Section Break", + "label": "Validate Pricing Rule" + }, + { + "fieldname": "column_break_texp", + "fieldtype": "Column Break" + }, + { + "fieldname": "column_break_sayg", + "fieldtype": "Column Break" + }, + { + "default": "0", + "description": "Enable this checkbox even if you want to set the zero priority", + "fieldname": "has_priority", + "fieldtype": "Check", + "label": "Has Priority" } ], "icon": "fa fa-gift", "idx": 1, "links": [], - "modified": "2023-02-14 04:53:34.887358", + "modified": "2024-05-17 13:16:34.496704", "modified_by": "Administrator", "module": "Accounts", "name": "Pricing Rule", diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index bc30118a0c6..30dbb14f84c 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -47,6 +47,12 @@ class PricingRule(Document): frappe.throw(_("Duplicate {0} found in the table").format(self.apply_on)) def validate_mandatory(self): + if self.has_priority and not self.priority: + throw(_("Priority is mandatory"), frappe.MandatoryError, _("Please Set Priority")) + + if self.priority and not self.has_priority: + self.has_priority = 1 + for apply_on, field in apply_on_dict.items(): if self.apply_on == apply_on and len(self.get(field) or []) < 1: throw(_("{0} is not added in the table").format(apply_on), frappe.MandatoryError) diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py index 18658e6e4a6..6f1cee61637 100644 --- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py @@ -1031,6 +1031,62 @@ class TestPricingRule(unittest.TestCase): frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1") frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2") + def test_priority_of_multiple_pricing_rules(self): + frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1") + frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2") + + test_record = { + "doctype": "Pricing Rule", + "title": "_Test Pricing Rule 1", + "name": "_Test Pricing Rule 1", + "apply_on": "Item Code", + "currency": "USD", + "items": [ + { + "item_code": "_Test Item", + } + ], + "selling": 1, + "price_or_product_discount": "Price", + "rate_or_discount": "Discount Percentage", + "discount_percentage": 10, + "has_priority": 1, + "priority": 1, + "company": "_Test Company", + } + + frappe.get_doc(test_record.copy()).insert() + + test_record = { + "doctype": "Pricing Rule", + "title": "_Test Pricing Rule 2", + "name": "_Test Pricing Rule 2", + "apply_on": "Item Code", + "currency": "USD", + "items": [ + { + "item_code": "_Test Item", + } + ], + "selling": 1, + "price_or_product_discount": "Price", + "rate_or_discount": "Discount Percentage", + "discount_percentage": 20, + "has_priority": 1, + "priority": 3, + "company": "_Test Company", + } + + frappe.get_doc(test_record.copy()).insert() + + so = make_sales_order(item_code="_Test Item", qty=1, price_list_rate=1000, do_not_submit=True) + self.assertEqual(so.items[0].discount_percentage, 20) + self.assertEqual(so.items[0].rate, 800) + + frappe.delete_doc_if_exists("Sales Order", so.name) + frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1") + frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2") + test_dependencies = ["Campaign"] @@ -1059,6 +1115,7 @@ def make_pricing_rule(**args): "priority": args.priority or 1, "discount_amount": args.discount_amount or 0.0, "apply_multiple_pricing_rules": args.apply_multiple_pricing_rules or 0, + "has_priority": args.has_priority or 0, } ) diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py index 2a78bebd103..ab9894a52a8 100644 --- a/erpnext/accounts/doctype/pricing_rule/utils.py +++ b/erpnext/accounts/doctype/pricing_rule/utils.py @@ -33,6 +33,9 @@ def get_pricing_rules(args, doc=None): for apply_on in ["Item Code", "Item Group", "Brand"]: pricing_rules.extend(_get_pricing_rules(apply_on, args, values)) + if pricing_rules and pricing_rules[0].has_priority: + continue + if pricing_rules and not apply_multiple_pricing_rules(pricing_rules): break diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 078aa5e0a0f..25f038173d6 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -362,4 +362,5 @@ erpnext.stock.doctype.delivery_note.patches.drop_unused_return_against_index # 2 erpnext.patches.v14_0.set_maintain_stock_for_bom_item execute:frappe.db.set_single_value('E Commerce Settings', 'show_actual_qty', 1) erpnext.patches.v14_0.delete_orphaned_asset_movement_item_records -erpnext.patches.v14_0.remove_cancelled_asset_capitalization_from_asset \ No newline at end of file +erpnext.patches.v14_0.remove_cancelled_asset_capitalization_from_asset +erpnext.patches.v14_0.enable_set_priority_for_pricing_rules #1 diff --git a/erpnext/patches/v14_0/enable_set_priority_for_pricing_rules.py b/erpnext/patches/v14_0/enable_set_priority_for_pricing_rules.py new file mode 100644 index 00000000000..af87eeb2727 --- /dev/null +++ b/erpnext/patches/v14_0/enable_set_priority_for_pricing_rules.py @@ -0,0 +1,10 @@ +import frappe + + +def execute(): + pr_table = frappe.qb.DocType("Pricing Rule") + ( + frappe.qb.update(pr_table) + .set(pr_table.has_priority, 1) + .where((pr_table.priority.isnotnull()) & (pr_table.priority != "")) + ).run() From 649c192abe17dcbe576a3f27ffd6c3984803d81d Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Thu, 23 May 2024 15:37:00 +0530 Subject: [PATCH 17/67] fix: dict can not be used as parameter (#41598) --- erpnext/stock/stock_ledger.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 4e624c9acb0..0cd2ecdaaf5 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -1196,7 +1196,11 @@ def get_previous_sle_of_current_voucher(args, operator="<", exclude_current_vouc order by posting_datetime desc, creation desc limit 1 for update""", - args, + { + "item_code": args.get("item_code"), + "warehouse": args.get("warehouse"), + "posting_datetime": args.get("posting_datetime"), + }, as_dict=1, ) From 50f6afd588e08b75a22989fe85d31ba72fe0052f Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 9 Apr 2024 15:25:36 +0530 Subject: [PATCH 18/67] fix: Fetch outstanding and total amount for reference journal entry (cherry picked from commit f331f9b15cd219ecafddb71ffd8e3367d731ae3b) # Conflicts: # erpnext/accounts/doctype/payment_entry/payment_entry.js # erpnext/accounts/doctype/payment_entry/payment_entry.py --- .../doctype/payment_entry/payment_entry.js | 9 +++ .../doctype/payment_entry/payment_entry.py | 63 ++++++++++++------- .../payment_entry/test_payment_entry.py | 4 +- .../payment_request/payment_request.py | 6 +- 4 files changed, 58 insertions(+), 24 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index c0716ff19ae..6909ca2b04b 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -1395,8 +1395,17 @@ frappe.ui.form.on('Payment Entry Reference', { args: { reference_doctype: row.reference_doctype, reference_name: row.reference_name, +<<<<<<< HEAD party_account_currency: frm.doc.payment_type=="Receive" ? frm.doc.paid_from_account_currency : frm.doc.paid_to_account_currency +======= + party_account_currency: + frm.doc.payment_type == "Receive" + ? frm.doc.paid_from_account_currency + : frm.doc.paid_to_account_currency, + party_type: frm.doc.party_type, + party: frm.doc.party, +>>>>>>> f331f9b15c (fix: Fetch outstanding and total amount for reference journal entry) }, callback: function(r, rt) { if(r.message) { diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 370e1deaa40..0182e80c59d 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -348,7 +348,11 @@ class PaymentEntry(AccountsController): continue ref_details = get_reference_details( - d.reference_doctype, d.reference_name, self.party_account_currency + d.reference_doctype, + d.reference_name, + self.party_account_currency, + self.party_type, + self.party, ) # Only update exchange rate when the reference is Journal Entry @@ -1883,34 +1887,48 @@ def get_company_defaults(company): return frappe.get_cached_value("Company", company, fields, as_dict=1) -def get_outstanding_on_journal_entry(name): - gl = frappe.qb.DocType("GL Entry") - res = ( - frappe.qb.from_(gl) - .select( - Case() - .when( - gl.party_type == "Customer", - Coalesce(Sum(gl.debit_in_account_currency - gl.credit_in_account_currency), 0), - ) - .else_(Coalesce(Sum(gl.credit_in_account_currency - gl.debit_in_account_currency), 0)) - .as_("outstanding_amount") - ) +def get_outstanding_on_journal_entry(voucher_no, party_type, party): + ple = frappe.qb.DocType("Payment Ledger Entry") + + outstanding = ( + frappe.qb.from_(ple) + .select(Sum(ple.amount_in_account_currency)) .where( - (Coalesce(gl.party_type, "") != "") - & (gl.is_cancelled == 0) - & ((gl.voucher_no == name) | (gl.against_voucher == name)) + (ple.against_voucher_no == voucher_no) + & (ple.party_type == party_type) + & (ple.party == party) + & (ple.delinked == 0) ) - ).run(as_dict=True) + ).run() - outstanding_amount = res[0].get("outstanding_amount", 0) if res else 0 + outstanding_amount = outstanding[0][0] if outstanding else 0 - return outstanding_amount + total = ( + frappe.qb.from_(ple) + .select(Sum(ple.amount_in_account_currency)) + .where( + (ple.voucher_no == voucher_no) + & (ple.party_type == party_type) + & (ple.party == party) + & (ple.delinked == 0) + ) + ).run() + + total_amount = total[0][0] if total else 0 + + return outstanding_amount, total_amount @frappe.whitelist() +<<<<<<< HEAD def get_reference_details(reference_doctype, reference_name, party_account_currency): total_amount = outstanding_amount = exchange_rate = None +======= +def get_reference_details( + reference_doctype, reference_name, party_account_currency, party_type=None, party=None +): + total_amount = outstanding_amount = exchange_rate = account = None +>>>>>>> f331f9b15c (fix: Fetch outstanding and total amount for reference journal entry) ref_doc = frappe.get_doc(reference_doctype, reference_name) company_currency = ref_doc.get("company_currency") or erpnext.get_company_currency(ref_doc.company) @@ -1920,12 +1938,13 @@ def get_reference_details(reference_doctype, reference_name, party_account_curre exchange_rate = 1 elif reference_doctype == "Journal Entry" and ref_doc.docstatus == 1: - total_amount = ref_doc.get("total_amount") if ref_doc.multi_currency: exchange_rate = get_exchange_rate(party_account_currency, company_currency, ref_doc.posting_date) else: exchange_rate = 1 - outstanding_amount = get_outstanding_on_journal_entry(reference_name) + outstanding_amount, total_amount = get_outstanding_on_journal_entry( + reference_name, party_type, party + ) elif reference_doctype != "Journal Entry": if not total_amount: diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py index c600198999e..28dfae29966 100644 --- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py @@ -1087,7 +1087,9 @@ class TestPaymentEntry(FrappeTestCase): pe.source_exchange_rate = 50 pe.save() - ref_details = get_reference_details(so.doctype, so.name, pe.paid_from_account_currency) + ref_details = get_reference_details( + so.doctype, so.name, pe.paid_from_account_currency, "Customer", so.customer + ) expected_response = { "total_amount": 5000.0, "outstanding_amount": 5000.0, diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index 583735b1cc6..0fa2e7835eb 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -596,7 +596,11 @@ def update_payment_req_status(doc, method): if payment_request_name: ref_details = get_reference_details( - ref.reference_doctype, ref.reference_name, doc.party_account_currency + ref.reference_doctype, + ref.reference_name, + doc.party_account_currency, + doc.party_type, + doc.party, ) pay_req_doc = frappe.get_doc("Payment Request", payment_request_name) status = pay_req_doc.status From a6bf7c1ebdfbb9ca46db2284ebc4561759c44473 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 23 May 2024 15:06:05 +0530 Subject: [PATCH 19/67] chore: remove unused imports --- erpnext/accounts/doctype/payment_entry/payment_entry.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 0182e80c59d..5218f0ea344 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -9,8 +9,7 @@ import frappe from frappe import ValidationError, _, qb, scrub, throw from frappe.utils import cint, comma_or, flt, getdate, nowdate from frappe.utils.data import comma_and, fmt_money -from pypika import Case -from pypika.functions import Coalesce, Sum +from pypika.functions import Sum import erpnext from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_dimensions From 5230d411bf30ce2f168a7dca1fbf4f8087a7fd39 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 23 May 2024 15:05:58 +0530 Subject: [PATCH 20/67] chore: resolve conflicts --- .../accounts/doctype/payment_entry/payment_entry.js | 10 +--------- .../accounts/doctype/payment_entry/payment_entry.py | 7 +------ 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index 6909ca2b04b..e184a3e00fd 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -1395,17 +1395,9 @@ frappe.ui.form.on('Payment Entry Reference', { args: { reference_doctype: row.reference_doctype, reference_name: row.reference_name, -<<<<<<< HEAD - party_account_currency: frm.doc.payment_type=="Receive" ? - frm.doc.paid_from_account_currency : frm.doc.paid_to_account_currency -======= - party_account_currency: - frm.doc.payment_type == "Receive" - ? frm.doc.paid_from_account_currency - : frm.doc.paid_to_account_currency, + party_account_currency: frm.doc.payment_type == "Receive" ? frm.doc.paid_from_account_currency : frm.doc.paid_to_account_currency, party_type: frm.doc.party_type, party: frm.doc.party, ->>>>>>> f331f9b15c (fix: Fetch outstanding and total amount for reference journal entry) }, callback: function(r, rt) { if(r.message) { diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 5218f0ea344..fa5aabe1268 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -1919,15 +1919,10 @@ def get_outstanding_on_journal_entry(voucher_no, party_type, party): @frappe.whitelist() -<<<<<<< HEAD -def get_reference_details(reference_doctype, reference_name, party_account_currency): - total_amount = outstanding_amount = exchange_rate = None -======= def get_reference_details( reference_doctype, reference_name, party_account_currency, party_type=None, party=None ): - total_amount = outstanding_amount = exchange_rate = account = None ->>>>>>> f331f9b15c (fix: Fetch outstanding and total amount for reference journal entry) + total_amount = outstanding_amount = exchange_rate = None ref_doc = frappe.get_doc(reference_doctype, reference_name) company_currency = ref_doc.get("company_currency") or erpnext.get_company_currency(ref_doc.company) From c834a9de855ceaff128a96b74cbe006f2e1d1037 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 23 May 2024 17:01:24 +0530 Subject: [PATCH 21/67] refactor: remove 'format:' based naming in internal doctypes (cherry picked from commit e2ec3e453a4995cacabb676165b135cf43e07315) # Conflicts: # erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json # erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.json --- .../repost_accounting_ledger/repost_accounting_ledger.json | 7 ++++--- .../repost_payment_ledger/repost_payment_ledger.json | 5 ++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json index 5b7cd2b0b20..cef88965f6b 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json @@ -1,7 +1,5 @@ { "actions": [], - "allow_rename": 1, - "autoname": "format:ACC-REPOST-{#####}", "creation": "2023-07-04 13:07:32.923675", "default_view": "List", "doctype": "DocType", @@ -55,11 +53,14 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], +<<<<<<< HEAD "modified": "2023-09-26 14:21:27.362567", +======= + "modified": "2024-05-23 17:00:42.984798", +>>>>>>> e2ec3e453a (refactor: remove 'format:' based naming in internal doctypes) "modified_by": "Administrator", "module": "Accounts", "name": "Repost Accounting Ledger", - "naming_rule": "Expression", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.json b/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.json index ed8d395a0ec..84205990dda 100644 --- a/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.json +++ b/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.json @@ -1,6 +1,5 @@ { "actions": [], - "allow_rename": 1, "creation": "2022-10-19 21:59:33.553852", "doctype": "DocType", "editable_grid": 1, @@ -99,7 +98,11 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], +<<<<<<< HEAD "modified": "2023-09-26 14:21:35.719727", +======= + "modified": "2024-05-23 17:00:31.540640", +>>>>>>> e2ec3e453a (refactor: remove 'format:' based naming in internal doctypes) "modified_by": "Administrator", "module": "Accounts", "name": "Repost Payment Ledger", From 0dc2f78a2ed55677f837da4de3544935220c4910 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 23 May 2024 11:52:11 +0530 Subject: [PATCH 22/67] refactor: query payment ledger for payments (cherry picked from commit cb3c20dcd3704afc9d02539ca931e2bdd6fe4e4b) --- .../payment_period_based_on_invoice_date.py | 76 ++++++++++++------- 1 file changed, 47 insertions(+), 29 deletions(-) diff --git a/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py b/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py index 834eb5f519c..c78424cfab6 100644 --- a/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py +++ b/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py @@ -3,7 +3,8 @@ import frappe -from frappe import _ +from frappe import _, qb +from frappe.query_builder import Criterion from frappe.utils import flt, getdate from erpnext.accounts.report.accounts_receivable.accounts_receivable import ReceivablePayableReport @@ -129,51 +130,68 @@ def get_columns(filters): def get_conditions(filters): + ple = qb.DocType("Payment Ledger Entry") conditions = [] - if not filters.party_type: - if filters.payment_type == _("Outgoing"): - filters.party_type = "Supplier" - else: - filters.party_type = "Customer" - - if filters.party_type: - conditions.append("party_type=%(party_type)s") + conditions.append(ple.delinked.eq(0)) + if filters.payment_type == _("Outgoing"): + conditions.append(ple.party_type.eq("Supplier")) + conditions.append(ple.against_voucher_type.eq("Purchase Invoice")) + else: + conditions.append(ple.party_type.eq("Customer")) + conditions.append(ple.against_voucher_type.eq("Sales Invoice")) if filters.party: - conditions.append("party=%(party)s") - - if filters.party_type: - conditions.append("against_voucher_type=%(reference_type)s") - filters["reference_type"] = ( - "Sales Invoice" if filters.party_type == "Customer" else "Purchase Invoice" - ) + conditions.append(ple.party.eq(filters.party)) if filters.get("from_date"): - conditions.append("posting_date >= %(from_date)s") + conditions.append(ple.posting_date.gte(filters.get("from_date"))) if filters.get("to_date"): - conditions.append("posting_date <= %(to_date)s") + conditions.append(ple.posting_date.lte(filters.get("to_date"))) - return "and " + " and ".join(conditions) if conditions else "" + if filters.get("company"): + conditions.append(ple.company.eq(filters.get("company"))) + + return conditions def get_entries(filters): - return frappe.db.sql( - """select - voucher_type, voucher_no, party_type, party, posting_date, debit, credit, remarks, against_voucher - from `tabGL Entry` - where company=%(company)s and voucher_type in ('Journal Entry', 'Payment Entry') and is_cancelled = 0 {} - """.format(get_conditions(filters)), - filters, - as_dict=1, + ple = qb.DocType("Payment Ledger Entry") + conditions = get_conditions(filters) + + query = ( + qb.from_(ple) + .select( + ple.voucher_type, + ple.voucher_no, + ple.party_type, + ple.party, + ple.posting_date, + ple.amount, + ple.remarks, + ple.against_voucher_no, + ) + .where(Criterion.all(conditions)) ) + res = query.run(as_dict=True) + return res def get_invoice_posting_date_map(filters): invoice_details = {} - dt = "Sales Invoice" if filters.get("payment_type") == _("Incoming") else "Purchase Invoice" - for t in frappe.db.sql(f"select name, posting_date, due_date from `tab{dt}`", as_dict=1): + dt = ( + qb.DocType("Sales Invoice") + if filters.get("payment_type") == _("Incoming") + else qb.DocType("Purchase Invoice") + ) + res = ( + qb.from_(dt) + .select(dt.name, dt.posting_date, dt.due_date) + .where((dt.docstatus.eq(1)) & (dt.company.eq(filters.get("company")))) + .run(as_dict=1) + ) + for t in res: invoice_details[t.name] = t return invoice_details From 3512f7d528533cf8204b74ece9083d14af013ca5 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 23 May 2024 11:59:57 +0530 Subject: [PATCH 23/67] refactor: remove debit and credit (cherry picked from commit 014b542cf3aacba93f87f380470cd692598c14e3) --- .../payment_period_based_on_invoice_date.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py b/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py index c78424cfab6..04626bc528f 100644 --- a/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py +++ b/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py @@ -23,11 +23,7 @@ def execute(filters=None): data = [] for d in entries: invoice = invoice_details.get(d.against_voucher) or frappe._dict() - - if d.reference_type == "Purchase Invoice": - payment_amount = flt(d.debit) or -1 * flt(d.credit) - else: - payment_amount = flt(d.credit) or -1 * flt(d.debit) + payment_amount = d.amount d.update({"range1": 0, "range2": 0, "range3": 0, "range4": 0, "outstanding": payment_amount}) @@ -43,8 +39,7 @@ def execute(filters=None): d.against_voucher, invoice.posting_date, invoice.due_date, - d.debit, - d.credit, + d.amount, d.remarks, d.age, d.range1, @@ -112,8 +107,7 @@ def get_columns(filters): "width": 100, }, {"fieldname": "due_date", "label": _("Payment Due Date"), "fieldtype": "Date", "width": 100}, - {"fieldname": "debit", "label": _("Debit"), "fieldtype": "Currency", "width": 140}, - {"fieldname": "credit", "label": _("Credit"), "fieldtype": "Currency", "width": 140}, + {"fieldname": "amount", "label": _("Amount"), "fieldtype": "Currency", "width": 140}, {"fieldname": "remarks", "label": _("Remarks"), "fieldtype": "Data", "width": 200}, {"fieldname": "age", "label": _("Age"), "fieldtype": "Int", "width": 50}, {"fieldname": "range1", "label": _("0-30"), "fieldtype": "Currency", "width": 140}, From 190900cd1bcaec3aebe7a2d757caa6da79ab93ef Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 23 May 2024 12:08:51 +0530 Subject: [PATCH 24/67] refactor: replace against_voucher with against_voucher_no (cherry picked from commit c4e2abb9739da20be3409cde87c014d0d689e1b6) --- .../payment_period_based_on_invoice_date.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py b/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py index 04626bc528f..f3f30d38a04 100644 --- a/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py +++ b/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.py @@ -5,6 +5,7 @@ import frappe from frappe import _, qb from frappe.query_builder import Criterion +from frappe.query_builder.functions import Abs from frappe.utils import flt, getdate from erpnext.accounts.report.accounts_receivable.accounts_receivable import ReceivablePayableReport @@ -22,12 +23,12 @@ def execute(filters=None): data = [] for d in entries: - invoice = invoice_details.get(d.against_voucher) or frappe._dict() + invoice = invoice_details.get(d.against_voucher_no) or frappe._dict() payment_amount = d.amount d.update({"range1": 0, "range2": 0, "range3": 0, "range4": 0, "outstanding": payment_amount}) - if d.against_voucher: + if d.against_voucher_no: ReceivablePayableReport(filters).get_ageing_data(invoice.posting_date, d) row = [ @@ -36,7 +37,7 @@ def execute(filters=None): d.party_type, d.party, d.posting_date, - d.against_voucher, + d.against_voucher_no, invoice.posting_date, invoice.due_date, d.amount, @@ -162,7 +163,7 @@ def get_entries(filters): ple.party_type, ple.party, ple.posting_date, - ple.amount, + Abs(ple.amount).as_("amount"), ple.remarks, ple.against_voucher_no, ) From 0f9b5074a6a4b02b1a3e3bdf56e6c8c1c62cca06 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 23 May 2024 17:46:23 +0530 Subject: [PATCH 25/67] chore: resolve conflicts --- .../repost_accounting_ledger/repost_accounting_ledger.json | 4 ---- .../doctype/repost_payment_ledger/repost_payment_ledger.json | 4 ---- 2 files changed, 8 deletions(-) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json index cef88965f6b..f9344ce4f3a 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json @@ -53,11 +53,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], -<<<<<<< HEAD - "modified": "2023-09-26 14:21:27.362567", -======= "modified": "2024-05-23 17:00:42.984798", ->>>>>>> e2ec3e453a (refactor: remove 'format:' based naming in internal doctypes) "modified_by": "Administrator", "module": "Accounts", "name": "Repost Accounting Ledger", diff --git a/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.json b/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.json index 84205990dda..4ecff8cac3b 100644 --- a/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.json +++ b/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.json @@ -98,11 +98,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], -<<<<<<< HEAD - "modified": "2023-09-26 14:21:35.719727", -======= "modified": "2024-05-23 17:00:31.540640", ->>>>>>> e2ec3e453a (refactor: remove 'format:' based naming in internal doctypes) "modified_by": "Administrator", "module": "Accounts", "name": "Repost Payment Ledger", From 459d13636823cf9faef760b1fd7f1f303e6b3d8d Mon Sep 17 00:00:00 2001 From: "Nihantra C. Patel" <141945075+Nihantra-Patel@users.noreply.github.com> Date: Fri, 10 May 2024 12:31:15 +0530 Subject: [PATCH 26/67] fix: cost center filter according to the company in project (cherry picked from commit 249e8264ddde2f3397a65b19492560069e18a02b) --- erpnext/projects/doctype/project/project.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/erpnext/projects/doctype/project/project.js b/erpnext/projects/doctype/project/project.js index 3ea8189feec..271fe4e36e2 100644 --- a/erpnext/projects/doctype/project/project.js +++ b/erpnext/projects/doctype/project/project.js @@ -57,6 +57,14 @@ frappe.ui.form.on("Project", { filters: filters, }; }); + + frm.set_query("cost_center", () => { + return { + filters: { + company: frm.doc.company, + } + } + }); }, refresh: function (frm) { From 0cf97f255982c921d528747b6daa6d96a12e265d Mon Sep 17 00:00:00 2001 From: "Nihantra C. Patel" <141945075+Nihantra-Patel@users.noreply.github.com> Date: Fri, 10 May 2024 12:35:24 +0530 Subject: [PATCH 27/67] fix: cost center filter according to the company in project (cherry picked from commit cfde8088b43d884858dbfaec5ce1937a4ccf9eb3) --- erpnext/projects/doctype/project/project.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/projects/doctype/project/project.js b/erpnext/projects/doctype/project/project.js index 271fe4e36e2..8d320e84713 100644 --- a/erpnext/projects/doctype/project/project.js +++ b/erpnext/projects/doctype/project/project.js @@ -62,8 +62,8 @@ frappe.ui.form.on("Project", { return { filters: { company: frm.doc.company, - } - } + }, + }, }); }, From 7035969db7563061b2df89349eed8c22dc365150 Mon Sep 17 00:00:00 2001 From: "Nihantra C. Patel" <141945075+Nihantra-Patel@users.noreply.github.com> Date: Fri, 10 May 2024 12:40:01 +0530 Subject: [PATCH 28/67] fix: cost center filter according to the company in project (cherry picked from commit 501c6aa1267a11109ca47bb9bfeab3d4ead0d794) --- erpnext/projects/doctype/project/project.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/projects/doctype/project/project.js b/erpnext/projects/doctype/project/project.js index 8d320e84713..6ac6d1f88a6 100644 --- a/erpnext/projects/doctype/project/project.js +++ b/erpnext/projects/doctype/project/project.js @@ -63,7 +63,7 @@ frappe.ui.form.on("Project", { filters: { company: frm.doc.company, }, - }, + }; }); }, From c16c41ee593bfafa4c5563f527babdb4c16b309a Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Thu, 23 May 2024 16:36:41 +0530 Subject: [PATCH 29/67] fix: add in some indices to speed up Purchase Order deletion `tabSales Order`.`inter_company_order_reference` `tabSales Invoice Item`.`purchase_order` Signed-off-by: Akhil Narang (cherry picked from commit 0303d7dbdc7a84679034e5ba793a13823a7c8f24) # Conflicts: # erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json # erpnext/selling/doctype/sales_order/sales_order.json --- .../doctype/sales_invoice_item/sales_invoice_item.json | 7 ++++++- erpnext/selling/doctype/sales_order/sales_order.json | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json index 87cf1ae80d6..29261e47627 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -867,7 +867,8 @@ "label": "Purchase Order", "options": "Purchase Order", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "search_index": 1 }, { "fieldname": "column_break_92", @@ -892,7 +893,11 @@ "idx": 1, "istable": 1, "links": [], +<<<<<<< HEAD "modified": "2023-11-14 18:34:10.479329", +======= + "modified": "2024-05-23 16:36:18.970862", +>>>>>>> 0303d7dbdc (fix: add in some indices to speed up Purchase Order deletion) "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index 09b73878aa2..b3fb51c4fb8 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -1138,7 +1138,8 @@ "hide_seconds": 1, "label": "Inter Company Order Reference", "options": "Purchase Order", - "read_only": 1 + "read_only": 1, + "search_index": 1 }, { "fieldname": "project", @@ -1631,7 +1632,11 @@ "idx": 105, "is_submittable": 1, "links": [], +<<<<<<< HEAD "modified": "2024-03-20 16:04:43.627183", +======= + "modified": "2024-05-23 16:35:54.905804", +>>>>>>> 0303d7dbdc (fix: add in some indices to speed up Purchase Order deletion) "modified_by": "Administrator", "module": "Selling", "name": "Sales Order", From f1f2f6e3388df52cc883805d4b8d0195728abf81 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Fri, 24 May 2024 11:05:45 +0530 Subject: [PATCH 30/67] chore: resolve conflicts --- .../doctype/sales_invoice_item/sales_invoice_item.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json index 29261e47627..5e7a75b8a3f 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -893,11 +893,7 @@ "idx": 1, "istable": 1, "links": [], -<<<<<<< HEAD - "modified": "2023-11-14 18:34:10.479329", -======= "modified": "2024-05-23 16:36:18.970862", ->>>>>>> 0303d7dbdc (fix: add in some indices to speed up Purchase Order deletion) "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", From 220ae118e816a2a1a1f0a1fbc387315fca5d68af Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Fri, 24 May 2024 11:08:53 +0530 Subject: [PATCH 31/67] chore: resolve conflicts --- erpnext/selling/doctype/sales_order/sales_order.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index b3fb51c4fb8..43e8e41f7f3 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -1632,11 +1632,7 @@ "idx": 105, "is_submittable": 1, "links": [], -<<<<<<< HEAD - "modified": "2024-03-20 16:04:43.627183", -======= "modified": "2024-05-23 16:35:54.905804", ->>>>>>> 0303d7dbdc (fix: add in some indices to speed up Purchase Order deletion) "modified_by": "Administrator", "module": "Selling", "name": "Sales Order", @@ -1715,4 +1711,4 @@ "title_field": "customer_name", "track_changes": 1, "track_seen": 1 -} \ No newline at end of file +} From 518dad8ecba61acd80ce6eb0bd3e050b0f585024 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 17 Apr 2024 12:49:01 +0530 Subject: [PATCH 32/67] ci: dont auto apply fixes I've personally encountered ~5 instances of bad auto fixes, let developers apply the fixes. (cherry picked from commit 3b4913ec810bcee60537380bdc721c04a4e823c6) --- .pre-commit-config.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1f670f2bec3..14bd9e8f0c4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -69,8 +69,7 @@ repos: rev: v0.2.0 hooks: - id: ruff - name: "Run ruff linter and apply fixes" - args: ["--fix"] + name: "Run ruff linter" - id: ruff-format name: "Format Python code" From 76b7884fb7a8d60e1282f58e652b73f597439bce Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 21 May 2024 16:05:16 +0530 Subject: [PATCH 33/67] ci: ruff only fix imports (cherry picked from commit 85b1a8001b30429800ca5c6bef960c885368819b) --- .pre-commit-config.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 14bd9e8f0c4..56bcb22c9bb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -68,12 +68,15 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.2.0 hooks: + - id: ruff + name: "Run ruff import sorter" + args: ["--select=I", "--fix"] + - id: ruff name: "Run ruff linter" - id: ruff-format - name: "Format Python code" - + name: "Run ruff formatter" ci: autoupdate_schedule: weekly From 5b2c13dacf32c80ca1cf444f2bf98829d59850e1 Mon Sep 17 00:00:00 2001 From: Akhil Narang Date: Thu, 23 May 2024 19:30:42 +0530 Subject: [PATCH 34/67] refactor: use `json` directly instead of using `frappe.json` (#41609) (cherry picked from commit 3f06f1905f6c86eaa5eb4d33765a46470892f576) Signed-off-by: Akhil Narang --- .../doctype/pos_invoice_merge_log/pos_invoice_merge_log.py | 2 +- .../process_payment_reconciliation.py | 4 +++- erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py | 5 +++-- .../doctype/unreconcile_payment/unreconcile_payment.py | 4 +++- erpnext/accounts/utils.py | 2 +- erpnext/selling/doctype/customer/test_customer.py | 4 +++- 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py index 1302a0c386c..0d02172226e 100644 --- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py +++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py @@ -441,7 +441,7 @@ def create_merge_logs(invoice_by_customer, closing_entry=None): if closing_entry: closing_entry.set_status(update=True, status="Failed") if isinstance(error_message, list): - error_message = frappe.json.dumps(error_message) + error_message = json.dumps(error_message) closing_entry.db_set("error_message", error_message) raise diff --git a/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.py b/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.py index c7535e76d7e..b1419020f0f 100644 --- a/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.py +++ b/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.py @@ -1,6 +1,8 @@ # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt +import json + import frappe from frappe import _, qb from frappe.model.document import Document @@ -479,7 +481,7 @@ def is_any_doc_running(for_filter: str | dict | None = None) -> str | None: running_doc = None if for_filter: if isinstance(for_filter, str): - for_filter = frappe.json.loads(for_filter) + for_filter = json.loads(for_filter) running_doc = frappe.db.get_value( "Process Payment Reconciliation", diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 87d297f4aa1..9c7cfa4387e 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2,6 +2,7 @@ # License: GNU General Public License v3. See license.txt import copy +import json import frappe from frappe.model.dynamic_links import get_dynamic_link_map @@ -3479,9 +3480,9 @@ class TestSalesInvoice(FrappeTestCase): map_docs( method="erpnext.stock.doctype.delivery_note.delivery_note.make_sales_invoice", - source_names=frappe.json.dumps([dn1.name, dn2.name]), + source_names=json.dumps([dn1.name, dn2.name]), target_doc=si, - args=frappe.json.dumps({"customer": dn1.customer, "merge_taxes": 1, "filtered_children": []}), + args=json.dumps({"customer": dn1.customer, "merge_taxes": 1, "filtered_children": []}), ) si.save().submit() diff --git a/erpnext/accounts/doctype/unreconcile_payment/unreconcile_payment.py b/erpnext/accounts/doctype/unreconcile_payment/unreconcile_payment.py index 091bccf5099..6ba1de35238 100644 --- a/erpnext/accounts/doctype/unreconcile_payment/unreconcile_payment.py +++ b/erpnext/accounts/doctype/unreconcile_payment/unreconcile_payment.py @@ -1,6 +1,8 @@ # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt +import json + import frappe from frappe import _, qb from frappe.model.document import Document @@ -142,7 +144,7 @@ def get_linked_payments_for_doc( @frappe.whitelist() def create_unreconcile_doc_for_selection(selections=None): if selections: - selections = frappe.json.loads(selections) + selections = json.loads(selections) # assuming each row is a unique voucher for row in selections: unrecon = frappe.new_doc("Unreconcile Payment") diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 377eeae7cff..7e67085f5dd 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -56,7 +56,7 @@ def get_fiscal_year( date=None, fiscal_year=None, label="Date", verbose=1, company=None, as_dict=False, boolean=False ): if isinstance(boolean, str): - boolean = frappe.json.loads(boolean) + boolean = loads(boolean) fiscal_years = get_fiscal_years( date, fiscal_year, label, verbose, company, as_dict=as_dict, boolean=boolean diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py index 61e5d5e457c..23052299330 100644 --- a/erpnext/selling/doctype/customer/test_customer.py +++ b/erpnext/selling/doctype/customer/test_customer.py @@ -2,6 +2,8 @@ # License: GNU General Public License v3. See license.txt +import json + import frappe from frappe.custom.doctype.property_setter.property_setter import make_property_setter from frappe.test_runner import make_test_records @@ -322,7 +324,7 @@ class TestCustomer(FrappeTestCase): frappe.ValidationError, update_child_qty_rate, so.doctype, - frappe.json.dumps([modified_item]), + json.dumps([modified_item]), so.name, ) 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 35/67] 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 349c328c06c..7b300d57195 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 36/67] 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 ff4ac50850f..24962f2088e 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 37/67] 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 24962f2088e..496dd44ad86 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 7b300d57195..70a0872a2c4 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 014486de39dd7da6fe79bf803adcf1b66d890876 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 29 May 2024 10:46:06 +0530 Subject: [PATCH 38/67] fix: set expense account as Assets RBNB only if it is booked in linked PR (#41368) * fix: set expense account as Assets RBNB only if it is booked in linked PR * fix: broken translations --- .../pos_closing_entry/pos_closing_entry.py | 2 +- .../pos_invoice_merge_log.py | 2 +- .../purchase_invoice/purchase_invoice.py | 52 ++++++++++++------- 3 files changed, 35 insertions(+), 21 deletions(-) diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py index f61bfdb58ab..4e4a7492a00 100644 --- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py +++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py @@ -33,7 +33,7 @@ class POSClosingEntry(StatusUpdater): for key, value in pos_occurences.items(): if len(value) > 1: error_list.append( - _(f"{frappe.bold(key)} is added multiple times on rows: {frappe.bold(value)}") + _("{0} is added multiple times on rows: {1}").format(frappe.bold(key), frappe.bold(value)) ) if error_list: diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py index 0d02172226e..a183a5ee6aa 100644 --- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py +++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py @@ -29,7 +29,7 @@ class POSInvoiceMergeLog(Document): for key, value in pos_occurences.items(): if len(value) > 1: error_list.append( - _(f"{frappe.bold(key)} is added multiple times on rows: {frappe.bold(value)}") + _("{0} is added multiple times on rows: {1}").format(frappe.bold(key), frappe.bold(value)) ) if error_list: diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 77f879a1f42..c5f089fd24d 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -284,7 +284,7 @@ class PurchaseInvoice(BuyingController): stock_not_billed_account = self.get_company_default("stock_received_but_not_billed") stock_items = self.get_stock_items() - asset_received_but_not_billed = None + asset_received_but_not_billed = self.get_company_default("asset_received_but_not_billed") if self.update_stock: self.validate_item_code() @@ -367,26 +367,40 @@ class PurchaseInvoice(BuyingController): frappe.msgprint(msg, title=_("Expense Head Changed")) item.expense_account = stock_not_billed_account - elif item.is_fixed_asset and item.pr_detail: - if not asset_received_but_not_billed: - asset_received_but_not_billed = self.get_company_default("asset_received_but_not_billed") - item.expense_account = asset_received_but_not_billed elif item.is_fixed_asset: - account_type = ( - "capital_work_in_progress_account" - if is_cwip_accounting_enabled(item.asset_category) - else "fixed_asset_account" - ) - asset_category_account = get_asset_category_account( - account_type, item=item.item_code, company=self.company - ) - if not asset_category_account: - form_link = get_link_to_form("Asset Category", item.asset_category) - throw( - _("Please set Fixed Asset Account in {} against {}.").format(form_link, self.company), - title=_("Missing Account"), + account = None + if item.pr_detail: + # check if 'Asset Received But Not Billed' account is credited in Purchase receipt or not + arbnb_booked_in_pr = frappe.db.get_value( + "GL Entry", + { + "voucher_type": "Purchase Receipt", + "voucher_no": item.purchase_receipt, + "account": asset_received_but_not_billed, + }, + "name", ) - item.expense_account = asset_category_account + if arbnb_booked_in_pr: + account = asset_received_but_not_billed + + if not account: + account_type = ( + "capital_work_in_progress_account" + if is_cwip_accounting_enabled(item.asset_category) + else "fixed_asset_account" + ) + account = get_asset_category_account( + account_type, item=item.item_code, company=self.company + ) + if not account: + form_link = get_link_to_form("Asset Category", item.asset_category) + throw( + _("Please set Fixed Asset Account in {} against {}.").format( + form_link, self.company + ), + title=_("Missing Account"), + ) + item.expense_account = account elif not item.expense_account and for_validate: throw(_("Expense account is mandatory for item {0}").format(item.item_code or item.item_name)) From eb418e865945a208338db65e7fb1f259cc7f94b5 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 29 May 2024 11:07:03 +0530 Subject: [PATCH 39/67] fix: Update depreciation schedule via asset repair (#41344) * fix: Update depreciation schedule via asset repair * fix: test cases related to modified depreciation schedule --- .../sales_invoice/test_sales_invoice.py | 4 +--- erpnext/assets/doctype/asset/asset.py | 22 +++++++++++++------ erpnext/assets/doctype/asset/test_asset.py | 4 ++-- .../test_asset_value_adjustment.py | 11 +++++----- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 9c7cfa4387e..f22218fcd33 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2979,10 +2979,8 @@ class TestSalesInvoice(FrappeTestCase): ["2021-06-30", 20000.0, 21366.12, True], ["2022-06-30", 20000.0, 41366.12, False], ["2023-06-30", 20000.0, 61366.12, False], - ["2024-06-30", 20000.0, 81366.12, False], - ["2025-06-06", 18633.88, 100000.0, False], + ["2024-06-06", 38633.88, 100000.0, False], ] - for i, schedule in enumerate(asset.schedules): self.assertEqual(getdate(expected_values[i][0]), schedule.schedule_date) self.assertEqual(expected_values[i][1], schedule.depreciation_amount) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index fd00a495030..405eda8d09f 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -12,6 +12,7 @@ from frappe.utils import ( add_months, add_years, cint, + cstr, date_diff, flt, get_datetime, @@ -361,9 +362,11 @@ class Asset(AccountsController): final_number_of_depreciations = cint(finance_book.total_number_of_depreciations) - cint( self.number_of_depreciations_booked ) - has_pro_rata = self.check_is_pro_rata(finance_book) - if has_pro_rata: + depr_already_booked = any( + [d.journal_entry for d in self.get("schedules") if d.finance_book == finance_book.finance_book] + ) + if has_pro_rata and not depr_already_booked: final_number_of_depreciations += 1 has_wdv_or_dd_non_yearly_pro_rata = False @@ -543,7 +546,7 @@ class Asset(AccountsController): "depreciation_amount": depreciation_amount, "depreciation_method": finance_book.depreciation_method, "finance_book": finance_book.finance_book, - "finance_book_id": finance_book.idx, + "finance_book_id": cstr(finance_book.idx), "shift": shift, }, ) @@ -749,7 +752,6 @@ class Asset(AccountsController): ): straight_line_idx = [] finance_books = [] - for i, d in enumerate(self.get("schedules")): if ignore_booked_entry and d.journal_entry: continue @@ -771,7 +773,10 @@ class Asset(AccountsController): finance_books.append(int(d.finance_book_id)) depreciation_amount = flt(d.depreciation_amount, d.precision("depreciation_amount")) - value_after_depreciation -= flt(depreciation_amount) + if not d.journal_entry: + value_after_depreciation = flt( + flt(value_after_depreciation) - depreciation_amount, d.precision("depreciation_amount") + ) # for the last row, if depreciation method = Straight Line if ( @@ -783,10 +788,13 @@ class Asset(AccountsController): book = self.get("finance_books")[cint(d.finance_book_id) - 1] if not book.shift_based: - depreciation_amount += flt( + adjustment_amount = flt( value_after_depreciation - flt(book.expected_value_after_useful_life), d.precision("depreciation_amount"), ) + depreciation_amount = flt( + depreciation_amount + adjustment_amount, d.precision("depreciation_amount") + ) d.depreciation_amount = depreciation_amount accumulated_depreciation += d.depreciation_amount @@ -1433,7 +1441,7 @@ def get_straight_line_or_manual_depr_amount(asset, row, schedule_idx, number_of_ # if the Depreciation Schedule is being modified after Asset Repair due to increase in asset value elif asset.flags.increase_in_asset_value_due_to_repair: return (flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)) / flt( - row.total_number_of_depreciations + number_of_pending_depreciations ) # if the Depreciation Schedule is being modified after Asset Value Adjustment due to decrease in asset value elif asset.flags.decrease_in_asset_value_due_to_value_adjustment: diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index 00a53aa80d2..dc58222008a 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -1355,9 +1355,9 @@ class TestDepreciationBasics(AssetSetup): for schedule in asset.schedules: if schedule.idx <= 3: - self.assertEqual(schedule.finance_book_id, 1) + self.assertEqual(schedule.finance_book_id, "1") else: - self.assertEqual(schedule.finance_book_id, 2) + self.assertEqual(schedule.finance_book_id, "2") def test_depreciation_entry_cancellation(self): asset = create_asset( diff --git a/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py index 7661e70fd17..f3583b0768d 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py +++ b/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py @@ -103,12 +103,11 @@ class TestAssetValueAdjustment(unittest.TestCase): ["2023-05-31", 9983.33, 45408.05], ["2023-06-30", 9983.33, 55391.38], ["2023-07-31", 9983.33, 65374.71], - ["2023-08-31", 8300.0, 73674.71], - ["2023-09-30", 8300.0, 81974.71], - ["2023-10-31", 8300.0, 90274.71], - ["2023-11-30", 8300.0, 98574.71], - ["2023-12-31", 8300.0, 106874.71], - ["2024-01-15", 8300.0, 115174.71], + ["2023-08-31", 9960.0, 75334.71], + ["2023-09-30", 9960.0, 85294.71], + ["2023-10-31", 9960.0, 95254.71], + ["2023-11-30", 9960.0, 105214.71], + ["2023-12-15", 9960.0, 115174.71], ] schedules = [ From 570985f40e06554edf6c349a16baafd0fb6a01bd Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 29 May 2024 12:25:56 +0530 Subject: [PATCH 40/67] fix: Filters in account balance report (cherry picked from commit 1c9fe691ea924a4b5f579544b639c7fb51017d07) --- erpnext/accounts/report/account_balance/account_balance.py | 1 - 1 file changed, 1 deletion(-) diff --git a/erpnext/accounts/report/account_balance/account_balance.py b/erpnext/accounts/report/account_balance/account_balance.py index 6f9f7ebcb8d..f385c71a9f4 100644 --- a/erpnext/accounts/report/account_balance/account_balance.py +++ b/erpnext/accounts/report/account_balance/account_balance.py @@ -49,7 +49,6 @@ def get_conditions(filters): if filters.account_type: conditions["account_type"] = filters.account_type - return conditions if filters.company: conditions["company"] = filters.company From 39885b2b010b25257ca82d41d316ca3b87c7dfca Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 3 Jun 2024 14:05:57 +0530 Subject: [PATCH 41/67] fix: get assets received but not billed account only if any asset item is received (#41734) fix: get assets received but not billed account only if any asset item received --- .../doctype/purchase_invoice/purchase_invoice.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index c5f089fd24d..e0debba6fd5 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -284,7 +284,7 @@ class PurchaseInvoice(BuyingController): stock_not_billed_account = self.get_company_default("stock_received_but_not_billed") stock_items = self.get_stock_items() - asset_received_but_not_billed = self.get_company_default("asset_received_but_not_billed") + self.asset_received_but_not_billed = None if self.update_stock: self.validate_item_code() @@ -370,18 +370,23 @@ class PurchaseInvoice(BuyingController): elif item.is_fixed_asset: account = None if item.pr_detail: + if not self.asset_received_but_not_billed: + self.asset_received_but_not_billed = self.get_company_default( + "asset_received_but_not_billed" + ) + # check if 'Asset Received But Not Billed' account is credited in Purchase receipt or not arbnb_booked_in_pr = frappe.db.get_value( "GL Entry", { "voucher_type": "Purchase Receipt", "voucher_no": item.purchase_receipt, - "account": asset_received_but_not_billed, + "account": self.asset_received_but_not_billed, }, "name", ) if arbnb_booked_in_pr: - account = asset_received_but_not_billed + account = self.asset_received_but_not_billed if not account: account_type = ( From 8c09968e1bd227bdd714b8148aca87dc4ee702de Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 3 Jun 2024 17:31:27 +0530 Subject: [PATCH 42/67] chore: Sys Manager shluld have submit permission for repost doctypes (cherry picked from commit 4558f64c0fa7c2297a378211468186a7df8f2a8a) --- .../repost_accounting_ledger/repost_accounting_ledger.json | 6 +++++- .../repost_payment_ledger/repost_payment_ledger.json | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json index f9344ce4f3a..0d74b2150f7 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json +++ b/erpnext/accounts/doctype/repost_accounting_ledger/repost_accounting_ledger.json @@ -53,13 +53,15 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2024-05-23 17:00:42.984798", + "modified": "2024-06-03 17:30:37.012593", "modified_by": "Administrator", "module": "Accounts", "name": "Repost Accounting Ledger", "owner": "Administrator", "permissions": [ { + "amend": 1, + "cancel": 1, "create": 1, "delete": 1, "email": 1, @@ -68,7 +70,9 @@ "read": 1, "report": 1, "role": "System Manager", + "select": 1, "share": 1, + "submit": 1, "write": 1 } ], diff --git a/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.json b/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.json index 4ecff8cac3b..2b4efead7f3 100644 --- a/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.json +++ b/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.json @@ -98,13 +98,15 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2024-05-23 17:00:31.540640", + "modified": "2024-06-03 17:31:04.472279", "modified_by": "Administrator", "module": "Accounts", "name": "Repost Payment Ledger", "owner": "Administrator", "permissions": [ { + "amend": 1, + "cancel": 1, "create": 1, "delete": 1, "email": 1, @@ -113,7 +115,9 @@ "read": 1, "report": 1, "role": "System Manager", + "select": 1, "share": 1, + "submit": 1, "write": 1 }, { From dc3265751c55e493a8ea617703dc5113b87d2c14 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 18:37:26 +0530 Subject: [PATCH 43/67] fix: payment term when creating PO from SO (backport #41376) (#41743) fix: payment term when creating PO from SO (#41376) * fix: payment term when creating PO from SO * fix: payment term when creating PO from SO * fix: payment term when creating PO from SO * fix: payment term when creating PO from SO (cherry picked from commit 441596f795b7968fb0166dc794a11cfb73408358) Co-authored-by: Nihantra C. Patel <141945075+Nihantra-Patel@users.noreply.github.com> --- erpnext/selling/doctype/sales_order/sales_order.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 68fa67e92f1..c3f14e1f948 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -932,11 +932,19 @@ def make_purchase_order_for_default_supplier(source_name, selected_items=None, t target.discount_amount = 0.0 target.inter_company_order_reference = "" target.shipping_rule = "" + target.tc_name = "" + target.terms = "" + target.payment_terms_template = "" + target.payment_schedule = [] default_price_list = frappe.get_value("Supplier", supplier, "default_price_list") if default_price_list: target.buying_price_list = default_price_list + default_payment_terms = frappe.get_value("Supplier", supplier, "payment_terms") + if default_payment_terms: + target.payment_terms_template = default_payment_terms + if any(item.delivered_by_supplier == 1 for item in source.items): if source.shipping_address_name: target.shipping_address = source.shipping_address_name @@ -988,7 +996,6 @@ def make_purchase_order_for_default_supplier(source_name, selected_items=None, t "contact_person", "taxes_and_charges", "shipping_address", - "terms", ], "validation": {"docstatus": ["=", 1]}, }, @@ -1056,6 +1063,10 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None): target.discount_amount = 0.0 target.inter_company_order_reference = "" target.shipping_rule = "" + target.tc_name = "" + target.terms = "" + target.payment_terms_template = "" + target.payment_schedule = [] if is_drop_ship_order(target): target.customer = source.customer @@ -1091,7 +1102,6 @@ def make_purchase_order(source_name, selected_items=None, target_doc=None): "contact_person", "taxes_and_charges", "shipping_address", - "terms", ], "validation": {"docstatus": ["=", 1]}, }, From 5ab5bd138fe65f131afec8608af0f42c1ede037f Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 4 Jun 2024 11:55:42 +0530 Subject: [PATCH 44/67] fix: Ignore disabling default currency field while creating new company (backport #41699) (#41760) fix: Ignore disabling default currency field while creating new company (#41699) (cherry picked from commit 80f6228d45b67147815af15b27058b0173b402af) Co-authored-by: Nabin Hait --- erpnext/setup/doctype/company/company.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js index 6c237d787bb..ff4e186d6ce 100644 --- a/erpnext/setup/doctype/company/company.js +++ b/erpnext/setup/doctype/company/company.js @@ -12,10 +12,11 @@ frappe.ui.form.on("Company", { } }); } - - frm.call("check_if_transactions_exist").then((r) => { - frm.toggle_enable("default_currency", !r.message); - }); + if (!frm.doc.__islocal) { + frm.call("check_if_transactions_exist").then((r) => { + frm.toggle_enable("default_currency", !r.message); + }); + } }, setup: function (frm) { frm.__rename_queue = "long"; From a5bda0180e866571a566fb93d23e8a7841d0873c Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 6 Jun 2024 13:57:14 +0530 Subject: [PATCH 45/67] chore: repost settings permission overhaul (cherry picked from commit 458d8f5ed8affecf0d25bd732dc5af6f786d894c) --- .../repost_accounting_ledger_settings.json | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/repost_accounting_ledger_settings/repost_accounting_ledger_settings.json b/erpnext/accounts/doctype/repost_accounting_ledger_settings/repost_accounting_ledger_settings.json index 8aa0a840c7e..dd314ca6601 100644 --- a/erpnext/accounts/doctype/repost_accounting_ledger_settings/repost_accounting_ledger_settings.json +++ b/erpnext/accounts/doctype/repost_accounting_ledger_settings/repost_accounting_ledger_settings.json @@ -17,7 +17,7 @@ "in_create": 1, "issingle": 1, "links": [], - "modified": "2023-11-07 14:24:13.321522", + "modified": "2024-06-06 13:56:37.908879", "modified_by": "Administrator", "module": "Accounts", "name": "Repost Accounting Ledger Settings", @@ -30,13 +30,17 @@ "print": 1, "read": 1, "role": "Administrator", + "select": 1, "share": 1, "write": 1 }, { + "create": 1, + "delete": 1, "read": 1, "role": "System Manager", - "select": 1 + "select": 1, + "write": 1 } ], "sort_field": "modified", From 5d97c7cff941cb2af01912a5e6543af0b7e8efc1 Mon Sep 17 00:00:00 2001 From: Poorvi Date: Fri, 10 May 2024 11:47:57 +0530 Subject: [PATCH 46/67] fix: fixing Item-wise sales register (cherry picked from commit c90185f5331e2271afb5ddc22340d3704f5bbcd3) --- .../accounts/report/purchase_register/purchase_register.py | 6 ++++-- erpnext/accounts/report/sales_register/sales_register.py | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index 92d91a4cc46..c5f6e97d542 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -376,8 +376,10 @@ def get_account_columns(invoice_list, include_payments): def get_invoices(filters, additional_query_columns): pi = frappe.qb.DocType("Purchase Invoice") + pii = frappe.qb.DocType("Purchase Invoice Item") query = ( frappe.qb.from_(pi) + .left_join(pii).on(pi.name == pii.parent) .select( ConstantColumn("Purchase Invoice").as_("doctype"), pi.name, @@ -386,7 +388,7 @@ def get_invoices(filters, additional_query_columns): pi.supplier, pi.supplier_name, pi.tax_id, - pi.bill_no, + pi.bill_no, pi.bill_date, pi.remarks, pi.base_net_total, @@ -395,7 +397,7 @@ def get_invoices(filters, additional_query_columns): pi.outstanding_amount, pi.mode_of_payment, ) - .where(pi.docstatus == 1) + .where((pi.docstatus == 1) & pii.item_code.isnotnull()) .orderby(pi.posting_date, pi.name, order=Order.desc) ) diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index 3e7ac1a818d..31fcf0da963 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -414,9 +414,11 @@ def get_account_columns(invoice_list, include_payments): def get_invoices(filters, additional_query_columns): si = frappe.qb.DocType("Sales Invoice") + sii = frappe.qb.DocType("Sales Invoice Item") query = ( frappe.qb.from_(si) - .select( + .left_join(sii).on(si.name == sii.parent) + .select( ConstantColumn("Sales Invoice").as_("doctype"), si.name, si.posting_date, @@ -437,7 +439,7 @@ def get_invoices(filters, additional_query_columns): si.represents_company, si.company, ) - .where(si.docstatus == 1) + .where((si.docstatus == 1) & sii.item_code.isnotnull()) .orderby(si.posting_date, si.name, order=Order.desc) ) From bc24e75c246160678d731dbfc0a043523583a940 Mon Sep 17 00:00:00 2001 From: Poorvi-R-Bhat Date: Mon, 13 May 2024 09:35:10 +0530 Subject: [PATCH 47/67] fix: Item-wise Sales and Purchase register with no item codes #41373 (cherry picked from commit 1b45ecfcae5ed9587c5d03e14afaf6d39d3fa84f) # Conflicts: # erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py # erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py --- .../item_wise_purchase_register.py | 36 +++++++++++++++- .../item_wise_sales_register.py | 43 +++++++++++++++++++ .../purchase_register/purchase_register.py | 4 +- .../report/sales_register/sales_register.py | 6 +-- 4 files changed, 81 insertions(+), 8 deletions(-) diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index 2f87b5be836..97057121536 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -310,8 +310,8 @@ def get_conditions(filters): return conditions - def get_items(filters, additional_query_columns): +<<<<<<< HEAD conditions = get_conditions(filters) if additional_query_columns: additional_query_columns = "," + ",".join(additional_query_columns) @@ -339,6 +339,40 @@ def get_items(filters, additional_query_columns): filters, as_dict=1, ) +======= + pi = frappe.qb.DocType('Purchase Invoice') + pii = frappe.qb.DocType('Purchase Invoice Item') + Item = frappe.qb.DocType('Item') + query = (frappe.qb.from_(pi) + .join(pii).on(pi.name == pii.parent) + .left_join(Item).on(pii.item_code == Item.name) + .select( + pii.name.as_('pii_name'), pii.parent, + pi.posting_date, pi.credit_to, pi.company, + pi.supplier, pi.remarks, pi.base_net_total, + pi.unrealized_profit_loss_account, + pii.item_code, pii.description, pii.item_group, + pii.item_name.as_('pi_item_name'), pii.item_group.as_('pi_item_group'), + Item.item_name.as_('i_item_name'), Item.item_group.as_('i_item_group'), + pii.project, pii.purchase_order, + pii.purchase_receipt, pii.po_detail, + pii.expense_account, pii.stock_qty, + pii.stock_uom, pii.base_net_amount, + pi.supplier_name, pi.mode_of_payment + ) + .where(pi.docstatus == 1)) + + if additional_query_columns: + query = query.select(*additional_query_columns) + + if filters.get("supplier"): + query = query.where(pi.supplier == filters['supplier']) + if filters.get("company"): + query = query.where(pi.company == filters['company']) + + return query.run(as_dict=True) + +>>>>>>> 1b45ecfcae (fix: Item-wise Sales and Purchase register with no item codes #41373) def get_aii_accounts(): diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py index c7819731930..fd538b7bfa6 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -388,6 +388,7 @@ def get_group_by_conditions(filters, doctype): return "ORDER BY `tab{}`.{}".format(doctype, frappe.scrub(filters.get("group_by"))) +<<<<<<< HEAD def get_items(filters, additional_query_columns, additional_conditions=None): conditions = get_conditions(filters, additional_conditions) if additional_query_columns: @@ -420,6 +421,48 @@ def get_items(filters, additional_query_columns, additional_conditions=None): filters, as_dict=1, ) # nosec +======= +def get_items(filters, additional_query_columns,additional_conditions=None): + si = frappe.qb.DocType('Sales Invoice') + sii = frappe.qb.DocType('Sales Invoice Item') + Item = frappe.qb.DocType('Item') + + query = ( + frappe.qb.from_(si) + .join(sii).on(si.name == sii.parent) + .left_join(Item).on(sii.item_code == Item.name) + .select( + sii.name, sii.parent, + si.posting_date, si.debit_to, + si.unrealized_profit_loss_account, + si.is_internal_customer, + si.customer, si.remarks, + si.territory, si.company, si.base_net_total, + sii.project, + sii.item_code, sii.description, + sii.item_name, sii.item_group, + sii.item_name.as_('si_item_name'), sii.item_group.as_('si_item_group'), + Item.item_name.as_('i_item_name'), Item.item_group.as_('i_item_group'), + sii.sales_order, sii.delivery_note, + sii.income_account, sii.cost_center, + sii.enable_deferred_revenue, sii.deferred_revenue_account, + sii.stock_qty, sii.stock_uom, + sii.base_net_rate, sii.base_net_amount, + si.customer_name, si.customer_group, sii.so_detail, + si.update_stock, sii.uom, sii.qty + ) + .where(si.docstatus == 1) + ) + if filters.get("customer"): + query = query.where(si.customer == filters['customer']) + + if filters.get("customer_group"): + query = query.where(si.customer_group == filters['customer_group']) + + return query.run(as_dict=True) + + +>>>>>>> 1b45ecfcae (fix: Item-wise Sales and Purchase register with no item codes #41373) def get_delivery_notes_against_sales_order(item_list): diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index c5f6e97d542..0eacf2cb4ca 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -376,10 +376,8 @@ def get_account_columns(invoice_list, include_payments): def get_invoices(filters, additional_query_columns): pi = frappe.qb.DocType("Purchase Invoice") - pii = frappe.qb.DocType("Purchase Invoice Item") query = ( frappe.qb.from_(pi) - .left_join(pii).on(pi.name == pii.parent) .select( ConstantColumn("Purchase Invoice").as_("doctype"), pi.name, @@ -397,7 +395,7 @@ def get_invoices(filters, additional_query_columns): pi.outstanding_amount, pi.mode_of_payment, ) - .where((pi.docstatus == 1) & pii.item_code.isnotnull()) + .where((pi.docstatus == 1)) .orderby(pi.posting_date, pi.name, order=Order.desc) ) diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index 31fcf0da963..1a0351123e6 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -414,11 +414,9 @@ def get_account_columns(invoice_list, include_payments): def get_invoices(filters, additional_query_columns): si = frappe.qb.DocType("Sales Invoice") - sii = frappe.qb.DocType("Sales Invoice Item") query = ( frappe.qb.from_(si) - .left_join(sii).on(si.name == sii.parent) - .select( + .select( ConstantColumn("Sales Invoice").as_("doctype"), si.name, si.posting_date, @@ -439,7 +437,7 @@ def get_invoices(filters, additional_query_columns): si.represents_company, si.company, ) - .where((si.docstatus == 1) & sii.item_code.isnotnull()) + .where((si.docstatus == 1)) .orderby(si.posting_date, si.name, order=Order.desc) ) From ee47440063a06a178ac407c75468fbbef4b37899 Mon Sep 17 00:00:00 2001 From: Poorvi-R-Bhat Date: Wed, 22 May 2024 12:26:02 +0530 Subject: [PATCH 48/67] fix: fixing Item-wise sales register and purchase register #41373 (cherry picked from commit 76073ae228d9f3ebe67eae562e2e48bd54ace252) # Conflicts: # erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py --- .../item_wise_purchase_register.py | 62 ++++++++++++++++--- 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index 97057121536..0d90fcd515f 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -310,7 +310,9 @@ def get_conditions(filters): return conditions + def get_items(filters, additional_query_columns): +<<<<<<< HEAD <<<<<<< HEAD conditions = get_conditions(filters) if additional_query_columns: @@ -361,18 +363,62 @@ def get_items(filters, additional_query_columns): pi.supplier_name, pi.mode_of_payment ) .where(pi.docstatus == 1)) +======= + pi = frappe.qb.DocType("Purchase Invoice") + pii = frappe.qb.DocType("Purchase Invoice Item") + Item = frappe.qb.DocType("Item") + query = ( + frappe.qb.from_(pi) + .join(pii) + .on(pi.name == pii.parent) + # added left join + .left_join(Item) + .on(pii.item_code == Item.name) + .select( + pii.name.as_("pii_name"), + pii.parent, + pi.posting_date, + pi.credit_to, + pi.company, + pi.supplier, + pi.remarks, + pi.base_net_total, + pi.unrealized_profit_loss_account, + pii.item_code, + pii.description, + pii.item_group, + pii.item_name.as_("pi_item_name"), + pii.item_group.as_("pi_item_group"), + Item.item_name.as_("i_item_name"), + Item.item_group.as_("i_item_group"), + pii.project, + pii.purchase_order, + pii.purchase_receipt, + pii.po_detail, + pii.expense_account, + pii.stock_qty, + pii.stock_uom, + pii.base_net_amount, + pi.supplier_name, + pi.mode_of_payment, + ) + .where(pi.docstatus == 1) + ) +>>>>>>> 76073ae228 (fix: fixing Item-wise sales register and purchase register #41373) - if additional_query_columns: - query = query.select(*additional_query_columns) + if additional_query_columns: + query = query.select(*additional_query_columns) - if filters.get("supplier"): - query = query.where(pi.supplier == filters['supplier']) - if filters.get("company"): - query = query.where(pi.company == filters['company']) - - return query.run(as_dict=True) + if filters.get("supplier"): + query = query.where(pi.supplier == filters["supplier"]) + if filters.get("company"): + query = query.where(pi.company == filters["company"]) +<<<<<<< HEAD >>>>>>> 1b45ecfcae (fix: Item-wise Sales and Purchase register with no item codes #41373) +======= + return query.run(as_dict=True) +>>>>>>> 76073ae228 (fix: fixing Item-wise sales register and purchase register #41373) def get_aii_accounts(): From ab90b815e335573ab6f337c4fd377bb793a895dd Mon Sep 17 00:00:00 2001 From: Poorvi-R-Bhat Date: Wed, 22 May 2024 12:39:22 +0530 Subject: [PATCH 49/67] fix: fixing Item-wise sales register #41373 (cherry picked from commit eafa88b8e9da824d89e5673504c0de3422b54b6b) # Conflicts: # erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py --- .../item_wise_purchase_register.py | 1 - .../item_wise_sales_register.py | 66 +++++++++++++++++-- .../purchase_register/purchase_register.py | 6 +- .../report/sales_register/sales_register.py | 4 +- 4 files changed, 67 insertions(+), 10 deletions(-) diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index 0d90fcd515f..6891a4b107f 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -371,7 +371,6 @@ def get_items(filters, additional_query_columns): frappe.qb.from_(pi) .join(pii) .on(pi.name == pii.parent) - # added left join .left_join(Item) .on(pii.item_code == Item.name) .select( diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py index fd538b7bfa6..102d9d6a0af 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -388,6 +388,7 @@ def get_group_by_conditions(filters, doctype): return "ORDER BY `tab{}`.{}".format(doctype, frappe.scrub(filters.get("group_by"))) +<<<<<<< HEAD <<<<<<< HEAD def get_items(filters, additional_query_columns, additional_conditions=None): conditions = get_conditions(filters, additional_conditions) @@ -455,14 +456,71 @@ def get_items(filters, additional_query_columns,additional_conditions=None): ) if filters.get("customer"): query = query.where(si.customer == filters['customer']) +======= +def get_items(filters, additional_query_columns, additional_conditions=None): + si = frappe.qb.DocType("Sales Invoice") + sii = frappe.qb.DocType("Sales Invoice Item") + Item = frappe.qb.DocType("Item") +>>>>>>> eafa88b8e9 (fix: fixing Item-wise sales register #41373) - if filters.get("customer_group"): - query = query.where(si.customer_group == filters['customer_group']) - - return query.run(as_dict=True) + query = ( + frappe.qb.from_(si) + .join(sii) + .on(si.name == sii.parent) + # added left join + .left_join(Item) + .on(sii.item_code == Item.name) + .select( + sii.name, + sii.parent, + si.posting_date, + si.debit_to, + si.unrealized_profit_loss_account, + si.is_internal_customer, + si.customer, + si.remarks, + si.territory, + si.company, + si.base_net_total, + sii.project, + sii.item_code, + sii.description, + sii.item_name, + sii.item_group, + sii.item_name.as_("si_item_name"), + sii.item_group.as_("si_item_group"), + Item.item_name.as_("i_item_name"), + Item.item_group.as_("i_item_group"), + sii.sales_order, + sii.delivery_note, + sii.income_account, + sii.cost_center, + sii.enable_deferred_revenue, + sii.deferred_revenue_account, + sii.stock_qty, + sii.stock_uom, + sii.base_net_rate, + sii.base_net_amount, + si.customer_name, + si.customer_group, + sii.so_detail, + si.update_stock, + sii.uom, + sii.qty, + ) + .where(si.docstatus == 1) + ) + if filters.get("customer"): + query = query.where(si.customer == filters["customer"]) + if filters.get("customer_group"): + query = query.where(si.customer_group == filters["customer_group"]) +<<<<<<< HEAD >>>>>>> 1b45ecfcae (fix: Item-wise Sales and Purchase register with no item codes #41373) +======= + return query.run(as_dict=True) +>>>>>>> eafa88b8e9 (fix: fixing Item-wise sales register #41373) def get_delivery_notes_against_sales_order(item_list): diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index 0eacf2cb4ca..81245b7522d 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -377,7 +377,7 @@ def get_account_columns(invoice_list, include_payments): def get_invoices(filters, additional_query_columns): pi = frappe.qb.DocType("Purchase Invoice") query = ( - frappe.qb.from_(pi) + frappe.qb.from_(pi) # qb .select( ConstantColumn("Purchase Invoice").as_("doctype"), pi.name, @@ -386,7 +386,7 @@ def get_invoices(filters, additional_query_columns): pi.supplier, pi.supplier_name, pi.tax_id, - pi.bill_no, + pi.bill_no, pi.bill_date, pi.remarks, pi.base_net_total, @@ -395,7 +395,7 @@ def get_invoices(filters, additional_query_columns): pi.outstanding_amount, pi.mode_of_payment, ) - .where((pi.docstatus == 1)) + .where(pi.docstatus == 1) .orderby(pi.posting_date, pi.name, order=Order.desc) ) diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index 1a0351123e6..6797149bd42 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -415,7 +415,7 @@ def get_account_columns(invoice_list, include_payments): def get_invoices(filters, additional_query_columns): si = frappe.qb.DocType("Sales Invoice") query = ( - frappe.qb.from_(si) + frappe.qb.from_(si) # qb .select( ConstantColumn("Sales Invoice").as_("doctype"), si.name, @@ -437,7 +437,7 @@ def get_invoices(filters, additional_query_columns): si.represents_company, si.company, ) - .where((si.docstatus == 1)) + .where(si.docstatus == 1) .orderby(si.posting_date, si.name, order=Order.desc) ) From e94e15259b2b8c44112c3453582d9dea8e73547b Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 2 Jun 2024 20:17:24 +0530 Subject: [PATCH 50/67] chore: update condition queries in qb (cherry picked from commit d2af36e1eb2ba395b3bf35f933f40b6906852fa0) # Conflicts: # erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py # erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py --- .../item_wise_purchase_register.py | 34 +++-- .../item_wise_sales_register.js | 6 + .../item_wise_sales_register.py | 126 ++++++++++-------- .../purchase_register/purchase_register.py | 2 +- .../report/sales_register/sales_register.py | 2 +- 5 files changed, 108 insertions(+), 62 deletions(-) diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index 6891a4b107f..05a7d952036 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -5,14 +5,15 @@ import frappe from frappe import _ from frappe.utils import flt +from pypika import Order import erpnext from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import ( add_sub_total_row, add_total_row, + apply_group_by_conditions, get_grand_total, get_group_by_and_display_fields, - get_group_by_conditions, get_tax_accounts, ) from erpnext.accounts.report.utils import get_query_columns, get_values_for_columns @@ -287,9 +288,12 @@ def get_columns(additional_table_columns, filters): return columns -def get_conditions(filters): - conditions = "" +def apply_conditions(query, pi, pii, filters): + for opts in ("company", "supplier", "item_code", "mode_of_payment"): + if filters.get(opts): + query = query.where(pi[opts] == filters[opts]) +<<<<<<< HEAD for opts in ( ("company", " and `tabPurchase Invoice`.company=%(company)s"), ("supplier", " and `tabPurchase Invoice`.supplier = %(supplier)s"), @@ -300,15 +304,24 @@ def get_conditions(filters): ): if filters.get(opts[0]): conditions += opts[1] +======= + if filters.get("from_date"): + query = query.where(pi.posting_date >= filters.get("from_date")) + + if filters.get("to_date"): + query = query.where(pi.posting_date <= filters.get("to_date")) + + if filters.get("item_group"): + query = query.where(pii.item_group == filters.get("item_group")) +>>>>>>> d2af36e1eb (chore: update condition queries in qb) if not filters.get("group_by"): - conditions += ( - "ORDER BY `tabPurchase Invoice`.posting_date desc, `tabPurchase Invoice Item`.item_code desc" - ) + query = query.orderby(pi.posting_date, order=Order.desc) + query = query.orderby(pii.item_group, order=Order.desc) else: - conditions += get_group_by_conditions(filters, "Purchase Invoice") + query = apply_group_by_conditions(filters, "Purchase Invoice") - return conditions + return query def get_items(filters, additional_query_columns): @@ -413,9 +426,14 @@ def get_items(filters, additional_query_columns): if filters.get("company"): query = query.where(pi.company == filters["company"]) +<<<<<<< HEAD <<<<<<< HEAD >>>>>>> 1b45ecfcae (fix: Item-wise Sales and Purchase register with no item codes #41373) ======= +======= + query = apply_conditions(query, pi, pii, filters) + +>>>>>>> d2af36e1eb (chore: update condition queries in qb) return query.run(as_dict=True) >>>>>>> 76073ae228 (fix: fixing Item-wise sales register and purchase register #41373) diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js index 7ed2ebd89ab..1f155de63a0 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js @@ -41,6 +41,12 @@ frappe.query_reports["Item-wise Sales Register"] = { label: __("Warehouse"), fieldtype: "Link", options: "Warehouse", + get_query: function () { + const company = frappe.query_report.get_filter_value("company"); + return { + filters: { company: company }, + }; + }, }, { fieldname: "brand", diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py index 102d9d6a0af..192cbc0e0cc 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -7,6 +7,7 @@ from frappe import _ from frappe.model.meta import get_field_precision from frappe.utils import cstr, flt from frappe.utils.xlsxutils import handle_html +from pypika import Order from erpnext.accounts.report.sales_register.sales_register import get_mode_of_payments from erpnext.accounts.report.utils import get_query_columns, get_values_for_columns @@ -333,59 +334,69 @@ def get_columns(additional_table_columns, filters): return columns -def get_conditions(filters, additional_conditions=None): - conditions = "" +def apply_conditions(query, si, sii, filters, additional_conditions=None): + for opts in ("company", "customer", "item_code"): + if filters.get(opts): + query = query.where(si[opts] == filters[opts]) - for opts in ( - ("company", " and `tabSales Invoice`.company=%(company)s"), - ("customer", " and `tabSales Invoice`.customer = %(customer)s"), - ("item_code", " and `tabSales Invoice Item`.item_code = %(item_code)s"), - ("from_date", " and `tabSales Invoice`.posting_date>=%(from_date)s"), - ("to_date", " and `tabSales Invoice`.posting_date<=%(to_date)s"), - ): - if filters.get(opts[0]): - conditions += opts[1] + if filters.get("from_date"): + query = query.where(si.posting_date >= filters.get("from_date")) - if additional_conditions: - conditions += additional_conditions + if filters.get("to_date"): + query = query.where(si.posting_date <= filters.get("to_date")) if filters.get("mode_of_payment"): - conditions += """ and exists(select name from `tabSales Invoice Payment` - where parent=`tabSales Invoice`.name - and ifnull(`tabSales Invoice Payment`.mode_of_payment, '') = %(mode_of_payment)s)""" + sales_invoice = frappe.db.get_all( + "Sales Invoice Payment", {"mode_of_payment": filters.get("mode_of_payment")}, pluck="parent" + ) + query = query.where(si.name.isin(sales_invoice)) if filters.get("warehouse"): if frappe.db.get_value("Warehouse", filters.get("warehouse"), "is_group"): lft, rgt = frappe.db.get_all( "Warehouse", filters={"name": filters.get("warehouse")}, fields=["lft", "rgt"], as_list=True )[0] - conditions += f"and ifnull(`tabSales Invoice Item`.warehouse, '') in (select name from `tabWarehouse` where lft > {lft} and rgt < {rgt}) " + warehouses = frappe.db.get_all("Warehouse", {"lft": (">", lft), "rgt": ("<", rgt)}, pluck="name") + query = query.where(sii.warehouse.isin(warehouses)) else: - conditions += """and ifnull(`tabSales Invoice Item`.warehouse, '') = %(warehouse)s""" + query = query.where(sii.warehouse == filters.get("warehouse")) if filters.get("brand"): - conditions += """and ifnull(`tabSales Invoice Item`.brand, '') = %(brand)s""" + query = query.where(sii.brand == filters.get("brand")) if filters.get("item_group"): - conditions += """and ifnull(`tabSales Invoice Item`.item_group, '') = %(item_group)s""" + query = query.where(sii.item_group == filters.get("item_group")) +<<<<<<< HEAD +======= + if filters.get("income_account"): + query = query.where( + (sii.income_account == filters.get("income_account")) + | (sii.deferred_revenue_account == filters.get("income_account")) + | (si.unrealized_profit_loss_account == filters.get("income_account")) + ) + +>>>>>>> d2af36e1eb (chore: update condition queries in qb) if not filters.get("group_by"): - conditions += "ORDER BY `tabSales Invoice`.posting_date desc, `tabSales Invoice Item`.item_group desc" + query = query.orderby(si.posting_date, order=Order.desc) + query = query.orderby(sii.item_group, order=Order.desc) else: - conditions += get_group_by_conditions(filters, "Sales Invoice") + query = apply_group_by_conditions(query, si, sii, filters) - return conditions + return query -def get_group_by_conditions(filters, doctype): +def apply_group_by_conditions(query, si, ii, filters): if filters.get("group_by") == "Invoice": - return f"ORDER BY `tab{doctype} Item`.parent desc" + query = query.orderby(ii.parent, order=Order.desc) elif filters.get("group_by") == "Item": - return f"ORDER BY `tab{doctype} Item`.`item_code`" + query = query.orderby(ii.item_code) elif filters.get("group_by") == "Item Group": - return "ORDER BY `tab{} Item`.{}".format(doctype, frappe.scrub(filters.get("group_by"))) + query = query.orderby(ii.item_group) elif filters.get("group_by") in ("Customer", "Customer Group", "Territory", "Supplier"): - return "ORDER BY `tab{}`.{}".format(doctype, frappe.scrub(filters.get("group_by"))) + query = query.orderby(si[frappe.scrub(filters.get("group_by"))]) + + return query <<<<<<< HEAD @@ -460,16 +471,19 @@ def get_items(filters, additional_query_columns,additional_conditions=None): def get_items(filters, additional_query_columns, additional_conditions=None): si = frappe.qb.DocType("Sales Invoice") sii = frappe.qb.DocType("Sales Invoice Item") +<<<<<<< HEAD Item = frappe.qb.DocType("Item") >>>>>>> eafa88b8e9 (fix: fixing Item-wise sales register #41373) +======= + item = frappe.qb.DocType("Item") +>>>>>>> d2af36e1eb (chore: update condition queries in qb) query = ( frappe.qb.from_(si) .join(sii) .on(si.name == sii.parent) - # added left join - .left_join(Item) - .on(sii.item_code == Item.name) + .left_join(item) + .on(sii.item_code == item.name) .select( sii.name, sii.parent, @@ -489,8 +503,8 @@ def get_items(filters, additional_query_columns, additional_conditions=None): sii.item_group, sii.item_name.as_("si_item_name"), sii.item_group.as_("si_item_group"), - Item.item_name.as_("i_item_name"), - Item.item_group.as_("i_item_group"), + item.item_name.as_("i_item_name"), + item.item_group.as_("i_item_group"), sii.sales_order, sii.delivery_note, sii.income_account, @@ -510,15 +524,24 @@ def get_items(filters, additional_query_columns, additional_conditions=None): ) .where(si.docstatus == 1) ) + + if additional_query_columns: + query = query.select(*additional_query_columns) + if filters.get("customer"): query = query.where(si.customer == filters["customer"]) if filters.get("customer_group"): query = query.where(si.customer_group == filters["customer_group"]) +<<<<<<< HEAD <<<<<<< HEAD >>>>>>> 1b45ecfcae (fix: Item-wise Sales and Purchase register with no item codes #41373) ======= +======= + query = apply_conditions(query, si, sii, filters, additional_conditions) + +>>>>>>> d2af36e1eb (chore: update condition queries in qb) return query.run(as_dict=True) >>>>>>> eafa88b8e9 (fix: fixing Item-wise sales register #41373) @@ -528,16 +551,14 @@ def get_delivery_notes_against_sales_order(item_list): so_item_rows = list(set([d.so_detail for d in item_list])) if so_item_rows: - delivery_notes = frappe.db.sql( - """ - select parent, so_detail - from `tabDelivery Note Item` - where docstatus=1 and so_detail in (%s) - group by so_detail, parent - """ - % (", ".join(["%s"] * len(so_item_rows))), - tuple(so_item_rows), - as_dict=1, + dn_item = frappe.qb.DocType("Delivery Note Item") + delivery_notes = ( + frappe.qb.from_(dn_item) + .select(dn_item.parent, dn_item.so_detail) + .where(dn_item.docstatus == 1) + .where(dn_item.so_detail.isin(so_item_rows)) + .groupby(dn_item.so_detail, dn_item.parent) + .run(as_dict=True) ) for dn in delivery_notes: @@ -547,15 +568,16 @@ def get_delivery_notes_against_sales_order(item_list): def get_grand_total(filters, doctype): - return frappe.db.sql( - f""" SELECT - SUM(`tab{doctype}`.base_grand_total) - FROM `tab{doctype}` - WHERE `tab{doctype}`.docstatus = 1 - and posting_date between %s and %s - """, - (filters.get("from_date"), filters.get("to_date")), - )[0][0] # nosec + return flt( + frappe.db.get_value( + doctype, + { + "docstatus": 1, + "posting_date": ("between", [filters.get("from_date"), filters.get("to_date")]), + }, + "sum(base_grand_total)", + ) + ) def get_tax_accounts( diff --git a/erpnext/accounts/report/purchase_register/purchase_register.py b/erpnext/accounts/report/purchase_register/purchase_register.py index 81245b7522d..92d91a4cc46 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.py +++ b/erpnext/accounts/report/purchase_register/purchase_register.py @@ -377,7 +377,7 @@ def get_account_columns(invoice_list, include_payments): def get_invoices(filters, additional_query_columns): pi = frappe.qb.DocType("Purchase Invoice") query = ( - frappe.qb.from_(pi) # qb + frappe.qb.from_(pi) .select( ConstantColumn("Purchase Invoice").as_("doctype"), pi.name, diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index 6797149bd42..3e7ac1a818d 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -415,7 +415,7 @@ def get_account_columns(invoice_list, include_payments): def get_invoices(filters, additional_query_columns): si = frappe.qb.DocType("Sales Invoice") query = ( - frappe.qb.from_(si) # qb + frappe.qb.from_(si) .select( ConstantColumn("Sales Invoice").as_("doctype"), si.name, From e79e9e94d09b76b6dc3397d2ed791fc7ad8ebd36 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 7 Jun 2024 18:48:16 +0530 Subject: [PATCH 51/67] fix: Add additional condition application (cherry picked from commit 8ec364df6fe07817fd6c69c6e9db31af08d1a455) # Conflicts: # erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py --- .../item_wise_purchase_register.py | 20 +++++++++++++++---- .../item_wise_sales_register.py | 12 +++++++++-- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index 05a7d952036..bbe4fecdb33 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -30,7 +30,7 @@ def _execute(filters=None, additional_table_columns=None): company_currency = erpnext.get_company_currency(filters.company) - item_list = get_items(filters, get_query_columns(additional_table_columns)) + item_list = get_items(filters, additional_table_columns) aii_account_map = get_aii_accounts() if item_list: itemised_tax, tax_columns = get_tax_accounts( @@ -324,6 +324,7 @@ def apply_conditions(query, pi, pii, filters): return query +<<<<<<< HEAD def get_items(filters, additional_query_columns): <<<<<<< HEAD <<<<<<< HEAD @@ -377,6 +378,9 @@ def get_items(filters, additional_query_columns): ) .where(pi.docstatus == 1)) ======= +======= +def get_items(filters, additional_table_columns): +>>>>>>> 8ec364df6f (fix: Add additional condition application) pi = frappe.qb.DocType("Purchase Invoice") pii = frappe.qb.DocType("Purchase Invoice Item") Item = frappe.qb.DocType("Item") @@ -418,19 +422,27 @@ def get_items(filters, additional_query_columns): ) >>>>>>> 76073ae228 (fix: fixing Item-wise sales register and purchase register #41373) - if additional_query_columns: - query = query.select(*additional_query_columns) - if filters.get("supplier"): query = query.where(pi.supplier == filters["supplier"]) if filters.get("company"): query = query.where(pi.company == filters["company"]) +<<<<<<< HEAD <<<<<<< HEAD <<<<<<< HEAD >>>>>>> 1b45ecfcae (fix: Item-wise Sales and Purchase register with no item codes #41373) ======= ======= +======= + if additional_table_columns: + for column in additional_table_columns: + if column.get("_doctype"): + table = frappe.qb.DocType(column.get("_doctype")) + query = query.select(table[column.get("fieldname")]) + else: + query = query.select(pi[column.get("fieldname")]) + +>>>>>>> 8ec364df6f (fix: Add additional condition application) query = apply_conditions(query, pi, pii, filters) >>>>>>> d2af36e1eb (chore: update condition queries in qb) diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py index 192cbc0e0cc..5a989a929ab 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -27,7 +27,7 @@ def _execute(filters=None, additional_table_columns=None, additional_conditions= company_currency = frappe.get_cached_value("Company", filters.get("company"), "default_currency") - item_list = get_items(filters, get_query_columns(additional_table_columns), additional_conditions) + item_list = get_items(filters, additional_table_columns, additional_conditions) if item_list: itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency) @@ -383,6 +383,9 @@ def apply_conditions(query, si, sii, filters, additional_conditions=None): else: query = apply_group_by_conditions(query, si, sii, filters) + for key, value in (additional_conditions or {}).items(): + query = query.where(si[key] == value) + return query @@ -526,7 +529,12 @@ def get_items(filters, additional_query_columns, additional_conditions=None): ) if additional_query_columns: - query = query.select(*additional_query_columns) + for column in additional_query_columns: + if column.get("_doctype"): + table = frappe.qb.DocType(column.get("_doctype")) + query = query.select(table[column.get("fieldname")]) + else: + query = query.select(si[column.get("fieldname")]) if filters.get("customer"): query = query.where(si.customer == filters["customer"]) From e9b7d00afbeec082617d2a39376310d09ce56bd4 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 9 Jun 2024 22:17:30 +0530 Subject: [PATCH 52/67] chore: resolve conflicts --- .../item_wise_purchase_register.py | 80 --------------- .../item_wise_sales_register.py | 97 ++----------------- 2 files changed, 10 insertions(+), 167 deletions(-) diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index bbe4fecdb33..80c246cad55 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -293,18 +293,6 @@ def apply_conditions(query, pi, pii, filters): if filters.get(opts): query = query.where(pi[opts] == filters[opts]) -<<<<<<< HEAD - for opts in ( - ("company", " and `tabPurchase Invoice`.company=%(company)s"), - ("supplier", " and `tabPurchase Invoice`.supplier = %(supplier)s"), - ("item_code", " and `tabPurchase Invoice Item`.item_code = %(item_code)s"), - ("from_date", " and `tabPurchase Invoice`.posting_date>=%(from_date)s"), - ("to_date", " and `tabPurchase Invoice`.posting_date<=%(to_date)s"), - ("mode_of_payment", " and ifnull(mode_of_payment, '') = %(mode_of_payment)s"), - ): - if filters.get(opts[0]): - conditions += opts[1] -======= if filters.get("from_date"): query = query.where(pi.posting_date >= filters.get("from_date")) @@ -313,7 +301,6 @@ def apply_conditions(query, pi, pii, filters): if filters.get("item_group"): query = query.where(pii.item_group == filters.get("item_group")) ->>>>>>> d2af36e1eb (chore: update condition queries in qb) if not filters.get("group_by"): query = query.orderby(pi.posting_date, order=Order.desc) @@ -324,63 +311,7 @@ def apply_conditions(query, pi, pii, filters): return query -<<<<<<< HEAD -def get_items(filters, additional_query_columns): -<<<<<<< HEAD -<<<<<<< HEAD - conditions = get_conditions(filters) - if additional_query_columns: - additional_query_columns = "," + ",".join(additional_query_columns) - return frappe.db.sql( - """ - select - `tabPurchase Invoice Item`.`name`, `tabPurchase Invoice Item`.`parent`, - `tabPurchase Invoice`.posting_date, `tabPurchase Invoice`.credit_to, `tabPurchase Invoice`.company, - `tabPurchase Invoice`.supplier, `tabPurchase Invoice`.remarks, `tabPurchase Invoice`.base_net_total, - `tabPurchase Invoice`.unrealized_profit_loss_account, - `tabPurchase Invoice Item`.`item_code`, `tabPurchase Invoice Item`.description, - `tabPurchase Invoice Item`.`item_name` as pi_item_name, `tabPurchase Invoice Item`.`item_group` - ,`tabPurchase Invoice Item`.`item_group` as pi_item_group, - `tabItem`.`item_name` as i_item_name, `tabItem`.`item_group` as i_item_group, - `tabPurchase Invoice Item`.`project`, `tabPurchase Invoice Item`.`purchase_order`, - `tabPurchase Invoice Item`.`purchase_receipt`, `tabPurchase Invoice Item`.`po_detail`, - `tabPurchase Invoice Item`.`expense_account`, `tabPurchase Invoice Item`.`stock_qty`, - `tabPurchase Invoice Item`.`stock_uom`, `tabPurchase Invoice Item`.`base_net_amount`, - `tabPurchase Invoice`.`supplier_name`, `tabPurchase Invoice`.`mode_of_payment` {} - from `tabPurchase Invoice`, `tabPurchase Invoice Item`, `tabItem` - where `tabPurchase Invoice`.name = `tabPurchase Invoice Item`.`parent` and - `tabItem`.name = `tabPurchase Invoice Item`.`item_code` and - `tabPurchase Invoice`.docstatus = 1 {} - """.format(additional_query_columns, conditions), - filters, - as_dict=1, - ) -======= - pi = frappe.qb.DocType('Purchase Invoice') - pii = frappe.qb.DocType('Purchase Invoice Item') - Item = frappe.qb.DocType('Item') - query = (frappe.qb.from_(pi) - .join(pii).on(pi.name == pii.parent) - .left_join(Item).on(pii.item_code == Item.name) - .select( - pii.name.as_('pii_name'), pii.parent, - pi.posting_date, pi.credit_to, pi.company, - pi.supplier, pi.remarks, pi.base_net_total, - pi.unrealized_profit_loss_account, - pii.item_code, pii.description, pii.item_group, - pii.item_name.as_('pi_item_name'), pii.item_group.as_('pi_item_group'), - Item.item_name.as_('i_item_name'), Item.item_group.as_('i_item_group'), - pii.project, pii.purchase_order, - pii.purchase_receipt, pii.po_detail, - pii.expense_account, pii.stock_qty, - pii.stock_uom, pii.base_net_amount, - pi.supplier_name, pi.mode_of_payment - ) - .where(pi.docstatus == 1)) -======= -======= def get_items(filters, additional_table_columns): ->>>>>>> 8ec364df6f (fix: Add additional condition application) pi = frappe.qb.DocType("Purchase Invoice") pii = frappe.qb.DocType("Purchase Invoice Item") Item = frappe.qb.DocType("Item") @@ -420,20 +351,12 @@ def get_items(filters, additional_table_columns): ) .where(pi.docstatus == 1) ) ->>>>>>> 76073ae228 (fix: fixing Item-wise sales register and purchase register #41373) if filters.get("supplier"): query = query.where(pi.supplier == filters["supplier"]) if filters.get("company"): query = query.where(pi.company == filters["company"]) -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD ->>>>>>> 1b45ecfcae (fix: Item-wise Sales and Purchase register with no item codes #41373) -======= -======= -======= if additional_table_columns: for column in additional_table_columns: if column.get("_doctype"): @@ -442,12 +365,9 @@ def get_items(filters, additional_table_columns): else: query = query.select(pi[column.get("fieldname")]) ->>>>>>> 8ec364df6f (fix: Add additional condition application) query = apply_conditions(query, pi, pii, filters) ->>>>>>> d2af36e1eb (chore: update condition queries in qb) return query.run(as_dict=True) ->>>>>>> 76073ae228 (fix: fixing Item-wise sales register and purchase register #41373) def get_aii_accounts(): diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py index 5a989a929ab..cd50b118715 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -84,9 +84,7 @@ def _execute(filters=None, additional_table_columns=None, additional_conditions= "company": d.company, "sales_order": d.sales_order, "delivery_note": d.delivery_note, - "income_account": d.unrealized_profit_loss_account - if d.is_internal_customer == 1 - else d.income_account, + "income_account": get_income_account(d), "cost_center": d.cost_center, "stock_qty": d.stock_qty, "stock_uom": d.stock_uom, @@ -151,6 +149,15 @@ def _execute(filters=None, additional_table_columns=None, additional_conditions= return columns, data, None, None, None, skip_total_row +def get_income_account(row): + if row.enable_deferred_revenue: + return row.deferred_revenue_account + elif row.is_internal_customer == 1: + return row.unrealized_profit_loss_account + else: + return row.income_account + + def get_columns(additional_table_columns, filters): columns = [] @@ -367,8 +374,6 @@ def apply_conditions(query, si, sii, filters, additional_conditions=None): if filters.get("item_group"): query = query.where(sii.item_group == filters.get("item_group")) -<<<<<<< HEAD -======= if filters.get("income_account"): query = query.where( (sii.income_account == filters.get("income_account")) @@ -376,7 +381,6 @@ def apply_conditions(query, si, sii, filters, additional_conditions=None): | (si.unrealized_profit_loss_account == filters.get("income_account")) ) ->>>>>>> d2af36e1eb (chore: update condition queries in qb) if not filters.get("group_by"): query = query.orderby(si.posting_date, order=Order.desc) query = query.orderby(sii.item_group, order=Order.desc) @@ -402,84 +406,10 @@ def apply_group_by_conditions(query, si, ii, filters): return query -<<<<<<< HEAD -<<<<<<< HEAD -def get_items(filters, additional_query_columns, additional_conditions=None): - conditions = get_conditions(filters, additional_conditions) - if additional_query_columns: - additional_query_columns = "," + ",".join(additional_query_columns) - return frappe.db.sql( - """ - select - `tabSales Invoice Item`.name, `tabSales Invoice Item`.parent, - `tabSales Invoice`.posting_date, `tabSales Invoice`.debit_to, - `tabSales Invoice`.unrealized_profit_loss_account, - `tabSales Invoice`.is_internal_customer, - `tabSales Invoice`.customer, `tabSales Invoice`.remarks, - `tabSales Invoice`.territory, `tabSales Invoice`.company, `tabSales Invoice`.base_net_total, - `tabSales Invoice Item`.project, - `tabSales Invoice Item`.item_code, `tabSales Invoice Item`.description, - `tabSales Invoice Item`.`item_name`, `tabSales Invoice Item`.`item_group`, - `tabSales Invoice Item`.`item_name` as si_item_name, `tabSales Invoice Item`.`item_group` as si_item_group, - `tabItem`.`item_name` as i_item_name, `tabItem`.`item_group` as i_item_group, - `tabSales Invoice Item`.sales_order, `tabSales Invoice Item`.delivery_note, - `tabSales Invoice Item`.income_account, `tabSales Invoice Item`.cost_center, - `tabSales Invoice Item`.stock_qty, `tabSales Invoice Item`.stock_uom, - `tabSales Invoice Item`.base_net_rate, `tabSales Invoice Item`.base_net_amount, - `tabSales Invoice`.customer_name, `tabSales Invoice`.customer_group, `tabSales Invoice Item`.so_detail, - `tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom, `tabSales Invoice Item`.qty {} - from `tabSales Invoice`, `tabSales Invoice Item`, `tabItem` - where `tabSales Invoice`.name = `tabSales Invoice Item`.parent and - `tabItem`.name = `tabSales Invoice Item`.`item_code` and - `tabSales Invoice`.docstatus = 1 {} - """.format(additional_query_columns, conditions), - filters, - as_dict=1, - ) # nosec -======= -def get_items(filters, additional_query_columns,additional_conditions=None): - si = frappe.qb.DocType('Sales Invoice') - sii = frappe.qb.DocType('Sales Invoice Item') - Item = frappe.qb.DocType('Item') - - query = ( - frappe.qb.from_(si) - .join(sii).on(si.name == sii.parent) - .left_join(Item).on(sii.item_code == Item.name) - .select( - sii.name, sii.parent, - si.posting_date, si.debit_to, - si.unrealized_profit_loss_account, - si.is_internal_customer, - si.customer, si.remarks, - si.territory, si.company, si.base_net_total, - sii.project, - sii.item_code, sii.description, - sii.item_name, sii.item_group, - sii.item_name.as_('si_item_name'), sii.item_group.as_('si_item_group'), - Item.item_name.as_('i_item_name'), Item.item_group.as_('i_item_group'), - sii.sales_order, sii.delivery_note, - sii.income_account, sii.cost_center, - sii.enable_deferred_revenue, sii.deferred_revenue_account, - sii.stock_qty, sii.stock_uom, - sii.base_net_rate, sii.base_net_amount, - si.customer_name, si.customer_group, sii.so_detail, - si.update_stock, sii.uom, sii.qty - ) - .where(si.docstatus == 1) - ) - if filters.get("customer"): - query = query.where(si.customer == filters['customer']) -======= def get_items(filters, additional_query_columns, additional_conditions=None): si = frappe.qb.DocType("Sales Invoice") sii = frappe.qb.DocType("Sales Invoice Item") -<<<<<<< HEAD - Item = frappe.qb.DocType("Item") ->>>>>>> eafa88b8e9 (fix: fixing Item-wise sales register #41373) -======= item = frappe.qb.DocType("Item") ->>>>>>> d2af36e1eb (chore: update condition queries in qb) query = ( frappe.qb.from_(si) @@ -542,16 +472,9 @@ def get_items(filters, additional_query_columns, additional_conditions=None): if filters.get("customer_group"): query = query.where(si.customer_group == filters["customer_group"]) -<<<<<<< HEAD -<<<<<<< HEAD ->>>>>>> 1b45ecfcae (fix: Item-wise Sales and Purchase register with no item codes #41373) -======= -======= query = apply_conditions(query, si, sii, filters, additional_conditions) ->>>>>>> d2af36e1eb (chore: update condition queries in qb) return query.run(as_dict=True) ->>>>>>> eafa88b8e9 (fix: fixing Item-wise sales register #41373) def get_delivery_notes_against_sales_order(item_list): From 7234625d652fd4d2bd8896af31f9136c028ba232 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 15:17:06 +0530 Subject: [PATCH 53/67] fix: terms and conditions for material request (backport #41834) (#41836) fix: terms and conditions for material request (#41834) (cherry picked from commit 4b026d66dc32de2a8447a8007e56719cf31872dc) Co-authored-by: rohitwaghchaure --- erpnext/selling/doctype/sales_order/sales_order.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index c3f14e1f948..52b5e4051bb 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -576,6 +576,11 @@ def get_requested_item_qty(sales_order): def make_material_request(source_name, target_doc=None): requested_item_qty = get_requested_item_qty(source_name) + def postprocess(source, target): + if source.tc_name and frappe.db.get_value("Terms and Conditions", source.tc_name, "buying") != 1: + target.tc_name = None + target.terms = None + def get_remaining_qty(so_item): return flt( flt(so_item.qty) @@ -631,6 +636,7 @@ def make_material_request(source_name, target_doc=None): }, }, target_doc, + postprocess, ) return doc 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 54/67] 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 99deca5c19d..fa6b9ad4a55 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 55/67] 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 89226453b7f..364aadc8eae 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -8,6 +8,7 @@ from frappe.contacts.doctype.address.address import render_address 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 @@ class BuyingController(SubcontractingController): 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 56/67] 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 41085181720..1fcde1119da 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -51,7 +51,37 @@ class StockController(AccountsController): 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 @@ class StockController(AccountsController): 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 f6b7e0d8435..77f3d2ba2b3 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 @@ class LandedCostVoucher(Document): # 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 a6fd929ea34..7bbe7b9ff75 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -307,13 +307,13 @@ class PurchaseReceipt(BuyingController): 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 @@ class PurchaseReceipt(BuyingController): 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 @@ class PurchaseReceipt(BuyingController): 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 57/67] 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 1fcde1119da..e0c41ff1dfa 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -102,7 +102,11 @@ class StockController(AccountsController): 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 b185fd471f9..e2639ac0815 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 @@ class TestPurchaseReceipt(FrappeTestCase): 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 58/67] 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 77f3d2ba2b3..81dea899f39 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 @@ class LandedCostVoucher(Document): # 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 e2639ac0815..b1678aff7be 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 @@ class TestPurchaseReceipt(FrappeTestCase): ("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 59/67] 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 b1678aff7be..1379715b7b9 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 @@ from pypika import functions as fn 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 @@ class TestPurchaseReceipt(FrappeTestCase): 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 @@ class TestPurchaseReceipt(FrappeTestCase): 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 @@ class TestPurchaseReceipt(FrappeTestCase): 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 @@ class TestPurchaseReceipt(FrappeTestCase): ) 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 60/67] 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 81dea899f39..abfa604e2f3 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 @@ class LandedCostVoucher(Document): 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 61/67] 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 e0c41ff1dfa..a4d8e3efee1 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -51,37 +51,7 @@ class StockController(AccountsController): 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 abfa604e2f3..81dea899f39 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 @@ class LandedCostVoucher(Document): 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 1379715b7b9..52dd85767f8 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 @@ class TestPurchaseReceipt(FrappeTestCase): 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 @@ class TestPurchaseReceipt(FrappeTestCase): 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 62/67] 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 e47c1f8aba7..60a7707228d 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 @@ class RepostItemValuation(Document): 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 @@ class RepostItemValuation(Document): 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 63/67] 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 52a0f4ac2a2..ced0b5fb4a1 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 58d7440211c..705e8fd6dd8 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -345,7 +345,13 @@ class PurchaseOrder(BuyingController): 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 2995a1e99bc..d0f85790553 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 52b5e4051bb..5b4597125fb 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -269,7 +269,13 @@ class SalesOrder(SellingController): 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 64/67] 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 ced0b5fb4a1..1abd10ec3f8 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 d0f85790553..db3d6c2ca54 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 65/67] 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 ec72527552c..d740a5b9c8e 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 66/67] 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 53df9330784..a20e6c2723c 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 }} From 966521260752b50ddc5586c8dbd7a8a8f4012e5a Mon Sep 17 00:00:00 2001 From: ljain112 Date: Thu, 20 Jun 2024 11:11:43 +0530 Subject: [PATCH 67/67] fix: consistent query field name in item wise purchase register with item wise sales register --- .../item_wise_purchase_register/item_wise_purchase_register.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index 80c246cad55..06afb4c0e8f 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -322,7 +322,7 @@ def get_items(filters, additional_table_columns): .left_join(Item) .on(pii.item_code == Item.name) .select( - pii.name.as_("pii_name"), + pii.name, pii.parent, pi.posting_date, pi.credit_to,