From e1c168766198d44dc7e28746bcad9f4c266c3a39 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 21 Apr 2022 20:01:48 +0530 Subject: [PATCH 1/9] refactor: use db agnostic `CombineDatetime` --- erpnext/stock/stock_ledger.py | 10 ++++------ erpnext/stock/utils.py | 6 +++--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index a781479cf6..7e5c231d9c 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -8,9 +8,8 @@ from typing import Optional, Set, Tuple import frappe from frappe import _ from frappe.model.meta import get_field_precision -from frappe.query_builder.functions import Sum +from frappe.query_builder.functions import CombineDatetime, Sum from frappe.utils import cint, cstr, flt, get_link_to_form, getdate, now, nowdate -from pypika import CustomFunction import erpnext from erpnext.stock.doctype.bin.bin import update_qty as update_bin_qty @@ -1158,16 +1157,15 @@ def get_batch_incoming_rate( item_code, warehouse, batch_no, posting_date, posting_time, creation=None ): - Timestamp = CustomFunction("timestamp", ["date", "time"]) - sle = frappe.qb.DocType("Stock Ledger Entry") - timestamp_condition = Timestamp(sle.posting_date, sle.posting_time) < Timestamp( + timestamp_condition = CombineDatetime(sle.posting_date, sle.posting_time) < CombineDatetime( posting_date, posting_time ) if creation: timestamp_condition |= ( - Timestamp(sle.posting_date, sle.posting_time) == Timestamp(posting_date, posting_time) + CombineDatetime(sle.posting_date, sle.posting_time) + == CombineDatetime(posting_date, posting_time) ) & (sle.creation < creation) batch_details = ( diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py index d40218e143..2120304097 100644 --- a/erpnext/stock/utils.py +++ b/erpnext/stock/utils.py @@ -7,6 +7,7 @@ from typing import Dict, Optional import frappe from frappe import _ +from frappe.query_builder.functions import CombineDatetime from frappe.utils import cstr, flt, get_link_to_form, nowdate, nowtime import erpnext @@ -143,12 +144,10 @@ def get_stock_balance( def get_serial_nos_data_after_transactions(args): - from pypika import CustomFunction serial_nos = set() args = frappe._dict(args) sle = frappe.qb.DocType("Stock Ledger Entry") - Timestamp = CustomFunction("timestamp", ["date", "time"]) stock_ledger_entries = ( frappe.qb.from_(sle) @@ -157,7 +156,8 @@ def get_serial_nos_data_after_transactions(args): (sle.item_code == args.item_code) & (sle.warehouse == args.warehouse) & ( - Timestamp(sle.posting_date, sle.posting_time) < Timestamp(args.posting_date, args.posting_time) + CombineDatetime(sle.posting_date, sle.posting_time) + < CombineDatetime(args.posting_date, args.posting_time) ) & (sle.is_cancelled == 0) ) From cdac2b8c63e5856498e5c4cbcc871a1178f7cb80 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 21 Apr 2022 20:43:07 +0530 Subject: [PATCH 2/9] fix: ignore duplicate fixtures --- erpnext/regional/india/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index 446faaa708..062c2ef5c5 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -1219,7 +1219,7 @@ def make_fixtures(company=None): try: doc = frappe.get_doc(d) doc.flags.ignore_permissions = True - doc.insert() + doc.insert(ignore_if_duplicate=True) except frappe.NameError: frappe.clear_messages() except frappe.DuplicateEntryError: From ce75fe0ec405c68f1c5dd7b4a5d1bbde1af70705 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 22 Apr 2022 11:44:30 +0530 Subject: [PATCH 3/9] fix: out of range date value --- erpnext/stock/doctype/stock_entry/stock_entry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index c4aa8a4711..27a6eaf08b 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -1167,7 +1167,7 @@ class StockEntry(StockController): from `tabItem` i LEFT JOIN `tabItem Default` id ON i.name=id.parent and id.company=%s where i.name=%s and i.disabled=0 - and (i.end_of_life is null or i.end_of_life='0000-00-00' or i.end_of_life > %s)""", + and (i.end_of_life is null or i.end_of_life<'1900-01-01' or i.end_of_life > %s)""", (self.company, args.get("item_code"), nowdate()), as_dict=1, ) From 0fdfc1e76e7aa89268e89a67c968b7acb6d980ec Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 24 Apr 2022 19:19:22 +0530 Subject: [PATCH 4/9] fix: only query fields that exist --- erpnext/crm/doctype/opportunity/opportunity.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py index 96c730c668..19b4d68e1c 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.py +++ b/erpnext/crm/doctype/opportunity/opportunity.py @@ -54,11 +54,11 @@ class Opportunity(TransactionBase): self.calculate_totals() def map_fields(self): - for field in self.meta.fields: - if not self.get(field.fieldname): + for field in self.meta.get_valid_columns(): + if not self.get(field) and frappe.db.field_exists(self.opportunity_from, field): try: - value = frappe.db.get_value(self.opportunity_from, self.party_name, field.fieldname) - frappe.db.set(self, field.fieldname, value) + value = frappe.db.get_value(self.opportunity_from, self.party_name, field) + frappe.db.set(self, field, value) except Exception: continue From 7d2587c0a9b2ab30ab45bbc9c2af40b1f2ade1fb Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 24 Apr 2022 19:26:15 +0530 Subject: [PATCH 5/9] fix: nullish check and table name --- erpnext/manufacturing/doctype/bom/bom.py | 2 +- erpnext/stock/doctype/item_price/item_price.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index fefb2e59f0..220ce1dbd8 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -753,7 +753,7 @@ class BOM(WebsiteGenerator): bom_item.include_item_in_manufacturing, bom_item.sourced_by_supplier, bom_item.stock_qty / ifnull(bom.quantity, 1) AS qty_consumed_per_unit - FROM `tabBOM Explosion Item` bom_item, tabBOM bom + FROM `tabBOM Explosion Item` bom_item, `tabBOM` bom WHERE bom_item.parent = bom.name AND bom.name = %s diff --git a/erpnext/stock/doctype/item_price/item_price.py b/erpnext/stock/doctype/item_price/item_price.py index 562f7b9e12..ab797cd039 100644 --- a/erpnext/stock/doctype/item_price/item_price.py +++ b/erpnext/stock/doctype/item_price/item_price.py @@ -64,7 +64,7 @@ class ItemPrice(Document): if self.get(field): conditions += " and {0} = %({0})s ".format(field) else: - conditions += "and (isnull({0}) or {0} = '')".format(field) + conditions += "and ({0} is null or {0} = '')".format(field) price_list_rate = frappe.db.sql( """ From 7e555d3d8c47bc7f304905a3d52b02e9da6b0283 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 24 Apr 2022 19:47:07 +0530 Subject: [PATCH 6/9] fix: item price query for postgres postgres doesn't like bad type comparisons and doesn't have `isnull` funciton --- .../stock/doctype/item_price/item_price.py | 64 +++++++++++++------ 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/erpnext/stock/doctype/item_price/item_price.py b/erpnext/stock/doctype/item_price/item_price.py index ab797cd039..bcd31ada83 100644 --- a/erpnext/stock/doctype/item_price/item_price.py +++ b/erpnext/stock/doctype/item_price/item_price.py @@ -5,6 +5,8 @@ import frappe from frappe import _ from frappe.model.document import Document +from frappe.query_builder import Criterion +from frappe.query_builder.functions import Cast_ from frappe.utils import getdate @@ -48,35 +50,57 @@ class ItemPrice(Document): ) def check_duplicates(self): - conditions = ( - """where item_code = %(item_code)s and price_list = %(price_list)s and name != %(name)s""" - ) - for field in [ + item_price = frappe.qb.DocType("Item Price") + + query = ( + frappe.qb.from_(item_price) + .select(item_price.price_list_rate) + .where( + (item_price.item_code == self.item_code) + & (item_price.price_list == self.price_list) + & (item_price.name != self.name) + ) + ) + data_fields = ( "uom", "valid_from", "valid_upto", - "packing_unit", "customer", "supplier", "batch_no", - ]: - if self.get(field): - conditions += " and {0} = %({0})s ".format(field) - else: - conditions += "and ({0} is null or {0} = '')".format(field) - - price_list_rate = frappe.db.sql( - """ - select price_list_rate - from `tabItem Price` - {conditions} - """.format( - conditions=conditions - ), - self.as_dict(), ) + number_fields = ["packing_unit"] + + for field in data_fields: + if self.get(field): + query = query.where(item_price[field] == self.get(field)) + else: + query = query.where( + Criterion.any( + [ + item_price[field].isnull(), + Cast_(item_price[field], "varchar") == "", + ] + ) + ) + + for field in number_fields: + if self.get(field): + query = query.where(item_price[field] == self.get(field)) + else: + query = query.where( + Criterion.any( + [ + item_price[field].isnull(), + item_price[field] == 0, + ] + ) + ) + + price_list_rate = query.run(as_dict=True) + if price_list_rate: frappe.throw( _( From a90e7e32a42362f5a03ad1467c7a1e5757fe95fe Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 24 Apr 2022 20:05:36 +0530 Subject: [PATCH 7/9] fix: proper quoting in sql queries --- erpnext/accounts/party.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index b0b3049d48..ac1dfec7a5 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -881,11 +881,11 @@ def get_default_contact(doctype, name): """ SELECT dl.parent, c.is_primary_contact, c.is_billing_contact FROM `tabDynamic Link` dl - INNER JOIN tabContact c ON c.name = dl.parent + INNER JOIN `tabContact` c ON c.name = dl.parent WHERE dl.link_doctype=%s AND dl.link_name=%s AND - dl.parenttype = "Contact" + dl.parenttype = 'Contact' ORDER BY is_primary_contact DESC, is_billing_contact DESC """, (doctype, name), From 052171f51c17c77459c05423a87ca935dd0ab555 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 24 Apr 2022 20:14:01 +0530 Subject: [PATCH 8/9] fix: date condition in tax rule --- erpnext/accounts/doctype/tax_rule/tax_rule.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/tax_rule/tax_rule.py b/erpnext/accounts/doctype/tax_rule/tax_rule.py index 27b78e9fab..5bfca96bb1 100644 --- a/erpnext/accounts/doctype/tax_rule/tax_rule.py +++ b/erpnext/accounts/doctype/tax_rule/tax_rule.py @@ -163,10 +163,15 @@ def get_party_details(party, party_type, args=None): def get_tax_template(posting_date, args): """Get matching tax rule""" args = frappe._dict(args) + from_date = to_date = posting_date + if not posting_date: + from_date = "1900-01-01" + to_date = "4000-01-01" + conditions = [ """(from_date is null or from_date <= '{0}') - and (to_date is null or to_date >= '{0}')""".format( - posting_date + and (to_date is null or to_date >= '{1}')""".format( + from_date, to_date ) ] From 88e257ff6d89ba03e3b273be33fec62714751b69 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sun, 24 Apr 2022 20:17:17 +0530 Subject: [PATCH 9/9] fix: column name in party query --- erpnext/accounts/party.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index ac1dfec7a5..db741d97e1 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -831,9 +831,9 @@ def get_party_shipping_address(doctype, name): "where " "dl.link_doctype=%s " "and dl.link_name=%s " - 'and dl.parenttype="Address" ' + "and dl.parenttype='Address' " "and ifnull(ta.disabled, 0) = 0 and" - '(ta.address_type="Shipping" or ta.is_shipping_address=1) ' + "(ta.address_type='Shipping' or ta.is_shipping_address=1) " "order by ta.is_shipping_address desc, ta.address_type desc limit 1", (doctype, name), )