|
10 | 10 | import os |
11 | 11 | from ast import literal_eval |
12 | 12 | from collections import defaultdict |
| 13 | +from datetime import timedelta |
13 | 14 | from typing import Literal # noqa # pylint: disable=unused-import |
14 | 15 |
|
15 | 16 | from odoo import api, fields, models, tools |
@@ -786,3 +787,86 @@ def action_dms_files_all_directory(self): |
786 | 787 | searchpanel_default_directory_id=self.id, |
787 | 788 | ) |
788 | 789 | return action |
| 790 | + |
| 791 | + @api.model |
| 792 | + def get_dashboard_stats(self): |
| 793 | + # Global file stats scoped by the current user's ir.rule access. |
| 794 | + # Stats are global across all readable files; directory-domain |
| 795 | + # translation is deliberately not applied in this iteration. |
| 796 | + # |
| 797 | + # Sparklines + deltas are computed live via _read_group over |
| 798 | + # create_date (always indexed by Odoo) — no snapshot table required. |
| 799 | + # The arrays describe *activity* (creations), not state-over-time; |
| 800 | + # storage_sparkline shows daily bytes-added, not the running total |
| 801 | + # (which would require a snapshot to be faithful under deletions). |
| 802 | + File = self.env["dms.file"] |
| 803 | + now = fields.Datetime.now() |
| 804 | + files_total = File.search_count([]) |
| 805 | + storage_groups = File._read_group( |
| 806 | + domain=[], groupby=[], aggregates=["size:sum"] |
| 807 | + ) |
| 808 | + storage_bytes = int(storage_groups[0][0] or 0) if storage_groups else 0 |
| 809 | + new_today = File.search_count([("create_date", ">=", now - timedelta(days=1))]) |
| 810 | + |
| 811 | + # 30-day daily buckets: (created_count, size_sum) per day. |
| 812 | + day_start = (now - timedelta(days=29)).replace( |
| 813 | + hour=0, minute=0, second=0, microsecond=0 |
| 814 | + ) |
| 815 | + daily_rows = File._read_group( |
| 816 | + domain=[("create_date", ">=", day_start)], |
| 817 | + groupby=["create_date:day"], |
| 818 | + aggregates=["__count", "size:sum"], |
| 819 | + ) |
| 820 | + daily_by_key = {} |
| 821 | + for day_value, count, size_sum in daily_rows: |
| 822 | + if not day_value: |
| 823 | + continue |
| 824 | + key = day_value.date().isoformat() |
| 825 | + daily_by_key[key] = (int(count or 0), int(size_sum or 0)) |
| 826 | + files_sparkline = [] |
| 827 | + storage_sparkline = [] |
| 828 | + for offset in range(29, -1, -1): |
| 829 | + day = (now - timedelta(days=offset)).date().isoformat() |
| 830 | + count, size_sum = daily_by_key.get(day, (0, 0)) |
| 831 | + files_sparkline.append(count) |
| 832 | + storage_sparkline.append(size_sum) |
| 833 | + |
| 834 | + # 24 hourly buckets across the past day for the "new today" tile. |
| 835 | + hour_start = (now - timedelta(hours=23)).replace( |
| 836 | + minute=0, second=0, microsecond=0 |
| 837 | + ) |
| 838 | + hourly_rows = File._read_group( |
| 839 | + domain=[("create_date", ">=", hour_start)], |
| 840 | + groupby=["create_date:hour"], |
| 841 | + aggregates=["__count"], |
| 842 | + ) |
| 843 | + hourly_by_key = {} |
| 844 | + for hour_value, count in hourly_rows: |
| 845 | + if not hour_value: |
| 846 | + continue |
| 847 | + hourly_by_key[hour_value.replace(minute=0, second=0, microsecond=0)] = int( |
| 848 | + count or 0 |
| 849 | + ) |
| 850 | + new_today_sparkline = [] |
| 851 | + for offset in range(23, -1, -1): |
| 852 | + slot = (now - timedelta(hours=offset)).replace( |
| 853 | + minute=0, second=0, microsecond=0 |
| 854 | + ) |
| 855 | + new_today_sparkline.append(hourly_by_key.get(slot, 0)) |
| 856 | + |
| 857 | + files_last_week = sum(files_sparkline[-7:]) |
| 858 | + storage_last_week = sum(storage_sparkline[-7:]) |
| 859 | + avg_per_day = round(sum(files_sparkline[-7:]) / 7.0, 1) |
| 860 | + |
| 861 | + return { |
| 862 | + "files_total": files_total, |
| 863 | + "storage_total_bytes": storage_bytes, |
| 864 | + "storage_total_human": human_size(storage_bytes), |
| 865 | + "new_today": new_today, |
| 866 | + "files_sparkline": files_sparkline, |
| 867 | + "storage_sparkline": storage_sparkline, |
| 868 | + "new_today_sparkline": new_today_sparkline, |
| 869 | + "files_delta_week": files_last_week, |
| 870 | + "storage_delta_week_human": human_size(storage_last_week), |
| 871 | + "new_today_avg_per_day": avg_per_day, |
| 872 | + } |
0 commit comments