
    giaB                         d Z ddlZddlZddlmZ ddlmZmZmZmZ ddl	Z	 e	j
        e          Z G d d          Z G d d          Z G d	 d
          ZdS )a  
ENIGMA Inventario - Database Models
====================================

Models per gestione inventario con database MySQL.
Usa le tabelle esistenti:
- inv_sessioni_inventario
- inv_risultati_inventario
- inv_cache_prodotti

Author: HetGi & Claude
Date: 2026-01-14
    N)datetime)OptionalDictListAnyc            
           e Zd ZdZdefdZd Zddededed	ee         fd
Z	deded	ee         fdZ
deded	ee         fdZddededed	efdZddeded	ee         fdZdS )InventorySessionz'Model per gestione sessioni inventario.	db_configc                     || _         dS zs
        Inizializza model.
        
        Args:
            db_config: {host, user, password, database}
        Nr
   selfr
   s     ?/var/www/tmov.alphamb/tmov_inventario/models_inventory_fixed.py__init__zInventorySession.__init__        #    c                     t          j        | j        d         | j        d         | j        d         | j        d         dt           j        j                  S zCrea connessione database.hostuserpassworddatabaseutf8mb4)r   r   r   r   charsetcursorclasspymysqlconnectr
   cursors
DictCursorr   s    r   _get_connectionz InventorySession._get_connection$   N    ''^J/^J/2
 
 
 	
r      	tenant_iduser_idsede_idreturnc                    |                                  }|                                }	 |                    d||f           |                                }|rVt                              d| d|d                     |d         |                                 |                                 S d}|                    ||||f           |                                 |j        }t          	                    d| d|            ||                                 |                                 S # t          $ rd}	|                                 t                              d|	            Y d	}	~	|                                 |                                 d	S d	}	~	ww xY w# |                                 |                                 w xY w)
z
        Crea nuova sessione inventario.
        
        Args:
            tenant_id: ID tenant
            user_id: ID utente
            sede_id: ID sede (default 1)
        
        Returns:
            ID sessione creata, None se errore
        z
                SELECT id FROM inv_sessioni_inventario
                WHERE id_tenant = %s AND id_user = %s AND stato = 'aperta'
                LIMIT 1
            u   Sessione già aperta per user z: idz
                INSERT INTO inv_sessioni_inventario (
                    id_tenant, id_user, id_sede, timestamp_inizio, stato
                ) VALUES (
                    %s, %s, %s, NOW(), 'aperta'
                )
            zSessione creata: z
 per user zErrore creazione sessione: N)r#   cursorexecutefetchoneloggerwarningclosecommit	lastrowidinfo	Exceptionrollbackerror)
r   r&   r'   r(   connr,   existingsql
session_ides
             r   create_sessionzInventorySession.create_session/   s    ##%%"	NN  W%	' ' ' ((H &[[[8TX>[[\\\~, LLNNNJJLLLL)C NN3GW =>>>KKMMM)JKKKJKK'KKLLL LLNNNJJLLLL  	 	 	MMOOOLL:q::;;;444LLNNNJJLLLLL	
 LLNNNJJLLLLs1   AD. .AD. .
F81F)F FF *G	c                 Z   |                                  }|                                }	 d}|                    |||f           |                                |                                 |                                 S # |                                 |                                 w xY w)z
        Ottiene sessione aperta corrente.
        
        Args:
            tenant_id: ID tenant
            user_id: ID utente
        
        Returns:
            Dati sessione o None
        ay  
                SELECT 
                    id, id_tenant, id_user, id_sede,
                    timestamp_inizio, stato, note,
                    total_items, total_scans
                FROM inv_sessioni_inventario
                WHERE id_tenant = %s AND id_user = %s AND stato = 'aperta'
                ORDER BY timestamp_inizio DESC
                LIMIT 1
            r#   r,   r-   r.   r1   )r   r&   r'   r8   r,   r:   s         r   get_active_sessionz#InventorySession.get_active_sessionb   s     ##%%		C NN3G 4555??$$LLNNNJJLLLL LLNNNJJLLLL   -B   *B*r;   c                 Z   |                                  }|                                }	 d}|                    |||f           |                                |                                 |                                 S # |                                 |                                 w xY w)z
        Ottiene dettagli sessione.
        
        Args:
            session_id: ID sessione
            tenant_id: ID tenant
        
        Returns:
            Dati sessione o None
        a  
                SELECT 
                    s.*,
                    u.email as user_email,
                    u.nome as user_name,
                    COUNT(r.id) as items_count
                FROM inv_sessioni_inventario s
                LEFT JOIN tenant_users u ON s.id_user = u.id
                LEFT JOIN inv_risultati_inventario r ON s.id = r.id_sessione
                WHERE s.id = %s AND s.id_tenant = %s
                GROUP BY s.id
            r?   r   r;   r&   r8   r,   r:   s         r   get_sessionzInventorySession.get_session   s     ##%%	C NN3Y 7888??$$LLNNNJJLLLL LLNNNJJLLLLrA   Nnotec                 $   |                                  }|                                }	 |                    d|f           |                                }|r|d         nd}|r|d         nd}d}	|                    |	|||||f           |                                 |j        }
t                              d| d| d           |
dk    |                                 |                                 S # t          $ rd}|
                                 t                              d	|            Y d
}~|                                 |                                 dS d
}~ww xY w# |                                 |                                 w xY w)z
        Chiude una sessione inventario.
        
        Args:
            session_id: ID sessione
            tenant_id: ID tenant
            note: Note opzionali
        
        Returns:
            True se successo, False altrimenti
        z
                SELECT COUNT(DISTINCT id) as total_items, COUNT(id) as total_scans
                FROM inv_risultati_inventario
                WHERE id_sessione = %s
            total_itemsr   total_scansaN  
                UPDATE inv_sessioni_inventario
                SET stato = 'chiusa',
                    timestamp_fine = NOW(),
                    total_items = %s,
                    total_scans = %s,
                    note = COALESCE(%s, note)
                WHERE id = %s AND id_tenant = %s AND stato = 'aperta'
            z	Sessione z	 chiusa (z items)zErrore chiusura sessione: NF)r#   r,   r-   r.   r2   rowcountr/   r4   r1   r5   r6   r7   )r   r;   r&   rE   r8   r,   countsrG   rH   r:   affectedr<   s               r   close_sessionzInventorySession.close_session   s    ##%%#	NN  	      __&&F39@&//qK39@&//qKC NN3k4Y WXXXKKMMMHKKMJMMMMMNNNa< LLNNNJJLLLL  	 	 	MMOOOLL9a99:::555LLNNNJJLLLLL	
 LLNNNJJLLLLs*   B!C4 4
E">1E/E% E""E% %*F
   limitc                 Z   |                                  }|                                }	 d}|                    |||f           |                                |                                 |                                 S # |                                 |                                 w xY w)z
        Ottiene sessioni recenti.
        
        Args:
            tenant_id: ID tenant
            limit: Numero massimo risultati
        
        Returns:
            Lista sessioni
        a	  
                SELECT 
                    s.*,
                    u.email as user_email,
                    u.nome as user_name,
                    COUNT(r.id) as items_count
                FROM inv_sessioni_inventario s
                LEFT JOIN tenant_users u ON s.id_user = u.id
                LEFT JOIN inv_risultati_inventario r ON s.id = r.id_sessione
                WHERE s.id_tenant = %s
                GROUP BY s.id
                ORDER BY s.timestamp_inizio DESC
                LIMIT %s
            r#   r,   r-   fetchallr1   )r   r&   rN   r8   r,   r:   s         r   get_recent_sessionsz$InventorySession.get_recent_sessions   s     ##%%	C NN3E 2333??$$LLNNNJJLLLL LLNNNJJLLLLrA   )r%   )N)rM   )__name__
__module____qualname____doc__r   r   r#   intr   r=   r@   rD   strboolrL   r   rR    r   r   r	   r	      sE       11#$ # # # #	
 	
 	
1 1 1c 1C 1PXY\P] 1 1 1 1fC # (4.    >c c htn    B2 2 2 23 2RV 2 2 2 2h! !S ! !d4j ! ! ! ! ! !r   r	   c                       e Zd ZdZdefdZd Z	 	 dded	ed
ede	e         de
dede	e         fdZded	edee         fdZdedede
fdZdS )InventoryItemz#Model per gestione item inventario.r
   c                     || _         dS r   r   r   s     r   r   zInventoryItem.__init__   r   r   c                     t          j        | j        d         | j        d         | j        d         | j        d         dt           j        j                  S r   r   r"   s    r   r#   zInventoryItem._get_connection  r$   r   NFr%   r;   r&   barcodeproduct_datafound_in_apiquantitar)   c                    |                                  }|                                }	 d}	d}
d}d}|r|                    d          }	|                    d          p|                    d          }
t          |                    d          t                    r)|                    di                               d          nd}|                    d          }|                    d||f           |                                }|r|d         |z   }|                    d	||d         f           |                                 t          	                    d
|d          d|            |d         |
                                 |
                                 S d}|rt          j        |          nd}| }|                    |||||	||||
|||f           |                                 |j        }t          	                    d| d|            ||
                                 |
                                 S # t          $ rd}|                                 t                              d|            Y d}~|
                                 |
                                 dS d}~ww xY w# |
                                 |
                                 w xY w)u  
        Aggiunge item alla sessione inventario.
        
        Args:
            session_id: ID sessione
            tenant_id: ID tenant
            barcode: Codice a barre
            product_data: Dati prodotto da API (opzionale)
            found_in_api: Se trovato in Cassanova
            quantita: Quantità (default 1)
        
        Returns:
            ID item creato, None se errore
        Nr+   descriptionnamecategorypricez
                SELECT id, quantita_fisica FROM inv_risultati_inventario
                WHERE id_sessione = %s AND barcode = %s
                LIMIT 1
            quantita_fisicaz
                    UPDATE inv_risultati_inventario
                    SET quantita_fisica = %s
                    WHERE id = %s
                zItem aggiornato: u   , nuova quantità: a  
                    INSERT INTO inv_risultati_inventario (
                        id_tenant, id_sessione, barcode, codice_prodotto,
                        product_data, found_in_api, manual_entry,
                        scanned_at, nome_prodotto, categoria, 
                        quantita_fisica, prezzo_pubblico
                    ) VALUES (
                        %s, %s, %s, %s, %s, %s, %s, NOW(), %s, %s, %s, %s
                    )
                zItem creato: z per sessione zErrore add_item: )r#   r,   get
isinstancedictr-   r.   r2   r/   r4   r1   jsondumpsr3   r5   r6   r7   )r   r;   r&   r_   r`   ra   rb   r8   r,   codice_prodottonome_prodotto	categoriaprezzo_pubblicor9   new_quantityr:   product_jsonmanual_entryitem_idr<   s                       r   add_itemzInventoryItem.add_item  s   " ##%%C	"O MI"O <"."2"24"8"8 , 0 0 ? ? [<CSCSTZC[C[LVWcWgWghrWsWsuyLzLz  EL,,Z<<@@HHH  AE	"."2"27";"; NN  g&	( ( ( ((H %'(9:XE   #HTN3	5 5 5
 aaaS_aabbb~D LLNNNJJLLLL?	 <HQtz,777T#//sz7O ,!9h%   
  *OGOO:OOPPP LLNNNJJLLLL  	 	 	MMOOOLL0Q00111444LLNNNJJLLLLL	
 LLNNNJJLLLLs1   E	H? A:H? ?
J-	1J(:J0 (J--J0 0*Kc                 Z   |                                  }|                                }	 d}|                    |||f           |                                |                                 |                                 S # |                                 |                                 w xY w)z
        Ottiene tutti gli item di una sessione.
        
        Args:
            session_id: ID sessione
            tenant_id: ID tenant
        
        Returns:
            Lista items
        z
                SELECT *
                FROM inv_risultati_inventario
                WHERE id_sessione = %s AND id_tenant = %s
                ORDER BY scanned_at DESC
            rP   rC   s         r   get_session_itemszInventoryItem.get_session_itemsj  s     ##%%	C NN3Y 7888??$$LLNNNJJLLLL LLNNNJJLLLLrA   ru   c                    |                                  }|                                }	 d}|                    |||f           |                                 |j        }t
                              d| d           |dk    |                                 |                                 S # t          $ rd}|	                                 t
          
                    d|            Y d}~|                                 |                                 dS d}~ww xY w# |                                 |                                 w xY w)z
        Elimina un item dalla sessione.
        
        Args:
            item_id: ID item
            session_id: ID sessione
        
        Returns:
            True se successo, False altrimenti
        zu
                DELETE FROM inv_risultati_inventario
                WHERE id = %s AND id_sessione = %s
            zItem z
 eliminator   zErrore delete_item: NF)r#   r,   r-   r2   rI   r/   r4   r1   r5   r6   r7   )r   ru   r;   r8   r,   r:   rK   r<   s           r   delete_itemzInventoryItem.delete_item  s2    ##%%	C NN3* 5666KKMMMHKK3333444a< LLNNNJJLLLL  	 	 	MMOOOLL333444555LLNNNJJLLLLL	
 LLNNNJJLLLLs*   AB+ +
D51D&D DD *E)NFr%   )rS   rT   rU   rV   r   r   r#   rW   rX   r   rY   rv   r   rx   rz   rZ   r   r   r\   r\      s       --#$ # # # #	
 	
 	
 LQ!"W W3 W3 W W'~WDHWW'/}W W W WrC C DJ    6 3  C  D            r   r\   c                   d    e Zd ZdZdefdZd Z	 ddededed	ed
e	f
dZ
deded
ee         fdZdS )ProductCachez&Model per cache prodotti da Cassanova.r
   c                     || _         dS r   r   r   s     r   r   zProductCache.__init__  r   r   c                     t          j        | j        d         | j        d         | j        d         | j        d         dt           j        j                  S r   r   r"   s    r   r#   zProductCache._get_connection  r$   r   Q r&   r_   r`   ttlr)   c                    |                                  }|                                }	 d}t          j        |          }|                    |||||f           |                                 t                              d| d           	 |                                 |                                 dS # t          $ rd}	|
                                 t                              d|	            Y d}	~	|                                 |                                 dS d}	~	ww xY w# |                                 |                                 w xY w)a;  
        Salva prodotto in cache.
        
        Args:
            tenant_id: ID tenant
            barcode: Codice a barre
            product_data: Dati prodotto da Cassanova
            ttl: Time-to-live in secondi (default 24h)
        
        Returns:
            True se successo, False altrimenti
        a  
                INSERT INTO inv_cache_prodotti (
                    id_tenant, codice_barcode, dati_cassanova, 
                    cache_timestamp, ttl
                ) VALUES (
                    %s, %s, %s, NOW(), %s
                )
                ON DUPLICATE KEY UPDATE
                    dati_cassanova = VALUES(dati_cassanova),
                    cache_timestamp = NOW(),
                    ttl = VALUES(ttl)
            z	Prodotto z salvato in cacheTzErrore cache_product: NF)r#   r,   rl   rm   r-   r2   r/   debugr1   r5   r6   r7   )
r   r&   r_   r`   r   r8   r,   r:   rs   r<   s
             r   cache_productzProductCache.cache_product  s<    ##%%	C  :l33LNN3G\3 GHHHKKMMMLL?W???@@@ LLNNNJJLLLLL  	 	 	MMOOOLL5!55666555LLNNNJJLLLLL	
 LLNNNJJLLLLs*   A"B7 7
D%1D 2D(  D%%D( (*Ec                    |                                  }|                                }	 d}|                    |||f           |                                }|rJ|d         rBt	          j        |d                   |                                 |                                 S 	 |                                 |                                 dS # t          $ rP}t          	                    d|            Y d}~|                                 |                                 dS d}~ww xY w# |                                 |                                 w xY w)z
        Recupera prodotto dalla cache.
        
        Args:
            tenant_id: ID tenant
            barcode: Codice a barre
        
        Returns:
            Dati prodotto o None se non in cache o scaduto
        z
                SELECT dati_cassanova, cache_timestamp, ttl
                FROM inv_cache_prodotti
                WHERE id_tenant = %s AND codice_barcode = %s
                AND TIMESTAMPDIFF(SECOND, cache_timestamp, NOW()) < ttl
            dati_cassanovaNzErrore get_cached_product: )
r#   r,   r-   r.   rl   loadsr1   r5   r/   r7   )r   r&   r_   r8   r,   r:   resultr<   s           r   get_cached_productzProductCache.get_cached_product  sH    ##%%	C NN3G 4555__&&F <&!12 <z&)9":;; LLNNNJJLLLL  LLNNNJJLLLLL  	 	 	LL:q::;;;444LLNNNJJLLLLL	 LLNNNJJLLLLs*   AC 
D)D$6D, $D))D, ,*EN)r   )rS   rT   rU   rV   r   r   r#   rW   rX   rY   r   r   r   rZ   r   r   r|   r|     s        00#$ # # # #	
 	
 	
 5:, ,s ,S ,#',.1,>B, , , ,\!C !# !(4. ! ! ! ! ! !r   r|   )rV   r   rl   r   typingr   r   r   r   logging	getLoggerrS   r/   r	   r\   r|   rZ   r   r   <module>r      s            , , , , , , , , , , , , 		8	$	$_ _ _ _ _ _ _ _Dk k k k k k k k\f f f f f f f f f fr   