forderung_data.py 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. """One authorized projection for list results and dashboard aggregates."""
  2. from sqlalchemy import text
  3. from .jinja_templates import templates
  4. from .query_filter import EMPTY_FILTER_LABEL, EMPTY_FILTER_VALUE
  5. def read_filter_suggestions(db, username, field, clauses, values, search="", *, selected=None):
  6. # Reuse the authorized projection, including local changes to its WHERE clause.
  7. query = templates.env.get_template("forderungen/liste/queries/forderungen_liste.sql").render()
  8. query = query.rsplit("ORDER BY", 1)[0]
  9. raw_key, raw_label, sort = (f"F.[{column}]" for column in (field.key_column, field.value_column, field.sort_column))
  10. key = f"COALESCE(NULLIF(CAST({raw_key} AS nvarchar(4000)), ''), '{EMPTY_FILTER_VALUE}')"
  11. label = (
  12. f"CASE WHEN NULLIF(CAST({raw_key} AS nvarchar(4000)), '') IS NULL THEN '{EMPTY_FILTER_LABEL}' "
  13. f"ELSE CAST({raw_label} AS nvarchar(4000)) END"
  14. )
  15. limit = "TOP 51 " if selected is None else ""
  16. query = query.replace(
  17. "SELECT F.*", f"SELECT {limit}{key} AS value, MIN({label}) AS label, MIN({sort}) AS sort_value", 1
  18. )
  19. predicates = list(clauses)
  20. values = dict(values, auth_username=username)
  21. if selected is not None:
  22. placeholders = []
  23. for index, value in enumerate(selected):
  24. parameter = f"selected_{index}"
  25. placeholders.append(":" + parameter)
  26. values[parameter] = value
  27. if not placeholders:
  28. return []
  29. predicates.append(f"{key} IN ({', '.join(placeholders)})")
  30. if search:
  31. predicates.append(
  32. f"(CAST({key} AS nvarchar(max)) LIKE :suggest_search OR CAST({label} AS nvarchar(max)) LIKE :suggest_search)"
  33. )
  34. values["suggest_search"] = f"%{search}%"
  35. if predicates:
  36. query = query.replace("AND 1 = 1", "AND 1 = 1 AND " + " AND ".join(predicates))
  37. query += f" GROUP BY {key} ORDER BY MIN({sort}), {key}"
  38. rows = db.execute(text(query), values).fetchall()
  39. return [{"value": str(row[0]), "label": str(row[1] if row[1] is not None else row[0])} for row in rows]
  40. def read_invoices(db, username, clauses=(), values=None):
  41. query = templates.env.get_template("forderungen/liste/queries/forderungen_liste.sql").render()
  42. if clauses:
  43. query = query.replace("AND 1 = 1", "AND 1 = 1 AND " + " AND ".join(clauses))
  44. result = db.execute(
  45. text(query).execution_options(query_name="forderungen/liste/queries/forderungen_liste.sql"),
  46. dict(values or {}, auth_username=username),
  47. )
  48. columns = list(result.keys())
  49. tenant, number = columns.index("Client_DB"), columns.index("Beleg_Nr")
  50. seen, rows = set(), []
  51. for row in result.fetchall():
  52. identity = (str(row[tenant]), str(row[number]))
  53. if identity not in seen:
  54. rows.append(row)
  55. seen.add(identity)
  56. return columns, rows