When I Generate Account Receivable Report Using Api Gives Error

When i try to generate account receivable report using api its return data but when i pass filter party_type = ‘Customer’ and party = party_name is return error.

My Code

def get_receivable_report_content(name):
filters = {‘company’: ‘My Private Limited’, ‘ageing_based_on’: ‘Due Date’, ‘range1’: ‘30’, ‘range2’: ‘60’, ‘range3’: ‘90’, ‘range4’: ‘120’, ‘party_type’: ‘Customer’, ‘party’: ‘India-02’}
“”“Returns file in for the report in given format”“”

report = frappe.get_doc("Report", "Accounts Receivable")

filters = frappe.parse_json(filters) if filters else {}

columns, data = report.get_data(
    limit= 100,
    user= frappe.session.user,
    filters= filters,
    as_dict=True,
    ignore_prepared_report=True,
    are_default_filters=False,
) 

Error

Traceback (most recent call last):
File “apps/frappe/frappe/app.py”, line 95, in application
response = frappe.api.handle()
File “apps/frappe/frappe/api.py”, line 54, in handle
return frappe.handler.handle()
File “apps/frappe/frappe/handler.py”, line 47, in handle
data = execute_cmd(cmd)
File “apps/frappe/frappe/handler.py”, line 85, in execute_cmd
return frappe.call(method, **frappe.form_dict)
File “apps/frappe/frappe/init.py”, line 1622, in call
return fn(*args, **newargs)
File “apps/vijay_whatsapp/vijay_whatsapp/report.py”, line 15, in get_receivable_report_content
columns, data = report.get_data(
File “apps/frappe/frappe/core/doctype/report/report.py”, line 169, in get_data
columns, result = self.run_query_report(
File “apps/frappe/frappe/core/doctype/report/report.py”, line 184, in run_query_report
data = frappe.desk.query_report.run(
File “apps/frappe/frappe/init.py”, line 802, in wrapper_fn
retval = fn(*args, **get_newargs(fn, kwargs))
File “apps/frappe/frappe/desk/query_report.py”, line 239, in run
result = generate_report_result(report, filters, user, custom_columns, is_tree, parent_field)
File “apps/frappe/frappe/init.py”, line 802, in wrapper_fn
retval = fn(*args, **get_newargs(fn, kwargs))
File “apps/frappe/frappe/desk/query_report.py”, line 89, in generate_report_result
res = get_report_result(report, filters) or []
File “apps/frappe/frappe/desk/query_report.py”, line 70, in get_report_result
res = report.execute_script_report(filters)
File “apps/frappe/frappe/core/doctype/report/report.py”, line 131, in execute_script_report
res = self.execute_module(filters)
File “apps/frappe/frappe/core/doctype/report/report.py”, line 148, in execute_module
return frappe.get_attr(method_name)(frappe.dict(filters))
File “apps/erpnext/erpnext/accounts/report/accounts_receivable/accounts_receivable.py”, line 40, in execute
return ReceivablePayableReport(filters).run(args)
File “apps/erpnext/erpnext/accounts/report/accounts_receivable/accounts_receivable.py”, line 62, in run
self.get_data()
File “apps/erpnext/erpnext/accounts/report/accounts_receivable/accounts_receivable.py”, line 88, in get_data
self.get_ple_entries()
File “apps/erpnext/erpnext/accounts/report/accounts_receivable/accounts_receivable.py”, line 737, in get_ple_entries
.where(Criterion.all(self.qb_selection_filter))
File “env/lib/python3.10/site-packages/pypika/utils.py”, line 50, in copy
result = func(self_copy, args, *kwargs)
File “env/lib/python3.10/site-packages/pypika/queries.py”, line 930, in where
if not self.validate_table(criterion):
File “env/lib/python3.10/site-packages/pypika/queries.py”, line 1155, in validate_table
for field in term.fields
():
File “env/lib/python3.10/site-packages/pypika/terms.py”, line 57, in fields

return set(self.find
(Field))
File “env/lib/python3.10/site-packages/pypika/terms.py”, line 37, in find

return [node for node in self.nodes_() if isinstance(node, type)]
File “env/lib/python3.10/site-packages/pypika/terms.py”, line 37, in
return [node for node in self.nodes_() if isinstance(node, type)]
File “env/lib/python3.10/site-packages/pypika/terms.py”, line 743, in nodes_
yield from self.left.nodes_()
File “env/lib/python3.10/site-packages/pypika/terms.py”, line 743, in nodes_
yield from self.left.nodes_()
File “env/lib/python3.10/site-packages/pypika/terms.py”, line 742, in nodes_
yield from self.right.nodes_()
File “env/lib/python3.10/site-packages/pypika/terms.py”, line 795, in nodes_
yield from self.container.nodes_()
AttributeError: ‘str’ object has no attribute ‘nodes_’

Hi @pithiya_Nilesh,

Please check the syntax and try it.

import frappe

def generate_accounts_receivable_report():
    filters = {
        'company': 'My Private Limited',
        'ageing_based_on': 'Due Date',
        'range1': '30',
        'range2': '60',
        'range3': '90',
        'range4': '120',
        'party_type': 'Customer',
        'party': 'India-02',
    }

    # Convert the filters to JSON format
    filters_json = frappe.as_json(filters)

    try:
        # Call API to generate the report
        result = frappe.get_all("Report", filters=filters_json, as_list=True)

        columns = result[0]
        data = result[1:]

        # For the testing
        print("Columns:", columns)
        print("Data:", data)

    except Exception as e:
        print("Error:", str(e))

generate_accounts_receivable_report()

First, define the filters as a dictionary containing criteria such as company name, aging criteria, and party information.
convert these filters into JSON format. Then, make an API call using the filters and retrieve the report results. It handles the report data, separating column names and data rows, which can be further processed or displayed as needed. Any errors during the API call are also caught and displayed.

I hope this helps.

Thank You!

its not works

it create proble only when i send party in filter otherwise is work fine.

I am getting the same error in version 15.18, if your issue is solved can you help me to resolve the same.Thank You.

Did you get the issue fixed. I am getting a similar one while trying to get stock_balance with inventory_dimension field (customer), not issue when the field customer is not passed

erpnext version = "15.17.1"

from erpnext.stock.report.stock_balance.stock_balance import execute

In [11]: execute(frappe._dict({'company':'NNNN','customer':'AAAAA'}))
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[11], line 1
----> 1 execute(frappe._dict({'company':'NNNN','customer':'AAAA'}))

File /workspace/frappe-15/apps/erpnext/erpnext/stock/report/stock_balance/stock_balance.py:39, in execute(filters)
     38 def execute(filters: Optional[StockBalanceFilter] = None):
---> 39         return StockBalanceReport(filters).run()

File /workspace/frappe-15/apps/erpnext/erpnext/stock/report/stock_balance/stock_balance.py:65, in StockBalanceReport.run(self)
     63 self.inventory_dimensions = self.get_inventory_dimension_fields()
     64 self.prepare_opening_data_from_closing_balance()
---> 65 self.prepare_stock_ledger_entries()
     66 self.prepare_new_data()
     68 if not self.columns:

File /workspace/frappe-15/apps/erpnext/erpnext/stock/report/stock_balance/stock_balance.py:308, in StockBalanceReport.prepare_stock_ledger_entries(self)
    277 item_table = frappe.qb.DocType("Item")
    279 query = (
    280         frappe.qb.from_(sle)
    281         .inner_join(item_table)
   (...)
    305         .orderby(sle.actual_qty)
    306 )
--> 308 query = self.apply_inventory_dimensions_filters(query, sle)
    309 query = self.apply_warehouse_filters(query, sle)
    310 query = self.apply_items_filters(query, item_table)

File /workspace/frappe-15/apps/erpnext/erpnext/stock/report/stock_balance/stock_balance.py:324, in StockBalanceReport.apply_inventory_dimensions_filters(self, query, sle)
    322                 query = query.select(fieldname)
    323                 if self.filters.get(fieldname):
--> 324                         query = query.where(sle[fieldname].isin(self.filters.get(fieldname)))
    326 return query

File /workspace/frappe-15/env/lib/python3.11/site-packages/pypika/utils.py:50, in builder.<locals>._copy(self, *args, **kwargs)
     48 def _copy(self, *args, **kwargs):
     49     self_copy = copy.copy(self) if getattr(self, "immutable", True) else self
---> 50     result = func(self_copy, *args, **kwargs)
     52     # Return self if the inner function returns None.  This way the inner function can return something
     53     # different (for example when creating joins, a different builder is returned).
     54     if result is None:

File /workspace/frappe-15/env/lib/python3.11/site-packages/pypika/queries.py:930, in QueryBuilder.where(self, criterion)
    927 if isinstance(criterion, EmptyCriterion):
    928     return
--> 930 if not self._validate_table(criterion):
    931     self._foreign_table = True
    933 if self._wheres:

File /workspace/frappe-15/env/lib/python3.11/site-packages/pypika/queries.py:1155, in QueryBuilder._validate_table(self, term)
   1149 """
   1150 Returns False if the term references a table not already part of the
   1151 FROM clause or JOINS and True otherwise.
   1152 """
   1153 base_tables = self._from + [self._update_table]
-> 1155 for field in term.fields_():
   1156     table_in_base_tables = field.table in base_tables
   1157     table_in_joins = field.table in [join.item for join in self._joins]

File /workspace/frappe-15/env/lib/python3.11/site-packages/pypika/terms.py:57, in Term.fields_(self)
     56 def fields_(self) -> Set["Field"]:
---> 57     return set(self.find_(Field))

File /workspace/frappe-15/env/lib/python3.11/site-packages/pypika/terms.py:37, in Node.find_(self, type)
     36 def find_(self, type: Type[NodeT]) -> List[NodeT]:
---> 37     return [node for node in self.nodes_() if isinstance(node, type)]

File /workspace/frappe-15/env/lib/python3.11/site-packages/pypika/terms.py:37, in <listcomp>(.0)
     36 def find_(self, type: Type[NodeT]) -> List[NodeT]:
---> 37     return [node for node in self.nodes_() if isinstance(node, type)]

File /workspace/frappe-15/env/lib/python3.11/site-packages/pypika/terms.py:795, in ContainsCriterion.nodes_(self)
    793 yield self
    794 yield from self.term.nodes_()
--> 795 yield from self.container.nodes_()

AttributeError: 'str' object has no attribute 'nodes_'

this is my workaround for anyone having the same issue: I passed the inventory dimension parameter as a list as as pypika is expecting something as a list or tuple