
    a{iΗ                        d Z ddlmZmZmZmZ ddlmZ ddlmZ ddl	Z	ddl
Z
 e	j        e          Z eded          Zd	 Zd
 Ze                    ddg          ed                         Ze                    ddg          ed                         Ze                    ddg          ed                         Ze                    ddg          ed                         Ze                    ddg          ed                         Ze                    ddg          ed                         Ze                    ddg          ed                         Ze                    ddg          ed                         Ze                    ddg          ed                         Ze                    d dg          ed!                         Ze                    d"d#g          ed$                         Ze                    d%d&g          ed'                         Ze                    dd#g          ed(                         Ze                    d)dg          ed*                         Ze                    d+dg          ed,                         Z e                    d-dg          ed.                         Z!e                    d/dg          ed0                         Z"e                    d1dg          ed2                         Z#e                    d3dg          ed4                         Z$dS )5a=  
ENIGMA Inventario - API Routes FIXED v2
=========================================

Endpoints REST con FIX per:
1. Isolamento filiali (sede_id filtering)
2. Gestione nomi sessioni (nome_sessione field)
3. Chiusura sessioni pulita (no note override)

Author: HetGi & Claude  
Date: 2026-01-21 (ISOLAMENTO FILIALI FIX)
    )	Blueprintrequestjsonifyrender_templatewraps)datetimeN	inventoryz/api/v1/inventory)
url_prefixc                 <     t                      fd            }|S )zDecorator auth (mock per demo).c                  6    dddddt           _         | i |S )N   zdemo@studium.itadmin)id	tenant_idemailrole)r   user)argskwargsfs     =/var/www/tmov.alphamb/tmov_inventario/app/routes/inventory.py	decoratedzrequire_auth.<locals>.decorated   s6     &	
 
 q$!&!!!    r   )r   r   s   ` r   require_authr      s4    
1XX" " " " X" r   c                     ddl m}  t          j        dd          t          j        dd          t          j        dd          t          j        d	d
          d}t          j        d          }|st	          d           | ||          S )zFactory per InventoryService.r   )create_inventory_serviceDB_HOST	localhostDB_USERenigma_userDB_PASSWORD
arcana2026DB_NAMEenigma)hostr   passworddatabaseCASSANOVA_API_KEYz'CASSANOVA_API_KEY non trovata nel .env!)app.services.inventory_servicer   osgetenv
ValueError)r   	db_configapi_keys      r   get_servicer0   '   s    GGGGGG 	)[11	)]33Im\::Ii22	 I i+,,G DBCCC##Iw777r   z/salespointsGET)methodsc                  6   	 t                      } t          j        d         }ddl} |j        di | j        j        }|                    |j        j	                  }|
                    d||f           |                                }|                                 |                                 t          dd|id          dfS # t          $ rH}t                              d	|            t          d
t#          |          d          dfcY d}~S d}~ww xY w)zARecupera tutti i Sales Points da inv_sedi con conteggio prodotti.r   r   Nu   
            SELECT 
                s.id,
                s.nome as name,
                s.indirizzo as address,
                s.città as city,
                COUNT(DISTINCT p.codice_barcode) as product_count
            FROM inv_sedi s
            LEFT JOIN inv_cache_prodotti p ON p.id_tenant = %s
                AND JSON_SEARCH(p.dati_cassanova, 'one', s.id, NULL, '$.prices[*].idSalesPoint') IS NOT NULL
            WHERE s.id_tenant = %s
            GROUP BY s.id
            ORDER BY s.nome
        Tsalespointssuccessdata   zErrore get salespoints: Fr6   error   )r0   r   r   pymysqlconnectsession_modelr.   cursorcursors
DictCursorexecutefetchallcloser   	Exceptionloggerr:   str)servicer   r=   connr@   r4   es          r   get_salespointsrL   >   sL   #A--L-	wAA!6!@AAW_788  #	% 	% 	% oo''

{
 
  
  	  A A A33344453q66::;;S@@@@@@@As   CC 
D=DDDz/products/syncPOSTc                  @   	 t                      } t          j        d         }|                     |          }t	          d|d          dfS # t
          $ rH}t                              d|            t	          dt          |          d          dfcY d	}~S d	}~ww xY w)
z
    Sincronizza TUTTI i prodotti da Cassanova.
    
    Returns:
        {
            "success": true,
            "data": {
                "total": 1234,
                "cached": 1230,
                "errors": 4
            }
        }
    r   Tr5   r8   zErrore sync: Fr9   r;   N)	r0   r   r   sync_all_productsr   rF   rG   r:   rH   )rI   r   resultrK   s       r   sync_productsrQ   l   s     A--L-	**955
 
    	  A A A(Q(()))53q66::;;S@@@@@@@As   AA 
B=BBBz/cache/infoc            	      (   	 t                      } t          j        d         }ddl}|                    t          j        dd          t          j        dd          t          j        dd	          t          j        d
d          d|j        j                  }|	                                }|
                    d|f           |                                }|                                 |                                 t          d|d         pd|d         r|d                                         nddd          dfS # t          $ rH}t                               d|            t          dt%          |          d          dfcY d}~S d}~ww xY w)z Ritorna info sulla cache locale.r   r   Nr   r   r    r!   r"   r#   r$   r%   utf8mb4)r&   r   r'   r(   charsetcursorclassz
            SELECT COUNT(*) as total, MAX(cache_timestamp) as last_sync
            FROM inv_cache_prodotti
            WHERE id_tenant = %s
        Ttotal	last_sync)product_countrW   r5   r8   zErrore get cache info: Fr9   r;   )r0   r   r   r=   r>   r+   r,   rA   rB   r@   rC   fetchonerE   r   	isoformatrF   rG   r:   rH   )rI   r   r=   rJ   r@   rP   rK   s          r   get_cache_infor[      s   #A--L-	9k229m44Y}l;;Yy(332  
 
  	  \		 	 	 ""

!'!5A@F{@S]VK0::<<<Y] 
 
    	  A A A2q2233353q66::;;S@@@@@@@As   D<D? ?
F	=FFFz/products/searchc                     	 t                      } t          j        d         }t          j                            d          }t          j                            d          }|s|st          ddd          dfS |                     |||          }t          d|t          |          d	d
          dfS # t          $ rH}t          
                    d|            t          dt          |          d          dfcY d}~S d}~ww xY w)a  
    Cerca prodotti per barcode o nome.
    
    Query params:
        - barcode: Codice a barre
        - description: Nome prodotto
    
    Returns:
        {
            "success": true,
            "data": {
                "products": [...]
            }
        }
    r   barcodedescriptionFz!Specificare barcode o descriptionr9     T)productscountr5   r8   zErrore ricerca: r;   N)r0   r   r   r   getr   search_productlenrF   rG   r:   rH   )rI   r   r]   r^   r`   rK   s         r   search_productsre      sJ   $A--L-	,""9--l&&}55 	{ 	 <     
 )))WkJJ$X 
 
    	  A A A+++,,,53q66::;;S@@@@@@@As$   A5B3 8:B3 3
D==D :D Dz/session/startc                     	 t                      } t          j        }t          j        d          pi }|                    dd          }|                    ddt          j                                        d                     }|                     |d         |d	         |          }|rP| 	                    ||d         |           | 
                    ||d                   }t          d||d
d          dfS t          ddd          dfS # t          $ rH}t                              d|            t          dt          |          d          dfcY d}~S d}~ww xY w)aE  
    Avvia nuova sessione inventario.
    
    Body:
        {
            "sede_id": 17117,
            "session_name": "Libreria Piano 1"
        }
    
    Returns:
        {
            "success": true,
            "data": {
                "session_id": 123,
                "session": {...}
            }
        }
    Tsilentsede_idB  session_namezInventario z%d/%m/%Yr   r   )
session_idsessionr5      Fu'   Sessione già aperta o errore creazioner9   r_   zErrore start: r;   N)r0   r   r   get_jsonrb   r	   nowstrftimestart_sessionupdate_session_nameget_session_detailsr   rF   rG   r:   rH   )rI   r   r7   ri   rk   rl   session_datarK   s           r   rr   rr      s   * A--|t,,,2((9e,,xx0chlnn>U>UV`>a>a0c0cdd **4+<d4j'RR
 	''
D4E|TTT #66z4CTUUL",+        B       A A A)a))***53q66::;;S@@@@@@@As$   C8D ;D 
E!=EE!E!z/session/currentc                     	 t                      } t          j        }t          j                            dt
          d          }|                     |d         |d         |          }|r|d         |k    rDt                              d| d|d                     t          d	d
|d          dd          dfS | 
                    |d         |d         |d                   }||d<   t          dd|id          dfS t          d	dd          dfS # t          $ rH}t                              d|            t          d	t          |          d          dfcY d}~S d}~ww xY w)u   
    Ottiene sessione corrente per una filiale specifica.
    
    Query params:
        - sede_id: ID filiale (opzionale, default 17117)
    
    ✅ FIX 2: Filtra per sede_id per isolare le filiali
    ri   rj   )typedefaultr   r   id_sedez'Sessione su filiale diversa: richiesta z
, trovata Fz)Sessione aperta su filiale diversa (sede z). Chiuderla prima.r9   r_   itemsTrm   r5   r8   Nessuna sessione apertazErrore get current: r;   N)r0   r   r   r   rb   intget_current_sessionrG   warningr   get_session_itemsrF   r:   rH   )rI   r   ri   ru   rz   rK   s         r   r}   r}   %  s   !A--| ,""93"FF2243Dd4jRYZZ 	I&'11uuu\hir\suuvvv$uV_I`uuu        --l4.@${BSUabkUlmmE$)L!"L1     
  2       A A A/A//00053q66::;;S@@@@@@@As+   B5D 8AD <D 
E"=EE"E"z/session/closec                     	 t                      } t          j        }|                     |d         |d                   }|st	          ddd          dfS t          j        d          pi }|                    d	          }|r#|                     |d         |d         |           |                     |d         |d         d
          }|rt	          ddd          dfS t	          ddd          dfS # t          $ rH}t                              d|            t	          dt          |          d          dfcY d
}~S d
}~ww xY w)u   
    Chiude sessione corrente.
    
    Body (opzionale):
        {"note": "Inventario completato"}
    
    ✅ FIX 3: Non sovrascrive il nome della sessione
    
    Returns:
        {"success": true}
    r   r   Fr{   r9   r_   Trg   rk   NzSessione chiusar6   messager8   zErrore chiusura sessioner;   zErrore close: )r0   r   r   r}   r   ro   rb   rs   close_sessionrF   rG   r:   rH   )rI   r   currentr7   rk   r6   rK   s          r   r   r   T  s   !A--| --d;.?dLL 	 2     
 t,,,2xx//  	X''tK7H,WWW ''tK7H$OO 		,     
  3       A A A)a))***53q66::;;S@@@@@@@As+   AC2 B	C2 C2 2
E<=D?9E?Ez/sessions/recentc                  z   	 t                      } t          j        d         }t          t          j                            dd                    }t          j                            d          }ddl}| j        j        } |j	        di |}|
                    |j        j                  }d}|g}	|r'|dz  }|	                    t          |                     |d	z  }|	                    |           |                    ||	           |                                }
|                                 |                                 t#          d
|
t%          |
          dd          dfS # t&          $ rH}t(                              d|            t#          dt-          |          d          dfcY d}~S d}~ww xY w)zALista sessioni recenti, opzionalmente filtrate per punto vendita.r   limit
   salespoint_idr   Nz\
            SELECT * FROM inv_sessioni_inventario
            WHERE id_tenant = %s
        z AND id_sede = %sz( ORDER BY timestamp_inizio DESC LIMIT %sT)sessionsra   r5   r8   zErrore get recent: Fr9   r;   r<   )r0   r   r   r|   r   rb   r=   r?   r.   r>   r@   rA   rB   appendrC   rD   rE   r   rd   rF   rG   r:   rH   )rI   r   r   r   r=   r.   rJ   r@   sqlparamsr   rK   s               r   get_recent_sessionsr     s   'A--L-	GL$$Wb1122((99)3	w++++W_788  	.&&CMM#m,,---99esF###??$$

$X 
 
    	  A A A.1..///53q66::;;S@@@@@@@As   E%E( (
F:2=F5/F:5F:z/session/<int:session_id>c                    	 t                      }t          j        d         }|                    | |          }|                    | |          }t          d||t          |          dd          dfS # t          $ rH}t          	                    d|            t          dt          |          d          d	fcY d
}~S d
}~ww xY w)zDettaglio sessione con items.r   T)rm   rz   items_countr5   r8   zErrore get detail: Fr9   r;   N)r0   r   r   rt   r   r   rd   rF   rG   r:   rH   )rl   rI   r   ru   rz   rK   s         r   get_session_detailr     s    A--L-	22:yII))*i@@'"5zz 
 
    	  A A A.1..///53q66::;;S@@@@@@@As   A0A3 3
C==C :C Cz/scanc            
         	 t                      } t          j        }t          j                    }|rd|vrt	          ddd          dfS |d                                         }|                    dd          }|                    d          }|s)|                     |d	         |
          }|r|d         nd}t          |          }| 	                    |d	         |d                   }|st	          ddd          dfS | 
                    |d         |d	         |||||d                   }	|	r(|	||d}
|r||
d<   |rdnd}t	          d|
|d          dfS t	          ddd          dfS # t          $ rH}t                              d|            t	          dt          |          d          dfcY d}~S d}~ww xY w)as  
    Scansiona barcode e aggiunge a sessione.
    
    Body:
        {
            "barcode": "8001234567890",
            "quantita": 1  // opzionale
        }
    
    Returns:
        {
            "success": true,
            "data": {
                "item_id": 456,
                "found_in_api": true,
                "product": {...}
            }
        }
    r]   FzCampo barcode richiestor9   r_   quantitar   product_datar   )r]   r   Nr   z2Nessuna sessione aperta. Avvia prima una sessione.ry   )item_idr]   found_in_apiproductzProdotto trovato e aggiuntoz Barcode registrato (non trovato)T)r6   r7   r   rn   zErrore aggiunta itemr;   zErrore scan: )r0   r   r   ro   r   striprb   rc   boolr}   add_itemrF   rG   r:   rH   )rI   r   r7   r]   r   r   r`   r   r   r   response_datar   rK   s                r   scan_barcoder     s   ,BA--|!! 	y,, 2     
 y/''))88J** xx//  	=--d;.?-QQH*2<8A;;LL)) --d;.?dLL 	 M      ""DMI
 
  	"" , M
  8+7i(7Ck33IkG%"    	   /       A A A(Q(()))53q66::;;S@@@@@@@As2   AE+ 	B6E+  AE+ E+ +
F=5=F82F=8F=z/item/<int:item_id>DELETEc                    	 t                      }t          j        }|                    |d         |d                   }|st	          ddd          dfS |                    | |d                   }|rt	          ddd	          d
fS t	          ddd          dfS # t          $ rH}t                              d|            t	          dt          |          d          dfcY d}~S d}~ww xY w)zElimina item da sessione.r   r   Fr{   r9   r_   TzItem eliminator   r8   Item non trovato o errore  zErrore delete: r;   N)
r0   r   r   r}   r   delete_itemrF   rG   r:   rH   )r   rI   r   r   r6   rK   s         r   r   r   +  sY   A--| --d;.?dLL 	 2     
 %%gwt}== 		+     
  4       A A A*q**+++53q66::;;S@@@@@@@As*   AB 1B B 
C,$=C'!C,'C,z/item/<int:item_id>/quantityPUTc                 d   	 t                      }t          j        }t          j                    }|                    d          }|t          ddd          dfS |                    |d         |d                   }|st          dd	d          dfS |                    | |d         |          }|rt          d
d| |dd          dfS t          ddd          dfS # t          $ rH}t          
                    d|            t          dt          |          d          dfcY d}~S d}~ww xY w)u   Aggiorna quantità item.r   NFzCampo quantita richiestor9   r_   r   r   r{   Tu   Quantità aggiornata)r   r   )r6   r   r7   r8   r   r   zErrore update quantity: r;   )r0   r   r   ro   rb   r   r}   update_item_quantityrF   rG   r:   rH   )r   rI   r   r7   new_quantityr   r6   rK   s           r   r   r   L  s   (A--|!!xx
++ 3      --d;.?dLL 	 2     
 ..w|TT 	1& ,        4     
  A A A33344453q66::;;S@@@@@@@As0   AC 7C 6C 	C 
D/'=D*$D/*D/c                 d   	 t                      }t          j        d         }ddl} |j        di t                      j        j        }|                                }|                    d| |f           |                    d| |f           |	                                 |
                                 |
                                 t          ddd          d	fS # t          $ rH}t                              d
|            t          dt          |          d          dfcY d}~S d}~ww xY w)z*Elimina una sessione e tutti i suoi items.r   r   NzNDELETE FROM inv_risultati_inventario WHERE id_sessione = %s AND id_tenant = %szDDELETE FROM inv_sessioni_inventario WHERE id = %s AND id_tenant = %sTzSessione eliminatar   r8   zErrore delete session: Fr9   r;   r<   )r0   r   r   r=   r>   r?   r.   r@   rC   commitrE   r   rF   rG   r:   rH   )rl   rI   r   r=   rJ   r@   rK   s          r   delete_session_endpointr   z  sK   A--L-	 	wGG!<!FGGg!9-	/ 	/ 	/]!9-	/ 	/ 	/ 	

44HIIJJCOO A A A2q2233353q66::;;S@@@@@@@As   CC 
D/'=D*$D/*D/z%/salespoint/<int:salespoint_id>/statsc           	         	 ddl }ddlm} t          j        dd          t          j        dd          t          j        dd	          t          j        d
d          dd} |j        di |}|                    |j        j                  }t          j
        d         }|                    d|| f           |                                d         }|                    d|| f           |                                rdnd}|                    d|| f           |                                }	|	d         pd}
|	d         pd}|                                 |                                 t          d||t          |
          t!          |          dd          dfS # t"          $ rH}t$                              d|            t          dt)          |          d          dfcY d}~S d}~ww xY w)z+Statistiche per un punto vendita specifico.r   N)InventorySessionr   r   r    r!   r"   r#   r$   r%   rS   )r&   r   r'   r(   rT   r   z
            SELECT COUNT(*) as total
            FROM inv_sessioni_inventario
            WHERE id_tenant = %s AND id_sede = %s
        rV   z
            SELECT id FROM inv_sessioni_inventario
            WHERE id_tenant = %s AND id_sede = %s AND stato = 'aperta'
            LIMIT 1
        r   a.  
            SELECT COALESCE(SUM(i.quantita_fisica), 0) as total_items,
                   COALESCE(SUM(
                       CAST(JSON_EXTRACT(p.dati_cassanova, '$.prices[0].value') AS DECIMAL(10,2)) 
                       * i.quantita_fisica
                   ), 0) as total_value
            FROM inv_risultati_inventario i
            JOIN inv_sessioni_inventario s ON i.id_sessione = s.id
            LEFT JOIN inv_cache_prodotti p ON i.barcode = p.codice_barcode
            WHERE s.id_tenant = %s AND s.id_sede = %s AND s.stato = 'chiusa'
        total_itemstotal_valueT)total_sessionsactive_sessionr   r   r5   r8   zErrore get salespoint stats: Fr9   r;   r<   )r=   app.models.inventoryr   r+   r,   r>   r@   rA   rB   r   r   rC   rY   rE   r   r|   floatrF   rG   r:   rH   )r   r=   r   r.   rJ   r@   r   r   r   
items_datar   r   rK   s                r   get_salespoint_statsr     sX   ?A999999 Ii55Ii77	->>	)X66 
 
	 w++++W_788L-	 	  '		) 	) 	)
  **73 	  '		) 	) 	)
 %oo//6Q 	 
 '
	) 
	) 
	) __&&
 /41 /41

"0"0";//$[11	 
 
    	  A A A8Q8899953q66::;;S@@@@@@@As   FF 
G-%=G("G-(G-z /session/<int:session_id>/reopenc                    	 t                      }t          j        d         }ddl} |j        di |j        j        }|                    |j        j	                  }|
                    d| |f           |                                 |
                    d| |f           |                                }t                              d|            |                                 |                                 t!          dd|id	          d
fS # t"          $ rH}t                              d|            t!          dt'          |          d          dfcY d}~S d}~ww xY w)zRiapre una sessione chiusa.r   r   Nz
            UPDATE inv_sessioni_inventario 
            SET stato = 'aperta', timestamp_fine = NULL
            WHERE id = %s AND id_tenant = %s
        zh
            SELECT * FROM inv_sessioni_inventario
            WHERE id = %s AND id_tenant = %s
        zSession data: Trm   r5   r8   zErrore reopen session: Fr9   r;   r<   )r0   r   r   r=   r>   r?   r.   r@   rA   rB   rC   r   rY   rG   inforE   r   rF   r:   rH   )rl   rI   r   r=   rJ   r@   ru   rK   s           r   reopen_sessionr     s   #A--L-	wAA!6!@AAW_788 	  )$		& 	& 	& 	 	  )$	& 	& 	&
 ((3\33444

-
 
    	  A A A2q2233353q66::;;S@@@@@@@As   DD 
E!=EE!E!z/sync-stocksc                     	 t                      } t          j        }t          j                    }|                    d          }|st          ddd          dfS |                     |d         |          }t          d|| d| d	d
          dfS # t          $ rH}t          	                    d|            t          dt          |          d          dfcY d}~S d}~ww xY w)aH  
    Sincronizza giacenze da Cassanova per un salespoint.
    
    Body:
        {
            "salespoint_id": 17117
        }
    
    Returns:
        {
            "success": true,
            "data": {
                "synced_count": 150,
                "message": "150 giacenze sincronizzate"
            }
        }
    r   Fsalespoint_id richiestor9   r_   r   Tz! giacenze sincronizzate per sede )synced_countr   r5   r8   zErrore sync_stocks: r;   N)r0   r   r   ro   rb   r   sync_stocksrF   rG   r:   rH   )rI   r   r7   r   ra   rK   s         r   r   r     s>   (A--|!!11 	 2      ##D$5}EE %#UUmUU 
 
    	  A A A/A//00053q66::;;S@@@@@@@As$   AB 7B 
C$=CC$C$z/stock/<product_id>c                    	 t                      }t          j        }t          j                            dt
                    }|st          ddd          dfS ddl} |j        di |j	        j
        }|                    |j        j                  }|                    d	|d
         || f           |                                }|                                 |                                 |rt          d|d          dfS t          dd| dd          dfS # t"          $ rH}t$                              d|            t          dt)          |          d          dfcY d}~S d}~ww xY w)a  
    Ottiene giacenza di un prodotto per un salespoint.
    
    Query params:
        salespoint_id: ID sede
    
    Returns:
        {
            "success": true,
            "data": {
                "quantita": 50,
                "id_prodotto": "..."
            }
        }
    r   )rw   Fr   r9   r_   r   Nz
            SELECT quantita, id_prodotto
            FROM inv_giacenze
            WHERE id_tenant = %s AND id_sede = %s AND id_prodotto = %s
            LIMIT 1
        r   Tr5   r8   )r   id_prodottozErrore get_stock: r;   r<   )r0   r   r   r   rb   r|   r   r=   r>   r?   r.   r@   rA   rB   rC   rY   rE   rF   rG   r:   rH   )	
product_idrI   r   r   r=   rJ   r@   rP   rK   s	            r   	get_stockr   7  s   $$A--|((s(CC 	Xu7PQQRRTWWWwAA!6!@AAW_788 
 ;
;	= 	= 	= ""

 		     
 %&zBB     
  A A A-!--...53q66::;;S@@@@@@@As+   AD B*D D 
E,$=E'!E,'E,z$/report/warehouse/sede/<int:sede_id>c                 .   	 t                      }t          j        d         }ddl} |j        di |j        j        }|                    |j        j	                  }|
                    d| |f           |                                }|s<|                                 |                                 t          ddd          dfS |
                    d	| |f           |                                }g }d}	d}
d}d}|D ]}|
                    d
|d         |f           |                                }t          |          }t!          d |D                       }t!          d |D                       }t!          d |D                       }|                    |d         |d         |d         r|d                                         nd|||||dd           |	|z  }	|
|z  }
||z  }||z  }|                                 |                                 t          d|||	|
||t          |          ddd          dfS # t&          $ rH}t(                              d|            t          dt-          |          d          dfcY d}~S d}~ww xY w)a   
    Genera report magazzino AGGREGATO per una filiale.
    Aggrega TUTTE le sessioni chiuse della filiale.
    
    Returns:
        {
            "success": true,
            "data": {
                "sede": {...},
                "sessions": [
                    {
                        "session_id": 43,
                        "nome_sessione": "TEST",
                        "items": [...],
                        "subtotal": {...}
                    }
                ],
                "totals": {...}
            }
        }
    r   r   NzT
            SELECT id, nome FROM inv_sedi WHERE id = %s AND id_tenant = %s
        FzFiliale non trovatar9   r   z
            SELECT id, nome_sessione, timestamp_fine
            FROM inv_sessioni_inventario
            WHERE id_sede = %s AND id_tenant = %s AND stato = 'chiusa'
            ORDER BY timestamp_fine DESC
        aE  
                SELECT 
                  r.id as item_id,
                  r.nome_prodotto,
                  r.barcode,
                  r.quantita_fisica as contato,
                  COALESCE(g.quantita, 0) as teorico,
                  (r.quantita_fisica - COALESCE(g.quantita, 0)) as differenza,
                  r.prezzo_pubblico,
                  (r.quantita_fisica * COALESCE(r.prezzo_pubblico, 0)) as valore_contato,
                  CASE 
                    WHEN (r.quantita_fisica - COALESCE(g.quantita, 0)) = 0 THEN 'ok'
                    WHEN (r.quantita_fisica - COALESCE(g.quantita, 0)) > 0 THEN 'excess'
                    ELSE 'deficit'
                  END as status
                FROM inv_risultati_inventario r
                LEFT JOIN inv_giacenze g ON 
                  r.id_sede = g.id_sede 
                  AND r.codice_prodotto COLLATE utf8mb4_unicode_ci = g.id_prodotto COLLATE utf8mb4_unicode_ci
                WHERE 
                  r.id_sessione = %s
                  AND r.id_tenant = %s
                ORDER BY r.nome_prodotto
            r   c              3   D   K   | ]}t          |d          pd          V  dS )valore_contator   N)r   .0items     r   	<genexpr>z/get_warehouse_report_by_sede.<locals>.<genexpr>  s5      "X"X$5.>)?)D1#E#E"X"X"X"X"X"Xr   c              3   2   K   | ]}|d          dk    dV  dS )statusexcessr   Nr<   r   s     r   r   z/get_warehouse_report_by_sede.<locals>.<genexpr>  s0      PPDT(^x5O5Oa5O5O5O5OPPr   c              3   2   K   | ]}|d          dk    dV  dS )r   deficitr   Nr<   r   s     r   r   z/get_warehouse_report_by_sede.<locals>.<genexpr>  s0      RRTd8n	6Q6Qq6Q6Q6Q6QRRr   nome_sessionetimestamp_fine)r   r   anomalies_excessanomalies_deficit)rl   r   r   rz   subtotalT)r   r   r   r   r   )seder   totalsr5   r8   z%Errore get_warehouse_report_by_sede: r;   r<   )r0   r   r   r=   r>   r?   r.   r@   rA   rB   rC   rY   rE   r   rD   rd   sumr   rZ   rF   rG   r:   rH   )ri   rI   r   r=   rJ   r@   r   sessions_listsessions_datagrand_total_itemsgrand_total_valuegrand_total_excessgrand_total_deficitsessrz   sess_total_itemssess_total_valuesess_excesssess_deficitrK   s                       r   get_warehouse_report_by_seder   s  s[   0lA--L-	wAA!6!@AAW_788 	 y!	# 	# 	#    	TLLNNNJJLLLu7LMMNNPSSS 	 
 y!	# 	# 	# )) ! 2	0 2	0DNN . t*i(/* * *2 OO%%E  #5zz""X"XRW"X"X"XXXPPEPPPPPKRRURRRRRL  "4j!%o!6HLM]H^"h$'7"8"B"B"D"D"Ddh#3#3(3)5	 " "    !11!11+-</

)#4#4(:)<&)-&8&8 
 

 
    	  A A A@Q@@AAA53q66::;;S@@@@@@@As%   CI E;I 
J=J	JJz"/report/warehouse/<int:session_id>c                 f   	 t                      }t          j        d         }ddl} |j        di |j        j        }|                    |j        j	                  }|
                    d| |f           |                                }|s<|                                 |                                 t          ddd          dfS |
                    d	| |f           |                                }|
                    d
| |f           |                                }|                                 |                                 t          d|||dd          dfS # t          $ rH}	t                               d|	            t          dt%          |	          d          dfcY d}	~	S d}	~	ww xY w)a  
    Genera report magazzino per una sessione.
    
    Query params (opzionali):
        - format: 'json' (default) o 'html' per redirect a template
    
    Returns (JSON):
        {
            "success": true,
            "data": {
                "session": {
                    "id": 43,
                    "nome_sessione": "TEST FIX",
                    "id_sede": 640,
                    "sede_nome": "BOUTIQUE MILANO",
                    "user_nome": "Demo User",
                    "timestamp_fine": "2026-01-21T21:50:00"
                },
                "items": [
                    {
                        "item_id": 44,
                        "nome_prodotto": "All the pretty horses",
                        "barcode": "9781035003754",
                        "contato": 5,
                        "teorico": 5,
                        "differenza": 0,
                        "valore_contato": 75.00,
                        "status": "ok"
                    },
                    {
                        "item_id": 43,
                        "nome_prodotto": "Leonardo frida and the others",
                        "barcode": "9783791377186",
                        "contato": 7,
                        "teorico": 5,
                        "differenza": 2,
                        "valore_contato": 301.00,
                        "status": "excess"
                    }
                ],
                "totals": {
                    "total_items": 3,
                    "total_contato": 15,
                    "total_teorico": 18,
                    "total_differenza": -3,
                    "total_value": 500.50,
                    "anomalies_excess": 1,
                    "anomalies_deficit": 1
                }
            }
        }
    r   r   Na.  
            SELECT s.*, se.nome as sede_nome, u.nome as user_nome, u.email as user_email
            FROM inv_sessioni_inventario s
            LEFT JOIN inv_sedi se ON s.id_sede = se.id
            LEFT JOIN tenant_users u ON s.id_user = u.id
            WHERE s.id = %s AND s.id_tenant = %s
        FzSessione non trovatar9   r   a  
            SELECT 
              r.id as item_id,
              r.nome_prodotto,
              r.barcode,
              r.codice_prodotto,
              r.quantita_fisica as contato,
              COALESCE(g.quantita, 0) as teorico,
              (r.quantita_fisica - COALESCE(g.quantita, 0)) as differenza,
              r.prezzo_pubblico,
              (r.quantita_fisica * COALESCE(r.prezzo_pubblico, 0)) as valore_contato,
              CASE 
                WHEN (r.quantita_fisica - COALESCE(g.quantita, 0)) = 0 THEN 'ok'
                WHEN (r.quantita_fisica - COALESCE(g.quantita, 0)) > 0 THEN 'excess'
                ELSE 'deficit'
              END as status
            FROM inv_risultati_inventario r
            LEFT JOIN inv_giacenze g ON 
              r.id_sede = g.id_sede 
              AND r.codice_prodotto COLLATE utf8mb4_unicode_ci = g.id_prodotto COLLATE utf8mb4_unicode_ci
            WHERE 
              r.id_sessione = %s
              AND r.id_tenant = %s
            ORDER BY 
              CASE 
                WHEN (r.quantita_fisica - COALESCE(g.quantita, 0)) != 0 THEN 0
                ELSE 1
              END,
              ABS(r.quantita_fisica - COALESCE(g.quantita, 0)) DESC,
              r.nome_prodotto ASC
        a  
            SELECT 
              COUNT(DISTINCT r.id) as total_items,
              SUM(r.quantita_fisica) as total_contato,
              SUM(COALESCE(g.quantita, 0)) as total_teorico,
              SUM(r.quantita_fisica - COALESCE(g.quantita, 0)) as total_differenza,
              SUM(r.quantita_fisica * COALESCE(r.prezzo_pubblico, 0)) as total_value,
              SUM(CASE WHEN (r.quantita_fisica - COALESCE(g.quantita, 0)) > 0 THEN 1 ELSE 0 END) as anomalies_excess,
              SUM(CASE WHEN (r.quantita_fisica - COALESCE(g.quantita, 0)) < 0 THEN 1 ELSE 0 END) as anomalies_deficit
            FROM inv_risultati_inventario r
            LEFT JOIN inv_giacenze g ON 
              r.id_sede = g.id_sede 
              AND r.codice_prodotto COLLATE utf8mb4_unicode_ci = g.id_prodotto COLLATE utf8mb4_unicode_ci
            WHERE 
              r.id_sessione = %s
              AND r.id_tenant = %s
        T)rm   rz   r   r5   r8   zErrore get_warehouse_report: r;   r<   )r0   r   r   r=   r>   r?   r.   r@   rA   rB   rC   rY   rE   r   rD   rF   rG   r:   rH   )
rl   rI   r   r=   rJ   r@   ru   rz   r   rK   s
             r   get_warehouse_reportr     s   nbA--L-	wAA!6!@AAW_788 	  )$	& 	& 	& (( 	LLNNNJJLLL /      	 < )$=	& 	& 	&@ !! 	   )$!	& 	& 	&$ ""

 '  
 
    	  A A A8Q8899953q66::;;S@@@@@@@As%   CE BE 
F0(=F+%F0+F0)%__doc__flaskr   r   r   r   	functoolsr   r	   loggingr+   	getLogger__name__rG   inventory_bpr   r0   routerL   rQ   r[   re   rr   r}   r   r   r   r   r   r   r   r   r   r   r   r   r   r<   r   r   <module>r      s    ? > > > > > > > > > > >              						8	$	$yh;NOOO  8 8 8. NUG44%A %A  54%AX $vh77A A  87AB ME733%A %A  43%AV &88(A (A  98(A^ $vh773A 3A  873Al &88*A *A  98*AZ $vh77-A -A  87-A` &88)A )A  98)AX /%AAA A  BAA4 GfX..VA VA  /.VAr )H:>>A A  ?>A> 2UGDD*A *A  ED*AX /(DDA A  EDA2 ;eWMMAA AA  NMAAF 6II%A %A  JI%AV NVH55+A +A  65+A\ )E7;;4A 4A  <;4At :UGLLBA BA  MLBAJ 85'JJWA WA  KJWA WA WAr   