arthexis 0.1.23__py3-none-any.whl → 0.1.25__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of arthexis might be problematic. Click here for more details.

core/system.py CHANGED
@@ -4,6 +4,7 @@ from collections import deque
4
4
  from contextlib import closing
5
5
  from dataclasses import dataclass
6
6
  from datetime import datetime
7
+ from functools import lru_cache
7
8
  from pathlib import Path
8
9
  import json
9
10
  import re
@@ -12,6 +13,7 @@ import subprocess
12
13
  import shutil
13
14
  import logging
14
15
  from typing import Callable, Iterable, Optional
16
+ from urllib.parse import urlparse
15
17
 
16
18
  from django import forms
17
19
  from django.conf import settings
@@ -46,6 +48,69 @@ AUTO_UPGRADE_LOG_NAME = "auto-upgrade.log"
46
48
  logger = logging.getLogger(__name__)
47
49
 
48
50
 
51
+ def _github_repo_path(remote_url: str | None) -> str:
52
+ """Return the ``owner/repo`` path for a GitHub *remote_url* if possible."""
53
+
54
+ if not remote_url:
55
+ return ""
56
+
57
+ normalized = remote_url.strip()
58
+ if not normalized:
59
+ return ""
60
+
61
+ path = ""
62
+ if normalized.startswith("git@"):
63
+ host, _, remainder = normalized.partition(":")
64
+ if "github.com" not in host.lower():
65
+ return ""
66
+ path = remainder
67
+ else:
68
+ parsed = urlparse(normalized)
69
+ if "github.com" not in parsed.netloc.lower():
70
+ return ""
71
+ path = parsed.path
72
+
73
+ path = path.strip("/")
74
+ if path.endswith(".git"):
75
+ path = path[: -len(".git")]
76
+
77
+ if not path:
78
+ return ""
79
+
80
+ segments = [segment for segment in path.split("/") if segment]
81
+ if len(segments) < 2:
82
+ return ""
83
+
84
+ owner, repo = segments[-2], segments[-1]
85
+ return f"{owner}/{repo}"
86
+
87
+
88
+ @lru_cache()
89
+ def _github_commit_url_base() -> str:
90
+ """Return the GitHub commit URL template for the configured repository."""
91
+
92
+ try:
93
+ remote_url = _git_remote_url()
94
+ except FileNotFoundError: # pragma: no cover - depends on environment setup
95
+ logger.debug("Skipping GitHub commit URL generation; git executable not found")
96
+ remote_url = None
97
+
98
+ repo_path = _github_repo_path(remote_url)
99
+ if not repo_path:
100
+ return ""
101
+ return f"https://github.com/{repo_path}/commit/{{sha}}"
102
+
103
+
104
+ def _github_commit_url(sha: str) -> str:
105
+ """Return the GitHub commit URL for *sha* when available."""
106
+
107
+ base = _github_commit_url_base()
108
+ clean_sha = (sha or "").strip()
109
+ if not base or not clean_sha:
110
+ return ""
111
+ return base.replace("{sha}", clean_sha)
112
+
113
+
49
114
  def _auto_upgrade_mode_file(base_dir: Path) -> Path:
50
115
  return base_dir / "locks" / AUTO_UPGRADE_LOCK_NAME
51
116
 
@@ -96,7 +161,7 @@ def _open_changelog_entries() -> list[dict[str, str]]:
96
161
  parts = trimmed.split(" ", 1)
97
162
  sha = parts[0]
98
163
  message = parts[1] if len(parts) > 1 else ""
99
- entries.append({"sha": sha, "message": message})
164
+ entries.append({"sha": sha, "message": message, "url": _github_commit_url(sha)})
100
165
 
101
166
  return entries
102
167
 
@@ -162,7 +227,7 @@ def _latest_release_changelog() -> dict[str, object]:
162
227
  parts = trimmed.split(" ", 1)
163
228
  sha = parts[0]
164
229
  message = parts[1] if len(parts) > 1 else ""
165
- entries.append({"sha": sha, "message": message})
230
+ entries.append({"sha": sha, "message": message, "url": _github_commit_url(sha)})
166
231
 
167
232
  return {"title": release_title, "entries": entries}
168
233
 
core/tasks.py CHANGED
@@ -405,3 +405,28 @@ def run_client_report_schedule(schedule_id: int) -> None:
405
405
  except Exception:
406
406
  logger.exception("ClientReportSchedule %s failed", schedule_id)
407
407
  raise
408
+
409
+
410
+ @shared_task
411
+ def ensure_recurring_client_reports() -> None:
412
+ """Ensure scheduled consumer reports run for the current period."""
413
+
414
+ from core.models import ClientReportSchedule
415
+
416
+ reference = timezone.localdate()
417
+ schedules = ClientReportSchedule.objects.filter(
418
+ periodicity__in=[
419
+ ClientReportSchedule.PERIODICITY_DAILY,
420
+ ClientReportSchedule.PERIODICITY_WEEKLY,
421
+ ClientReportSchedule.PERIODICITY_MONTHLY,
422
+ ]
423
+ ).prefetch_related("chargers")
424
+
425
+ for schedule in schedules:
426
+ try:
427
+ schedule.generate_missing_reports(reference=reference)
428
+ except Exception:
429
+ logger.exception(
430
+ "Automatic consumer report generation failed for schedule %s",
431
+ schedule.pk,
432
+ )
core/views.py CHANGED
@@ -58,7 +58,6 @@ def odoo_products(request):
58
58
  products = profile.execute(
59
59
  "product.product",
60
60
  "search_read",
61
- [[]],
62
61
  fields=["name"],
63
62
  limit=50,
64
63
  )
@@ -137,7 +136,6 @@ def odoo_quote_report(request):
137
136
  templates = profile.execute(
138
137
  "sale.order.template",
139
138
  "search_read",
140
- [[]],
141
139
  fields=["name"],
142
140
  order="name asc",
143
141
  )
@@ -287,7 +285,6 @@ def odoo_quote_report(request):
287
285
  products = profile.execute(
288
286
  "product.product",
289
287
  "search_read",
290
- [[]],
291
288
  fields=["name", "default_code", "write_date", "create_date"],
292
289
  limit=10,
293
290
  order="write_date desc, create_date desc",