11import datetime
22from typing import Dict
3+
4+ import pytz
35from pytz import UTC
46
57from odoo import http
1315
1416class 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