Create a Script report with 'is standard' as 'no'

Hi! I’m trying to create a report that shows some KPIs. I’m doing a test with just one KPI wich divides Current assets by current liabilities.

Table must include the following columns: Çategoria, Indicador, Valor al periodo, valor de referencia

To create the report I’m using the following configurations:
Report type: Script
Ref DocType: Account
Running: ERPNext v15.23 self-hosted.

As far as I undertand with a script report that is not standard you can in v15 add the script and java in the report UI but after adding the script and filters whatever I do the report always says ‘Nothing to show’

Script I’m using is:

def execute(filters=None):
    if not filters or not filters.get("fecha"):
        frappe.throw("Por favor selecciona una fecha para el reporte.")

    fecha = filters.get("fecha")
    empresa = filters.get("empresa") or frappe.defaults.get_user_default("Company")

    def obtener_balance(cuenta_padre, es_pasivo=False):
        cuenta_info = frappe.get_all("Account", filters={"name": cuenta_padre}, fields=["lft", "rgt"])
        if not cuenta_info:
            return 0

        limites = cuenta_info[0]
        cuentas = frappe.get_all("Account", filters={
            "lft": [">", limites.lft],
            "rgt": ["<", limites.rgt],
            "is_group": 0,
            "company": empresa
        }, fields=["name"])

        cuentas_hoja = [c.name for c in cuentas]
        if not cuentas_hoja:
            return 0

        resultado = frappe.db.sql("""
            SELECT SUM(debit - credit) AS balance
            FROM `tabGL Entry`
            WHERE account IN %(cuentas)s
              AND posting_date <= %(fecha)s
              AND company = %(empresa)s
        """, {
            "cuentas": tuple(cuentas_hoja),
            "fecha": fecha,
            "empresa": empresa
        }, as_dict=True)

        balance = resultado[0]["balance"] if resultado and resultado[0]["balance"] is not None else 0
        return abs(balance) if es_pasivo else balance

    # Indicadores base
    indicadores = []

    activos_corrientes = obtener_balance("1.1 - Activos corriente - IP")
    pasivos_corrientes = obtener_balance("2.1 - Pasivo corriente - IP", es_pasivo=True)
    razon_corriente = activos_corrientes / pasivos_corrientes if pasivos_corrientes else 0

    indicadores.append({
        "categoria": "Liquidez",
        "indicador": "Razón corriente",
        "valor": razon_corriente,
        "referencia": 1.2
    })

    # Filtros dinámicos
    if filters.get("categoria"):
        indicadores = [i for i in indicadores if i["categoria"] == filters["categoria"]]
    if filters.get("indicador"):
        indicadores = [i for i in indicadores if i["indicador"] == filters["indicador"]]

    columns = [
        {"label": "Categoría", "fieldname": "categoria", "fieldtype": "Data", "width": 150},
        {"label": "Indicador", "fieldname": "indicador", "fieldtype": "Data", "width": 200},
        {"label": "Valor al período", "fieldname": "valor", "fieldtype": "Float", "width": 150},
        {"label": "Valor de referencia", "fieldname": "referencia", "fieldtype": "Float", "width": 150}
    ]

    return columns, indicadores or [{"categoria": "N/A", "indicador": "Sin datos", "valor": 0, "referencia": 0}]

I’d like to know what I should do since I have tested a couple of things and I don’t seems to have the report to read the script and generate the report.

I’m using chatgpt to help me with the code but since documentations is so lacky I couldn’t figure out what is wrong of feed the AI with proper guidance.

Thanks in advance!

are you calling execute after your method definition… like

def execute(filters=None):
    ........


result = execute(filters)

You screenshot is clipped, so can’t tell.

If you are setting the result and still getting nothing, then check the function in bench console, or the ‘System Console’ page

Try:
Send output as result = [result] , or for old style data = [columns], [result]

I managed to get the right result with this script in the system console:

def obtener_balance(cuenta_padre, fecha, empresa, es_pasivo=False):
    cuenta_info = frappe.get_all("Account", filters={"name": cuenta_padre}, fields=["lft", "rgt"])
    if not cuenta_info:
        log(f"Cuenta no encontrada: {cuenta_padre}")
        return 0

    limites = cuenta_info[0]
    cuentas = frappe.get_all("Account", filters={
        "lft": [">", limites["lft"]],
        "rgt": ["<", limites["rgt"]],
        "is_group": 0,
        "company": empresa
    }, fields=["name"])

    cuentas_hoja = [c["name"] for c in cuentas]
    if not cuentas_hoja:
        log(f"Sin cuentas hoja: {cuenta_padre}")
        return 0

    resultado = frappe.db.sql("""
        SELECT SUM(debit - credit) AS balance
        FROM `tabGL Entry`
        WHERE account IN %(cuentas)s
          AND posting_date <= %(fecha)s
          AND company = %(empresa)s
    """, {
        "cuentas": tuple(cuentas_hoja),
        "fecha": fecha,
        "empresa": empresa
    }, as_dict=True)

    balance = resultado[0]["balance"] if resultado and resultado[0]["balance"] is not None else 0
    return abs(balance) if es_pasivo else balance

# Parámetros
fecha = "2025-05-31"
empresa = "Isy Pisy"

# Cálculo
activos_corrientes = obtener_balance("1.1 - Activos corriente - IP", fecha, empresa)
pasivos_corrientes = obtener_balance("2.1 - Pasivo corriente - IP", fecha, empresa, es_pasivo=True)

razon_corriente = (
    activos_corrientes / pasivos_corrientes
    if isinstance(activos_corrientes, (int, float)) and isinstance(pasivos_corrientes, (int, float)) and pasivos_corrientes != 0
    else "N/A"
)

# Mostrar resultados
log(f"Activos Corrientes: {activos_corrientes}")
log(f"Pasivos Corrientes: {pasivos_corrientes}")
log(f"Razón Corriente: {razon_corriente}")

Values are correct here:

Nonetheless when I used the version for the report it still says ‘Nothing to show’. This is the script in the report section:

def execute(filters=None):
    if not filters or not filters.get("fecha"):
        frappe.throw("Por favor selecciona una fecha para el reporte.")
    
    fecha = filters.get("fecha")
    empresa = filters.get("empresa") or frappe.defaults.get_user_default("Company")

    def obtener_balance(cuenta_padre, es_pasivo=False):
        cuenta_info = frappe.get_all("Account", filters={"name": cuenta_padre}, fields=["lft", "rgt"])
        if not cuenta_info:
            return 0

        limites = cuenta_info[0]
        cuentas = frappe.get_all("Account", filters={
            "lft": [">", limites["lft"]],
            "rgt": ["<", limites["rgt"]],
            "is_group": 0,
            "company": empresa
        }, fields=["name"])

        cuentas_hoja = [c["name"] for c in cuentas]
        if not cuentas_hoja:
            return 0

        resultado = frappe.db.sql("""
            SELECT SUM(debit - credit) AS balance
            FROM `tabGL Entry`
            WHERE account IN %(cuentas)s
              AND posting_date <= %(fecha)s
              AND company = %(empresa)s
        """, {
            "cuentas": tuple(cuentas_hoja),
            "fecha": fecha,
            "empresa": empresa
        }, as_dict=True)

        balance = resultado[0]["balance"] if resultado and resultado[0]["balance"] is not None else 0
        return abs(balance) if es_pasivo else balance

    # Calcular indicadores
    activos_corrientes = obtener_balance("1.1 - Activos corriente - IP")
    pasivos_corrientes = obtener_balance("2.1 - Pasivo corriente - IP", es_pasivo=True)
    razon_corriente = (
        activos_corrientes / pasivos_corrientes
        if pasivos_corrientes else 0
    )

    indicadores = [{
        "categoria": "Liquidez",
        "indicador": "Razón corriente",
        "valor": razon_corriente,
        "referencia": 1.2
    }]

    # Filtros opcionales
    if filters.get("categoria"):
        indicadores = [i for i in indicadores if i["categoria"] == filters["categoria"]]
    if filters.get("indicador"):
        indicadores = [i for i in indicadores if i["indicador"] == filters["indicador"]]

    # Columnas del reporte
    columns = [
        {"label": "Categoría", "fieldname": "categoria", "fieldtype": "Data", "width": 150},
        {"label": "Indicador", "fieldname": "indicador", "fieldtype": "Data", "width": 200},
        {"label": "Valor al período", "fieldname": "valor", "fieldtype": "Float", "width": 150},
        {"label": "Valor de referencia", "fieldname": "referencia", "fieldtype": "Float", "width": 150}
    ]

    return columns, indicadores or [{"categoria": "N/A", "indicador": "Sin datos", "valor": 0, "referencia": 0}]

Filters per image:

I’m still getting ‘Nothing to show’

@enavash

use the data = columns, rows syntax

move the code out of the execute method and just return columns , rows. Also don’t use data or result as variable names in your code! Thats why I have used ‘rows’

1 Like

To use the result = [{...},{....}] syntax, you have to define columns in the columns table, and assign only the rows to result!! :astonished:

1 Like

Thanks for that suggestion. It worked! Now I’m having problems with filters. I set a couple of custom filters but they are not working as expected. I can select them but filter won’t apply

This is my current code:

# Validación de filtros
fecha = filters.get("fecha")
empresa = filters.get("empresa") or frappe.defaults.get_user_default("Company")
categoria = frappe.form_dict.get("categoria")
indicador = frappe.form_dict.get("indicador")

if not fecha:
    frappe.throw("Por favor selecciona una fecha para el reporte.")

# Función para obtener el balance contable desde una cuenta padre
def obtener_balance(cuenta_padre, fecha, empresa, es_pasivo=False):
    cuenta_info = frappe.get_all("Account", filters={"name": cuenta_padre}, fields=["lft", "rgt"])
    if not cuenta_info:
        frappe.msgprint(f"Cuenta no encontrada: {cuenta_padre}")
        return 0

    limites = cuenta_info[0]
    cuentas = frappe.get_all("Account", filters={
        "lft": [">", limites["lft"]],
        "rgt": ["<", limites["rgt"]],
        "is_group": 0,
        "company": empresa
    }, fields=["name"])

    cuentas_hoja = [c["name"] for c in cuentas]
    if not cuentas_hoja:
        frappe.msgprint(f"Sin cuentas hoja para: {cuenta_padre}")
        return 0

    resultado = frappe.db.sql("""
        SELECT SUM(debit - credit) AS balance
        FROM `tabGL Entry`
        WHERE account IN %(cuentas)s
          AND posting_date <= %(fecha)s
          AND company = %(empresa)s
    """, {
        "cuentas": tuple(cuentas_hoja),
        "fecha": fecha,
        "empresa": empresa
    }, as_dict=True)

    balance = resultado[0]["balance"] if resultado and resultado[0]["balance"] is not None else 0
    return abs(balance) if es_pasivo else balance

# Cálculo de indicadores
activos_corrientes = obtener_balance("1.1 - Activos corriente - IP", fecha, empresa)
pasivos_corrientes = obtener_balance("2.1 - Pasivo corriente - IP", fecha, empresa, es_pasivo=True)

razon_corriente = (
    activos_corrientes / pasivos_corrientes
    if isinstance(activos_corrientes, (int, float)) and isinstance(pasivos_corrientes, (int, float)) and pasivos_corrientes != 0
    else 0
)

rows = [{
    "categoria": "Liquidez",
    "indicador": "Razón corriente",
    "valor": razon_corriente,
    "referencia": 1.2
}]

# Columnas
columns = [
    {"label": "Categoría", "fieldname": "categoria", "fieldtype": "Data", "width": 150},
    {"label": "Indicador", "fieldname": "indicador", "fieldtype": "Data", "width": 200},
    {"label": "Valor al período", "fieldname": "valor", "fieldtype": "Float", "width": 150},
    {"label": "Valor de referencia", "fieldname": "referencia", "fieldtype": "Float", "width": 150}
]

# Retorno esperado por el reporte
data = columns, rows

As you see here I selected ‘Solvencia’ which is the category and the only indicator I have has the category ‘Liquidez’ so it shouldn’t be shown

This is my filters set up

I tried this other version but it always says that ‘categoria’ and ‘indicador’ are not defined

# Validación de filtros
fecha = filters.get("fecha")
empresa = filters.get("empresa") or frappe.defaults.get_user_default("Company")
categoria = filters.get("categoria")
indicador = filters.get("indicador")

if not fecha:
    frappe.throw("Por favor selecciona una fecha para el reporte.")

# Función para obtener el balance contable desde una cuenta padre
def obtener_balance(cuenta_padre, fecha, empresa, es_pasivo=False):
    cuenta_info = frappe.get_all("Account", filters={"name": cuenta_padre}, fields=["lft", "rgt"])
    if not cuenta_info:
        frappe.msgprint(f"Cuenta no encontrada: {cuenta_padre}")
        return 0

    limites = cuenta_info[0]
    cuentas = frappe.get_all("Account", filters={
        "lft": [">", limites["lft"]],
        "rgt": ["<", limites["rgt"]],
        "is_group": 0,
        "company": empresa
    }, fields=["name"])

    cuentas_hoja = [c["name"] for c in cuentas]
    if not cuentas_hoja:
        frappe.msgprint(f"Sin cuentas hoja para: {cuenta_padre}")
        return 0

    resultado = frappe.db.sql("""
        SELECT SUM(debit - credit) AS balance
        FROM `tabGL Entry`
        WHERE account IN %(cuentas)s
          AND posting_date <= %(fecha)s
          AND company = %(empresa)s
    """, {
        "cuentas": tuple(cuentas_hoja),
        "fecha": fecha,
        "empresa": empresa
    }, as_dict=True)

    balance = resultado[0]["balance"] if resultado and resultado[0]["balance"] is not None else 0
    return abs(balance) if es_pasivo else balance

# Cálculo de indicadores
activos_corrientes = obtener_balance("1.1 - Activos corriente - IP", fecha, empresa)
pasivos_corrientes = obtener_balance("2.1 - Pasivo corriente - IP", fecha, empresa, es_pasivo=True)

razon_corriente = (
    activos_corrientes / pasivos_corrientes
    if isinstance(activos_corrientes, (int, float)) and isinstance(pasivos_corrientes, (int, float)) and pasivos_corrientes != 0
    else 0
)

rows = [{
    "categoria": "Liquidez",
    "indicador": "Razón corriente",
    "valor": razon_corriente,
    "referencia": 1.2
}]

# Aplicar filtros (correctamente)
if categoria:
    rows = [r for r in rows if r["categoria"] == categoria]
if indicador:
    rows = [r for r in rows if r["indicador"] == indicador]

# Columnas del reporte
columns = [
    {"label": "Categoría", "fieldname": "categoria", "fieldtype": "Data", "width": 150},
    {"label": "Indicador", "fieldname": "indicador", "fieldtype": "Data", "width": 200},
    {"label": "Valor al período", "fieldname": "valor", "fieldtype": "Float", "width": 150},
    {"label": "Valor de referencia", "fieldname": "referencia", "fieldtype": "Float", "width": 150}
]

# Retorno esperado
data = columns, rows

Can you check if your selected filters appear in the url? There is report bug going around currently, just to confirm its not related. Make a url with your filters and try that url directly

and filters.get is the correct way