Tägliche Statistiken mit Drill-Down und Jahresvergleich

- Tägliche Statistiken (DailyStats) implementiert mit 2034 Datensätzen
- Wochenende vs. Wochentag farblich unterschieden in Tagesansicht
- Jahr/Monat Felder für Jahresvergleich hinzugefügt
- Button 'Tagesansicht' in Kanban-Dashboard für Drill-Down zu täglichen Statistiken
- Alle Dashboard-Graphen auf Jahresvergleich umgestellt (Monat × Jahr, nicht gestapelt)
- Jahresvergleich, Ø Nutzer/Tag, Wiederholungstäter, Nutzer pro Monat - alle mit Jahresvergleich
This commit is contained in:
Matthias Lotz 2025-12-26 21:35:22 +01:00
parent d6a98cfbd0
commit 9be8f320f7
10 changed files with 510 additions and 30 deletions

View File

@ -25,6 +25,8 @@
'data/cron_data.xml',
'views/dashboard_views.xml',
'views/usage_stats_views.xml',
'views/daily_stats_views.xml',
'views/specialized_dashboards.xml',
'reports/usage_report_templates.xml',
'reports/usage_reports.xml',
],

View File

@ -0,0 +1,59 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Generiere Tagesstatistiken für Open Workshop
"""
import sys
sys.path.insert(0, '/odoo')
import odoo
from datetime import datetime, timedelta
# Initialisiere Odoo
odoo.tools.config['db_name'] = 'hh18'
odoo.tools.config.parse_config(['-c', '/etc/odoo/odoo-dev.conf'])
# Registry laden
registry = odoo.registry('hh18')
with registry.cursor() as cr:
env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
DailyStats = env['open_workshop.daily.stats']
# Finde älteste und neuste Session
Session = env['pos.session']
sessions = Session.search([('state', '=', 'closed')], order='start_at', limit=1)
if not sessions:
print('Keine Sessions gefunden!')
sys.exit(1)
start_date = sessions[0].start_at.date()
end_date = datetime.now().date()
print(f'Generiere Tagesstatistiken von {start_date} bis {end_date}')
current_date = start_date
created_count = 0
updated_count = 0
while current_date <= end_date:
# Prüfe ob schon vorhanden
existing = DailyStats.search([('date', '=', current_date)], limit=1)
if existing:
# Neu berechnen
existing._compute_stats()
updated_count += 1
else:
DailyStats.create({'date': current_date})
created_count += 1
if (created_count + updated_count) % 100 == 0:
print(f' Verarbeitet: {created_count + updated_count} Tage...')
cr.commit()
current_date += timedelta(days=1)
cr.commit()
print(f'\n{created_count} neue Tagesstatistiken erstellt')
print(f'{updated_count} Tagesstatistiken aktualisiert')
print(f'✅ Gesamt: {created_count + updated_count} Tage')

View File

@ -1 +1,2 @@
from . import usage_stats
from . import daily_stats

View File

@ -0,0 +1,121 @@
# -*- coding: utf-8 -*-
from odoo import api, fields, models, _
from datetime import datetime, timedelta
class DailyStats(models.Model):
"""Tägliche Nutzungsstatistiken"""
_name = 'open_workshop.daily.stats'
_description = 'Tägliche Nutzungsstatistiken'
_order = 'date desc'
date = fields.Date('Datum', required=True, index=True)
year = fields.Integer('Jahr', compute='_compute_weekday', store=True, group_operator='')
month = fields.Integer('Monat', compute='_compute_weekday', store=True)
month_name = fields.Char('Monat Name', compute='_compute_weekday', store=True)
weekday = fields.Selection([
('0', 'Montag'),
('1', 'Dienstag'),
('2', 'Mittwoch'),
('3', 'Donnerstag'),
('4', 'Freitag'),
('5', 'Samstag'),
('6', 'Sonntag'),
], string='Wochentag', compute='_compute_weekday', store=True)
is_weekend = fields.Char('Tag-Typ', compute='_compute_weekday', store=True, group_expand='_group_expand_weekend')
# Buchungen
total_bookings = fields.Integer('Buchungen gesamt', compute='_compute_stats', store=True)
total_bookings_no_heroes = fields.Integer('Buchungen ohne Thekenhelden', compute='_compute_stats', store=True)
# Nutzer
unique_users = fields.Integer('Nutzer gesamt', compute='_compute_stats', store=True)
unique_users_no_heroes = fields.Integer('Nutzer ohne Thekenhelden', compute='_compute_stats', store=True)
# Monatszugehörigkeit
month_stats_id = fields.Many2one('open_workshop.usage.stats', string='Monatsstatistik',
compute='_compute_month_stats', store=True)
@api.depends('date')
def _compute_weekday(self):
month_names = {
1: 'Januar', 2: 'Februar', 3: 'März', 4: 'April',
5: 'Mai', 6: 'Juni', 7: 'Juli', 8: 'August',
9: 'September', 10: 'Oktober', 11: 'November', 12: 'Dezember'
}
for record in self:
wd = record.date.weekday()
record.weekday = str(wd)
record.is_weekend = 'Wochenende' if wd >= 5 else 'Wochentag' # Sa=5, So=6
record.year = record.date.year
record.month = record.date.month
record.month_name = month_names.get(record.date.month, '')
def _group_expand_weekend(self, weekends, domain, order):
"""Stelle sicher dass beide Kategorien immer angezeigt werden"""
return ['Wochentag', 'Wochenende']
@api.depends('date')
def _compute_month_stats(self):
"""Verknüpfe mit Monatsstatistik"""
for record in self:
month_stat = self.env['open_workshop.usage.stats'].search([
('period_type', '=', 'month'),
('period_start', '<=', record.date),
('period_end', '>=', record.date),
], limit=1)
record.month_stats_id = month_stat
@api.depends('date')
def _compute_stats(self):
for record in self:
start_datetime = datetime.combine(record.date, datetime.min.time())
end_datetime = datetime.combine(record.date, datetime.max.time())
# Alle POS Orders an diesem Tag
orders = self.env['pos.order'].search([
('date_order', '>=', start_datetime),
('date_order', '<=', end_datetime),
('partner_id', '!=', False),
])
record.total_bookings = len(orders)
# Thekenheld-Kategorie
hero_category = self.env['res.partner.category'].search([
'|', ('name', 'ilike', 'thekenheld'), ('name', 'ilike', 'thk')
], limit=1)
if hero_category:
orders_no_heroes = orders.filtered(lambda o: hero_category not in o.partner_id.category_id)
partners_no_heroes = orders_no_heroes.mapped('partner_id')
else:
orders_no_heroes = orders
partners_no_heroes = orders.mapped('partner_id')
record.total_bookings_no_heroes = len(orders_no_heroes)
record.unique_users = len(orders.mapped('partner_id'))
record.unique_users_no_heroes = len(partners_no_heroes)
@api.model
def generate_daily_stats_for_month(self, year, month):
"""Generiere Tagesstatistiken für einen Monat"""
start_date = datetime(year, month, 1).date()
if month == 12:
end_date = datetime(year + 1, 1, 1).date() - timedelta(days=1)
else:
end_date = datetime(year, month + 1, 1).date() - timedelta(days=1)
current_date = start_date
created_count = 0
while current_date <= end_date:
# Prüfe ob schon vorhanden
existing = self.search([('date', '=', current_date)], limit=1)
if not existing:
self.create({'date': current_date})
created_count += 1
current_date += timedelta(days=1)
return created_count

View File

@ -22,17 +22,60 @@ class UsageStats(models.Model):
('year', 'Jahr'),
], string='Periodentyp', default='month', required=True)
# Statistiken
total_sessions = fields.Integer('Gesamt Nutzungen', compute='_compute_stats', store=True)
# Für Jahresvergleich
year = fields.Integer('Jahr', compute='_compute_year', store=True)
month = fields.Integer('Monat', compute='_compute_year', store=True)
month_name = fields.Char('Monat Name', compute='_compute_year', store=True)
# Statistiken - Alle Nutzer
total_sessions = fields.Integer('Gesamt Buchungen', compute='_compute_stats', store=True)
total_revenue = fields.Monetary('Gesamtumsatz', compute='_compute_stats', store=True, currency_field='currency_id')
avg_per_day = fields.Float('Durchschnitt pro Tag', compute='_compute_stats', store=True, digits=(5, 2))
unique_users = fields.Integer('Einzigartige Nutzer', compute='_compute_stats', store=True)
# Statistiken - Ohne Thekenhelden
total_bookings_no_heroes = fields.Integer('Buchungen ohne Thekenhelden', compute='_compute_stats', store=True)
unique_users_no_heroes = fields.Integer('Nutzer ohne Thekenhelden', compute='_compute_stats', store=True)
avg_per_day_no_heroes = fields.Float('Ø Nutzer pro Tag ohne Thekenhelden', compute='_compute_stats', store=True, digits=(10, 2))
# Wiederholungstäter
repeat_users = fields.Integer('Wiederholungstäter', compute='_compute_stats', store=True,
help='Nutzer die mehr als 1x im Zeitraum gebucht haben')
repeat_users_no_heroes = fields.Integer('Wiederholungstäter ohne Thekenhelden', compute='_compute_stats', store=True)
currency_id = fields.Many2one('res.currency', string='Währung',
default=lambda self: self.env.company.currency_id)
# POS Session IDs für diese Periode
session_ids = fields.Many2many('pos.session', string='POS Sessions', compute='_compute_stats', store=True)
# Tägliche Statistiken für diese Periode
daily_stats_ids = fields.One2many('open_workshop.daily.stats', compute='_compute_daily_stats', string='Tägliche Statistiken')
@api.depends('period_start', 'period_end')
def _compute_daily_stats(self):
"""Lädt die täglichen Statistiken für diese Periode"""
for record in self:
record.daily_stats_ids = self.env['open_workshop.daily.stats'].search([
('date', '>=', record.period_start),
('date', '<=', record.period_end)
], order='date asc')
def action_view_details(self):
"""Öffnet die Detailansicht mit Tages-Diagramm"""
self.ensure_one()
return {
'type': 'ir.actions.act_window',
'name': f'Tagesansicht: {self.period_name}',
'res_model': 'open_workshop.daily.stats',
'view_mode': 'graph,list',
'domain': [('date', '>=', self.period_start), ('date', '<=', self.period_end)],
'context': {
'search_default_period': 1,
'default_date': self.period_start,
},
'target': 'current',
}
@api.depends('period_start', 'period_end', 'period_type')
def _compute_period_name(self):
@ -46,6 +89,18 @@ class UsageStats(models.Model):
else:
record.period_name = f"{record.period_start.strftime('%d.%m.%Y')} - {record.period_end.strftime('%d.%m.%Y')}"
@api.depends('period_start')
def _compute_year(self):
month_names = {
1: 'Januar', 2: 'Februar', 3: 'März', 4: 'April',
5: 'Mai', 6: 'Juni', 7: 'Juli', 8: 'August',
9: 'September', 10: 'Oktober', 11: 'November', 12: 'Dezember'
}
for record in self:
record.year = record.period_start.year
record.month = record.period_start.month
record.month_name = month_names.get(record.period_start.month, '')
@api.depends('period_start', 'period_end')
def _compute_stats(self):
for record in self:
@ -68,12 +123,45 @@ class UsageStats(models.Model):
days = (record.period_end - record.period_start).days + 1
record.avg_per_day = record.total_sessions / days if days > 0 else 0.0
# Einzigartige Nutzer (über POS Orders)
# Hole Thekenheld-Kategorie
hero_category = self.env['res.partner.category'].search([
'|', ('name', 'ilike', 'thekenheld'), ('name', 'ilike', 'thk')
], limit=1)
# Alle POS Orders im Zeitraum
orders = self.env['pos.order'].search([
('session_id', 'in', sessions.ids),
('partner_id', '!=', False),
])
record.unique_users = len(orders.mapped('partner_id'))
# Einzigartige Nutzer (alle)
all_partners = orders.mapped('partner_id')
record.unique_users = len(all_partners)
# Filter: Ohne Thekenhelden
if hero_category:
partners_no_heroes = all_partners.filtered(lambda p: hero_category not in p.category_id)
orders_no_heroes = orders.filtered(lambda o: hero_category not in o.partner_id.category_id)
else:
partners_no_heroes = all_partners
orders_no_heroes = orders
record.unique_users_no_heroes = len(partners_no_heroes)
record.total_bookings_no_heroes = len(orders_no_heroes)
record.avg_per_day_no_heroes = record.unique_users_no_heroes / days if days > 0 else 0.0
# Wiederholungstäter: Partner die mehr als 1 Order haben
partner_order_count = {}
for order in orders:
partner_id = order.partner_id.id
partner_order_count[partner_id] = partner_order_count.get(partner_id, 0) + 1
record.repeat_users = len([p for p, count in partner_order_count.items() if count > 1])
partner_order_count_no_heroes = {}
for order in orders_no_heroes:
partner_id = order.partner_id.id
partner_order_count_no_heroes[partner_id] = partner_order_count_no_heroes.get(partner_id, 0) + 1
record.repeat_users_no_heroes = len([p for p, count in partner_order_count_no_heroes.items() if count > 1])
@api.model
def generate_monthly_stats(self, year=None, month=None):

View File

@ -1,3 +1,5 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_usage_stats_user,access.usage.stats.user,model_open_workshop_usage_stats,base.group_user,1,0,0,0
access_usage_stats_manager,access.usage.stats.manager,model_open_workshop_usage_stats,point_of_sale.group_pos_manager,1,1,1,1
access_daily_stats_user,access.daily.stats.user,model_open_workshop_daily_stats,base.group_user,1,0,0,0
access_daily_stats_manager,access.daily.stats.manager,model_open_workshop_daily_stats,point_of_sale.group_pos_manager,1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_usage_stats_user access.usage.stats.user model_open_workshop_usage_stats base.group_user 1 0 0 0
3 access_usage_stats_manager access.usage.stats.manager model_open_workshop_usage_stats point_of_sale.group_pos_manager 1 1 1 1
4 access_daily_stats_user access.daily.stats.user model_open_workshop_daily_stats base.group_user 1 0 0 0
5 access_daily_stats_manager access.daily.stats.manager model_open_workshop_daily_stats point_of_sale.group_pos_manager 1 1 1 1

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Tree View -->
<record id="view_daily_stats_tree" model="ir.ui.view">
<field name="name">open_workshop.daily.stats.tree</field>
<field name="model">open_workshop.daily.stats</field>
<field name="arch" type="xml">
<list string="Tägliche Statistiken" create="false">
<field name="date"/>
<field name="weekday"/>
<field name="total_bookings_no_heroes" string="Buchungen"/>
<field name="unique_users_no_heroes" string="Nutzer"/>
</list>
</field>
</record>
<!-- Graph View - Nutzerzahlen pro Tag -->
<record id="view_daily_stats_graph" model="ir.ui.view">
<field name="name">open_workshop.daily.stats.graph</field>
<field name="model">open_workshop.daily.stats</field>
<field name="arch" type="xml">
<graph string="Nutzerzahlen pro Tag" type="bar" stacked="False">
<field name="date" interval="day"/>
<field name="is_weekend" type="col"/>
<field name="unique_users_no_heroes" type="measure"/>
</graph>
</field>
</record>
<!-- Pivot View -->
<record id="view_daily_stats_pivot" model="ir.ui.view">
<field name="name">open_workshop.daily.stats.pivot</field>
<field name="model">open_workshop.daily.stats</field>
<field name="arch" type="xml">
<pivot string="Tägliche Analyse">
<field name="date" interval="day" type="row"/>
<field name="weekday" type="col"/>
<field name="total_bookings_no_heroes" type="measure"/>
<field name="unique_users_no_heroes" type="measure"/>
</pivot>
</field>
</record>
<!-- Action für Tagesstatistiken -->
<record id="action_daily_stats" model="ir.actions.act_window">
<field name="name">Tägliche Nutzung</field>
<field name="res_model">open_workshop.daily.stats</field>
<field name="view_mode">graph,pivot,list</field>
<field name="context">{}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Keine täglichen Statistiken vorhanden
</p>
<p>
Tägliche Statistiken werden automatisch generiert.
</p>
</field>
</record>
<!-- Menu für Tagesstatistiken -->
<menuitem id="menu_daily_stats"
name="Tägliche Nutzung"
parent="menu_open_workshop_stats"
action="action_daily_stats"
sequence="30"/>
</odoo>

View File

@ -5,39 +5,52 @@
<field name="name">open_workshop.usage.dashboard</field>
<field name="model">open_workshop.usage.stats</field>
<field name="arch" type="xml">
<kanban class="o_kanban_dashboard">
<field name="total_sessions"/>
<field name="avg_per_day"/>
<field name="unique_users"/>
<kanban class="o_kanban_dashboard" default_order="period_start desc">
<field name="id"/>
<field name="total_bookings_no_heroes"/>
<field name="avg_per_day_no_heroes"/>
<field name="unique_users_no_heroes"/>
<field name="repeat_users_no_heroes"/>
<field name="total_revenue"/>
<field name="period_name"/>
<templates>
<t t-name="kanban-box">
<div class="oe_kanban_global_click">
<div class="o_kanban_record" style="cursor: pointer;">
<div class="o_kanban_record_top">
<strong><field name="period_name"/></strong>
</div>
<div class="o_kanban_record_body">
<div class="row">
<div class="col-6">
<div class="text-muted">Nutzungen</div>
<strong><field name="total_sessions"/></strong>
<div class="text-muted">Buchungen (ohne Theken)</div>
<strong class="fs-3"><field name="total_bookings_no_heroes"/></strong>
</div>
<div class="col-6">
<div class="text-muted">⌀/Tag</div>
<strong><field name="avg_per_day"/></strong>
<div class="text-muted">Nutzer (ohne Theken)</div>
<strong class="fs-3"><field name="unique_users_no_heroes"/></strong>
</div>
</div>
<div class="row mt-2">
<div class="col-6">
<div class="text-muted">Nutzer</div>
<strong><field name="unique_users"/></strong>
<div class="text-muted">⌀/Tag (ohne Theken)</div>
<strong><field name="avg_per_day_no_heroes" widget="float" digits="[10,2]"/></strong>
</div>
<div class="col-6">
<div class="text-muted">Wiederholungstäter</div>
<strong><field name="repeat_users_no_heroes"/></strong>
</div>
</div>
<div class="row mt-2">
<div class="col-12">
<div class="text-muted">Umsatz</div>
<strong><field name="total_revenue" widget="monetary"/></strong>
</div>
</div>
<div class="row mt-3">
<div class="col-12">
<button type="object" name="action_view_details" class="btn btn-primary w-100">📊 Tagesansicht</button>
</div>
</div>
</div>
</div>
</t>
@ -46,24 +59,24 @@
</field>
</record>
<!-- Dashboard Action -->
<!-- Dashboard Action - Alle -->
<record id="action_usage_dashboard" model="ir.actions.act_window">
<field name="name">Nutzungs-Dashboard</field>
<field name="res_model">open_workshop.usage.stats</field>
<field name="view_mode">kanban,graph,pivot</field>
<field name="view_mode">kanban,form,graph,pivot</field>
<field name="view_id" ref="view_usage_dashboard"/>
</record>
<!-- Submenu unter Point of Sale > Berichtswesen -->
<menuitem id="menu_open_workshop_reports"
<menuitem id="menu_open_workshop_stats"
name="Open Workshop"
parent="point_of_sale.menu_point_rep"
sequence="100"/>
<!-- Dashboard Menu -->
<menuitem id="menu_usage_dashboard"
name="Nutzungs-Dashboard"
parent="menu_open_workshop_reports"
name="📊 Alle Statistiken"
parent="menu_open_workshop_stats"
action="action_usage_dashboard"
sequence="1"/>
</odoo>

View File

@ -0,0 +1,119 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Graph: Jahresvergleich Buchungen -->
<record id="view_usage_stats_yearly_comparison" model="ir.ui.view">
<field name="name">open_workshop.usage.stats.graph.yearly</field>
<field name="model">open_workshop.usage.stats</field>
<field name="arch" type="xml">
<graph string="Buchungen pro Monat im Jahresvergleich" type="bar" stacked="0" order="month asc">
<field name="month" type="row"/>
<field name="year" type="col"/>
<field name="total_bookings_no_heroes" type="measure"/>
</graph>
</field>
</record>
<!-- Graph: Durchschnittliche Nutzer Trend -->
<record id="view_usage_stats_avg_users_trend" model="ir.ui.view">
<field name="name">open_workshop.usage.stats.graph.avg.trend</field>
<field name="model">open_workshop.usage.stats</field>
<field name="arch" type="xml">
<graph string="Durchschnittliche Nutzer pro Tag (Trend)" type="bar" stacked="0" order="month asc">
<field name="month" type="row"/>
<field name="year" type="col"/>
<field name="avg_per_day_no_heroes" type="measure"/>
</graph>
</field>
</record>
<!-- Graph: Wiederholungstäter -->
<record id="view_usage_stats_repeat_users" model="ir.ui.view">
<field name="name">open_workshop.usage.stats.graph.repeat</field>
<field name="model">open_workshop.usage.stats</field>
<field name="arch" type="xml">
<graph string="Wiederholungstäter pro Monat" type="bar" stacked="0" order="month asc">
<field name="month" type="row"/>
<field name="year" type="col"/>
<field name="repeat_users_no_heroes" type="measure"/>
</graph>
</field>
</record>
<!-- Graph: Nutzer pro Monat -->
<record id="view_usage_stats_users_per_month" model="ir.ui.view">
<field name="name">open_workshop.usage.stats.graph.users</field>
<field name="model">open_workshop.usage.stats</field>
<field name="arch" type="xml">
<graph string="Anzahl Nutzer pro Monat" type="bar" stacked="0" order="month asc">
<field name="month" type="row"/>
<field name="year" type="col"/>
<field name="unique_users_no_heroes" type="measure"/>
</graph>
</field>
</record>
<!-- ACTION: Jahresvergleich -->
<record id="action_yearly_comparison" model="ir.actions.act_window">
<field name="name">Jahresvergleich Buchungen</field>
<field name="res_model">open_workshop.usage.stats</field>
<field name="view_mode">graph</field>
<field name="view_id" ref="view_usage_stats_yearly_comparison"/>
<field name="domain">[('period_type', '=', 'month')]</field>
</record>
<!-- ACTION: Durchschnitt Trend -->
<record id="action_avg_users_trend" model="ir.actions.act_window">
<field name="name">Ø Nutzer pro Tag (Trend)</field>
<field name="res_model">open_workshop.usage.stats</field>
<field name="view_mode">graph</field>
<field name="view_id" ref="view_usage_stats_avg_users_trend"/>
<field name="domain">[('period_type', '=', 'month')]</field>
</record>
<!-- ACTION: Wiederholungstäter -->
<record id="action_repeat_users" model="ir.actions.act_window">
<field name="name">Wiederholungstäter</field>
<field name="res_model">open_workshop.usage.stats</field>
<field name="view_mode">graph</field>
<field name="view_id" ref="view_usage_stats_repeat_users"/>
<field name="domain">[('period_type', '=', 'month')]</field>
</record>
<!-- ACTION: Nutzer pro Monat -->
<record id="action_users_per_month" model="ir.actions.act_window">
<field name="name">Nutzer pro Monat</field>
<field name="res_model">open_workshop.usage.stats</field>
<field name="view_mode">graph</field>
<field name="view_id" ref="view_usage_stats_users_per_month"/>
<field name="domain">[('period_type', '=', 'month')]</field>
</record>
<!-- MENU: Jahresvergleich -->
<menuitem id="menu_yearly_comparison"
name="📊 Jahresvergleich"
parent="menu_open_workshop_stats"
action="action_yearly_comparison"
sequence="20"/>
<!-- MENU: Durchschnitt Trend -->
<menuitem id="menu_avg_users_trend"
name="📈 Ø Nutzer/Tag Trend"
parent="menu_open_workshop_stats"
action="action_avg_users_trend"
sequence="21"/>
<!-- MENU: Wiederholungstäter -->
<menuitem id="menu_repeat_users"
name="🔁 Wiederholungstäter"
parent="menu_open_workshop_stats"
action="action_repeat_users"
sequence="22"/>
<!-- MENU: Nutzer pro Monat -->
<menuitem id="menu_users_per_month"
name="👥 Nutzer pro Monat"
parent="menu_open_workshop_stats"
action="action_users_per_month"
sequence="23"/>
</odoo>

View File

@ -9,9 +9,10 @@
<field name="period_name"/>
<field name="period_start"/>
<field name="period_end"/>
<field name="total_sessions" string="Gesamt Nutzungen"/>
<field name="avg_per_day" string="⌀ pro Tag"/>
<field name="unique_users" string="Einz. Nutzer"/>
<field name="total_bookings_no_heroes" string="Buchungen (ohne Theken)"/>
<field name="unique_users_no_heroes" string="Nutzer (ohne Theken)"/>
<field name="avg_per_day_no_heroes" string="⌀/Tag (ohne Theken)"/>
<field name="repeat_users_no_heroes" string="Wiederholungstäter"/>
<field name="total_revenue" widget="monetary"/>
</list>
</field>
@ -33,12 +34,19 @@
<field name="period_start"/>
<field name="period_end"/>
</group>
<group string="Statistiken">
<group string="Statistiken (Alle)">
<field name="total_sessions"/>
<field name="avg_per_day"/>
<field name="unique_users"/>
<field name="repeat_users"/>
<field name="total_revenue"/>
</group>
<group string="Statistiken (Ohne Thekenhelden)">
<field name="total_bookings_no_heroes"/>
<field name="avg_per_day_no_heroes"/>
<field name="unique_users_no_heroes"/>
<field name="repeat_users_no_heroes"/>
</group>
</group>
<notebook>
<page string="POS Sessions">
@ -73,14 +81,14 @@
</field>
</record>
<!-- Graph View - Bar Chart -->
<!-- Graph View - Bar Chart (Jahresvergleich) -->
<record id="view_usage_stats_graph_bar" model="ir.ui.view">
<field name="name">open_workshop.usage.stats.graph.bar</field>
<field name="model">open_workshop.usage.stats</field>
<field name="arch" type="xml">
<graph string="Nutzungen pro Monat" type="bar" sample="1" stacked="0">
<graph string="Buchungen pro Monat im Jahresvergleich (ohne Thekenhelden)" type="bar" sample="1" stacked="0">
<field name="period_start" interval="month"/>
<field name="total_sessions" type="measure"/>
<field name="total_bookings_no_heroes" type="measure"/>
</graph>
</field>
</record>
@ -90,10 +98,10 @@
<field name="name">open_workshop.usage.stats.graph.line</field>
<field name="model">open_workshop.usage.stats</field>
<field name="arch" type="xml">
<graph string="Nutzungen (Historie)" type="line" sample="1">
<graph string="Durchschnittliche Nutzer pro Tag (ohne Thekenhelden)" type="line" sample="1">
<field name="period_start" interval="month"/>
<field name="total_sessions" type="measure"/>
<field name="avg_per_day" type="measure"/>
<field name="avg_per_day_no_heroes" type="measure"/>
<field name="unique_users_no_heroes" type="measure"/>
</graph>
</field>
</record>