From a66002f774560082b2d88c72257d5d43cb128745 Mon Sep 17 00:00:00 2001 From: Sagar Sharma Date: Mon, 26 Sep 2022 09:40:49 +0530 Subject: [PATCH 01/18] refactor: rewrite `Item Price Stock Report` queries in `QB` (cherry picked from commit 22299d2382c912e8bc8dddca3af7d4cf94374339) --- .../item_price_stock/item_price_stock.py | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/erpnext/stock/report/item_price_stock/item_price_stock.py b/erpnext/stock/report/item_price_stock/item_price_stock.py index 15218e63a87..1b07f596c7b 100644 --- a/erpnext/stock/report/item_price_stock/item_price_stock.py +++ b/erpnext/stock/report/item_price_stock/item_price_stock.py @@ -62,22 +62,28 @@ def get_data(filters, columns): def get_item_price_qty_data(filters): - conditions = "" - if filters.get("item_code"): - conditions += "where a.item_code=%(item_code)s" + item_price = frappe.qb.DocType("Item Price") + bin = frappe.qb.DocType("Bin") - item_results = frappe.db.sql( - """select a.item_code, a.item_name, a.name as price_list_name, - a.brand as brand, b.warehouse as warehouse, b.actual_qty as actual_qty - from `tabItem Price` a left join `tabBin` b - ON a.item_code = b.item_code - {conditions}""".format( - conditions=conditions - ), - filters, - as_dict=1, + query = ( + frappe.qb.from_(item_price) + .left_join(bin) + .on(item_price.item_code == bin.item_code) + .select( + item_price.item_code, + item_price.item_name, + item_price.name.as_("price_list_name"), + item_price.brand.as_("brand"), + bin.warehouse.as_("warehouse"), + bin.actual_qty.as_("actual_qty"), + ) ) + if filters.get("item_code"): + query = query.where(item_price.item_code == filters.get("item_code")) + + item_results = query.run(as_dict=True) + price_list_names = list(set(item.price_list_name for item in item_results)) buying_price_map = get_price_map(price_list_names, buying=1) From 70c68f011a62516c166c9ae7a6ba8d0f261ed34a Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Fri, 23 Sep 2022 15:21:09 +0530 Subject: [PATCH 02/18] fix: opening entry causing discepancy between stock and trial balance (cherry picked from commit bc3ab45af2be165988b143b62318d865f83ee673) --- erpnext/accounts/report/general_ledger/general_ledger.py | 4 ++-- erpnext/accounts/report/trial_balance/trial_balance.py | 3 ++- .../trial_balance_for_party/trial_balance_for_party.py | 9 +++++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py index 6a3b38ae7b5..98c81086ab2 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.py +++ b/erpnext/accounts/report/general_ledger/general_ledger.py @@ -280,9 +280,9 @@ def get_conditions(filters): or filters.get("party") or filters.get("group_by") in ["Group by Account", "Group by Party"] ): - conditions.append("posting_date >=%(from_date)s") + conditions.append("(posting_date >=%(from_date)s or is_opening = 'Yes')") - conditions.append("(posting_date <=%(to_date)s or is_opening = 'Yes')") + conditions.append("(posting_date <=%(to_date)s)") if filters.get("project"): conditions.append("project in %(project)s") diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py index 6bd08ad837a..6d2cd8ed411 100644 --- a/erpnext/accounts/report/trial_balance/trial_balance.py +++ b/erpnext/accounts/report/trial_balance/trial_balance.py @@ -172,6 +172,7 @@ def get_rootwise_opening_balances(filters, report_type): query_filters = { "company": filters.company, "from_date": filters.from_date, + "to_date": filters.to_date, "report_type": report_type, "year_start_date": filters.year_start_date, "project": filters.project, @@ -200,7 +201,7 @@ def get_rootwise_opening_balances(filters, report_type): where company=%(company)s {additional_conditions} - and (posting_date < %(from_date)s or ifnull(is_opening, 'No') = 'Yes') + and (posting_date < %(from_date)s or (ifnull(is_opening, 'No') = 'Yes' and posting_date <= %(to_date)s)) and account in (select name from `tabAccount` where report_type=%(report_type)s) and is_cancelled = 0 group by account""".format( diff --git a/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py b/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py index 869f6aaf942..7ef2d22e309 100644 --- a/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py +++ b/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py @@ -106,12 +106,17 @@ def get_opening_balances(filters): where company=%(company)s and is_cancelled=0 and ifnull(party_type, '') = %(party_type)s and ifnull(party, '') != '' - and (posting_date < %(from_date)s or ifnull(is_opening, 'No') = 'Yes') + and (posting_date < %(from_date)s or (ifnull(is_opening, 'No') = 'Yes' and posting_date <= %(to_date)s)) {account_filter} group by party""".format( account_filter=account_filter ), - {"company": filters.company, "from_date": filters.from_date, "party_type": filters.party_type}, + { + "company": filters.company, + "from_date": filters.from_date, + "to_date": filters.to_date, + "party_type": filters.party_type, + }, as_dict=True, ) From 02468a902f7c6eeb75ef092c8b29bea3e135c57e Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 27 Sep 2022 13:47:54 +0530 Subject: [PATCH 03/18] fix: allow to return expired batches using purchase return (cherry picked from commit a4a86ee23fb36f448a308c4f3566ba4be05697ab) --- .../purchase_invoice/test_purchase_invoice.py | 31 +++++++++++++++++++ .../purchase_receipt/test_purchase_receipt.py | 31 +++++++++++++++++++ .../stock_ledger_entry/stock_ledger_entry.py | 3 ++ 3 files changed, 65 insertions(+) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 18b0636beca..60611b0edbb 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -1549,6 +1549,37 @@ class TestPurchaseInvoice(unittest.TestCase, StockTestMixin): pi.save() self.assertEqual(pi.items[0].conversion_factor, 1000) + def test_batch_expiry_for_purchase_invoice(self): + from erpnext.controllers.sales_and_purchase_return import make_return_doc + + item = self.make_item( + "_Test Batch Item For Return Check", + { + "is_purchase_item": 1, + "is_stock_item": 1, + "has_batch_no": 1, + "create_new_batch": 1, + "batch_number_series": "TBIRC.#####", + }, + ) + + pi = make_purchase_invoice( + qty=1, + item_code=item.name, + update_stock=True, + ) + + pi.load_from_db() + batch_no = pi.items[0].batch_no + self.assertTrue(batch_no) + + frappe.db.set_value("Batch", batch_no, "expiry_date", add_days(nowdate(), -1)) + + return_pi = make_return_doc(pi.doctype, pi.name) + return_pi.save().submit() + + self.assertTrue(return_pi.docstatus == 1) + def check_gl_entries(doc, voucher_no, expected_gle, posting_date): gl_entries = frappe.db.sql( diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 4ee2d2dc7dc..e9c52436bc4 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -1446,6 +1446,37 @@ class TestPurchaseReceipt(FrappeTestCase): self.assertEqual(query[0].value, 0) + def test_batch_expiry_for_purchase_receipt(self): + from erpnext.controllers.sales_and_purchase_return import make_return_doc + + item = make_item( + "_Test Batch Item For Return Check", + { + "is_purchase_item": 1, + "is_stock_item": 1, + "has_batch_no": 1, + "create_new_batch": 1, + "batch_number_series": "TBIRC.#####", + }, + ) + + pi = make_purchase_receipt( + qty=1, + item_code=item.name, + update_stock=True, + ) + + pi.load_from_db() + batch_no = pi.items[0].batch_no + self.assertTrue(batch_no) + + frappe.db.set_value("Batch", batch_no, "expiry_date", add_days(today(), -1)) + + return_pi = make_return_doc(pi.doctype, pi.name) + return_pi.save().submit() + + self.assertTrue(return_pi.docstatus == 1) + def prepare_data_for_internal_transfer(): from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index 5c1da420e24..38eb80ad927 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -153,6 +153,9 @@ class StockLedgerEntry(Document): def validate_batch(self): if self.batch_no and self.voucher_type != "Stock Entry": + if self.voucher_type in ["Purchase Receipt", "Purchase Invoice"] and self.actual_qty < 0: + return + expiry_date = frappe.db.get_value("Batch", self.batch_no, "expiry_date") if expiry_date: if getdate(self.posting_date) > getdate(expiry_date): From a194d28b698f0f6d68a196c268897780872dac79 Mon Sep 17 00:00:00 2001 From: Sagar Sharma Date: Tue, 27 Sep 2022 12:00:50 +0530 Subject: [PATCH 04/18] fix: `For Quantity` error msg in `Stock Entry` (cherry picked from commit 9049db41ae8793cdcb5fb770fe202c096c9ad53c) --- erpnext/stock/doctype/stock_entry/stock_entry.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 174fef1084f..3dff7d2e003 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -1015,8 +1015,8 @@ class StockEntry(StockController): # No work order could mean independent Manufacture entry, if so skip validation if self.work_order and self.fg_completed_qty > allowed_qty: frappe.throw( - _("For quantity {0} should not be greater than work order quantity {1}").format( - flt(self.fg_completed_qty), wo_qty + _("For quantity {0} should not be greater than allowed quantity {1}").format( + flt(self.fg_completed_qty), allowed_qty ) ) From ed4ac100ba98ff6287ac39025e3dd54caf67ce5e Mon Sep 17 00:00:00 2001 From: Sagar Sharma Date: Tue, 27 Sep 2022 15:30:08 +0530 Subject: [PATCH 05/18] fix: consider overproduction percentage for WO finish button (cherry picked from commit 05392e0918fce4aafffc016f246f21c8afcc5d8a) --- .../doctype/work_order/work_order.js | 65 ++++++++++++------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js index 9b0c8382c53..a27c42b109e 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.js +++ b/erpnext/manufacturing/doctype/work_order/work_order.js @@ -557,37 +557,52 @@ erpnext.work_order = { if(!frm.doc.skip_transfer){ // If "Material Consumption is check in Manufacturing Settings, allow Material Consumption - if ((flt(doc.produced_qty) < flt(doc.material_transferred_for_manufacturing)) - && frm.doc.status != 'Stopped') { - frm.has_finish_btn = true; + if (flt(doc.material_transferred_for_manufacturing) > 0 && frm.doc.status != 'Stopped') { + if ((flt(doc.produced_qty) < flt(doc.material_transferred_for_manufacturing))) { + frm.has_finish_btn = true; - if (frm.doc.__onload && frm.doc.__onload.material_consumption == 1) { - // Only show "Material Consumption" when required_qty > consumed_qty - var counter = 0; - var tbl = frm.doc.required_items || []; - var tbl_lenght = tbl.length; - for (var i = 0, len = tbl_lenght; i < len; i++) { - let wo_item_qty = frm.doc.required_items[i].transferred_qty || frm.doc.required_items[i].required_qty; - if (flt(wo_item_qty) > flt(frm.doc.required_items[i].consumed_qty)) { - counter += 1; + if (frm.doc.__onload && frm.doc.__onload.material_consumption == 1) { + // Only show "Material Consumption" when required_qty > consumed_qty + var counter = 0; + var tbl = frm.doc.required_items || []; + var tbl_lenght = tbl.length; + for (var i = 0, len = tbl_lenght; i < len; i++) { + let wo_item_qty = frm.doc.required_items[i].transferred_qty || frm.doc.required_items[i].required_qty; + if (flt(wo_item_qty) > flt(frm.doc.required_items[i].consumed_qty)) { + counter += 1; + } + } + if (counter > 0) { + var consumption_btn = frm.add_custom_button(__('Material Consumption'), function() { + const backflush_raw_materials_based_on = frm.doc.__onload.backflush_raw_materials_based_on; + erpnext.work_order.make_consumption_se(frm, backflush_raw_materials_based_on); + }); + consumption_btn.addClass('btn-primary'); } } - if (counter > 0) { - var consumption_btn = frm.add_custom_button(__('Material Consumption'), function() { - const backflush_raw_materials_based_on = frm.doc.__onload.backflush_raw_materials_based_on; - erpnext.work_order.make_consumption_se(frm, backflush_raw_materials_based_on); - }); - consumption_btn.addClass('btn-primary'); + + var finish_btn = frm.add_custom_button(__('Finish'), function() { + erpnext.work_order.make_se(frm, 'Manufacture'); + }); + + if(doc.material_transferred_for_manufacturing>=doc.qty) { + // all materials transferred for manufacturing, make this primary + finish_btn.addClass('btn-primary'); } - } + } else { + frappe.db.get_doc("Manufacturing Settings").then((doc) => { + let allowance_percentage = doc.overproduction_percentage_for_work_order; - var finish_btn = frm.add_custom_button(__('Finish'), function() { - erpnext.work_order.make_se(frm, 'Manufacture'); - }); + if (allowance_percentage > 0) { + let allowed_qty = frm.doc.qty + ((allowance_percentage / 100) * frm.doc.qty); - if(doc.material_transferred_for_manufacturing>=doc.qty) { - // all materials transferred for manufacturing, make this primary - finish_btn.addClass('btn-primary'); + if ((flt(doc.produced_qty) < allowed_qty)) { + frm.add_custom_button(__('Finish'), function() { + erpnext.work_order.make_se(frm, 'Manufacture'); + }); + } + } + }); } } } else { From 988c5b95e6bd8595a5d8de07de01841065d2673b Mon Sep 17 00:00:00 2001 From: Maharshi Patel <39730881+maharshivpatel@users.noreply.github.com> Date: Tue, 27 Sep 2022 22:21:14 +0530 Subject: [PATCH 06/18] fix: GST Itemised Sales Register GSTIN filter (#32367) fix: GST Itemised Sales Register GSTIN filte --- .../item_wise_sales_register.py | 18 +++-- .../gst_itemised_sales_register.js | 6 -- .../gst_itemised_sales_register.py | 65 ++++++++++++------- 3 files changed, 54 insertions(+), 35 deletions(-) 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 c987231fe17..dd9c0736128 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 @@ -19,14 +19,19 @@ def execute(filters=None): return _execute(filters) -def _execute(filters=None, additional_table_columns=None, additional_query_columns=None): +def _execute( + filters=None, + additional_table_columns=None, + additional_query_columns=None, + additional_conditions=None, +): if not filters: filters = {} columns = get_columns(additional_table_columns, filters) company_currency = frappe.get_cached_value("Company", filters.get("company"), "default_currency") - item_list = get_items(filters, additional_query_columns) + item_list = get_items(filters, additional_query_columns, additional_conditions) if item_list: itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency) @@ -328,7 +333,7 @@ def get_columns(additional_table_columns, filters): return columns -def get_conditions(filters): +def get_conditions(filters, additional_conditions=None): conditions = "" for opts in ( @@ -341,6 +346,9 @@ def get_conditions(filters): if filters.get(opts[0]): conditions += opts[1] + if additional_conditions: + conditions += additional_conditions + if filters.get("mode_of_payment"): conditions += """ and exists(select name from `tabSales Invoice Payment` where parent=`tabSales Invoice`.name @@ -376,8 +384,8 @@ def get_group_by_conditions(filters, doctype): return "ORDER BY `tab{0}`.{1}".format(doctype, frappe.scrub(filters.get("group_by"))) -def get_items(filters, additional_query_columns): - conditions = get_conditions(filters) +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) diff --git a/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.js b/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.js index 3a0f0c966d6..d5e832a83f4 100644 --- a/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.js +++ b/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.js @@ -15,12 +15,6 @@ filters = filters.concat({ "placeholder":"Company GSTIN", "options": [""], "width": "80" -}, { - "fieldname":"invoice_type", - "label": __("Invoice Type"), - "fieldtype": "Select", - "placeholder":"Invoice Type", - "options": ["", "Regular", "SEZ", "Export", "Deemed Export"] }); // Handle company on change diff --git a/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py b/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py index bb1843f1bd9..aef69b17868 100644 --- a/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py +++ b/erpnext/regional/report/gst_itemised_sales_register/gst_itemised_sales_register.py @@ -5,31 +5,48 @@ from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register import _execute +def get_conditions(filters, additional_query_columns): + conditions = "" + + for opts in additional_query_columns: + if filters.get(opts): + conditions += f" and {opts}=%({opts})s" + + return conditions + + def execute(filters=None): + additional_table_columns = [ + dict(fieldtype="Data", label="Customer GSTIN", fieldname="customer_gstin", width=120), + dict( + fieldtype="Data", label="Billing Address GSTIN", fieldname="billing_address_gstin", width=140 + ), + dict(fieldtype="Data", label="Company GSTIN", fieldname="company_gstin", width=120), + dict(fieldtype="Data", label="Place of Supply", fieldname="place_of_supply", width=120), + dict(fieldtype="Data", label="Reverse Charge", fieldname="reverse_charge", width=120), + dict(fieldtype="Data", label="GST Category", fieldname="gst_category", width=120), + dict(fieldtype="Data", label="Export Type", fieldname="export_type", width=120), + dict(fieldtype="Data", label="E-Commerce GSTIN", fieldname="ecommerce_gstin", width=130), + dict(fieldtype="Data", label="HSN Code", fieldname="gst_hsn_code", width=120), + ] + + additional_query_columns = [ + "customer_gstin", + "billing_address_gstin", + "company_gstin", + "place_of_supply", + "reverse_charge", + "gst_category", + "export_type", + "ecommerce_gstin", + "gst_hsn_code", + ] + + additional_conditions = get_conditions(filters, additional_query_columns) + return _execute( filters, - additional_table_columns=[ - dict(fieldtype="Data", label="Customer GSTIN", fieldname="customer_gstin", width=120), - dict( - fieldtype="Data", label="Billing Address GSTIN", fieldname="billing_address_gstin", width=140 - ), - dict(fieldtype="Data", label="Company GSTIN", fieldname="company_gstin", width=120), - dict(fieldtype="Data", label="Place of Supply", fieldname="place_of_supply", width=120), - dict(fieldtype="Data", label="Reverse Charge", fieldname="reverse_charge", width=120), - dict(fieldtype="Data", label="GST Category", fieldname="gst_category", width=120), - dict(fieldtype="Data", label="Export Type", fieldname="export_type", width=120), - dict(fieldtype="Data", label="E-Commerce GSTIN", fieldname="ecommerce_gstin", width=130), - dict(fieldtype="Data", label="HSN Code", fieldname="gst_hsn_code", width=120), - ], - additional_query_columns=[ - "customer_gstin", - "billing_address_gstin", - "company_gstin", - "place_of_supply", - "reverse_charge", - "gst_category", - "export_type", - "ecommerce_gstin", - "gst_hsn_code", - ], + additional_table_columns=additional_table_columns, + additional_query_columns=additional_query_columns, + additional_conditions=additional_conditions, ) From 6c528d469dfb6efd378700b54f4c89339777b3de Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 27 Sep 2022 15:37:41 +0530 Subject: [PATCH 07/18] fix: Add return against indexes for POS Invoice (cherry picked from commit 1f6205e1ea569dd25ac298f10812f6e9f44409ef) --- erpnext/accounts/doctype/pos_invoice/pos_invoice.json | 2 +- erpnext/accounts/doctype/pos_invoice/pos_invoice.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json index b8500270d1a..6458756957d 100644 --- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json +++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json @@ -1572,7 +1572,7 @@ "icon": "fa fa-file-text", "is_submittable": 1, "links": [], - "modified": "2022-03-22 13:00:24.166684", + "modified": "2022-09-27 13:00:24.166684", "modified_by": "Administrator", "module": "Accounts", "name": "POS Invoice", diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py index 59c7c843edf..e541c84fe16 100644 --- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py +++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py @@ -744,3 +744,7 @@ def add_return_modes(doc, pos_profile): ]: payment_mode = get_mode_of_payment_info(mode_of_payment, doc.company) append_payment(payment_mode[0]) + + +def on_doctype_update(): + frappe.db.add_index("POS Invoice", ["customer", "is_return", "return_against"]) From 9e8e7aab70506c10c9d381eaee583092e6d169fe Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 27 Sep 2022 16:22:59 +0530 Subject: [PATCH 08/18] fix: Add return against indexes for POS Invoice (cherry picked from commit cbfe28286acc9319901aeaa2c77fa50e95c0e481) --- erpnext/accounts/doctype/pos_invoice/pos_invoice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py index e541c84fe16..990fd22e4d6 100644 --- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py +++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py @@ -747,4 +747,4 @@ def add_return_modes(doc, pos_profile): def on_doctype_update(): - frappe.db.add_index("POS Invoice", ["customer", "is_return", "return_against"]) + frappe.db.add_index("POS Invoice", ["return_against"]) From 447c5539546b04d96332fe895ec8fd86444a8f98 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 27 Sep 2022 22:12:32 +0530 Subject: [PATCH 09/18] fix: Move subscription process to hourly long quque (cherry picked from commit 82a2f31ada358d896943d04bdb517ac33b9e2d7a) # Conflicts: # erpnext/hooks.py --- erpnext/hooks.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 0556d40a4b8..48af82869d4 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -477,9 +477,12 @@ scheduler_events = { "erpnext.crm.doctype.social_media_post.social_media_post.process_scheduled_social_media_posts", ], "hourly": [ +<<<<<<< HEAD "erpnext.hr.doctype.daily_work_summary_group.daily_work_summary_group.trigger_emails", "erpnext.accounts.doctype.subscription.subscription.process_all", "erpnext.erpnext_integrations.doctype.amazon_mws_settings.amazon_mws_settings.schedule_get_order_details", +======= +>>>>>>> 82a2f31ada (fix: Move subscription process to hourly long quque) "erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.automatic_synchronization", "erpnext.projects.doctype.project.project.hourly_reminder", "erpnext.projects.doctype.project.project.collect_project_status", @@ -487,6 +490,7 @@ scheduler_events = { "erpnext.erpnext_integrations.connectors.shopify_connection.sync_old_orders", ], "hourly_long": [ + "erpnext.accounts.doctype.subscription.subscription.process_all", "erpnext.stock.doctype.repost_item_valuation.repost_item_valuation.repost_entries", "erpnext.hr.doctype.shift_type.shift_type.process_auto_attendance_for_all_shifts", ], From f03fbc0e6dfdec83e4b00dfdc65789ff38646cfe Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 28 Sep 2022 08:10:37 +0530 Subject: [PATCH 10/18] chore: Resolve conflicts --- erpnext/hooks.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 48af82869d4..2f009fd494f 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -477,12 +477,8 @@ scheduler_events = { "erpnext.crm.doctype.social_media_post.social_media_post.process_scheduled_social_media_posts", ], "hourly": [ -<<<<<<< HEAD "erpnext.hr.doctype.daily_work_summary_group.daily_work_summary_group.trigger_emails", - "erpnext.accounts.doctype.subscription.subscription.process_all", "erpnext.erpnext_integrations.doctype.amazon_mws_settings.amazon_mws_settings.schedule_get_order_details", -======= ->>>>>>> 82a2f31ada (fix: Move subscription process to hourly long quque) "erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.automatic_synchronization", "erpnext.projects.doctype.project.project.hourly_reminder", "erpnext.projects.doctype.project.project.collect_project_status", From ac8100f1e53de005e7cd2386b3275433209d20f8 Mon Sep 17 00:00:00 2001 From: Maharshi Patel Date: Tue, 27 Sep 2022 15:44:38 +0530 Subject: [PATCH 11/18] fix: POS only validate QTY if is_stock_item POS invoice raised " Item not available " validation error even though item is non_stock. (cherry picked from commit e39e088f18177ab4a189da60c18d57b92a6f8aff) --- erpnext/accounts/doctype/pos_invoice/pos_invoice.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py index 990fd22e4d6..42084661074 100644 --- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py +++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py @@ -239,14 +239,14 @@ class POSInvoice(SalesInvoice): frappe.bold(d.warehouse), frappe.bold(d.qty), ) - if flt(available_stock) <= 0: + if is_stock_item and flt(available_stock) <= 0: frappe.throw( _("Row #{}: Item Code: {} is not available under warehouse {}.").format( d.idx, item_code, warehouse ), title=_("Item Unavailable"), ) - elif flt(available_stock) < flt(d.qty): + elif is_stock_item and flt(available_stock) < flt(d.qty): frappe.throw( _( "Row #{}: Stock quantity not enough for Item Code: {} under warehouse {}. Available quantity {}." From 96fa14be889832495ad7e87d33106175f6dc1060 Mon Sep 17 00:00:00 2001 From: Maharshi Patel Date: Tue, 27 Sep 2022 23:44:56 +0530 Subject: [PATCH 12/18] fix: POS properly validate stock for bundle products Stock availability was not calculated properly for Product Bundle with non stock item so i have added logic to properly calculate that as well. (cherry picked from commit e392ea1104fee5add5c893c4e092edb6ad21f486) # Conflicts: # erpnext/selling/page/point_of_sale/pos_item_details.js --- erpnext/accounts/doctype/pos_invoice/pos_invoice.py | 9 ++++++--- erpnext/selling/page/point_of_sale/pos_controller.js | 4 ++-- erpnext/selling/page/point_of_sale/pos_item_details.js | 7 ++++++- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py index 42084661074..6f1434d429b 100644 --- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py +++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py @@ -634,11 +634,12 @@ def get_stock_availability(item_code, warehouse): pos_sales_qty = get_pos_reserved_qty(item_code, warehouse) return bin_qty - pos_sales_qty, is_stock_item else: - is_stock_item = False + is_stock_item = True if frappe.db.exists("Product Bundle", item_code): return get_bundle_availability(item_code, warehouse), is_stock_item else: - # Is a service item + is_stock_item = False + # Is a service item or non_stock item return 0, is_stock_item @@ -652,7 +653,9 @@ def get_bundle_availability(bundle_item_code, warehouse): available_qty = item_bin_qty - item_pos_reserved_qty max_available_bundles = available_qty / item.qty - if bundle_bin_qty > max_available_bundles: + if bundle_bin_qty > max_available_bundles and frappe.get_value( + "Item", item.item_code, "is_stock_item" + ): bundle_bin_qty = max_available_bundles pos_sales_qty = get_pos_reserved_qty(bundle_item_code, warehouse) diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js index da7576e08de..24375d8252d 100644 --- a/erpnext/selling/page/point_of_sale/pos_controller.js +++ b/erpnext/selling/page/point_of_sale/pos_controller.js @@ -660,7 +660,7 @@ erpnext.PointOfSale.Controller = class { } else { return; } - } else if (available_qty < qty_needed) { + } else if (is_stock_item && available_qty < qty_needed) { frappe.throw({ message: __('Stock quantity not enough for Item Code: {0} under warehouse {1}. Available quantity {2}.', [bold_item_code, bold_warehouse, bold_available_qty]), indicator: 'orange' @@ -694,7 +694,7 @@ erpnext.PointOfSale.Controller = class { callback(res) { if (!me.item_stock_map[item_code]) me.item_stock_map[item_code] = {}; - me.item_stock_map[item_code][warehouse] = res.message[0]; + me.item_stock_map[item_code][warehouse] = res.message; } }); } diff --git a/erpnext/selling/page/point_of_sale/pos_item_details.js b/erpnext/selling/page/point_of_sale/pos_item_details.js index 1d720f7291a..5b4f22b65a8 100644 --- a/erpnext/selling/page/point_of_sale/pos_item_details.js +++ b/erpnext/selling/page/point_of_sale/pos_item_details.js @@ -242,13 +242,18 @@ erpnext.PointOfSale.ItemDetails = class { if (this.value) { me.events.form_updated(me.current_item, 'warehouse', this.value).then(() => { me.item_stock_map = me.events.get_item_stock_map(); +<<<<<<< HEAD const available_qty = me.item_stock_map[me.item_row.item_code][this.value]; +======= + const available_qty = me.item_stock_map[me.item_row.item_code][this.value][0]; + const is_stock_item = Boolean(me.item_stock_map[me.item_row.item_code][this.value][1]); +>>>>>>> e392ea1104 (fix: POS properly validate stock for bundle products) if (available_qty === undefined) { me.events.get_available_stock(me.item_row.item_code, this.value).then(() => { // item stock map is updated now reset warehouse me.warehouse_control.set_value(this.value); }) - } else if (available_qty === 0) { + } else if (available_qty === 0 && is_stock_item) { me.warehouse_control.set_value(''); const bold_item_code = me.item_row.item_code.bold(); const bold_warehouse = this.value.bold(); From a604eed1b9a2876ee53f9c430da9a640a26ddd00 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 28 Sep 2022 14:49:25 +0530 Subject: [PATCH 13/18] chore: Resolve conflicts --- erpnext/selling/page/point_of_sale/pos_item_details.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/erpnext/selling/page/point_of_sale/pos_item_details.js b/erpnext/selling/page/point_of_sale/pos_item_details.js index 5b4f22b65a8..f9b5bb2e452 100644 --- a/erpnext/selling/page/point_of_sale/pos_item_details.js +++ b/erpnext/selling/page/point_of_sale/pos_item_details.js @@ -242,12 +242,8 @@ erpnext.PointOfSale.ItemDetails = class { if (this.value) { me.events.form_updated(me.current_item, 'warehouse', this.value).then(() => { me.item_stock_map = me.events.get_item_stock_map(); -<<<<<<< HEAD - const available_qty = me.item_stock_map[me.item_row.item_code][this.value]; -======= const available_qty = me.item_stock_map[me.item_row.item_code][this.value][0]; const is_stock_item = Boolean(me.item_stock_map[me.item_row.item_code][this.value][1]); ->>>>>>> e392ea1104 (fix: POS properly validate stock for bundle products) if (available_qty === undefined) { me.events.get_available_stock(me.item_row.item_code, this.value).then(() => { // item stock map is updated now reset warehouse From 255aa7a84a5f3cc276819ff8705c3d714266d58f Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Wed, 28 Sep 2022 15:02:21 +0530 Subject: [PATCH 14/18] fix: don't count half day in absent days in Monthly Attendance Sheet summarized view (#32399) --- .../report/monthly_attendance_sheet/monthly_attendance_sheet.py | 1 - 1 file changed, 1 deletion(-) diff --git a/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py b/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py index c6f5bf05891..da94d96adb0 100644 --- a/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py +++ b/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py @@ -181,7 +181,6 @@ def add_data( total_l += 1 elif status == "Half Day": total_p += 0.5 - total_a += 0.5 total_l += 0.5 elif not status: total_um += 1 From b4a511cbb4aa7f2f7f7d25b6d4d291a3b4075e26 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 28 Sep 2022 15:36:59 +0530 Subject: [PATCH 15/18] fix: Disbursement Account in patch to update old loans (cherry picked from commit be623ce8e8e9c25d2327383c057b5e810b28c4a7) --- erpnext/patches/v13_0/update_old_loans.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/patches/v13_0/update_old_loans.py b/erpnext/patches/v13_0/update_old_loans.py index a1d40b739eb..0bd3fcdec4c 100644 --- a/erpnext/patches/v13_0/update_old_loans.py +++ b/erpnext/patches/v13_0/update_old_loans.py @@ -100,6 +100,7 @@ def execute(): "mode_of_payment": loan.mode_of_payment, "loan_account": loan.loan_account, "payment_account": loan.payment_account, + "disbursement_account": loan.payment_account, "interest_income_account": loan.interest_income_account, "penalty_income_account": loan.penalty_income_account, }, @@ -190,6 +191,7 @@ def create_loan_type(loan, loan_type_name, penalty_account): loan_type_doc.company = loan.company loan_type_doc.mode_of_payment = loan.mode_of_payment loan_type_doc.payment_account = loan.payment_account + loan_type_doc.disbursement_account = loan.payment_account loan_type_doc.loan_account = loan.loan_account loan_type_doc.interest_income_account = loan.interest_income_account loan_type_doc.penalty_income_account = penalty_account From 712432864095cb193a1e031bb2f3ab33d1619f01 Mon Sep 17 00:00:00 2001 From: Sagar Sharma Date: Wed, 28 Sep 2022 15:40:07 +0530 Subject: [PATCH 16/18] fix: show `Make Purchase Invoice` button based on permission (cherry picked from commit 80080a3d7bc2e4a69c7a18742ce89534920ab118) --- erpnext/templates/pages/order.html | 2 +- erpnext/templates/pages/order.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/erpnext/templates/pages/order.html b/erpnext/templates/pages/order.html index a10870db278..ec1d49788bd 100644 --- a/erpnext/templates/pages/order.html +++ b/erpnext/templates/pages/order.html @@ -18,7 +18,7 @@