Merge pull request #50550 from akhilnarang/qb-compat

refactor: adapt for query builder changes
This commit is contained in:
Akhil Narang
2025-11-19 21:55:25 +05:30
committed by GitHub
54 changed files with 247 additions and 146 deletions

View File

@@ -14,6 +14,7 @@ import openpyxl
from frappe import _ from frappe import _
from frappe.core.doctype.data_import.data_import import DataImport from frappe.core.doctype.data_import.data_import import DataImport
from frappe.core.doctype.data_import.importer import Importer, ImportFile from frappe.core.doctype.data_import.importer import Importer, ImportFile
from frappe.query_builder.functions import Count
from frappe.utils.background_jobs import enqueue from frappe.utils.background_jobs import enqueue
from frappe.utils.file_manager import get_file, save_file from frappe.utils.file_manager import get_file, save_file
from frappe.utils.xlsxutils import ILLEGAL_CHARACTERS_RE, handle_html from frappe.utils.xlsxutils import ILLEGAL_CHARACTERS_RE, handle_html
@@ -371,7 +372,7 @@ def get_import_status(docname):
logs = frappe.get_all( logs = frappe.get_all(
"Data Import Log", "Data Import Log",
fields=["count(*) as count", "success"], fields=[{"COUNT": "*", "as": "count"}, "success"],
filters={"data_import": docname}, filters={"data_import": docname},
group_by="success", group_by="success",
) )

View File

@@ -3,6 +3,8 @@
import frappe import frappe
from frappe.query_builder import functions
from frappe.query_builder.utils import DocType
from frappe.tests import IntegrationTestCase from frappe.tests import IntegrationTestCase
from frappe.utils import add_days, flt, today from frappe.utils import add_days, flt, today
@@ -81,10 +83,11 @@ class TestExchangeRateRevaluation(AccountsTestMixin, IntegrationTestCase):
self.assertEqual(je.total_debit, 8500.0) self.assertEqual(je.total_debit, 8500.0)
self.assertEqual(je.total_credit, 8500.0) self.assertEqual(je.total_credit, 8500.0)
gl = DocType("GL Entry")
acc_balance = frappe.db.get_all( acc_balance = frappe.db.get_all(
"GL Entry", "GL Entry",
filters={"account": self.debtors_usd, "is_cancelled": 0}, filters={"account": self.debtors_usd, "is_cancelled": 0},
fields=["sum(debit)-sum(credit) as balance"], fields=[(functions.Sum(gl.debit) - functions.Sum(gl.credit)).as_("balance")],
)[0] )[0]
self.assertEqual(acc_balance.balance, 8500.0) self.assertEqual(acc_balance.balance, 8500.0)
@@ -146,12 +149,15 @@ class TestExchangeRateRevaluation(AccountsTestMixin, IntegrationTestCase):
self.assertEqual(je.total_debit, 500.0) self.assertEqual(je.total_debit, 500.0)
self.assertEqual(je.total_credit, 500.0) self.assertEqual(je.total_credit, 500.0)
gl = DocType("GL Entry")
acc_balance = frappe.db.get_all( acc_balance = frappe.db.get_all(
"GL Entry", "GL Entry",
filters={"account": self.debtors_usd, "is_cancelled": 0}, filters={"account": self.debtors_usd, "is_cancelled": 0},
fields=[ fields=[
"sum(debit)-sum(credit) as balance", (functions.Sum(gl.debit) - functions.Sum(gl.credit)).as_("balance"),
"sum(debit_in_account_currency)-sum(credit_in_account_currency) as balance_in_account_currency", (
functions.Sum(gl.debit_in_account_currency) - functions.Sum(gl.credit_in_account_currency)
).as_("balance_in_account_currency"),
], ],
)[0] )[0]
# account shouldn't have balance in base and account currency # account shouldn't have balance in base and account currency
@@ -193,12 +199,15 @@ class TestExchangeRateRevaluation(AccountsTestMixin, IntegrationTestCase):
pe.references = [] pe.references = []
pe.save().submit() pe.save().submit()
gl = DocType("GL Entry")
acc_balance = frappe.db.get_all( acc_balance = frappe.db.get_all(
"GL Entry", "GL Entry",
filters={"account": self.debtors_usd, "is_cancelled": 0}, filters={"account": self.debtors_usd, "is_cancelled": 0},
fields=[ fields=[
"sum(debit)-sum(credit) as balance", (functions.Sum(gl.debit) - functions.Sum(gl.credit)).as_("balance"),
"sum(debit_in_account_currency)-sum(credit_in_account_currency) as balance_in_account_currency", (
functions.Sum(gl.debit_in_account_currency) - functions.Sum(gl.credit_in_account_currency)
).as_("balance_in_account_currency"),
], ],
)[0] )[0]
# account should have balance only in account currency # account should have balance only in account currency
@@ -235,12 +244,15 @@ class TestExchangeRateRevaluation(AccountsTestMixin, IntegrationTestCase):
self.assertEqual(flt(je.total_debit, precision), 0.0) self.assertEqual(flt(je.total_debit, precision), 0.0)
self.assertEqual(flt(je.total_credit, precision), 0.0) self.assertEqual(flt(je.total_credit, precision), 0.0)
gl = DocType("GL Entry")
acc_balance = frappe.db.get_all( acc_balance = frappe.db.get_all(
"GL Entry", "GL Entry",
filters={"account": self.debtors_usd, "is_cancelled": 0}, filters={"account": self.debtors_usd, "is_cancelled": 0},
fields=[ fields=[
"sum(debit)-sum(credit) as balance", (functions.Sum(gl.debit) - functions.Sum(gl.credit)).as_("balance"),
"sum(debit_in_account_currency)-sum(credit_in_account_currency) as balance_in_account_currency", (
functions.Sum(gl.debit_in_account_currency) - functions.Sum(gl.credit_in_account_currency)
).as_("balance_in_account_currency"),
], ],
)[0] )[0]
# account shouldn't have balance in base and account currency post revaluation # account shouldn't have balance in base and account currency post revaluation

View File

@@ -71,8 +71,8 @@ class OpeningInvoiceCreationTool(Document):
max_count = {} max_count = {}
fields = [ fields = [
"company", "company",
"count(name) as total_invoices", {"COUNT": "*", "as": "total_invoices"},
"sum(outstanding_amount) as outstanding_amount", {"SUM": "outstanding_amount", "as": "outstanding_amount"},
] ]
companies = frappe.get_all("Company", fields=["name as company", "default_currency as currency"]) companies = frappe.get_all("Company", fields=["name as company", "default_currency as currency"])
if not companies: if not companies:

View File

@@ -669,7 +669,7 @@ class PaymentReconciliation(Document):
"party": self.party, "party": self.party,
}, },
fields=[ fields=[
"parent as `name`", "parent as name",
"exchange_rate", "exchange_rate",
], ],
as_list=1, as_list=1,

View File

@@ -975,7 +975,7 @@ class TestPaymentReconciliation(IntegrationTestCase):
total_credit_amount = frappe.db.get_all( total_credit_amount = frappe.db.get_all(
"Journal Entry Account", "Journal Entry Account",
{"account": self.debtors_eur, "docstatus": 1, "reference_name": si.name}, {"account": self.debtors_eur, "docstatus": 1, "reference_name": si.name},
"sum(credit) as amount", [{"SUM": "credit", "as": "amount"}],
group_by="reference_name", group_by="reference_name",
)[0].amount )[0].amount
@@ -1069,7 +1069,7 @@ class TestPaymentReconciliation(IntegrationTestCase):
total_credit_amount = frappe.db.get_all( total_credit_amount = frappe.db.get_all(
"Journal Entry Account", "Journal Entry Account",
{"account": self.debtors_eur, "docstatus": 1, "reference_name": si.name}, {"account": self.debtors_eur, "docstatus": 1, "reference_name": si.name},
"sum(credit) as amount", [{"SUM": "credit", "as": "amount"}],
group_by="reference_name", group_by="reference_name",
)[0].amount )[0].amount

View File

@@ -713,6 +713,7 @@ def get_item_uoms(doctype, txt, searchfield, start, page_len, filters):
return frappe.get_all( return frappe.get_all(
"UOM Conversion Detail", "UOM Conversion Detail",
filters={"parent": ("in", items), "uom": ("like", f"{txt}%")}, filters={"parent": ("in", items), "uom": ("like", f"{txt}%")},
fields=["distinct uom"], fields=["uom"],
as_list=1, as_list=1,
distinct=True,
) )

View File

@@ -1374,7 +1374,7 @@ class TestPurchaseInvoice(IntegrationTestCase, StockTestMixin):
total_debit_amount = frappe.db.get_all( total_debit_amount = frappe.db.get_all(
"Journal Entry Account", "Journal Entry Account",
{"account": creditors_account, "docstatus": 1, "reference_name": pi.name}, {"account": creditors_account, "docstatus": 1, "reference_name": pi.name},
"sum(debit) as amount", [{"SUM": "debit", "as": "amount"}],
group_by="reference_name", group_by="reference_name",
)[0].amount )[0].amount
self.assertEqual(flt(total_debit_amount, 2), 2500) self.assertEqual(flt(total_debit_amount, 2), 2500)
@@ -1456,7 +1456,7 @@ class TestPurchaseInvoice(IntegrationTestCase, StockTestMixin):
total_debit_amount = frappe.db.get_all( total_debit_amount = frappe.db.get_all(
"Journal Entry Account", "Journal Entry Account",
{"account": creditors_account, "docstatus": 1, "reference_name": pi_2.name}, {"account": creditors_account, "docstatus": 1, "reference_name": pi_2.name},
"sum(debit) as amount", [{"SUM": "debit", "as": "amount"}],
group_by="reference_name", group_by="reference_name",
)[0].amount )[0].amount
self.assertEqual(flt(total_debit_amount, 2), 1500) self.assertEqual(flt(total_debit_amount, 2), 1500)

View File

@@ -213,7 +213,10 @@ def get_allowed_types_from_settings(child_doc: bool = False):
repost_docs = [ repost_docs = [
x.document_type x.document_type
for x in frappe.db.get_all( for x in frappe.db.get_all(
"Repost Allowed Types", filters={"allowed": True}, fields=["distinct(document_type)"] "Repost Allowed Types",
filters={"allowed": True},
fields=["document_type"],
distinct=True,
) )
] ]
result = repost_docs result = repost_docs
@@ -287,7 +290,11 @@ def get_repost_allowed_types(doctype, txt, searchfield, start, page_len, filters
filters.update({"document_type": ("like", f"%{txt}%")}) filters.update({"document_type": ("like", f"%{txt}%")})
if allowed_types := frappe.db.get_all( if allowed_types := frappe.db.get_all(
"Repost Allowed Types", filters=filters, fields=["distinct(document_type)"], as_list=1 "Repost Allowed Types",
filters=filters,
fields=["document_type"],
as_list=1,
distinct=True,
): ):
return allowed_types return allowed_types
return [] return []

View File

@@ -3612,7 +3612,7 @@ class TestSalesInvoice(ERPNextTestSuite):
frappe.db.get_all( frappe.db.get_all(
"Payment Ledger Entry", "Payment Ledger Entry",
filters={"against_voucher_no": si.name, "delinked": 0}, filters={"against_voucher_no": si.name, "delinked": 0},
fields=["sum(amount), sum(amount_in_account_currency)"], fields=[{"SUM": "amount"}, {"SUM": "amount_in_account_currency"}],
as_list=1, as_list=1,
) )

View File

@@ -121,7 +121,7 @@ class TestTaxWithholdingCategory(IntegrationTestCase):
gl_entries = frappe.db.get_all( gl_entries = frappe.db.get_all(
"GL Entry", "GL Entry",
filters={"voucher_no": pi.name}, filters={"voucher_no": pi.name},
fields=["account", "sum(debit) as debit", "sum(credit) as credit"], fields=["account", {"SUM": "debit", "as": "debit"}, {"SUM": "credit", "as": "credit"}],
group_by="account", group_by="account",
) )
self.assertEqual(len(gl_entries), 3) self.assertEqual(len(gl_entries), 3)

View File

@@ -854,8 +854,8 @@ def get_dashboard_info(party_type, party, loyalty_program=None):
group_by="company", group_by="company",
fields=[ fields=[
"company", "company",
"sum(grand_total) as grand_total", {"SUM": "grand_total", "as": "grand_total"},
"sum(base_grand_total) as base_grand_total", {"SUM": "base_grand_total", "as": "base_grand_total"},
], ],
) )
@@ -870,7 +870,7 @@ def get_dashboard_info(party_type, party, loyalty_program=None):
"expiry_date": (">=", getdate()), "expiry_date": (">=", getdate()),
}, },
group_by="company", group_by="company",
fields=["company", "sum(loyalty_points) as loyalty_points"], fields=["company", {"SUM": "loyalty_points", "as": "loyalty_points"}],
as_list=1, as_list=1,
) )
) )

View File

@@ -210,7 +210,7 @@ def get_gl_balance(report_date, company):
return frappe._dict( return frappe._dict(
frappe.db.get_all( frappe.db.get_all(
"GL Entry", "GL Entry",
fields=["party", "sum(debit - credit)"], fields=["party", {"SUM": [{"SUB": ["debit", "credit"]}], "as": "balance"}],
filters={"posting_date": ("<=", report_date), "is_cancelled": 0, "company": company}, filters={"posting_date": ("<=", report_date), "is_cancelled": 0, "company": company},
group_by="party", group_by="party",
as_list=1, as_list=1,

View File

@@ -323,22 +323,24 @@ def get_returned_qty_map_for_row(return_against, party, row_name, doctype):
party_type = "customer" party_type = "customer"
fields = [ fields = [
f"sum(abs(`tab{child_doctype}`.qty)) as qty", {"SUM": [{"ABS": f"`tab{child_doctype}`.qty"}], "as": "qty"},
] ]
if doctype != "Subcontracting Receipt": if doctype != "Subcontracting Receipt":
fields += [ fields += [
f"sum(abs(`tab{child_doctype}`.stock_qty)) as stock_qty", {"SUM": [{"ABS": f"`tab{child_doctype}`.stock_qty"}], "as": "stock_qty"},
] ]
if doctype in ("Purchase Receipt", "Purchase Invoice", "Subcontracting Receipt"): if doctype in ("Purchase Receipt", "Purchase Invoice", "Subcontracting Receipt"):
fields += [ fields += [
f"sum(abs(`tab{child_doctype}`.rejected_qty)) as rejected_qty", {"SUM": [{"ABS": f"`tab{child_doctype}`.rejected_qty"}], "as": "rejected_qty"},
f"sum(abs(`tab{child_doctype}`.received_qty)) as received_qty", {"SUM": [{"ABS": f"`tab{child_doctype}`.received_qty"}], "as": "received_qty"},
] ]
if doctype == "Purchase Receipt": if doctype == "Purchase Receipt":
fields += [f"sum(abs(`tab{child_doctype}`.received_stock_qty)) as received_stock_qty"] fields += [
{"SUM": [{"ABS": f"`tab{child_doctype}`.received_stock_qty"}], "as": "received_stock_qty"}
]
# Used retrun against and supplier and is_retrun because there is an index added for it # Used retrun against and supplier and is_retrun because there is an index added for it
data = frappe.get_all( data = frappe.get_all(

View File

@@ -563,11 +563,14 @@ class StatusUpdater(Document):
fields=[target_ref_field, target_field], fields=[target_ref_field, target_field],
) )
sum_ref = sum(abs(record[target_ref_field]) for record in child_records) # For operator dicts, the alias is in the "as" key; for strings, use the field name directly
ref_key = target_ref_field.get("as") if isinstance(target_ref_field, dict) else target_ref_field
sum_ref = sum(abs(record[ref_key]) for record in child_records)
if sum_ref > 0: if sum_ref > 0:
percentage = round( percentage = round(
sum(min(abs(record[target_field]), abs(record[target_ref_field])) for record in child_records) sum(min(abs(record[target_field]), abs(record[ref_key])) for record in child_records)
/ sum_ref / sum_ref
* 100, * 100,
6, 6,

View File

@@ -1320,7 +1320,7 @@ class StockController(AccountsController):
total_returned += flt(item.returned_qty * item.rate) total_returned += flt(item.returned_qty * item.rate)
if total_returned < total_amount: if total_returned < total_amount:
target_ref_field = "(amount - (returned_qty * rate))" target_ref_field = {"SUB": ["amount", {"MUL": ["returned_qty", "rate"]}], "as": "ref_amount"}
self._update_percent_field( self._update_percent_field(
{ {

View File

@@ -292,7 +292,7 @@ class SubcontractingController(StockController):
): ):
for row in frappe.get_all( for row in frappe.get_all(
f"{self.subcontract_data.order_doctype} Item", f"{self.subcontract_data.order_doctype} Item",
fields=["item_code", "(qty - received_qty) as qty", "parent", "name"], fields=["item_code", {"SUB": ["qty", "received_qty"], "as": "qty"}, "parent", "name"],
filters={"docstatus": 1, "parent": ("in", self.subcontract_orders)}, filters={"docstatus": 1, "parent": ("in", self.subcontract_orders)},
): ):
self.qty_to_be_received[(row.item_code, row.parent)] += row.qty self.qty_to_be_received[(row.item_code, row.parent)] += row.qty
@@ -553,7 +553,9 @@ class SubcontractingController(StockController):
data = [] data = []
doctype = "BOM Item" if not exploded_item else "BOM Explosion Item" doctype = "BOM Item" if not exploded_item else "BOM Explosion Item"
fields = [f"`tab{doctype}`.`stock_qty` / `tabBOM`.`quantity` as qty_consumed_per_unit"] fields = [
{"DIV": [f"`tab{doctype}`.`stock_qty`", "`tabBOM`.`quantity`"], "as": "qty_consumed_per_unit"}
]
alias_dict = { alias_dict = {
"item_code": "rm_item_code", "item_code": "rm_item_code",

View File

@@ -328,7 +328,7 @@ class TestItemWiseInventoryAccount(IntegrationTestCase):
"voucher_no": pr.name, "voucher_no": pr.name,
"item_code": ("in", items), "item_code": ("in", items),
}, },
fields=["sum(stock_value_difference) as value"], fields=[{"SUM": "stock_value_difference", "as": "value"}],
) )
gl_value = frappe.db.get_value( gl_value = frappe.db.get_value(
@@ -435,7 +435,7 @@ class TestItemWiseInventoryAccount(IntegrationTestCase):
sle_value = frappe.get_all( sle_value = frappe.get_all(
"Stock Ledger Entry", "Stock Ledger Entry",
filters={"voucher_type": "Delivery Note", "voucher_no": dn.name, "item_code": ("in", items)}, filters={"voucher_type": "Delivery Note", "voucher_no": dn.name, "item_code": ("in", items)},
fields=["sum(stock_value_difference) as value"], fields=[{"SUM": "stock_value_difference", "as": "value"}],
) )
gl_value = ( gl_value = (

View File

@@ -74,7 +74,7 @@ class OpportunitySummaryBySalesStage:
}[self.filters.get("based_on")] }[self.filters.get("based_on")]
data_based_on = { data_based_on = {
"Number": "count(name) as count", "Number": {"COUNT": "*", "as": "count"},
"Amount": "opportunity_amount as amount", "Amount": "opportunity_amount as amount",
}[self.filters.get("data_based_on")] }[self.filters.get("data_based_on")]

View File

@@ -8,6 +8,7 @@ from itertools import groupby
import frappe import frappe
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from frappe import _ from frappe import _
from frappe.query_builder.custom import Month, MonthName, Quarter
from frappe.utils import cint, flt, getdate from frappe.utils import cint, flt, getdate
from erpnext.setup.utils import get_exchange_rate from erpnext.setup.utils import get_exchange_rate
@@ -74,7 +75,7 @@ class SalesPipelineAnalytics:
] ]
self.data_based_on = { self.data_based_on = {
"Number": "count(name) as count", "Number": {"COUNT": "*", "as": "count"},
"Amount": "opportunity_amount as amount", "Amount": "opportunity_amount as amount",
}[self.filters.get("based_on")] }[self.filters.get("based_on")]
@@ -82,40 +83,52 @@ class SalesPipelineAnalytics:
self.filters.get("pipeline_by") self.filters.get("pipeline_by")
] ]
self.group_by_period = { opp = frappe.qb.DocType("Opportunity")
"Monthly": "month(expected_closing)",
"Quarterly": "QUARTER(expected_closing)", if self.filters.get("range") == "Monthly":
}[self.filters.get("range")] self.group_by_period = Month(opp.expected_closing)
self.duration = MonthName(opp.expected_closing).as_("month")
else:
self.group_by_period = Quarter(opp.expected_closing)
self.duration = Quarter(opp.expected_closing).as_("quarter")
self.pipeline_by = {"Owner": "opportunity_owner", "Sales Stage": "sales_stage"}[ self.pipeline_by = {"Owner": "opportunity_owner", "Sales Stage": "sales_stage"}[
self.filters.get("pipeline_by") self.filters.get("pipeline_by")
] ]
self.duration = {
"Monthly": "monthname(expected_closing) as month",
"Quarterly": "QUARTER(expected_closing) as quarter",
}[self.filters.get("range")]
self.period_by = {"Monthly": "month", "Quarterly": "quarter"}[self.filters.get("range")] self.period_by = {"Monthly": "month", "Quarterly": "quarter"}[self.filters.get("range")]
def get_data(self): def get_data(self):
self.get_fields() self.get_fields()
opp = frappe.qb.DocType("Opportunity")
query = frappe.qb.get_query(
"Opportunity",
filters=self.get_conditions(),
ignore_permissions=True,
)
pipeline_field = opp._assign if self.group_by_based_on == "_assign" else opp.sales_stage
if self.filters.get("based_on") == "Number": if self.filters.get("based_on") == "Number":
self.query_result = frappe.db.get_list( self.query_result = (
"Opportunity", query.select(
filters=self.get_conditions(), pipeline_field.as_(self.pipeline_by),
fields=[self.based_on, self.data_based_on, self.duration], frappe.query_builder.functions.Count("*").as_("count"),
group_by=f"{self.group_by_based_on},{self.group_by_period}", self.duration,
order_by=self.group_by_period, )
.groupby(pipeline_field, self.group_by_period)
.orderby(self.group_by_period)
.run(as_dict=True)
) )
if self.filters.get("based_on") == "Amount": if self.filters.get("based_on") == "Amount":
self.query_result = frappe.db.get_list( self.query_result = query.select(
"Opportunity", pipeline_field.as_(self.pipeline_by),
filters=self.get_conditions(), opp.opportunity_amount.as_("amount"),
fields=[self.based_on, self.data_based_on, self.duration, "currency"], self.duration,
) opp.currency,
).run(as_dict=True)
self.convert_to_base_currency() self.convert_to_base_currency()

View File

@@ -10,6 +10,8 @@ import frappe
from frappe import _, bold from frappe import _, bold
from frappe.core.doctype.version.version import get_diff from frappe.core.doctype.version.version import get_diff
from frappe.model.mapper import get_mapped_doc from frappe.model.mapper import get_mapped_doc
from frappe.query_builder import Field
from frappe.query_builder.functions import Count, IfNull, Sum
from frappe.utils import cint, cstr, flt, get_link_to_form, parse_json, today from frappe.utils import cint, cstr, flt, get_link_to_form, parse_json, today
from frappe.website.website_generator import WebsiteGenerator from frappe.website.website_generator import WebsiteGenerator
@@ -1191,7 +1193,6 @@ def get_valuation_rate(data):
2) If no value, get last valuation rate from SLE 2) If no value, get last valuation rate from SLE
3) If no value, get valuation rate from Item 3) If no value, get valuation rate from Item
""" """
from frappe.query_builder.functions import Count, IfNull, Sum
from pypika import Case from pypika import Case
item_code, company = data.get("item_code"), data.get("company") item_code, company = data.get("item_code"), data.get("company")
@@ -1482,7 +1483,10 @@ def add_non_stock_items_cost(stock_entry, work_order, expense_account, job_card=
non_stock_items = frappe.get_all( non_stock_items = frappe.get_all(
"Item", "Item",
fields="name", fields="name",
filters={"name": ("in", list(items.keys())), "ifnull(is_stock_item, 0)": 0}, filters=[
["name", "in", list(items.keys())],
[IfNull(Field("is_stock_item"), 0), "=", 0],
],
as_list=1, as_list=1,
) )
@@ -1601,8 +1605,6 @@ def add_operations_cost(stock_entry, work_order=None, expense_account=None, job_
) )
def get_max_operation_quantity(): def get_max_operation_quantity():
from frappe.query_builder.functions import Sum
table = frappe.qb.DocType("Job Card") table = frappe.qb.DocType("Job Card")
query = ( query = (
frappe.qb.from_(table) frappe.qb.from_(table)
@@ -1617,8 +1619,6 @@ def add_operations_cost(stock_entry, work_order=None, expense_account=None, job_
return min([d.qty for d in query.run(as_dict=True)], default=0) return min([d.qty for d in query.run(as_dict=True)], default=0)
def get_utilised_corrective_cost(): def get_utilised_corrective_cost():
from frappe.query_builder.functions import Sum
table = frappe.qb.DocType("Stock Entry") table = frappe.qb.DocType("Stock Entry")
subquery = ( subquery = (
frappe.qb.from_(table) frappe.qb.from_(table)
@@ -1728,7 +1728,10 @@ def item_query(doctype, txt, searchfield, start, page_len, filters):
if not searchfields: if not searchfields:
searchfields = ["name"] searchfields = ["name"]
query_filters = {"disabled": 0, "ifnull(end_of_life, '3099-12-31')": (">", today())} query_filters = [
["disabled", "=", 0],
[IfNull(Field("end_of_life"), "3099-12-31"), ">", today()],
]
or_cond_filters = {} or_cond_filters = {}
if txt: if txt:
@@ -1737,8 +1740,9 @@ def item_query(doctype, txt, searchfield, start, page_len, filters):
barcodes = frappe.get_all( barcodes = frappe.get_all(
"Item Barcode", "Item Barcode",
fields=["distinct parent as item_code"], fields=["parent as item_code"],
filters={"barcode": ("like", f"%{txt}%")}, filters={"barcode": ("like", f"%{txt}%")},
distinct=True,
) )
barcodes = [d.item_code for d in barcodes] barcodes = [d.item_code for d in barcodes]
@@ -1748,11 +1752,11 @@ def item_query(doctype, txt, searchfield, start, page_len, filters):
if filters and filters.get("item_code"): if filters and filters.get("item_code"):
has_variants = frappe.get_cached_value("Item", filters.get("item_code"), "has_variants") has_variants = frappe.get_cached_value("Item", filters.get("item_code"), "has_variants")
if not has_variants: if not has_variants:
query_filters["has_variants"] = 0 query_filters.append(["has_variants", "=", 0])
if filters: if filters:
for fieldname, value in filters.items(): for fieldname, value in filters.items():
query_filters[fieldname] = value query_filters.append([fieldname, "=", value])
return frappe.get_list( return frappe.get_list(
"Item", "Item",

View File

@@ -207,7 +207,7 @@ class JobCard(Document):
job_card_qty = frappe.get_all( job_card_qty = frappe.get_all(
"Job Card", "Job Card",
fields=["sum(for_quantity)"], fields=[{"SUM": "for_quantity"}],
filters={ filters={
"work_order": self.work_order, "work_order": self.work_order,
"operation_id": self.operation_id, "operation_id": self.operation_id,
@@ -933,9 +933,9 @@ class JobCard(Document):
return frappe.get_all( return frappe.get_all(
"Job Card", "Job Card",
fields=[ fields=[
"sum(total_time_in_mins) as time_in_mins", {"SUM": "total_time_in_mins", "as": "time_in_mins"},
"sum(total_completed_qty) as completed_qty", {"SUM": "total_completed_qty", "as": "completed_qty"},
"sum(process_loss_qty) as process_loss_qty", {"SUM": "process_loss_qty", "as": "process_loss_qty"},
], ],
filters={ filters={
"docstatus": 1, "docstatus": 1,
@@ -1423,11 +1423,12 @@ def get_operations(doctype, txt, searchfield, start, page_len, filters):
return frappe.get_all( return frappe.get_all(
"Work Order Operation", "Work Order Operation",
filters=args, filters=args,
fields=["distinct operation as operation"], fields=["operation"],
limit_start=start, limit_start=start,
limit_page_length=page_len, limit_page_length=page_len,
order_by="idx asc", order_by="idx asc",
as_list=1, as_list=1,
distinct=True,
) )

View File

@@ -624,7 +624,7 @@ class ProductionPlan(Document):
so_wise_planned_qty = frappe._dict() so_wise_planned_qty = frappe._dict()
data = frappe.get_all( data = frappe.get_all(
"Production Plan Item", "Production Plan Item",
fields=["sales_order", "sales_order_item", "SUM(planned_qty) as qty"], fields=["sales_order", "sales_order_item", {"SUM": "planned_qty", "as": "qty"}],
filters={ filters={
"sales_order": ("in", sales_orders), "sales_order": ("in", sales_orders),
"docstatus": 1, "docstatus": 1,

View File

@@ -73,9 +73,10 @@ class TestProductionPlan(IntegrationTestCase):
material_requests = frappe.get_all( material_requests = frappe.get_all(
"Material Request Item", "Material Request Item",
fields=["distinct parent"], fields=["parent"],
filters={"production_plan": pln.name}, filters={"production_plan": pln.name},
as_list=1, as_list=1,
distinct=True,
) )
self.assertTrue(len(material_requests), 2) self.assertTrue(len(material_requests), 2)

View File

@@ -976,8 +976,9 @@ class TestWorkOrder(IntegrationTestCase):
job_cards = frappe.get_all( job_cards = frappe.get_all(
"Job Card Time Log", "Job Card Time Log",
fields=["distinct parent as name", "docstatus"], fields=["parent as name", "docstatus"],
order_by="creation asc", order_by="creation asc",
distinct=True,
) )
for job_card in job_cards: for job_card in job_cards:

View File

@@ -166,7 +166,7 @@ class WorkOrder(Document):
operation_details = frappe._dict( operation_details = frappe._dict(
frappe.get_all( frappe.get_all(
"Job Card", "Job Card",
fields=["operation", "sum(for_quantity)"], fields=["operation", {"SUM": "for_quantity"}],
filters={"docstatus": ("<", 2), "work_order": self.name}, filters={"docstatus": ("<", 2), "work_order": self.name},
as_list=1, as_list=1,
group_by="operation_id", group_by="operation_id",
@@ -718,7 +718,7 @@ class WorkOrder(Document):
if self.production_plan_item: if self.production_plan_item:
total_qty = frappe.get_all( total_qty = frappe.get_all(
"Work Order", "Work Order",
fields="sum(produced_qty) as produced_qty", fields=[{"SUM": "produced_qty", "as": "produced_qty"}],
filters={ filters={
"docstatus": 1, "docstatus": 1,
"production_plan": self.production_plan, "production_plan": self.production_plan,
@@ -1347,7 +1347,7 @@ class WorkOrder(Document):
else: else:
data = frappe.get_all( data = frappe.get_all(
"Stock Entry", "Stock Entry",
fields=["timestamp(posting_date, posting_time) as posting_datetime"], fields=[{"TIMESTAMP": ["posting_date", "posting_time"], "as": "posting_datetime"}],
filters={ filters={
"work_order": self.name, "work_order": self.name,
"purpose": ("in", ["Material Transfer for Manufacture", "Manufacture"]), "purpose": ("in", ["Material Transfer for Manufacture", "Manufacture"]),

View File

@@ -80,7 +80,7 @@ def get_filtered_data(filters):
def get_bom_count(bom_data): def get_bom_count(bom_data):
data = frappe.get_all( data = frappe.get_all(
"BOM Item", "BOM Item",
fields=["count(name) as count", "bom_no"], fields=[{"COUNT": "*", "as": "count"}, "bom_no"],
filters={"bom_no": ("in", bom_data)}, filters={"bom_no": ("in", bom_data)},
group_by="bom_no", group_by="bom_no",
) )

View File

@@ -59,7 +59,7 @@ def get_data(filters):
job_card_time_details = {} job_card_time_details = {}
for job_card_data in frappe.get_all( for job_card_data in frappe.get_all(
"Job Card Time Log", "Job Card Time Log",
fields=["min(from_time) as from_time", "max(to_time) as to_time", "parent"], fields=[{"MIN": "from_time", "as": "from_time"}, {"MAX": "to_time", "as": "to_time"}, "parent"],
filters=job_card_time_filter, filters=job_card_time_filter,
group_by="parent", group_by="parent",
): ):

View File

@@ -230,7 +230,12 @@ class ProductionPlanReport:
purchased_items = frappe.get_all( purchased_items = frappe.get_all(
"Purchase Order Item", "Purchase Order Item",
fields=["item_code", "min(schedule_date) as arrival_date", "qty as arrival_qty", "warehouse"], fields=[
"item_code",
{"MIN": "schedule_date", "as": "arrival_date"},
"qty as arrival_qty",
"warehouse",
],
filters={ filters={
"item_code": ("in", self.item_codes), "item_code": ("in", self.item_codes),
"warehouse": ("in", self.warehouses), "warehouse": ("in", self.warehouses),

View File

@@ -10,7 +10,7 @@ def execute():
frappe.reload_doc("stock", "doctype", "item") frappe.reload_doc("stock", "doctype", "item")
for data in frappe.get_all( for data in frappe.get_all(
"Item Quality Inspection Parameter", fields=["distinct parent"], filters={"parenttype": "Item"} "Item Quality Inspection Parameter", fields=["parent"], filters={"parenttype": "Item"}, distinct=True
): ):
qc_doc = frappe.new_doc("Quality Inspection Template") qc_doc = frappe.new_doc("Quality Inspection Template")
qc_doc.quality_inspection_template_name = "QIT/%s" % data.parent qc_doc.quality_inspection_template_name = "QIT/%s" % data.parent

View File

@@ -8,7 +8,7 @@ import frappe
def execute(): def execute():
warehouse_perm = frappe.get_all( warehouse_perm = frappe.get_all(
"User Permission", "User Permission",
fields=["count(*) as p_count", "is_default", "user"], fields=[{"COUNT": "*", "as": "p_count"}, "is_default", "user"],
filters={"allow": "Warehouse"}, filters={"allow": "Warehouse"},
group_by="user", group_by="user",
) )

View File

@@ -401,8 +401,6 @@ def get_project_list(doctype, txt, filters, limit_start, limit_page_length=20, o
meta = frappe.get_meta(doctype) meta = frappe.get_meta(doctype)
fields = "distinct *"
or_filters = [] or_filters = []
if txt: if txt:
@@ -424,13 +422,14 @@ def get_project_list(doctype, txt, filters, limit_start, limit_page_length=20, o
return frappe.get_list( return frappe.get_list(
doctype, doctype,
fields=fields, fields="*",
filters=filters, filters=filters,
or_filters=or_filters, or_filters=or_filters,
limit_start=limit_start, limit_start=limit_start,
limit_page_length=limit_page_length, limit_page_length=limit_page_length,
order_by=order_by, order_by=order_by,
ignore_permissions=ignore_permissions, ignore_permissions=ignore_permissions,
distinct=True,
) )

View File

@@ -179,7 +179,11 @@ def get_reverse_charge_total(filters):
try: try:
return ( return (
frappe.db.get_all( frappe.db.get_all(
"Purchase Invoice", filters=query_filters, fields=["sum(base_total)"], as_list=True, limit=1 "Purchase Invoice",
filters=query_filters,
fields=[{"SUM": "base_total"}],
as_list=True,
limit=1,
)[0][0] )[0][0]
or 0 or 0
) )
@@ -219,7 +223,11 @@ def get_reverse_charge_recoverable_total(filters):
try: try:
return ( return (
frappe.db.get_all( frappe.db.get_all(
"Purchase Invoice", filters=query_filters, fields=["sum(base_total)"], as_list=True, limit=1 "Purchase Invoice",
filters=query_filters,
fields=[{"SUM": "base_total"}],
as_list=True,
limit=1,
)[0][0] )[0][0]
or 0 or 0
) )
@@ -274,7 +282,11 @@ def get_standard_rated_expenses_total(filters):
try: try:
return ( return (
frappe.db.get_all( frappe.db.get_all(
"Purchase Invoice", filters=query_filters, fields=["sum(base_total)"], as_list=True, limit=1 "Purchase Invoice",
filters=query_filters,
fields=[{"SUM": "base_total"}],
as_list=True,
limit=1,
)[0][0] )[0][0]
or 0 or 0
) )
@@ -292,7 +304,7 @@ def get_standard_rated_expenses_tax(filters):
frappe.db.get_all( frappe.db.get_all(
"Purchase Invoice", "Purchase Invoice",
filters=query_filters, filters=query_filters,
fields=["sum(recoverable_standard_rated_expenses)"], fields=[{"SUM": "recoverable_standard_rated_expenses"}],
as_list=True, as_list=True,
limit=1, limit=1,
)[0][0] )[0][0]
@@ -310,7 +322,7 @@ def get_tourist_tax_return_total(filters):
try: try:
return ( return (
frappe.db.get_all( frappe.db.get_all(
"Sales Invoice", filters=query_filters, fields=["sum(base_total)"], as_list=True, limit=1 "Sales Invoice", filters=query_filters, fields=[{"SUM": "base_total"}], as_list=True, limit=1
)[0][0] )[0][0]
or 0 or 0
) )
@@ -328,7 +340,7 @@ def get_tourist_tax_return_tax(filters):
frappe.db.get_all( frappe.db.get_all(
"Sales Invoice", "Sales Invoice",
filters=query_filters, filters=query_filters,
fields=["sum(tourist_tax_return)"], fields=[{"SUM": "tourist_tax_return"}],
as_list=True, as_list=True,
limit=1, limit=1,
)[0][0] )[0][0]

View File

@@ -14,6 +14,7 @@ from frappe.contacts.address_and_contact import (
from frappe.model.mapper import get_mapped_doc from frappe.model.mapper import get_mapped_doc
from frappe.model.naming import set_name_by_naming_series, set_name_from_naming_options from frappe.model.naming import set_name_by_naming_series, set_name_from_naming_options
from frappe.model.utils.rename_doc import update_linked_doctypes from frappe.model.utils.rename_doc import update_linked_doctypes
from frappe.query_builder import Field, functions
from frappe.utils import cint, cstr, flt, get_formatted_email, today from frappe.utils import cint, cstr, flt, get_formatted_email, today
from frappe.utils.user import get_users_with_role from frappe.utils.user import get_users_with_role
@@ -503,11 +504,11 @@ def get_loyalty_programs(doc):
loyalty_programs = frappe.get_all( loyalty_programs = frappe.get_all(
"Loyalty Program", "Loyalty Program",
fields=["name", "customer_group", "customer_territory"], fields=["name", "customer_group", "customer_territory"],
filters={ filters=[
"auto_opt_in": 1, ["auto_opt_in", "=", 1],
"from_date": ["<=", today()], ["from_date", "<=", today()],
"ifnull(to_date, '2500-01-01')": [">=", today()], [functions.IfNull(Field("to_date"), "2500-01-01"), ">=", today()],
}, ],
) )
for loyalty_program in loyalty_programs: for loyalty_program in loyalty_programs:

View File

@@ -630,7 +630,7 @@ def get_ordered_items(quotation: str):
frappe.get_all( frappe.get_all(
"Sales Order Item", "Sales Order Item",
filters={"prevdoc_docname": quotation, "docstatus": 1}, filters={"prevdoc_docname": quotation, "docstatus": 1},
fields=["quotation_item", "sum(qty)"], fields=["quotation_item", {"SUM": "qty"}],
group_by="quotation_item", group_by="quotation_item",
as_list=1, as_list=1,
) )

View File

@@ -992,7 +992,11 @@ def get_requested_item_qty(sales_order):
for d in frappe.db.get_all( for d in frappe.db.get_all(
"Material Request Item", "Material Request Item",
filters={"docstatus": 1, "sales_order": sales_order}, filters={"docstatus": 1, "sales_order": sales_order},
fields=["sales_order_item", "sum(qty) as qty", "sum(received_qty) as received_qty"], fields=[
"sales_order_item",
{"SUM": "qty", "as": "qty"},
{"SUM": "received_qty", "as": "received_qty"},
],
group_by="sales_order_item", group_by="sales_order_item",
): ):
result[d.sales_order_item] = frappe._dict({"qty": d.qty, "received_qty": d.received_qty}) result[d.sales_order_item] = frappe._dict({"qty": d.qty, "received_qty": d.received_qty})

View File

@@ -95,7 +95,7 @@ def get_data(filters=None):
items = get_selling_items(filters) items = get_selling_items(filters)
item_stock_map = frappe.get_all( item_stock_map = frappe.get_all(
"Bin", fields=["item_code", "sum(actual_qty) AS available"], group_by="item_code" "Bin", fields=["item_code", {"SUM": "actual_qty", "as": "available"}], group_by="item_code"
) )
item_stock_map = {item.item_code: item.available for item in item_stock_map} item_stock_map = {item.item_code: item.available for item in item_stock_map}
price_list_map = fetch_item_prices( price_list_map = fetch_item_prices(

View File

@@ -799,7 +799,7 @@ class EmailDigest(Document):
"status": ["not in", ("Cancelled")], "status": ["not in", ("Cancelled")],
"company": self.company, "company": self.company,
}, },
fields=["count(*) as count", "sum(grand_total) as grand_total"], fields=[{"COUNT": "*", "as": "count"}, {"SUM": "grand_total", "as": "grand_total"}],
) )
def get_from_to_date(self): def get_from_to_date(self):

View File

@@ -63,7 +63,7 @@ def get_all_customers(date_range, company, field, limit=None):
return frappe.get_list( return frappe.get_list(
"Sales Invoice", "Sales Invoice",
fields=["customer as name", "sum(outstanding_amount) as value"], fields=["customer as name", {"SUM": "outstanding_amount", "as": "value"}],
filters=filters, filters=filters,
group_by="customer", group_by="customer",
order_by="value desc", order_by="value desc",
@@ -80,7 +80,7 @@ def get_all_customers(date_range, company, field, limit=None):
return frappe.get_list( return frappe.get_list(
"Sales Order", "Sales Order",
fields=["customer as name", f"sum({select_field}) as value"], fields=["customer as name", {"SUM": select_field, "as": "value"}],
filters=filters, filters=filters,
group_by="customer", group_by="customer",
order_by="value desc", order_by="value desc",
@@ -91,10 +91,10 @@ def get_all_customers(date_range, company, field, limit=None):
@frappe.whitelist() @frappe.whitelist()
def get_all_items(date_range, company, field, limit=None): def get_all_items(date_range, company, field, limit=None):
if field in ("available_stock_qty", "available_stock_value"): if field in ("available_stock_qty", "available_stock_value"):
select_field = "sum(actual_qty)" if field == "available_stock_qty" else "sum(stock_value)" sum_field = "actual_qty" if field == "available_stock_qty" else "stock_value"
results = frappe.db.get_all( results = frappe.db.get_all(
"Bin", "Bin",
fields=["item_code as name", f"{select_field} as value"], fields=["item_code as name", {"SUM": sum_field, "as": "value"}],
group_by="item_code", group_by="item_code",
order_by="value desc", order_by="value desc",
limit=limit, limit=limit,
@@ -125,7 +125,7 @@ def get_all_items(date_range, company, field, limit=None):
select_doctype, select_doctype,
fields=[ fields=[
f"`tab{child_doctype}`.item_code as name", f"`tab{child_doctype}`.item_code as name",
f"sum(`tab{child_doctype}`.{select_field}) as value", {"SUM": f"`tab{child_doctype}`.{select_field}", "as": "value"},
], ],
filters=filters, filters=filters,
order_by="value desc", order_by="value desc",
@@ -145,7 +145,7 @@ def get_all_suppliers(date_range, company, field, limit=None):
return frappe.get_list( return frappe.get_list(
"Purchase Invoice", "Purchase Invoice",
fields=["supplier as name", "sum(outstanding_amount) as value"], fields=["supplier as name", {"SUM": "outstanding_amount", "as": "value"}],
filters=filters, filters=filters,
group_by="supplier", group_by="supplier",
order_by="value desc", order_by="value desc",
@@ -162,7 +162,7 @@ def get_all_suppliers(date_range, company, field, limit=None):
return frappe.get_list( return frappe.get_list(
"Purchase Order", "Purchase Order",
fields=["supplier as name", f"sum({select_field}) as value"], fields=["supplier as name", {"SUM": select_field, "as": "value"}],
filters=filters, filters=filters,
group_by="supplier", group_by="supplier",
order_by="value desc", order_by="value desc",
@@ -186,7 +186,7 @@ def get_all_sales_partner(date_range, company, field, limit=None):
"Sales Order", "Sales Order",
fields=[ fields=[
"sales_partner as name", "sales_partner as name",
f"sum({select_field}) as value", {"SUM": select_field, "as": "value"},
], ],
filters=filters, filters=filters,
group_by="sales_partner", group_by="sales_partner",
@@ -210,7 +210,7 @@ def get_all_sales_person(date_range, company, field=None, limit=0):
"Sales Order", "Sales Order",
fields=[ fields=[
"`tabSales Team`.sales_person as name", "`tabSales Team`.sales_person as name",
"sum(`tabSales Team`.allocated_amount) as value", {"SUM": "`tabSales Team`.allocated_amount", "as": "value"},
], ],
filters=filters, filters=filters,
group_by="`tabSales Team`.sales_person", group_by="`tabSales Team`.sales_person",

View File

@@ -31,7 +31,7 @@ def get(
warehouses = frappe.get_list( warehouses = frappe.get_list(
"Bin", "Bin",
fields=["warehouse", "sum(stock_value) stock_value"], fields=["warehouse", {"SUM": "stock_value", "as": "stock_value"}],
filters={"warehouse": ["IN", warehouses], "stock_value": [">", 0]}, filters={"warehouse": ["IN", warehouses], "stock_value": [">", 0]},
group_by="warehouse", group_by="warehouse",
order_by="stock_value DESC", order_by="stock_value DESC",

View File

@@ -405,8 +405,9 @@ def get_batches(item_code, warehouse, qty=1, throw=False, serial_no=None):
serial_nos = get_serial_nos(serial_no) serial_nos = get_serial_nos(serial_no)
batches = frappe.get_all( batches = frappe.get_all(
"Serial No", "Serial No",
fields=["distinct batch_no"], fields=["batch_no"],
filters={"item_code": item_code, "warehouse": warehouse, "name": ("in", serial_nos)}, filters={"item_code": item_code, "warehouse": warehouse, "name": ("in", serial_nos)},
distinct=True,
) )
if not batches: if not batches:

View File

@@ -320,12 +320,13 @@ def get_inventory_documents(
return frappe.get_all( return frappe.get_all(
"DocField", "DocField",
fields=["distinct parent"], fields=["parent"],
filters=and_filters, filters=and_filters,
or_filters=or_filters, or_filters=or_filters,
start=start, start=start,
page_length=page_len, page_length=page_len,
as_list=1, as_list=1,
distinct=True,
) )
@@ -382,7 +383,7 @@ def get_inventory_dimensions():
return frappe.get_all( return frappe.get_all(
"Inventory Dimension", "Inventory Dimension",
fields=[ fields=[
"distinct target_fieldname as fieldname", "target_fieldname as fieldname",
"source_fieldname", "source_fieldname",
"reference_document as doctype", "reference_document as doctype",
"validate_negative_stock", "validate_negative_stock",
@@ -390,6 +391,7 @@ def get_inventory_dimensions():
], ],
filters={"disabled": 0}, filters={"disabled": 0},
order_by="creation", order_by="creation",
distinct=True,
) )

View File

@@ -593,7 +593,7 @@ class TestPickList(IntegrationTestCase):
for dn in frappe.get_all( for dn in frappe.get_all(
"Delivery Note", "Delivery Note",
filters={"against_pick_list": pick_list.name, "customer": "_Test Customer"}, filters={"against_pick_list": pick_list.name, "customer": "_Test Customer"},
fields={"name"}, fields=["name"],
): ):
for dn_item in frappe.get_doc("Delivery Note", dn.name).get("items"): for dn_item in frappe.get_doc("Delivery Note", dn.name).get("items"):
self.assertEqual(dn_item.item_code, "_Test Item") self.assertEqual(dn_item.item_code, "_Test Item")
@@ -604,7 +604,7 @@ class TestPickList(IntegrationTestCase):
for dn in frappe.get_all( for dn in frappe.get_all(
"Delivery Note", "Delivery Note",
filters={"against_pick_list": pick_list.name, "customer": "_Test Customer 1"}, filters={"against_pick_list": pick_list.name, "customer": "_Test Customer 1"},
fields={"name"}, fields=["name"],
): ):
for dn_item in frappe.get_doc("Delivery Note", dn.name).get("items"): for dn_item in frappe.get_doc("Delivery Note", dn.name).get("items"):
self.assertEqual(dn_item.item_code, "_Test Item 2") self.assertEqual(dn_item.item_code, "_Test Item 2")
@@ -637,7 +637,7 @@ class TestPickList(IntegrationTestCase):
pick_list_1.submit() pick_list_1.submit()
create_delivery_note(pick_list_1.name) create_delivery_note(pick_list_1.name)
for dn in frappe.get_all( for dn in frappe.get_all(
"Delivery Note", filters={"against_pick_list": pick_list_1.name}, fields={"name"} "Delivery Note", filters={"against_pick_list": pick_list_1.name}, fields=["name"]
): ):
for dn_item in frappe.get_doc("Delivery Note", dn.name).get("items"): for dn_item in frappe.get_doc("Delivery Note", dn.name).get("items"):
if dn_item.item_code == "_Test Item": if dn_item.item_code == "_Test Item":

View File

@@ -1333,7 +1333,7 @@ def get_item_wise_returned_qty(pr_doc):
"Purchase Receipt", "Purchase Receipt",
fields=[ fields=[
"`tabPurchase Receipt Item`.purchase_receipt_item", "`tabPurchase Receipt Item`.purchase_receipt_item",
"sum(abs(`tabPurchase Receipt Item`.qty)) as qty", {"SUM": [{"ABS": "`tabPurchase Receipt Item`.qty"}], "as": "qty"},
], ],
filters=[ filters=[
["Purchase Receipt", "docstatus", "=", 1], ["Purchase Receipt", "docstatus", "=", 1],

View File

@@ -1900,7 +1900,7 @@ class TestPurchaseReceipt(IntegrationTestCase):
data = frappe.get_all( data = frappe.get_all(
"Stock Ledger Entry", "Stock Ledger Entry",
filters={"voucher_no": pr_return.name, "docstatus": 1}, filters={"voucher_no": pr_return.name, "docstatus": 1},
fields=["SUM(stock_value_difference) as stock_value_difference"], fields=[{"SUM": "stock_value_difference", "as": "stock_value_difference"}],
)[0] )[0]
self.assertEqual(abs(data["stock_value_difference"]), 400.00) self.assertEqual(abs(data["stock_value_difference"]), 400.00)

View File

@@ -2420,7 +2420,7 @@ class StockEntry(StockController, SubcontractingInwardController):
data = frappe.get_all( data = frappe.get_all(
"Work Order Operation", "Work Order Operation",
filters={"parent": self.work_order}, filters={"parent": self.work_order},
fields=["max(process_loss_qty) as process_loss_qty"], fields=[{"MAX": "process_loss_qty", "as": "process_loss_qty"}],
) )
if data and data[0].process_loss_qty is not None: if data and data[0].process_loss_qty is not None:
@@ -3145,7 +3145,7 @@ class StockEntry(StockController, SubcontractingInwardController):
stock_entries_child_list.append(d.ste_detail) stock_entries_child_list.append(d.ste_detail)
transferred_qty = frappe.get_all( transferred_qty = frappe.get_all(
"Stock Entry Detail", "Stock Entry Detail",
fields=["sum(qty) as qty"], fields=[{"SUM": "qty", "as": "qty"}],
filters={ filters={
"against_stock_entry": d.against_stock_entry, "against_stock_entry": d.against_stock_entry,
"ste_detail": d.ste_detail, "ste_detail": d.ste_detail,

View File

@@ -8,6 +8,7 @@ from uuid import uuid4
import frappe import frappe
from frappe.core.page.permission_manager.permission_manager import reset from frappe.core.page.permission_manager.permission_manager import reset
from frappe.custom.doctype.property_setter.property_setter import make_property_setter from frappe.custom.doctype.property_setter.property_setter import make_property_setter
from frappe.query_builder.functions import Timestamp
from frappe.tests import IntegrationTestCase from frappe.tests import IntegrationTestCase
from frappe.utils import add_days, add_to_date, flt, today from frappe.utils import add_days, add_to_date, flt, today
@@ -1281,12 +1282,16 @@ class TestStockLedgerEntry(IntegrationTestCase, StockTestMixin):
item=item, from_warehouse=source_warehouse, to_warehouse=target_warehouse, qty=1_728.0 item=item, from_warehouse=source_warehouse, to_warehouse=target_warehouse, qty=1_728.0
) )
filters = {"voucher_no": transfer.name, "voucher_type": transfer.doctype, "is_cancelled": 0} sle = frappe.qb.DocType("Stock Ledger Entry")
sles = frappe.get_all( sles = (
"Stock Ledger Entry", frappe.qb.from_(sle)
fields=["*"], .select("*")
filters=filters, .where(sle.voucher_no == transfer.name)
order_by="timestamp(posting_date, posting_time), creation", .where(sle.voucher_type == transfer.doctype)
.where(sle.is_cancelled == 0)
.orderby(Timestamp(sle.posting_date, sle.posting_time))
.orderby(sle.creation)
.run(as_dict=True)
) )
self.assertEqual(abs(sles[0].stock_value_difference), sles[1].stock_value_difference) self.assertEqual(abs(sles[0].stock_value_difference), sles[1].stock_value_difference)

View File

@@ -7,6 +7,8 @@ import json
import frappe import frappe
from frappe import _, throw from frappe import _, throw
from frappe.contacts.address_and_contact import load_address_and_contact from frappe.contacts.address_and_contact import load_address_and_contact
from frappe.query_builder import Field
from frappe.query_builder.functions import IfNull
from frappe.utils import cint from frappe.utils import cint
from frappe.utils.caching import request_cache from frappe.utils.caching import request_cache
from frappe.utils.nestedset import NestedSet from frappe.utils.nestedset import NestedSet
@@ -197,10 +199,12 @@ def get_children(doctype, parent=None, company=None, is_root=False, include_disa
include_disabled = json.loads(include_disabled) include_disabled = json.loads(include_disabled)
fields = ["name as value", "is_group as expandable"] fields = ["name as value", "is_group as expandable"]
filters = [ filters = [
["ifnull(`parent_warehouse`, '')", "=", parent], [IfNull(Field("parent_warehouse"), ""), "=", parent],
["company", "in", (company, None, "")], ["company", "in", (company, None, "")],
] ]
if frappe.db.has_column(doctype, "disabled") and not include_disabled: if frappe.db.has_column(doctype, "disabled") and not include_disabled:
filters.append(["disabled", "=", False]) filters.append(["disabled", "=", False])

View File

@@ -115,7 +115,7 @@ def get_stock_ledger_entries(report_filters):
"posting_time", "posting_time",
"company", "company",
"warehouse", "warehouse",
"(stock_value_difference / actual_qty) as valuation_rate", {"DIV": ["stock_value_difference", "actual_qty"], "as": "valuation_rate"},
] ]
filters = {"is_cancelled": 0} filters = {"is_cancelled": 0}

View File

@@ -143,9 +143,9 @@ def get_stock_details_map(variant_list):
stock_details = frappe.db.get_all( stock_details = frappe.db.get_all(
"Bin", "Bin",
fields=[ fields=[
"sum(planned_qty) as planned_qty", {"SUM": "planned_qty", "as": "planned_qty"},
"sum(actual_qty) as actual_qty", {"SUM": "actual_qty", "as": "actual_qty"},
"sum(projected_qty) as projected_qty", {"SUM": "projected_qty", "as": "projected_qty"},
"item_code", "item_code",
], ],
filters={"item_code": ["in", variant_list]}, filters={"item_code": ["in", variant_list]},
@@ -167,7 +167,7 @@ def get_buying_price_map(variant_list):
buying = frappe.db.get_all( buying = frappe.db.get_all(
"Item Price", "Item Price",
fields=[ fields=[
"avg(price_list_rate) as avg_rate", {"AVG": "price_list_rate", "as": "avg_rate"},
"item_code", "item_code",
], ],
filters={"item_code": ["in", variant_list], "buying": 1}, filters={"item_code": ["in", variant_list], "buying": 1},
@@ -185,7 +185,7 @@ def get_selling_price_map(variant_list):
selling = frappe.db.get_all( selling = frappe.db.get_all(
"Item Price", "Item Price",
fields=[ fields=[
"avg(price_list_rate) as avg_rate", {"AVG": "price_list_rate", "as": "avg_rate"},
"item_code", "item_code",
], ],
filters={"item_code": ["in", variant_list], "selling": 1}, filters={"item_code": ["in", variant_list], "selling": 1},

View File

@@ -183,14 +183,15 @@ def get_voucher_type(doctype, txt, searchfield, start, page_len, filters):
child_doctypes = frappe.get_all( child_doctypes = frappe.get_all(
"DocField", "DocField",
filters={"fieldname": "serial_and_batch_bundle"}, filters={"fieldname": "serial_and_batch_bundle"},
fields=["distinct parent as parent"], fields=["parent"],
distinct=True,
) )
query_filters = {"options": ["in", [d.parent for d in child_doctypes]]} query_filters = {"options": ["in", [d.parent for d in child_doctypes]]}
if txt: if txt:
query_filters["parent"] = ["like", f"%{txt}%"] query_filters["parent"] = ["like", f"%{txt}%"]
return frappe.get_all("DocField", filters=query_filters, fields=["distinct parent"], as_list=True) return frappe.get_all("DocField", filters=query_filters, fields=["parent"], as_list=True, distinct=True)
@frappe.whitelist() @frappe.whitelist()

View File

@@ -61,7 +61,7 @@ def get_stock_ledger_data(report_filters, filters):
"name", "name",
"voucher_type", "voucher_type",
"voucher_no", "voucher_no",
"sum(stock_value_difference) as stock_value", {"SUM": "stock_value_difference", "as": "stock_value"},
"posting_date", "posting_date",
"posting_time", "posting_time",
], ],
@@ -88,7 +88,10 @@ def get_gl_data(report_filters, filters):
"name", "name",
"voucher_type", "voucher_type",
"voucher_no", "voucher_no",
"sum(debit_in_account_currency) - sum(credit_in_account_currency) as account_value", {
"SUB": [{"SUM": "debit_in_account_currency"}, {"SUM": "credit_in_account_currency"}],
"as": "account_value",
},
], ],
group_by="voucher_type, voucher_no", group_by="voucher_type, voucher_no",
) )

View File

@@ -546,7 +546,10 @@ def get_opening_balance_from_batch(filters, columns, sl_entries):
opening_data = frappe.get_all( opening_data = frappe.get_all(
"Stock Ledger Entry", "Stock Ledger Entry",
fields=["sum(actual_qty) as qty_after_transaction", "sum(stock_value_difference) as stock_value"], fields=[
{"SUM": "actual_qty", "as": "qty_after_transaction"},
{"SUM": "stock_value_difference", "as": "stock_value"},
],
filters=query_filters, filters=query_filters,
)[0] )[0]

View File

@@ -1511,7 +1511,7 @@ def get_batchwise_qty(voucher_type, voucher_no):
batches = frappe.get_all( batches = frappe.get_all(
"Serial and Batch Entry", "Serial and Batch Entry",
filters={"parent": ("in", bundles), "batch_no": ("is", "set")}, filters={"parent": ("in", bundles), "batch_no": ("is", "set")},
fields=["batch_no", "SUM(qty) as qty"], fields=["batch_no", {"SUM": "qty", "as": "qty"}],
group_by="batch_no", group_by="batch_no",
as_list=1, as_list=1,
) )

View File

@@ -1,6 +1,7 @@
import json import json
import frappe import frappe
from frappe.query_builder.functions import Timestamp
from frappe.tests import IntegrationTestCase from frappe.tests import IntegrationTestCase
from erpnext.stock.utils import scan_barcode from erpnext.stock.utils import scan_barcode
@@ -20,11 +21,23 @@ class StockTestMixin:
filters = {"voucher_no": doc.name, "voucher_type": doc.doctype, "is_cancelled": 0} filters = {"voucher_no": doc.name, "voucher_type": doc.doctype, "is_cancelled": 0}
if sle_filters: if sle_filters:
filters.update(sle_filters) filters.update(sle_filters)
sles = frappe.get_all(
"Stock Ledger Entry", sle = frappe.qb.DocType("Stock Ledger Entry")
fields=["*"], query = (
filters=filters, frappe.qb.from_(sle)
order_by="timestamp(posting_date, posting_time), creation", .select("*")
.where(sle.voucher_no == doc.name)
.where(sle.voucher_type == doc.doctype)
.where(sle.is_cancelled == 0)
)
if sle_filters:
for key, value in sle_filters.items():
query = query.where(sle[key] == value)
sles = (
query.orderby(Timestamp(sle.posting_date, sle.posting_time))
.orderby(sle.creation)
.run(as_dict=True)
) )
self.assertGreaterEqual(len(sles), len(expected_sles)) self.assertGreaterEqual(len(sles), len(expected_sles))