Skip to content

Commit 2a62bb3

Browse files
committed
[FIX] portal and core
1 parent 88bf1b9 commit 2a62bb3

19 files changed

Lines changed: 1496 additions & 156 deletions
Lines changed: 234 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import datetime
22
from typing import Dict
3+
4+
import pytz
35
from pytz import UTC
46

57
from odoo import http
@@ -13,6 +15,216 @@
1315

1416
class PortalAnagrafiche(http.Controller):
1517

18+
def _get_day_start_utc(self, user):
19+
user_tz = pytz.timezone(user.tz or 'UTC')
20+
local_now = datetime.datetime.now(user_tz)
21+
return local_now.replace(
22+
hour=0,
23+
minute=0,
24+
second=0,
25+
microsecond=0,
26+
).astimezone(UTC).replace(tzinfo=None)
27+
28+
def _build_access_domain(self, user, query: str, filter_values: Dict):
29+
search_domain = [
30+
# The portal list must be built only from stamping events.
31+
("typology", "=", "stamping"),
32+
("ca_punto_accesso_category_id", "!=", False),
33+
("datetime_event", ">=", self._get_day_start_utc(user)),
34+
]
35+
if query:
36+
search_domain = expression.AND([
37+
search_domain,
38+
[("ca_persona_id.display_name", "ilike", query.strip())],
39+
])
40+
if filter_values.get("internal"):
41+
search_domain = expression.AND([
42+
search_domain,
43+
[("ca_persona_id.is_internal", "=", True)],
44+
])
45+
elif filter_values.get("external"):
46+
search_domain = expression.AND([
47+
search_domain,
48+
[("ca_persona_id.is_external", "=", True)],
49+
])
50+
if filter_values.get("is_present"):
51+
search_domain = expression.AND([
52+
search_domain,
53+
[("ca_persona_id.present", "=", "yes")],
54+
])
55+
if filter_values.get("pa_category_id"):
56+
search_domain = expression.AND([
57+
search_domain,
58+
[("ca_punto_accesso_category_id", "=", filter_values["pa_category_id"])],
59+
])
60+
return search_domain
61+
62+
def _normalize_order(self, order_by: str, order_dir: str):
63+
if order_by not in ('display_name', 'last_event'):
64+
order_by = 'last_event'
65+
if order_dir not in ('asc', 'desc'):
66+
order_dir = 'asc' if order_by == 'display_name' else 'desc'
67+
return order_by, order_dir
68+
69+
def _get_anagrafiche_data(
70+
self, env, user, limit: int, offset: int, query: str,
71+
filter_values: Dict, order_by: str = 'last_event',
72+
order_dir: str = 'desc'):
73+
access_model = env['ca.anag_registro_accesso']
74+
persona_model = env['ca.persona']
75+
filter_values = filter_values or {}
76+
order_by, order_dir = self._normalize_order(order_by, order_dir)
77+
access_domain = self._build_access_domain(user, query, filter_values)
78+
79+
grouped_accesses = access_model.read_group(
80+
access_domain,
81+
['ca_persona_id', 'last_event:max(datetime_event)'],
82+
['ca_persona_id'],
83+
lazy=False,
84+
)
85+
grouped_accesses = [
86+
group for group in grouped_accesses if group.get('ca_persona_id')
87+
]
88+
all_person_ids = [group['ca_persona_id'][0] for group in grouped_accesses]
89+
personas_by_id = {
90+
persona.id: persona
91+
for persona in persona_model.browse(all_person_ids).exists()
92+
}
93+
sortable_entries = []
94+
for group in grouped_accesses:
95+
person_id = group['ca_persona_id'][0]
96+
persona = personas_by_id.get(person_id)
97+
if not persona:
98+
continue
99+
sortable_entries.append({
100+
'person_id': person_id,
101+
'display_name_key': (persona.display_name or '').casefold(),
102+
'last_event': group.get('last_event') or datetime.datetime.min,
103+
})
104+
reverse = order_dir == 'desc'
105+
if order_by == 'display_name':
106+
sortable_entries.sort(
107+
key=lambda entry: (
108+
entry['display_name_key'],
109+
entry['person_id'],
110+
),
111+
reverse=reverse,
112+
)
113+
else:
114+
sortable_entries.sort(
115+
key=lambda entry: (
116+
entry['last_event'],
117+
entry['person_id'],
118+
),
119+
reverse=reverse,
120+
)
121+
122+
total = len(sortable_entries)
123+
page_end = offset + limit if limit is not None else None
124+
paged_entries = sortable_entries[offset:page_end]
125+
person_ids = [entry['person_id'] for entry in paged_entries]
126+
data = {"items": [], "total": total}
127+
if not person_ids:
128+
return data
129+
130+
latest_access_rows = access_model.search_read(
131+
expression.AND([access_domain, [('ca_persona_id', 'in', person_ids)]]),
132+
fields=[
133+
'ca_persona_id',
134+
'datetime_event',
135+
'direction',
136+
'ca_punto_accesso_id',
137+
'ca_punto_accesso_category_id',
138+
],
139+
order='datetime_event desc, id desc',
140+
)
141+
latest_access_map = {}
142+
for access in latest_access_rows:
143+
person_id = access['ca_persona_id'][0]
144+
if person_id not in latest_access_map:
145+
latest_access_map[person_id] = access
146+
147+
direction_selection = dict(
148+
access_model.fields_get(['direction'])['direction']['selection']
149+
)
150+
present_labels = dict(
151+
persona_model.fields_get(['present'])['present']['selection']
152+
)
153+
154+
access_point_ids = {
155+
access['ca_punto_accesso_id'][0]
156+
for access in latest_access_map.values()
157+
if access.get('ca_punto_accesso_id')
158+
}
159+
access_point_names = {
160+
point.id: point.display_name
161+
for point in env['ca.punto_accesso'].browse(access_point_ids)
162+
}
163+
164+
for person_id in person_ids:
165+
persona = personas_by_id.get(person_id)
166+
if not persona:
167+
continue
168+
row = {
169+
'id': persona.id,
170+
'display_name': persona.display_name,
171+
'fiscalcode': persona.fiscalcode,
172+
'is_external': persona.is_external,
173+
'is_internal': persona.is_internal,
174+
'present': (
175+
persona.present,
176+
present_labels.get(persona.present),
177+
),
178+
'datetime_event': '',
179+
'last_reading_event': '',
180+
'event_direction': '',
181+
'event_punto_accesso': '',
182+
}
183+
last_access = latest_access_map.get(persona.id)
184+
if last_access:
185+
if last_access.get('datetime_event'):
186+
row['datetime_event'] = format_datetime(
187+
env,
188+
last_access['datetime_event'],
189+
tz=user.tz,
190+
lang_code=user.lang,
191+
)
192+
raw_direction = last_access.get('direction')
193+
row['event_direction'] = direction_selection.get(
194+
raw_direction, raw_direction or ''
195+
)
196+
access_category = last_access.get('ca_punto_accesso_category_id')
197+
if access_category:
198+
row['event_punto_accesso'] = access_category[1]
199+
access_point = last_access.get('ca_punto_accesso_id')
200+
if access_point and not row['event_punto_accesso']:
201+
row['event_punto_accesso'] = access_point_names.get(
202+
access_point[0], access_point[1]
203+
)
204+
data["items"].append(row)
205+
return data
206+
207+
def _get_anagrafiche_access_point_categories(self, env, user):
208+
access_domain = self._build_access_domain(user, None, {})
209+
grouped_accesses = env['ca.anag_registro_accesso'].read_group(
210+
access_domain,
211+
['ca_punto_accesso_category_id'],
212+
['ca_punto_accesso_category_id'],
213+
lazy=False,
214+
)
215+
category_ids = [
216+
group['ca_punto_accesso_category_id'][0]
217+
for group in grouped_accesses
218+
if group.get('ca_punto_accesso_category_id')
219+
]
220+
if not category_ids:
221+
return []
222+
return env['ca.punto_accesso_category'].sudo().search_read(
223+
[('id', 'in', category_ids)],
224+
fields=['id', 'name', 'display_name'],
225+
order='name asc, id asc',
226+
)
227+
16228
@http.route('/anagrafiche', type='http', auth='user', website=True)
17229
def anagrafiche(self, **kwargs):
18230
user = request.env.user
@@ -21,85 +233,32 @@ def anagrafiche(self, **kwargs):
21233
return request.render('controllo_accessi_portale.portal_partner_view', {})
22234

23235
@http.route('/get/anagrafiche', type='json', auth='user', website=True, csrf=False)
24-
def get_anagrafiche(self, limit: int, offset: int, query: str, filter: Dict, **kwargs):
236+
def get_anagrafiche(
237+
self, limit: int, offset: int, query: str, filter: Dict,
238+
order_by: str = 'last_event', order_dir: str = 'desc', **kwargs):
25239
user = request.env.user
26-
today_at_00 = datetime.datetime.combine(datetime.date.today(), datetime.time.min).astimezone(UTC).replace(tzinfo=None)
27240
if not user.has_group('controllo_accessi_portale.inrim_access_portal'):
28241
raise Forbidden()
29-
search_domain = [("ca_tag_ids", "!=", False), ("last_access", ">=", today_at_00)]
30-
if query:
31-
search_domain = expression.AND([[("display_name", "ilike", query)], search_domain])
32-
if filter:
33-
if filter.get("internal"):
34-
search_domain = expression.AND([[("is_internal", "=", True)], search_domain])
35-
elif filter.get("external"):
36-
search_domain = expression.AND([[("is_external", "=", True)], search_domain])
37-
if filter.get("is_present"):
38-
search_domain = expression.AND([[("present", "=", "yes")], search_domain])
39-
if filter.get("pa_category_id"):
40-
search_domain = expression.AND([[("person_access_ids.ca_punto_accesso_category_id", "=", filter["pa_category_id"])], search_domain])
41-
records = request.env['ca.persona'].search(search_domain, limit=limit, offset=offset)
42-
count = request.env['ca.persona'].search_count(search_domain)
43-
access_map = {}
44-
if records:
45-
person_ids = records.ids
46-
access_domain = [
47-
('ca_persona_id', 'in', person_ids),
48-
('ca_punto_accesso_category_id', '!=', False),
49-
('typology', '=', 'stamping')
50-
]
51-
if filter and filter.get("pa_category_id"):
52-
access_domain = expression.AND([[("ca_punto_accesso_category_id", "=", filter["pa_category_id"])], access_domain])
53-
all_accesses = request.env['ca.anag_registro_accesso'].search_read(
54-
access_domain,
55-
fields=['ca_persona_id', 'datetime_event', 'direction', 'ca_punto_accesso_category_id'],
56-
order='datetime_event desc, id desc'
57-
)
58-
for acc in all_accesses:
59-
p_id = acc['ca_persona_id'][0]
60-
if p_id not in access_map:
61-
access_map[p_id] = acc
62-
data = {"items": [], "total": count}
63-
AccessModel = request.env['ca.anag_registro_accesso']
64-
direction_selection = dict(AccessModel.fields_get(['direction'])['direction']['selection'])
65-
cat_ids = set()
66-
for acc in access_map.values():
67-
if acc['ca_punto_accesso_category_id']:
68-
cat_ids.add(acc['ca_punto_accesso_category_id'][0])
69-
cat_names = {}
70-
if cat_ids:
71-
cats = request.env['ca.punto_accesso_category'].browse(cat_ids)
72-
for c in cats:
73-
cat_names[c.id] = c.display_name
74-
present_labels = dict(request.env['ca.persona'].fields_get(['present'])['present']['selection'])
75-
for record in records:
76-
row = {
77-
'id': record.id,
78-
'display_name': record.display_name,
79-
'fiscalcode': record.fiscalcode,
80-
'is_external': record.is_external,
81-
'is_internal': record.is_internal,
82-
'present': (record.present, present_labels.get(record.present)),
83-
'datetime_event': '',
84-
'last_reading_event': '',
85-
'event_direction': '',
86-
'event_punto_accesso': ''
87-
}
88-
last_access = access_map.get(record.id)
89-
if last_access:
90-
if last_access['datetime_event']:
91-
row['datetime_event'] = format_datetime(request.env, last_access['datetime_event'], tz=user.tz, lang_code=user.lang)
92-
raw_dir = last_access['direction']
93-
row['event_direction'] = direction_selection.get(raw_dir, raw_dir)
94-
cat_tuple = last_access['ca_punto_accesso_category_id']
95-
if cat_tuple:
96-
row['event_punto_accesso'] = cat_names.get(cat_tuple[0], cat_tuple[1])
97-
data["items"].append(row)
98-
return data
242+
return self._get_anagrafiche_data(
243+
request.env,
244+
user,
245+
limit,
246+
offset,
247+
query,
248+
filter,
249+
order_by,
250+
order_dir,
251+
)
99252

100-
@http.route('/get/anagrafiche/ca_punto_accesso_category', type='json', auth='user', website=True, csrf=False)
101-
def anagrafiche_pa_category(self, **kwargs):
253+
@http.route(
254+
['/get/anagrafiche/ca_punto_accesso_category', '/get/anagrafiche/ca_punto_accesso'],
255+
type='json',
256+
auth='user',
257+
website=True,
258+
csrf=False,
259+
)
260+
def anagrafiche_punto_accesso_category(self, **kwargs):
102261
user = request.env.user
103262
if not check_access_permission(user):
104263
raise NotFound()
105-
return request.env['ca.punto_accesso_category'].search([("ca_access_point_ids", "!=", False)]).read()
264+
return self._get_anagrafiche_access_point_categories(request.env, user)

0 commit comments

Comments
 (0)