fix: adapt to query builder

Signed-off-by: Akhil Narang <me@akhilnarang.dev>
This commit is contained in:
Akhil Narang
2025-11-16 22:50:58 +05:30
parent d40e660a52
commit 1cf9f903e5
49 changed files with 225 additions and 132 deletions

View File

@@ -3,6 +3,8 @@
import frappe
from frappe.query_builder import functions
from frappe.query_builder.utils import DocType
from frappe.tests import IntegrationTestCase
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_credit, 8500.0)
gl = DocType("GL Entry")
acc_balance = frappe.db.get_all(
"GL Entry",
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]
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_credit, 500.0)
gl = DocType("GL Entry")
acc_balance = frappe.db.get_all(
"GL Entry",
filters={"account": self.debtors_usd, "is_cancelled": 0},
fields=[
"sum(debit)-sum(credit) as balance",
"sum(debit_in_account_currency)-sum(credit_in_account_currency) as balance_in_account_currency",
(functions.Sum(gl.debit) - functions.Sum(gl.credit)).as_("balance"),
(
functions.Sum(gl.debit_in_account_currency) - functions.Sum(gl.credit_in_account_currency)
).as_("balance_in_account_currency"),
],
)[0]
# account shouldn't have balance in base and account currency
@@ -193,12 +199,15 @@ class TestExchangeRateRevaluation(AccountsTestMixin, IntegrationTestCase):
pe.references = []
pe.save().submit()
gl = DocType("GL Entry")
acc_balance = frappe.db.get_all(
"GL Entry",
filters={"account": self.debtors_usd, "is_cancelled": 0},
fields=[
"sum(debit)-sum(credit) as balance",
"sum(debit_in_account_currency)-sum(credit_in_account_currency) as balance_in_account_currency",
(functions.Sum(gl.debit) - functions.Sum(gl.credit)).as_("balance"),
(
functions.Sum(gl.debit_in_account_currency) - functions.Sum(gl.credit_in_account_currency)
).as_("balance_in_account_currency"),
],
)[0]
# 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_credit, precision), 0.0)
gl = DocType("GL Entry")
acc_balance = frappe.db.get_all(
"GL Entry",
filters={"account": self.debtors_usd, "is_cancelled": 0},
fields=[
"sum(debit)-sum(credit) as balance",
"sum(debit_in_account_currency)-sum(credit_in_account_currency) as balance_in_account_currency",
(functions.Sum(gl.debit) - functions.Sum(gl.credit)).as_("balance"),
(
functions.Sum(gl.debit_in_account_currency) - functions.Sum(gl.credit_in_account_currency)
).as_("balance_in_account_currency"),
],
)[0]
# account shouldn't have balance in base and account currency post revaluation

View File

@@ -72,7 +72,7 @@ class OpeningInvoiceCreationTool(Document):
fields = [
"company",
{"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"])
if not companies:

View File

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

View File

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

View File

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

View File

@@ -1374,7 +1374,7 @@ class TestPurchaseInvoice(IntegrationTestCase, StockTestMixin):
total_debit_amount = frappe.db.get_all(
"Journal Entry Account",
{"account": creditors_account, "docstatus": 1, "reference_name": pi.name},
"sum(debit) as amount",
[{"SUM": "debit", "as": "amount"}],
group_by="reference_name",
)[0].amount
self.assertEqual(flt(total_debit_amount, 2), 2500)
@@ -1456,7 +1456,7 @@ class TestPurchaseInvoice(IntegrationTestCase, StockTestMixin):
total_debit_amount = frappe.db.get_all(
"Journal Entry Account",
{"account": creditors_account, "docstatus": 1, "reference_name": pi_2.name},
"sum(debit) as amount",
[{"SUM": "debit", "as": "amount"}],
group_by="reference_name",
)[0].amount
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 = [
x.document_type
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
@@ -287,7 +290,11 @@ def get_repost_allowed_types(doctype, txt, searchfield, start, page_len, filters
filters.update({"document_type": ("like", f"%{txt}%")})
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 []

View File

@@ -3612,7 +3612,7 @@ class TestSalesInvoice(ERPNextTestSuite):
frappe.db.get_all(
"Payment Ledger Entry",
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,
)

View File

@@ -121,7 +121,7 @@ class TestTaxWithholdingCategory(IntegrationTestCase):
gl_entries = frappe.db.get_all(
"GL Entry",
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",
)
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",
fields=[
"company",
"sum(grand_total) as grand_total",
"sum(base_grand_total) as base_grand_total",
{"SUM": "grand_total", "as": "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()),
},
group_by="company",
fields=["company", "sum(loyalty_points) as loyalty_points"],
fields=["company", {"SUM": "loyalty_points", "as": "loyalty_points"}],
as_list=1,
)
)

View File

@@ -210,7 +210,7 @@ def get_gl_balance(report_date, company):
return frappe._dict(
frappe.db.get_all(
"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},
group_by="party",
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"
fields = [
f"sum(abs(`tab{child_doctype}`.qty)) as qty",
{"SUM": [{"ABS": f"`tab{child_doctype}`.qty"}], "as": "qty"},
]
if doctype != "Subcontracting Receipt":
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"):
fields += [
f"sum(abs(`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}`.rejected_qty"}], "as": "rejected_qty"},
{"SUM": [{"ABS": f"`tab{child_doctype}`.received_qty"}], "as": "received_qty"},
]
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
data = frappe.get_all(

View File

@@ -563,11 +563,14 @@ class StatusUpdater(Document):
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:
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
* 100,
6,

View File

@@ -1320,7 +1320,7 @@ class StockController(AccountsController):
total_returned += flt(item.returned_qty * item.rate)
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(
{

View File

@@ -292,7 +292,7 @@ class SubcontractingController(StockController):
):
for row in frappe.get_all(
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)},
):
self.qty_to_be_received[(row.item_code, row.parent)] += row.qty
@@ -553,7 +553,9 @@ class SubcontractingController(StockController):
data = []
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 = {
"item_code": "rm_item_code",

View File

@@ -328,7 +328,7 @@ class TestItemWiseInventoryAccount(IntegrationTestCase):
"voucher_no": pr.name,
"item_code": ("in", items),
},
fields=["sum(stock_value_difference) as value"],
fields=[{"SUM": "stock_value_difference", "as": "value"}],
)
gl_value = frappe.db.get_value(
@@ -435,7 +435,7 @@ class TestItemWiseInventoryAccount(IntegrationTestCase):
sle_value = frappe.get_all(
"Stock Ledger Entry",
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 = (

View File

@@ -8,6 +8,7 @@ from itertools import groupby
import frappe
from dateutil.relativedelta import relativedelta
from frappe import _
from frappe.query_builder.custom import Month, MonthName, Quarter
from frappe.utils import cint, flt, getdate
from erpnext.setup.utils import get_exchange_rate
@@ -82,40 +83,52 @@ class SalesPipelineAnalytics:
self.filters.get("pipeline_by")
]
self.group_by_period = {
"Monthly": "month(expected_closing)",
"Quarterly": "QUARTER(expected_closing)",
}[self.filters.get("range")]
opp = frappe.qb.DocType("Opportunity")
if self.filters.get("range") == "Monthly":
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.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")]
def get_data(self):
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":
self.query_result = frappe.db.get_list(
"Opportunity",
filters=self.get_conditions(),
fields=[self.based_on, self.data_based_on, self.duration],
group_by=f"{self.group_by_based_on},{self.group_by_period}",
order_by=self.group_by_period,
self.query_result = (
query.select(
pipeline_field.as_(self.pipeline_by),
frappe.query_builder.functions.Count("*").as_("count"),
self.duration,
)
.groupby(pipeline_field, self.group_by_period)
.orderby(self.group_by_period)
.run(as_dict=True)
)
if self.filters.get("based_on") == "Amount":
self.query_result = frappe.db.get_list(
"Opportunity",
filters=self.get_conditions(),
fields=[self.based_on, self.data_based_on, self.duration, "currency"],
)
self.query_result = query.select(
pipeline_field.as_(self.pipeline_by),
opp.opportunity_amount.as_("amount"),
self.duration,
opp.currency,
).run(as_dict=True)
self.convert_to_base_currency()

View File

@@ -1740,8 +1740,9 @@ def item_query(doctype, txt, searchfield, start, page_len, filters):
barcodes = frappe.get_all(
"Item Barcode",
fields=["distinct parent as item_code"],
fields=["parent as item_code"],
filters={"barcode": ("like", f"%{txt}%")},
distinct=True,
)
barcodes = [d.item_code for d in barcodes]
@@ -1751,11 +1752,11 @@ def item_query(doctype, txt, searchfield, start, page_len, filters):
if filters and filters.get("item_code"):
has_variants = frappe.get_cached_value("Item", filters.get("item_code"), "has_variants")
if not has_variants:
query_filters["has_variants"] = 0
query_filters.append(["has_variants", "=", 0])
if filters:
for fieldname, value in filters.items():
query_filters[fieldname] = value
query_filters.append([fieldname, "=", value])
return frappe.get_list(
"Item",

View File

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

View File

@@ -624,7 +624,7 @@ class ProductionPlan(Document):
so_wise_planned_qty = frappe._dict()
data = frappe.get_all(
"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={
"sales_order": ("in", sales_orders),
"docstatus": 1,

View File

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

View File

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

View File

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

View File

@@ -59,7 +59,7 @@ def get_data(filters):
job_card_time_details = {}
for job_card_data in frappe.get_all(
"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,
group_by="parent",
):

View File

@@ -230,7 +230,12 @@ class ProductionPlanReport:
purchased_items = frappe.get_all(
"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={
"item_code": ("in", self.item_codes),
"warehouse": ("in", self.warehouses),

View File

@@ -10,7 +10,7 @@ def execute():
frappe.reload_doc("stock", "doctype", "item")
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.quality_inspection_template_name = "QIT/%s" % data.parent

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)
fields = "distinct *"
or_filters = []
if txt:
@@ -424,13 +422,14 @@ def get_project_list(doctype, txt, filters, limit_start, limit_page_length=20, o
return frappe.get_list(
doctype,
fields=fields,
fields="*",
filters=filters,
or_filters=or_filters,
limit_start=limit_start,
limit_page_length=limit_page_length,
order_by=order_by,
ignore_permissions=ignore_permissions,
distinct=True,
)

View File

@@ -179,7 +179,11 @@ def get_reverse_charge_total(filters):
try:
return (
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]
or 0
)
@@ -219,7 +223,11 @@ def get_reverse_charge_recoverable_total(filters):
try:
return (
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]
or 0
)
@@ -274,7 +282,11 @@ def get_standard_rated_expenses_total(filters):
try:
return (
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]
or 0
)
@@ -292,7 +304,7 @@ def get_standard_rated_expenses_tax(filters):
frappe.db.get_all(
"Purchase Invoice",
filters=query_filters,
fields=["sum(recoverable_standard_rated_expenses)"],
fields=[{"SUM": "recoverable_standard_rated_expenses"}],
as_list=True,
limit=1,
)[0][0]
@@ -310,7 +322,7 @@ def get_tourist_tax_return_total(filters):
try:
return (
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]
or 0
)
@@ -328,7 +340,7 @@ def get_tourist_tax_return_tax(filters):
frappe.db.get_all(
"Sales Invoice",
filters=query_filters,
fields=["sum(tourist_tax_return)"],
fields=[{"SUM": "tourist_tax_return"}],
as_list=True,
limit=1,
)[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.naming import set_name_by_naming_series, set_name_from_naming_options
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.user import get_users_with_role
@@ -503,11 +504,11 @@ def get_loyalty_programs(doc):
loyalty_programs = frappe.get_all(
"Loyalty Program",
fields=["name", "customer_group", "customer_territory"],
filters={
"auto_opt_in": 1,
"from_date": ["<=", today()],
"ifnull(to_date, '2500-01-01')": [">=", today()],
},
filters=[
["auto_opt_in", "=", 1],
["from_date", "<=", today()],
[functions.IfNull(Field("to_date"), "2500-01-01"), ">=", today()],
],
)
for loyalty_program in loyalty_programs:

View File

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

View File

@@ -992,7 +992,11 @@ def get_requested_item_qty(sales_order):
for d in frappe.db.get_all(
"Material Request Item",
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",
):
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)
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}
price_list_map = fetch_item_prices(

View File

@@ -799,7 +799,7 @@ class EmailDigest(Document):
"status": ["not in", ("Cancelled")],
"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):

View File

@@ -63,7 +63,7 @@ def get_all_customers(date_range, company, field, limit=None):
return frappe.get_list(
"Sales Invoice",
fields=["customer as name", "sum(outstanding_amount) as value"],
fields=["customer as name", {"SUM": "outstanding_amount", "as": "value"}],
filters=filters,
group_by="customer",
order_by="value desc",
@@ -80,7 +80,7 @@ def get_all_customers(date_range, company, field, limit=None):
return frappe.get_list(
"Sales Order",
fields=["customer as name", f"sum({select_field}) as value"],
fields=["customer as name", {"SUM": select_field, "as": "value"}],
filters=filters,
group_by="customer",
order_by="value desc",
@@ -91,10 +91,10 @@ def get_all_customers(date_range, company, field, limit=None):
@frappe.whitelist()
def get_all_items(date_range, company, field, limit=None):
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(
"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",
order_by="value desc",
limit=limit,
@@ -125,7 +125,7 @@ def get_all_items(date_range, company, field, limit=None):
select_doctype,
fields=[
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,
order_by="value desc",
@@ -145,7 +145,7 @@ def get_all_suppliers(date_range, company, field, limit=None):
return frappe.get_list(
"Purchase Invoice",
fields=["supplier as name", "sum(outstanding_amount) as value"],
fields=["supplier as name", {"SUM": "outstanding_amount", "as": "value"}],
filters=filters,
group_by="supplier",
order_by="value desc",
@@ -162,7 +162,7 @@ def get_all_suppliers(date_range, company, field, limit=None):
return frappe.get_list(
"Purchase Order",
fields=["supplier as name", f"sum({select_field}) as value"],
fields=["supplier as name", {"SUM": select_field, "as": "value"}],
filters=filters,
group_by="supplier",
order_by="value desc",
@@ -186,7 +186,7 @@ def get_all_sales_partner(date_range, company, field, limit=None):
"Sales Order",
fields=[
"sales_partner as name",
f"sum({select_field}) as value",
{"SUM": select_field, "as": "value"},
],
filters=filters,
group_by="sales_partner",
@@ -210,7 +210,7 @@ def get_all_sales_person(date_range, company, field=None, limit=0):
"Sales Order",
fields=[
"`tabSales Team`.sales_person as name",
"sum(`tabSales Team`.allocated_amount) as value",
{"SUM": "`tabSales Team`.allocated_amount", "as": "value"},
],
filters=filters,
group_by="`tabSales Team`.sales_person",

View File

@@ -31,7 +31,7 @@ def get(
warehouses = frappe.get_list(
"Bin",
fields=["warehouse", "sum(stock_value) stock_value"],
fields=["warehouse", {"SUM": "stock_value", "as": "stock_value"}],
filters={"warehouse": ["IN", warehouses], "stock_value": [">", 0]},
group_by="warehouse",
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)
batches = frappe.get_all(
"Serial No",
fields=["distinct batch_no"],
fields=["batch_no"],
filters={"item_code": item_code, "warehouse": warehouse, "name": ("in", serial_nos)},
distinct=True,
)
if not batches:

View File

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

View File

@@ -593,7 +593,7 @@ class TestPickList(IntegrationTestCase):
for dn in frappe.get_all(
"Delivery Note",
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"):
self.assertEqual(dn_item.item_code, "_Test Item")
@@ -604,7 +604,7 @@ class TestPickList(IntegrationTestCase):
for dn in frappe.get_all(
"Delivery Note",
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"):
self.assertEqual(dn_item.item_code, "_Test Item 2")
@@ -637,7 +637,7 @@ class TestPickList(IntegrationTestCase):
pick_list_1.submit()
create_delivery_note(pick_list_1.name)
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"):
if dn_item.item_code == "_Test Item":

View File

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

View File

@@ -1900,7 +1900,7 @@ class TestPurchaseReceipt(IntegrationTestCase):
data = frappe.get_all(
"Stock Ledger Entry",
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]
self.assertEqual(abs(data["stock_value_difference"]), 400.00)

View File

@@ -2420,7 +2420,7 @@ class StockEntry(StockController, SubcontractingInwardController):
data = frappe.get_all(
"Work Order Operation",
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:
@@ -3145,7 +3145,7 @@ class StockEntry(StockController, SubcontractingInwardController):
stock_entries_child_list.append(d.ste_detail)
transferred_qty = frappe.get_all(
"Stock Entry Detail",
fields=["sum(qty) as qty"],
fields=[{"SUM": "qty", "as": "qty"}],
filters={
"against_stock_entry": d.against_stock_entry,
"ste_detail": d.ste_detail,

View File

@@ -8,6 +8,7 @@ from uuid import uuid4
import frappe
from frappe.core.page.permission_manager.permission_manager import reset
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.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
)
filters = {"voucher_no": transfer.name, "voucher_type": transfer.doctype, "is_cancelled": 0}
sles = frappe.get_all(
"Stock Ledger Entry",
fields=["*"],
filters=filters,
order_by="timestamp(posting_date, posting_time), creation",
sle = frappe.qb.DocType("Stock Ledger Entry")
sles = (
frappe.qb.from_(sle)
.select("*")
.where(sle.voucher_no == transfer.name)
.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)

View File

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

View File

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

View File

@@ -61,7 +61,7 @@ def get_stock_ledger_data(report_filters, filters):
"name",
"voucher_type",
"voucher_no",
"sum(stock_value_difference) as stock_value",
{"SUM": "stock_value_difference", "as": "stock_value"},
"posting_date",
"posting_time",
],
@@ -88,7 +88,10 @@ def get_gl_data(report_filters, filters):
"name",
"voucher_type",
"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",
)

View File

@@ -546,7 +546,10 @@ def get_opening_balance_from_batch(filters, columns, sl_entries):
opening_data = frappe.get_all(
"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,
)[0]

View File

@@ -1511,7 +1511,7 @@ def get_batchwise_qty(voucher_type, voucher_no):
batches = frappe.get_all(
"Serial and Batch Entry",
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",
as_list=1,
)

View File

@@ -1,6 +1,7 @@
import json
import frappe
from frappe.query_builder.functions import Timestamp
from frappe.tests import IntegrationTestCase
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}
if sle_filters:
filters.update(sle_filters)
sles = frappe.get_all(
"Stock Ledger Entry",
fields=["*"],
filters=filters,
order_by="timestamp(posting_date, posting_time), creation",
sle = frappe.qb.DocType("Stock Ledger Entry")
query = (
frappe.qb.from_(sle)
.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))