
    S ju                       d dl mZ d dlmZmZmZ d dlZd dlmZ d dlZd dl	Z	d dl
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mZmZmZ d dlmZ d dlmZmZmZmZ d d	lmZ d d
l m!Z!m"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,m-Z-m.Z. d dl/m0Z0 d dl1m2Z2 d dl3m4Z4 d dl5m6Z6 d dl7m8Z8 d dl9m:Z:m;Z; d dl<m=Z= d dl>m?Z?m@Z@mAZAmBZBmCZCmDZDmEZEmFZFmGZGmHZHmIZI d dlJmKZK  e       ZL e ee%      g      ZMdZNdZO ed      ZPdeQdeReef   fdZSdedz  deTdz  fd ZUd!eTdz  d"eTdz  deReTeTf   fd#ZVd$e!d%eTdeWfd&ZXdeTfd'ZYd$e!ddfd(ZZd$e!de[fd)Z\d$e!d*e[de[fd+Z]d,eTd-eTdeTfd.Z^d$e!deQfd/Z_dd0d$e!d*e[dz  de`eTeaf   fd1Zbd2e`eTeaf   deTfd3Zcd4ede`eTeaf      dedeT   fd5Zed6edeT   deTfd7Zfd$e!de`eTeaf   dz  fd8Zgd$e!d9eTd6edeT   d:eQd;eWddfd<ZhdeadeTfd=Zid>ede`eTeaf      d?eQd*e[de`eTeaf   fd@Zjd$e!dAe`eTeaf   deQfdBZkdCedeT   de`eTeQf   fdDZld$e!de`eReTeTf   e`eTeaf   f   fdEZmdddFdGe4dHe`eTeaf   dz  dIedeT   dz  de`eTeaf   fdJZndKe:de`eTeaf   fdLZod2e;de`eTeaf   fdMZpdddNdOeId"eTdz  dPeTdz  de`eTeaf   fdQZqddddRdSeQdTe[dz  dUe[dz  dVe[dz  dWe[dz  de[dz  fdXZrd2e2de[dz  fdYZsd2e2de`eTeaf   fdZZtd[e0de`eTeaf   fd\ZudeTde[dz  fd]Zvd!eTd^eTd_e[dz  de[dz  fd`Zwdae-de`eTeaf   fdbZxdeQd$e!dede0   fdcZyd$e!dedeQ   fddZzddeeTdz  dfeTdz  deTfdgZ{dhe`eTeQf   de`eTeQf   fdiZ|deTdeTfdjZ}dkeDdeReTeTeTf   fdlZ~dhedeD   dedeD   fdmZdGe4dkeDddfdnZdeTdz  deTfdoZdeTdz  deTfdpZddqedz  deReef   fdrZd$e!d"eTde0dz  fdsZd2e2dGe4dSeQddfdtZd[e0dGe4dSeQddfduZd[e0ddfdvZdeTdz  deeT   fdwZdxeTdz  dyeTdz  deRe[e[f   fdzZd{eTdeTfd|ZdOeId}e4dz  d"eTdz  d^eTdz  de`eTeaf   f
d~ZdeHdede4   de`eTeaf   fdZddd2e2de6deWdeWfdZd^eTdz  deWfdZd2e2de[dz  fdZd2e2de[fdZde6deWfdZd2e2de6de[fdZde6dede0   de`eTeaf   fdZeLj+                  d      de`eTeTf   fd       ZeLj/                  d      dhe@de`eTeaf   fd       ZeMj+                  d       ee%      fde-de`eTeaf   fd       ZeMj+                  d       ee$      fd$e!de`eTeaf   fd       ZeMj+                  d       ee$      fd$e!de`eTeaf   fd       ZeMj9                  d       ee$      fdheEd$e!de`eTeaf   fd       ZeMj+                  d       ee$      fd$e!dede`eTeaf      fd       ZeMj+                  d       ee$      fd$e!de`eTeaf   fd       ZeMj+                  d       ee$      fdeQd$e!de`eTeaf   fd       ZeMjC                  dejD                         ee$      fdeQd$e!defd       ZeMj+                  d       edd       eddd       ee$      fdeTdeQd$e!de`eTeaf   fd       ZeMj/                  d       ee$      fdheGd$e!de`eTeaf   fd       ZeMj/                  d       ee$      fdheHd$e!de`eTeaf   fd       ZeMj9                  d       ee$      fdeQdheDd$e!de`eTeaf   fd       ZeMjC                  d       ee$      fdeQd$e!de`eTeaf   fd       ZeMj/                  d       ee$      fdhedeD   d$e!de`eTeaf   fd       ZeMj+                  d       ed       ee$      fdeQdz  d$e!dede`eTeaf      fd       ZeMj+                  d       ee$      fd$e!de`eTeaf   fd       ZeMj/                  d       ee'       ee$      fdheAde-d$e!de`eTeaf   fd       ZeMj9                  d       ee'       ee$      fdheCde-d$e!de`eTeaf   fd       ZeMjC                  d       ee$      fdheBd$e!de`eTeaf   fd       ZeMj+                  d       ee$      fd$e!de`eTeaf   fd       ZeMj+                  d       ed       ee$      fdeQdz  d$e!de`eTeaf   fd       ZeMj+                  d       ed       ee'       ee$      fdeeTdz  de-d$e!de`eTeQf   fd       ZeMj/                  d       edë       ed       ee%       ee$      fdhe`eTeQf   deeTdz  de-d$e!de`eTeaf   f
dĄ       ZeMjC                  d       ed       ee%       ee$      fdeeTdz  de-d$e!defdń       ZeMj+                  dƫ       ee$      fd$e!dede`eTeaf      fdǄ       ZeMj/                  dƫ       ee%       ee$      fdheFde-d$e!de`eTeaf   fdȄ       ZeMjC                  dɫ       ee$      fdeQd$e!defd˄       ZeMj9                  d̫       ee$      fdeQdhe?d$e!de`eTeaf   fd΄       ZeMj+                  dϫ       ed       ee$      fdeQdz  d$e!de`eTeaf   fdЄ       ZeLj+                  dѫ       ed       ee%       ee$      fdeQdz  de-d$e!defdӄ       ZeLju                  eM       y)    )defaultdict)datetime	timedeltatimezoneN)SequenceMatcher)ZoneInfo)	APIRouterBodyDependsHTTPExceptionQueryResponsestatus)StreamingResponse)caseinspectselecttext)IntegrityError)Sessionselectinload)get_dbrequire_management_tokenrequire_query_tokenrequire_token)get_settings)db_session_context)AuthContextauthenticate_login)
OrderBatch)	OrderItem)Product)SeasonalGoal)
SharedNote)SupplierCatalogSupplierCatalogItem)SuspendedOrder)
GoalUpsertLoginRequestOrderCreateRequestOrderDeleteRequestOrderUpdateRequestProductUpsertSafetyStockSettingsUpdateSharedNoteCreateSupplierCatalogCreateRequestSupplierCatalogPreviewRequestSupplierCatalogRow)send_push_payload)dependenciesg      @understock_itemszEurope/Romeyearreturnc                     t        | ddt        j                        }t        | dz   ddt        j                        }||fS )N   tzinfo)r   r   utc)r6   startends      %apps/ordini/backend/app/api/routes.py_utc_year_boundsr@   9   s8    T1a5E
4!8Q(,,
7C#:    valuec                     | y | j                    | j                  t        j                        } | j	                         S )Nr:   )r;   replacer   r<   	isoformat)rB   s    r?   _format_isorF   ?   s5    }||X\\2??rA   product_namesupplier_namec                 .    t        |       t        |      fS N)_normalize_catalog_text)rG   rH   s     r?   _product_inventory_keyrL   G   s    #L13J=3YZZrA   db
table_namec                 \    | j                         }|yt        |      j                  |      S )NF)get_bindr   	has_table)rM   rN   binds      r?   _table_existsrS   K   s*    ;;=D|4="":..rA   c                  d    t        j                  t        j                        j	                         S rJ   )r   nowr   r<   rE    rA   r?   _iso_nowrW   R   s    <<%//11rA   c                     | j                  t        d             | j                  t        d             | j                  t        d             y )Nz
            CREATE TABLE IF NOT EXISTS ordini_safety_stock_settings (
                key TEXT PRIMARY KEY,
                value TEXT NOT NULL,
                updated_at TEXT NOT NULL
            )
            a;  
            CREATE TABLE IF NOT EXISTS tenant_inventory_consumption_product_stats (
                id TEXT PRIMARY KEY,
                product_id INTEGER,
                product_lookup TEXT NOT NULL,
                supplier_lookup TEXT NOT NULL,
                product_name TEXT NOT NULL,
                supplier_name TEXT NOT NULL,
                total_consumed_units REAL NOT NULL DEFAULT 0,
                workdays_count INTEGER NOT NULL DEFAULT 0,
                consumed_days_count INTEGER NOT NULL DEFAULT 0,
                average_daily_consumed_units REAL NOT NULL DEFAULT 0,
                average_consumed_units_on_consumption_days REAL NOT NULL DEFAULT 0,
                movement_count INTEGER NOT NULL DEFAULT 0,
                first_consumption_date TEXT,
                last_consumption_date TEXT,
                calculation_source TEXT NOT NULL DEFAULT 'manual_consumption_movements',
                created_at TEXT NOT NULL,
                updated_at TEXT NOT NULL,
                UNIQUE (product_lookup, supplier_lookup)
            )
            a}  
            CREATE TABLE IF NOT EXISTS ordini_safety_stock_notification_state (
                key TEXT PRIMARY KEY,
                signature TEXT NOT NULL DEFAULT '',
                item_keys_json TEXT NOT NULL DEFAULT '[]',
                count INTEGER NOT NULL DEFAULT 0,
                notified_at TEXT,
                updated_at TEXT NOT NULL
            )
            )executer   rM   s    r?   _ensure_safety_stock_tablesr[   V   sQ    JJ	

 JJ	
4 JJ		
rA   c                 <   t        |        | j                  t        d            j                         j	                         }|t
        S 	 t        |j                  d      xs t
              }t        dt        |d            S # t        t        f$ r	 t
        cY S w xY w)NzQSELECT value FROM ordini_safety_stock_settings WHERE key = 'minimum_days' LIMIT 1rB                v@)r[   rY   r   mappingsfirstDEFAULT_SAFETY_STOCK_DAYSfloatget	TypeError
ValueErrormaxmin)rM   rowparseds      r?   _read_safety_stock_daysrj      s    #
**`ahj  {(()swww'D+DE sC&'' z" )(()s   "B BBminimum_daysc           	          t        |        t        dt        t        |      d            }| j	                  t        d      t        t        |d            t               d       | j                          |S )Nr]   r^   a  
            INSERT INTO ordini_safety_stock_settings (key, value, updated_at)
            VALUES ('minimum_days', :value, :updated_at)
            ON CONFLICT(key) DO UPDATE SET
                value = excluded.value,
                updated_at = excluded.updated_at
               )rB   
updated_at)
r[   rf   rg   rb   rY   r   strroundrW   commit)rM   rk   sanitized_dayss      r?   _write_safety_stock_daysrs      sd    #c%"5u=>NJJ	
 eNA./xzJ IIKrA   product_lookupsupplier_lookupc                 |    dd l } |j                  |  d| j                  d            j                         }d| S )Nr    utf-8inventory_consumption_stat_)hashlibsha1encode	hexdigest)rt   ru   rz   digests       r?   _inventory_consumption_stat_idr      sC    W\\^,B.?@GGPQ[[]F(11rA   c                 
   t        |        t        | d      r| j                  t        d            j	                         j                         }|rT| j                  t        d             t               }d}|D ]&  }t        |j                  d      xs d      j                         }t        |j                  d      xs d      j                         }t        t        |j                  d      xs d      d	      }t        |j                  d
      xs d      }|r|r
|dk  s|dk  rt        t        |j                  d      xs d      d      }	| j                  t        d      i dt        ||      d|j                  d      t        |j                  d            nd d|d|dt        |j                  d      xs |      dt        |j                  d      xs |      d|d
t        t        |            d|	dt        ||z  d	      dt        |t        |	      z  d	      dt        |j                  d      xs d      dt        |j                  d      xs d      xs d dt        |j                  d      xs d      xs d d|d|       |dz  }) |S t        | d      sy| j                  t        d            j	                         j                         }
t        |
xs i j                  d      xs d      }| j                  t        d             |dk  ry| j                  t        d            j	                         j                         }t               }d}|D ]  }t        |j                  d      xs d      j                         }t        |j                  d      xs d      j                         }t        t        |j                  d      xs d      d	      }|r|r|dk  rt        t        |j                  d      xs d      d      }	| j                  t        d      i dt        ||      d|j                  d      t        |j                  d            nd d|d|dt        |j                  d      xs |      dt        |j                  d      xs |      d|d
|d|	dt        |t        |      z  d	      dt        |t        |	      z  d	      dt        |j                  d      xs d      dt        |j                  d      xs d      xs d dt        |j                  d      xs d      xs d d|d|       |dz  } |S )N'tenant_inventory_estimated_consumptionsa	  
                WITH positive AS (
                    SELECT *
                    FROM tenant_inventory_estimated_consumptions
                    WHERE COALESCE(consumed_units, 0) > 0
                      AND COALESCE(product_lookup, '') <> ''
                      AND COALESCE(supplier_lookup, '') <> ''
                      AND COALESCE(consumption_date, '') <> ''
                ),
                product_periods AS (
                    SELECT
                        product_lookup,
                        supplier_lookup,
                        period_start_date,
                        period_end_date,
                        MAX(COALESCE(period_days, 0)) AS period_days
                    FROM positive
                    WHERE COALESCE(period_start_date, '') <> ''
                      AND COALESCE(period_end_date, '') <> ''
                      AND COALESCE(period_days, 0) > 0
                    GROUP BY product_lookup, supplier_lookup, period_start_date, period_end_date
                ),
                product_days AS (
                    SELECT
                        product_lookup,
                        supplier_lookup,
                        ROUND(SUM(period_days), 6) AS workdays_count
                    FROM product_periods
                    GROUP BY product_lookup, supplier_lookup
                )
                SELECT
                    MIN(positive.product_id) AS product_id,
                    positive.product_lookup,
                    positive.supplier_lookup,
                    MAX(positive.product_name) AS product_name,
                    MAX(positive.supplier_name) AS supplier_name,
                    ROUND(SUM(positive.consumed_units), 6) AS total_consumed_units,
                    MAX(COALESCE(product_days.workdays_count, 0)) AS workdays_count,
                    COUNT(DISTINCT positive.consumption_date) AS consumed_days_count,
                    COUNT(*) AS movement_count,
                    MIN(positive.consumption_date) AS first_consumption_date,
                    MAX(positive.consumption_date) AS last_consumption_date
                FROM positive
                LEFT JOIN product_days
                    ON product_days.product_lookup = positive.product_lookup
                   AND product_days.supplier_lookup = positive.supplier_lookup
                GROUP BY positive.product_lookup, positive.supplier_lookup
                HAVING total_consumed_units > 0
                   AND workdays_count > 0
                z6DELETE FROM tenant_inventory_consumption_product_statsr   rt    ru   total_consumed_units   workdays_countconsumed_days_countr9   a  
                        INSERT INTO tenant_inventory_consumption_product_stats (
                            id,
                            product_id,
                            product_lookup,
                            supplier_lookup,
                            product_name,
                            supplier_name,
                            total_consumed_units,
                            workdays_count,
                            consumed_days_count,
                            average_daily_consumed_units,
                            average_consumed_units_on_consumption_days,
                            movement_count,
                            first_consumption_date,
                            last_consumption_date,
                            calculation_source,
                            created_at,
                            updated_at
                        ) VALUES (
                            :id,
                            :product_id,
                            :product_lookup,
                            :supplier_lookup,
                            :product_name,
                            :supplier_name,
                            :total_consumed_units,
                            :workdays_count,
                            :consumed_days_count,
                            :average_daily_consumed_units,
                            :average_consumed_units_on_consumption_days,
                            :movement_count,
                            :first_consumption_date,
                            :last_consumption_date,
                            'estimated_from_inventory_confirmed_orders',
                            :created_at,
                            :updated_at
                        )
                        id
product_idrG   rH   average_daily_consumed_units*average_consumed_units_on_consumption_daysmovement_countfirst_consumption_datelast_consumption_date
created_atrn   tenant_inventory_movementsa[  
            SELECT COUNT(DISTINCT substr(occurred_at, 1, 10)) AS total_workdays
            FROM tenant_inventory_movements
            WHERE movement_kind = 'out'
              AND source_type = 'manual_consumption'
              AND COALESCE(equivalent_units, 0) > 0
              AND substr(COALESCE(occurred_at, ''), 1, 10) <> ''
            total_workdaysa  
            SELECT
                MIN(product_id) AS product_id,
                product_lookup,
                supplier_lookup,
                MAX(product_name) AS product_name,
                MAX(supplier_name) AS supplier_name,
                ROUND(SUM(equivalent_units), 6) AS total_consumed_units,
                COUNT(DISTINCT substr(occurred_at, 1, 10)) AS consumed_days_count,
                COUNT(*) AS movement_count,
                MIN(substr(occurred_at, 1, 10)) AS first_consumption_date,
                MAX(substr(occurred_at, 1, 10)) AS last_consumption_date
            FROM tenant_inventory_movements
            WHERE movement_kind = 'out'
              AND source_type = 'manual_consumption'
              AND COALESCE(equivalent_units, 0) > 0
              AND COALESCE(product_lookup, '') <> ''
              AND COALESCE(supplier_lookup, '') <> ''
              AND substr(COALESCE(occurred_at, ''), 1, 10) <> ''
            GROUP BY product_lookup, supplier_lookup
            a  
                INSERT INTO tenant_inventory_consumption_product_stats (
                    id,
                    product_id,
                    product_lookup,
                    supplier_lookup,
                    product_name,
                    supplier_name,
                    total_consumed_units,
                    workdays_count,
                    consumed_days_count,
                    average_daily_consumed_units,
                    average_consumed_units_on_consumption_days,
                    movement_count,
                    first_consumption_date,
                    last_consumption_date,
                    calculation_source,
                    created_at,
                    updated_at
                ) VALUES (
                    :id,
                    :product_id,
                    :product_lookup,
                    :supplier_lookup,
                    :product_name,
                    :supplier_name,
                    :total_consumed_units,
                    :workdays_count,
                    :consumed_days_count,
                    :average_daily_consumed_units,
                    :average_consumed_units_on_consumption_days,
                    :movement_count,
                    :first_consumption_date,
                    :last_consumption_date,
                    'manual_consumption_movements',
                    :created_at,
                    :updated_at
                )
                )r[   rS   rY   r   r_   allrW   ro   rc   striprp   rb   rf   intr   r`   )rM   estimated_rowsrn   inserted_countrh   rt   ru   r   r   r   workdays_rowrowss               r?   "_refresh_consumption_product_statsr      s   #RBC135
j (*SSUk 	l JJtTUV!JN% E$!$SWW-=%>%D"!E!K!K!M"%cgg.?&@&FB"G"M"M"O',U377;Q3R3WVW-XZ['\$!&sww/?'@'EA!F%_@TXY@Y]kop]p&)#cgg6K.L.QPQ*RTU&V#

&(R<^_]$CGGLDYDec#'',*?&@ko ). *?	
 'CGGN,C,U~(V (SWW_-E-X)Y /0D )#eN.C*D ./B 7>RUc>cef8g EeL`chi|c}L}  @A  GB )#cgg6F.G.L1*M 1#cgg>V6W6][]2^2fbf 0SWW=T5U5[Y[1\1d`d %j  %j!U<z !#KE$L "!9:::		
 hj  ,,"112BCHqINJJtLMN::	
0 hj1 	4 JN DSWW%56<"=CCEcgg&78>B?EEG$U3773I+J+Oa%PRST_8LPQ8Q!#cgg.C&D&I"JAN


&(R4^_UCGGL<Q<]c#'',"78cg !. "?	
 CGGN$;$M~ N  SWW_%=%P!Q '(< !. &': /6JUSaMb6bde0f =eDX[`at[uDuwx>y !#cgg.>&?&D1"E )#cgg6N.O.USU*V*^Z^ (SWW5L-M-SQS)T)\X\ j  j!U<	
z 	!IDL rA   rk   c                R   |t        |       nt        dt        t        |      d            }t	        |        | j                          | j                  t        d            j                         j                         }t        |xs i j                  d      xs d      }t        | d      s||dg ddS | j                  t        d	      d
|i      j                         j                         }||t        |      |D cg c]  }|j                  d      t        |j                  d            nd t        |j                  d      xs d      t        |j                  d      xs d      t!        t        |j                  d      xs d      d      t!        t        |j                  d      xs d      d      t!        t        |j                  d      xs d      d      |j                  d      t        |j                  d            nd t!        t        |j                  d      xs d      d      t!        t        |j                  d      xs d      d      t!        t        |j                  d      xs d      d      t        |j                  d      xs d      t        |j                  d      xs d      t        |j                  d      xs d      t        |j                  d      xs d      xs d t        |j                  d      xs d      xs d d c}ddS c c}w )Nr]   r^   z
            SELECT COALESCE(MAX(workdays_count), 0) AS workdays_count
            FROM tenant_inventory_consumption_product_stats
            r   r   tenant_inventory_stock_itemsz2stock corrente / media consumi giornalieri manuali)rk   r   countitemscalculation_modea)	  
            WITH stock AS (
                SELECT
                    product_lookup,
                    supplier_lookup,
                    MAX(product_name) AS product_name,
                    MAX(supplier_name) AS supplier_name,
                    ROUND(SUM(COALESCE(total_equivalent_units, 0)), 6) AS current_stock_units,
                    COUNT(DISTINCT warehouse_id) AS warehouse_count
                FROM tenant_inventory_stock_items
                GROUP BY product_lookup, supplier_lookup
            )
            SELECT
                stats.product_id,
                COALESCE(stock.product_name, stats.product_name) AS product_name,
                COALESCE(stock.supplier_name, stats.supplier_name) AS supplier_name,
                COALESCE(stock.current_stock_units, 0) AS current_stock_units,
                COALESCE(stock.warehouse_count, 0) AS warehouse_count,
                stats.total_consumed_units,
                stats.workdays_count,
                stats.consumed_days_count,
                stats.average_daily_consumed_units,
                stats.average_consumed_units_on_consumption_days,
                stats.first_consumption_date,
                stats.last_consumption_date,
                ROUND(stats.average_daily_consumed_units * :minimum_days, 6) AS minimum_required_units,
                ROUND((stats.average_daily_consumed_units * :minimum_days) - COALESCE(stock.current_stock_units, 0), 6) AS missing_units,
                CASE
                    WHEN stats.average_daily_consumed_units > 0
                    THEN ROUND(COALESCE(stock.current_stock_units, 0) / stats.average_daily_consumed_units, 3)
                    ELSE NULL
                END AS covered_days
            FROM tenant_inventory_consumption_product_stats AS stats
            LEFT JOIN stock
                ON stock.product_lookup = stats.product_lookup
               AND stock.supplier_lookup = stats.supplier_lookup
            WHERE stats.average_daily_consumed_units > 0
              AND COALESCE(stock.current_stock_units, 0) < stats.average_daily_consumed_units * :minimum_days
            ORDER BY
                missing_units DESC,
                lower(COALESCE(stock.product_name, stats.product_name)) ASC,
                lower(COALESCE(stock.supplier_name, stats.supplier_name)) ASC
            rk   r   rG   r   rH   current_stock_unitsr   minimum_required_unitsmissing_unitscovered_daysr   r   r   r   warehouse_countr   r   )r   rG   rH   r   r   r   r   r   r   r   r   r   r   r   r   zUsotto-stock quando stock corrente < media giornaliera consumi manuali * giorni safety)rj   rf   rg   rb   r   rq   rY   r   r_   r`   r   rc   rS   r   lenro   rp   )rM   rk   safety_daysr   r   r   rh   s          r?   _load_safety_stock_statusr     s   1=1E)"-3sTWX]^jXkmrTsKtK&r*IIK::	
 hj  ,,"112BCHqIN;<', T
 	
 ::*,	
Z 
%]/^ hj_ 	d $(T, +
* ' =@GGL<Q<]c#'',"78cg #CGGN$;$Ar B!$SWW_%=%C!D',U377;P3Q3VUV-WYZ'[*/cgg>V6W6\[\0]_`*a!&uSWW_-E-J'KQ!OBE''.BYBecggn&= >ko05eCGGDb<c<hgh6ikl0m>C#''"NOTSTU? ).eCGG<R4S4XWX.Y[\(]"%cgg.>&?&D1"E'*3773H+I+NQ'O#&sww/@'A'FQ#G*-cgg6N.O.USU*V*^Z^),SWW5L-M-SQS)T)\X\%
. t7 
s   =H!L$
itemc           
          dj                  t        t        | j                  d      xs d            t        t        | j                  d      xs d            g      S )Nrw   rG   r   rH   )joinrK   ro   rc   r   s    r?   _safety_stock_item_keyr     sN    99#C(@(FB$GH#C(A(GR$HI	
 rA   r   c                 d    t        | D ch c]  }t        |      x}dk7  s| c}      }|S c c}w )Nrw   )sortedr   )r   r   keykeyss       r?   _safety_stock_item_keysr   $  s5    5Z44J44P-PSUY,Y3Z[DK [s   --	item_keysc                     t        j                  dj                  |       j                  d            j	                         S )N
rx   )rz   sha256r   r|   r}   )r   s    r?   _safety_stock_signaturer   )  s.    >>$))I.55g>?IIKKrA   c                 F   t        |        | j                  t        d      dt        i      j	                         j                         }|y 	 t        j                  t        |j                  d      xs d            }t        |t              sg }t        |j                  d      xs d      |D cg c]+  }t        |xs d      j                         s!t        |      - c}t        |j                  d      xs d      d	S # t        j                  $ r g }Y w xY wc c}w )
Nz
            SELECT signature, item_keys_json, count
            FROM ordini_safety_stock_notification_state
            WHERE key = :key
            LIMIT 1
            r   item_keys_jsonz[]	signaturer   r   r   )r   r   r   )r[   rY   r   #SAFETY_STOCK_NOTIFICATION_STATE_KEYr_   r`   jsonloadsro   rc   JSONDecodeError
isinstancelistr   r   )rM   rh   r   r   s       r?   %_read_safety_stock_notification_stater   -  s   #
**	
 
34
 hj  {JJs377+;#<#DEF	 i&	 -34,5QDTZR9N9N9Pc$iQSWWW%*+   	 Rs   1D 1"DDDDr   r   notifiedc          
          t               }| j                  t        d      t        |t	        j
                  |d      ||rdnd|d       | j                          y )Na  
            INSERT INTO ordini_safety_stock_notification_state (
                key,
                signature,
                item_keys_json,
                count,
                notified_at,
                updated_at
            ) VALUES (
                :key,
                :signature,
                :item_keys_json,
                :count,
                CASE WHEN :notified = 1 THEN :timestamp ELSE NULL END,
                :timestamp
            )
            ON CONFLICT(key) DO UPDATE SET
                signature = excluded.signature,
                item_keys_json = excluded.item_keys_json,
                count = excluded.count,
                notified_at = CASE
                    WHEN :notified = 1 THEN :timestamp
                    ELSE ordini_safety_stock_notification_state.notified_at
                END,
                updated_at = excluded.updated_at
            F)ensure_asciir9   r   )r   r   r   r   r   	timestamp)rW   rY   r   r   r   dumpsrq   )rM   r   r   r   r   r   s         r?   &_write_safety_stock_notification_stater   K  sX     
IJJ	
: 7""jjG%1"	
;%L IIKrA   c                     	 t        | xs d      }|j                         rt	        t        |            S |dj                  d      j                  d      S # t        t        f$ r d}Y Yw xY w)Nr   r]   z.1f0.)rb   rd   re   
is_integerro   r   rstrip)rB   numerics     r?   _format_stock_numberr   }  sm    
# 3w<  c]""3'..s33	 z" s   A A+*A+	new_itemstotal_countc                 .   | r| d   ni }t        |j                  d      xs d      j                         }t        |j                  d            }t	        |       dk(  r| d| d|dd	}nt	        |        d
| d| d}d|d d dddt	        |       |ddS )Nr   rG   Prodottor   r9   z
: mancano z unita rispetto al minimo di gz giorni.z% nuovi prodotti sotto-scorta. Primo: z
, mancano z unita.zMerce sotto-scorta   z/modules/ordinizordini-sotto-stocksafety_stock)type	new_countr   )titlebodyurltagdata)ro   rc   r   r   r   )r   r   rk   
first_item
first_namer   r   s          r?    _build_safety_stock_push_payloadr     s     "+1JZ^^N3AzBHHJJ()HIM
9~Z6ST`abScckli.!!FzlR\]j\kkrs%Tc
 #"Y&

 
rA   status_payloadc           	      <   |j                  d      }t        |t              r!|D cg c]  }t        |t              s| c}ng }t	        |      }t        |      }t        |       }|t        | ||t        |      d       yt        |j                  d      xs g       }|D cg c]  }t        |      |vs| }	}|	sX|j                  d      |k7  s*t        |j                  d      xs d      t        |      k7  rt        | ||t        |      d       y	 t        |j                  d      xs t              }
t!        | t#        |	t        |      |
	            }t        | ||t        |      |dkD         |S c c}w c c}w # t        t        f$ r	 t        }
Y `w xY w)
Nr   F)r   r   r   r   r   r   r   r   rk   )r   r   rk   )rc   r   r   dictr   r   r   r   r   setr   r   rb   ra   rd   re   r3   r   )rM   r   	raw_itemsr   r   r   r   previous_stateprevious_keysr   rk   
sent_counts               r?   notify_safety_stock_changesr     s   ""7+IFPQZ\`FaiBd:dD+ATBgiE'.I'	2I:2>N.e*	
 **;7=2>M"']$+A$+G}+\]I]k*i73~?Q?QRY?Z?_^_;`dghmdn;n2##%j 1^//?\C\] #
(E
%	
J +
%ja _ C  ^ z" 101s(   E9E9$E>7E>"F FFdatabase_urlsc                     d}d}d}| D ]6  }	 t        |      5 }t        |      }|t        ||      z  }|dz  }d d d        8 |||dS # 1 sw Y   xY w# t        $ r |dz  }Y [w xY w)Nr   r9   )checkedsentfailed)r   r   r   	Exception)r   r   r   r   database_urlrM   r   s          r?   "run_safety_stock_notification_scanr     s    GDF% 	#L1 R!:2!>3BGG1 ??   	aKF	s'   A AAA	AA%$A%c                 n   t        | d      rt        | d      si S | j                  t        d            j                         j	                         }i }i }|D ]+  }t        |j                  d      |j                  d            }t        |j                  d      xs d      j                         }|d   r|d	   r|sg|j                  |g d
i d      }t        |j                  d      xs d      t        |j                  d      xs d      z   |d<   t        |      }|j                  |t                     }	||	v r|	j                  |       |j                  d      }
t        |
t              s|
j!                  |       . t        | d      r| j                  t        d            j                         j	                         }|D ]F  }t        |j                  d      |j                  d            }|d   r|d	   s9t        |j                  d      xs d      j                         }t#        |      }|ss|j                  |g d
i d      }|j                  d      }t        |t$              si }||d<   |j                  ||d
d
d      }t        |j                  d      xs d      t        |j                  d      xs d      z   |d<   t        |j                  d      xs d      t        |j                  d      xs d      z   |d<   I |j'                         D ]  }t)        t        |j                  d      xs d      d      |d<   |j+                  di       }t        |t$              sg |d<   Wg }|j'                         D ]  }t        |t$              s|j!                  t        |j                  d      xs d      t)        t        |j                  d      xs d      d      t)        t        |j                  d      xs d      d      d        t-        |d       |d<    |S )Nr   tenant_inventory_warehousesa   
            SELECT
                items.product_name,
                items.supplier_name,
                items.total_equivalent_units,
                warehouses.name AS warehouse_name
            FROM tenant_inventory_stock_items AS items
            JOIN tenant_inventory_warehouses AS warehouses
                ON warehouses.id = items.warehouse_id
            WHERE COALESCE(items.total_equivalent_units, 0) > 0
            ORDER BY lower(warehouses.name) ASC, lower(items.product_name) ASC, lower(items.supplier_name) ASC
            rG   rH   warehouse_namer   r   r9   r]   )warehouse_namestotal_equivalent_units_lot_summariesr   r   tenant_inventory_stock_lotsa  
                SELECT
                    items.product_name,
                    items.supplier_name,
                    lots.lot_code,
                    COALESCE(lots.quantity, 0) AS quantity,
                    COALESCE(lots.equivalent_units, 0) AS equivalent_units
                FROM tenant_inventory_stock_lots AS lots
                JOIN tenant_inventory_stock_items AS items
                    ON items.id = lots.item_id
                WHERE COALESCE(lots.quantity, 0) > 0 OR COALESCE(lots.equivalent_units, 0) > 0
                ORDER BY lower(items.product_name) ASC, lower(items.supplier_name) ASC, lower(lots.lot_code) ASC
                lot_coder   )r   quantityequivalent_unitsr   r   r   lot_summariesc                     t        t        | j                  d      xs d            t        | j                  d      xs d      fS )Nr   r   )_normalize_catalog_lot_codero   rc   r   s    r?   <lambda>z3_load_product_inventory_summaries.<locals>.<lambda>[  s:    +C0D0J,KLDHHZ(.B/ rA   r   )rS   rY   r   r_   r   rL   rc   ro   r   
setdefaultrb   rK   r   addr   r   appendr   r   valuesrp   popr   )rM   	item_rowsinventory_by_productseen_by_productrh   product_keyr   summarynormalized_warehouse_name
seen_namesr   lot_rowsr   
lot_lookupr   lot_summaryraw_lot_summariess                    r?   !_load_product_inventory_summariesr    s0   ;<MRTVsDt	

	
 hj " FH79O 3,SWW^-DcggoF^_SWW%56<"=CCE1~[^>&11#%*-"$
 -2'++>V2W2\[\,]`eGG,-2a
 -
() %<N$K!$//SUC
$
201!++&78ot,"">2/32 R67::
  (*SSU! 	$  	C01H#''RaJbcKq>Q377:.4"5;;=H4X>J*55').1&(G $KK(89MmT2 ",9()'22 ( #(+K ',KOOJ,G,L1&MPUVYV]V]^hViVnmnPo&oK
#.3KOODV4W4\[\.]`e*+0qa /K*+;	B (..0 
,1%D\8]8bab2cef,g()#KK(8"=+T2')GO$,335 		Kk40   #KOOJ$?$E2 F %eKOOJ,G,L1&Mq Q(-eKOODV4W4\[\.]_`(a		 $*$
 #
2  rA   )inventory_summaryr   productr  r   c          	        
 t        |t              r|ni }|}|%|j                  d      }t        |t              r|ng }|xs g D cg c]  }t	        |      j                         s|  }}t        |j                  d      t              r|j                  d      ng }t        | j                        
t        
fd|D        d       }	i d| j                  d| j                  d| j                  d| j                  d| j                  d	| j                  d
| j                  d| j                  d| j                   d| j"                  d| j$                  d| j&                  d| j(                  d|dt+        |      dt-        t/        |j                  d      xs d      d      dt-        t/        |	xs i j                  d      xs d      d      dt-        t/        |	xs i j                  d      xs d      d      iS c c}w )Nr   r   c              3      K   | ]@  }t        |t              r.t        t        |j	                  d       xs d            k(  r| B yw)r   r   N)r   r   r   ro   rc   ).0r  normalized_product_lots     r?   	<genexpr>z%_serialize_product.<locals>.<genexpr>w  sD      	
+t,+C
0K0Qr,RSWmm 	
s   AA	r   rG   r   rH   product_codefinal_price_vatvat_rate	weight_kgunit_price_per_kgcategorynotesunits_per_packliters_per_unitr    inventory_total_equivalent_unitsr   r   r   inventory_lot_quantityr   inventory_lot_equivalent_unitsr   )r   r   rc   r   ro   r   r   r   nextr   rG   rH   r  r  r  r  r  r  r  r  r  r   rp   rb   )r  r  r   resolved_inventory_summarybase_warehouse_namessummary_warehouse_namesnameresolved_warehouse_namesr   matched_lot_summaryr  s             @r?   _serialize_productr)  d  sw    7AARTX6Y!2_a*#"<"@"@AR"S:DE\^b:c6ik2F2L"cQTUYQZQ`Q`Qbcc 044_EtL 	#&&7 
 99I9IJ	
,	
 	gjj,, 	G$$ 	..	
 	,, 	722 	G$$ 	W&& 	W66 	G$$ 	 	'00 	722 	3 	378  	+E%8R8V8VWo8p8utu2vxy,z!" 	!%/B/Hb.M.Mj.Y.^]^(_ab"c#$ 	)%7J7Pb6U6UVh6i6nmn0oqr*s% !  ds   H&Hcatalogc           	          | j                   | j                  | j                  | j                  | j                  t        | j                        t        | j                        dS )N)r   catalog_namerH   source_file_nametotal_itemsr   rn   )r   r,  rH   r-  r.  rF   r   rn   )r*  s    r?   _serialize_supplier_catalogr/    sS    jj,, ..#44**!'"4"45!'"4"45 rA   c                 R   | j                   | j                  | j                  | j                  | j                  | j
                  | j                  | j                  | j                  | j                  | j                  | j                  | j                  | j                  | j                  dS )Nr   
catalog_idsource_namesource_lot_codesource_supplier_namer  r  r  r  r  r  r  r  r  
sort_orderr1  r   s    r?    _serialize_supplier_catalog_itemr7    s    ggoo''// $ 9 9))//MM^^!33MM--//oo rA   rH   default_lot_coderh   r9  c                   | j                   xs |xs dj                         xs d }| j                  xs |xs dj                         xs d }| j                  j                         ||| j                  | j
                  | j                  | j                  | j                  | j                  | j                  | j                  | j                  dS )Nr   )r3  r4  r5  r  r  r  r  r  r  r  r  r  )r5  r   r4  r3  r  r  r  r  r  r  r  r  r  )rh   rH   r9  resolved_supplier_nameresolved_lot_codes        r?   _normalize_supplier_catalog_rowr=    s     "66M-M2TTV^Z^,,F0@FBMMOWSW,,., 6((..LL]] 22LL,,.. rA   r  r  r  r   r  r  r  r  c                   |&|dkD  r!t        t        |       t        |      z  d      S ||dk  ry ||dk  ry t        |      t        |      z  }||dkD  r|dt        |      dz  z   z  }t        t        |       |z  d      S )Nr      r9   d   )rp   rb   )r   r  r  r  r  
unit_totals         r?   _estimate_line_totalrC    s     "':U8_u_'==qAA $5$:IN()E),<<J1a5?S011
x:-q11rA   c                    | j                   .| j                   dkD  rt        t        | j                         d      S | j                  /| j                  dkD  r t	        | j
                  | j                        S | j                  }|y t	        | j
                  |j                  |j                  |j                  |j                        S )Nr   r@  r>  )estimated_line_totalrp   rb   final_price_vat_snapshotrC  r   r  r  r  r  r  )r   r  s     r?   _resolved_item_line_totalrG    s      ,1J1JQ1NU4445q99$$0T5R5RUV5V#DMM43P3PQQllG##!33!! rA   c                     t        |       }| j                  | j                  | j                  | j                  | j
                  | j                  | j                  || j                  | j                  d
S )N)
r   r   rG   r   rH   r   rF  rE  r  r  )
rG  r   r   rG   r   rH   r   rF  r  r  )r   resolved_line_totals     r?   _serialize_itemrJ    sc    3D9ggoo))MM++MM$($A$A 3--// rA   batchc                    | j                   D cg c]  }t        |       }}| j                  }||dk  rF|D cg c]"  }|j                  d      t	        |d         $ }}|rt        t        |      d      nd }| j                  | j                  |t        | j                        t        | j                        | j                  | j                  | j                  | j                  |d
S c c}w c c}w )Nr   rE  r@  )
r   stafftotal_estimated_amountconfirmed_atfiscal_document_matchedfiscal_document_idfiscal_document_namefiscal_document_typefiscal_document_matched_atr   )r   rJ  rN  rc   rb   rp   sumr   rM  rF   rO  boolrQ  rR  rS  rT  )rK  r   serialized_itemsresolved_batch_totalline_totalss        r?   _serialize_batchrZ    s    :?++F$-FF 77#';q'@GW  It[_[c[cdz[{  \HuT"89:  I  I=HuS%5q9dhh"6#E$6$67#'(@(@#A#66 % : : % : :&+&F&F!  G Is   C+C0C0c                    | xs dj                         j                  dd      }dD ]G  \  }}t        j                  ||      }|s	 t	        |j                  d            }||z  }|dkD  sE|c S  y # t        $ r Y Vw xY w)Nr   ,r   ))z(\d+(?:\.\d+)?)\s*(?:lt|l)\b      ?)z(\d+(?:\.\d+)?)\s*cl\bg{Gz?)z(\d+(?:\.\d+)?)\s*ml\bgMbP?r9   r   )lowerrD   researchrb   groupre   )rB   
normalizedpattern
multipliermatchamountliterss          r?   _extract_liters_from_textrh    s    +2$$&..sC8J  
 		':.	5;;q>*F *$A:M   		s   A22	A>=A>r   r  c                 R    ||dkD  r|S || fD ]  }t        |xs d      }||c S  y )Nr   r   )rh  )rG   r   r  source	estimateds        r?   _resolve_liters_per_unitrl  *  sH    "':\* -fl;	  rA   contextc                     d| j                   | j                  | j                  | j                  | j                  xs | j
                  xs | j                  dS )NT)successtokenrM  tenant_nametenant_slug	user_name)rp  default_staffrq  rr  rs  username
user_email)rm  s    r?   _login_responserw  4  sP    &&****&&P'*:*:Pg>P>P rA   c                    t        |       \  }}t        t              j                  t        j                  |k\  t        j                  |k        j                  t        t        j                        j                  t        j                              j                  t        j                  j                         t        j                  j                               }t        |j                  |            S rJ   )r@   r   r    whererO  optionsr   r   r!   r  order_bydescr   r   scalars)r6   rM   r=   r>   stmts        r?   _load_batches_for_yearr  ?  s    !$'JE3z	z&&%/1H1H31N	O	j../<<Y=N=NO	P	*))..0*--2D2D2F	G	 	 

4 !!rA   c                    | j                  t        t                    D ch c]X  }|j                  j                  *|j                  j                  t        j                        n|j                  j                  Z }}|j                  | j                  t        t        j                                     |s<|j                  t        j                  t        j                        j                         t        |d      S c c}w )Nr:   T)reverse)r}  r   r    rO  r;   rD   r   r<   r6   updater#   r   r   rU   r   )rM   rK  yearss      r?   
_all_yearsr  J  s     ZZz 23 =B<N<N<U<U<]			#	#8<<	#	8chcucu{{E  
LLF<#4#4567		(,,x||,112%&&s   ADrM  fallbackc                     | xs |xs t               j                  j                         j                         }|xs t               j                  S rJ   )r   rt  r   r^  )rM  r  rB   s      r?   _normalize_staffr  U  s>    >h>,.">">EEGMMOE0LN000rA   payloadc                     i }| j                         D ]%  \  }}	 t        |      }|dkD  s||t	        |      <   ' |S # t        t        f$ r Y ;w xY wNr   )r   r   rd   re   ro   )r  rb  r   	raw_valuer   s        r?   _normalize_suspended_payloadr  Z  sf    !#J!--/ ,Y	9~H a<#+Js3x , 	 :& 		s   =AAc                 `    | j                         }|st        t        j                  d      |S )Nz#Il testo della nota e' obbligatoriostatus_codedetail)r   r   r   HTTP_400_BAD_REQUEST)rB   r   s     r?   _normalize_note_textr  f  s)    ;;=D(C(CLqrrKrA   entryc                     | j                   j                         | j                  j                         | j                  j                         fS rJ   )rG   r   r   rH   )r  s    r?   _normalize_product_identityr  m  s@      "!!# rA   c                 b    i }| D ]  }||t        |      <    t        |j                               S rJ   )r  r   r  )r  dedupedr  s      r?   _dedupe_product_payloadr  u  s8    9;G <6;+E23< !!rA   c           
      8   |j                   |j                  |j                  |j                  |j                  |j
                  |j                  |j                  |j                  d	}|j                         D ]!  \  }}||j                  v st        | ||       # y )N	r  r  r  r  r  r  r  r  r  )r  r  r  r  r  r  r  r  r  r   model_fields_setsetattr)r  r  optional_fields
field_namerB   s        r?   _apply_product_metadatar  |  s    ** 00NN__"44NN.. 00
O -224 0
E///GZ/0rA   c                    t        j                  dt        | xs d            j                  dd      j	                  d      }|j                         j                  dd      }dt        j                  t           dt        fd	}t        j                  d
||      }t        j                  dd|      }dj                  |j                               S )NNFKDr   asciiignoreu   ’'re  r7   c                     | j                  d      j                  dd      }	 t        |      dz  }|dj	                  d      j	                  d      }| dS # t        $ r | j                  d      cY S w xY w)	Nr9   r\  r   g      Y@r   z.2fr   l)ra  rD   rb   re   r   )re  
raw_numberrg  rendereds       r?   convert_centilitersz4_normalize_catalog_text.<locals>.convert_centiliters  s|    [[^++C5
	":&.F S\))#.55c:1~  	";;q>!	"s   A A54A5z(\d+(?:[.,]\d+)?)\s*cl\bz
[^a-z0-9]+ )unicodedata	normalizero   r|   decoder^  rD   r_  Matchsubr   split)rB   rb  loweredr  s       r?   rK   rK     s    &&vs5;B/?@GGQYZaabijJ ((4G288C= S  ff02EwOGff]C1G88GMMO$$rA   c                     t        |       j                  dd      }|sy|dv s|j                  d      ry|dv s"|j                  d      s|j                  d      ry	|d
v s|j                  d      ry|S )Nr  r   >   bt	bottiglia	bottigliebottiglir     ctcassacassecartonecartonicartoncassr  >   pzpezzipezzopezzr  )rK   rD   
startswith)rB   rb  s     r?   r   r     s    (/77R@J559N9Nz9ZCCzG\G\]eGfjtjj  AG  kH--1F1Fv1NrA   	referencec                    | xs# t        j                  t        j                        }|j                   |j                  t        j                        }|j                  t              }t        |j                  |j                  |j                  t              }|j                  t        j                        |t        d      z   j                  t        j                        fS )Nr:   r9   )days)r   rU   r   r<   r;   rD   
astimezoneITALIAN_TIMEZONEr6   monthdayr   )r  currentlocallocal_starts       r?   _italian_day_utc_boundsr    s    58<<5G~~///6/0E5::u{{EIIFVWK""8<<0;PQAR3R2^2^_g_k_k2lmmrA   c           	         t        |      }|sy t               \  }}| j                  t        t              j                  t        j                  |k\  t        j                  |k  t        j                  j                  d             j                  t        t        j                        j                  t        j                              j                  t        j                  j                         t        j                   j                                     }|D ]M  }|j                  D ch c],  }t        |j"                        rt        |j"                        . }}||hk(  sK|c S  y c c}w rJ   )rK   r  r}  r   r    ry  rO  rQ  is_rz  r   r   r!   r  r{  ascr   rH   )	rM   rH   supplier_keyr=   r>   batchesrK  r   batch_supplier_keyss	            r?   _find_open_daily_supplier_batchr    s'   *=9L(*JE3jjz	##u,##c)))--d3


 
j../<<Y=N=NO	P	*))--/1B1B1D	E	G   
&t'9'9: $D$6$67
 

 <.0L 
s   (1E(c                    || _         |j                  | _        |j                  | _        |j                  | _        |j
                  | _        || _        |j                  | _        t        ||j                  |j                  |j                  |j                        | _        |j                  | _        t        |j                  |j                  |j                         | _        y )Nr>  )r  r   r   rG   r   rH   r   r  rF  rC  r  r  r  rE  r  rl  r  )r   r  r   s      r?   _update_order_item_from_productr    s    DLjjDO,,D$$DM ..DDM$+$;$;D! 4##!33!!!D "00D3G4H4H'JZJZ\c\s\stDrA   c                     t        fd| j                  D        d       }|3t               }t        ||       | j                  j	                  |       y t        |t        |j                  xs d      |z          y )Nc              3   V   K   | ]   }|j                   j                  k(  s| " y wrJ   )r   r   )r  r   r  s     r?   r  z+_append_product_to_batch.<locals>.<genexpr>  s      X4$//WZZ:W$Xs   ))r   )r"  r   r!   r  r   r   r   )rK  r  r   existing_itemr   s    `   r?   _append_product_to_batchr    sk    X5;;XZ^_M{'gx@4 #M7C@V@V@[Z[<\_g<ghrA   c                     | j                   D cg c]  }t        |      x}t        |       }}|rt        t	        |      d      | _        y d | _        y c c}w )Nr@  )r   rG  rb   rp   rU  rN  )rK  r   
line_totalrY  s       r?   _recalculate_batch_totalr    sa     KK3D99JF 	jK 
 BM5[)91#=E RVE s   Ac                 b    t        |       j                  d      D ch c]  }|s|	 c}S c c}w )Nr  )rK   r  )rB   rp  s     r?   _catalog_name_tokensr    s(    6u=CCCHReEERRRs   ,,leftrightc                 4   t        |       }t        |      }|r|sy||k(  ryt        |       }t        |      }t        ||z        t        t        |      t        |      d      z  }t	        d ||      j                         }t        d|dz  |dz  z         }||fS )N)r]   r]   )r]  r]  r9   r]  g(\?g{Gz?)rK   r  r   rf   r   ratiorg   )	r  r  left_normalizedright_normalizedleft_tokensright_tokenstoken_overlapsequence_scorescores	            r?   _catalog_name_similarityr    s    -d3O.u5"2**&t,K'.Ll23c#k:JCP\L]_`6aaM$T?<LMSSUNnt+0DEFE-rA   
match_typec                 :    dddddddd}|j                  | |       S )	Ncodicezidentita esattaznome esattoz
nome fortenuovoambiguosaltato)
exact_codeexact_identity
exact_namestrong_namenew	ambiguousskippedrc   )r  labelss     r?   _catalog_match_labelr  	  s1    +##F ::j*--rA   matched_productc          
      >   ||j                   n| j                  j                         }|xs ||j                  nd xs dj                         }|xs ||j                  nd xs dj                         }|||d}| j
                  | j
                  n||j
                  nd | j                  | j                  | j                  | j                  | j                  | j                  | j                  | j                  d	}|j                         D ]  \  }	}
|
	|
||	<    |S )Nr   )rG   rH   r   r  )rG   r3  r   rH   r   r  r  r  r  r  r  r  r  r  r   )rh   r  rH   r   rG   resolved_supplierresolved_lotr  r  r  rB   s              r?   $_product_upsert_payload_from_previewr    s7    4C3N?//TWTcTcTiTiTkL&xOLg?+H+Hmqxvx  Bi_=X!9!9^bigipprL %* "G -0,<,<,H((o~  pKOkOk  QU..LL]] 22LL,,..
O -224 (
E"'GJ( NrA   requestproductsc                    t        t              }t        t              }t        t              }t        t              }|D ]  }t        |j                        }t        |j                        }t        |j                        }	t        |j                        }
|
r||
   j                  |       |r|r|	r|||	|f   j                  |       |r||   j                  |       |s|	s|||	f   j                  |        g }ddddddddddd
}| j                  xs dj                         }| j                  xs dj                         }t        | j                  d      D ]  \  }}|dxx   dz  cc<   |j                  j                         }|j                  xs |xs dj                         }|j                  xs |xs dj                         }t        |      }t        |      }t        |      }	t        |j                        }
g }d }d}d}d	}|s|j                  d
       |s|j                  d       |s|j                  d       |
rx|j!                  |
g       }|r+|D cg c]  }t        |j                        |k(  r| }}|r|}t#        |      dk(  r
|d   }d}d}n!t#        |      dkD  r|j                  d       d}|T|rR|rP|	rN|j!                  ||	|fg       }t#        |      dk(  r
|d   }d}d}n!t#        |      dkD  r|j                  d       d}||r|r|j!                  |g       }|	r)|D cg c]  }t        |j                        |	k(  s| }}n|}|D cg c]  }t        |j                        |k(  s| }}t#        |      dk(  r|d   }d}d}nt#        |      dkD  r|j                  d       d}n|rg } |D ]X  }t%        ||j                        \  }!}"|	r't        |j                        |	k(  rt'        d|!dz         }!| j                  |!|"|f       Z | j)                  d d       | d   \  }#}$}%t#        |       dkD  r| d   d   nd}&|#dk\  s|#dk\  r|$dk\  r|#|&z
  dk\  r|%}d}t+        |#d       }n>|#d!k\  r9|j                  d"|%j                   d#t-        t+        |#d$z               d%       d}|4|dk7  r/|r-|	r+|j!                  ||	fg       }'t#        |'      dk(  r	|'d   }d}d&}|8|j                  }|j                  }d}|d'xx   dz  cc<   |d(| xx   dz  cc<   nH|dk(  r|d)xx   dz  cc<   n5|r$|r"|r | j.                  rd*}d}d}|d+xx   dz  cc<   nd}|d,xx   dz  cc<   |r|d-xx   dz  cc<   |rt1        ||||.      nd }(|j                  |||j                  |j                  |j                  |t3        |      t+        |d       |||t5        |      nd |(d/        d||d0S c c}w c c}w c c}w )1Nr   )

total_rowsimportable_rowsmatched_rowsmatched_exact_codematched_exact_identitymatched_exact_namematched_strong_namenew_rowsambiguous_rowsskipped_rowsr   r9   r=   r  r  r]   FzNome prodotto mancante.zLFornitore mancante: imposta una colonna fornitore o un fornitore di default.z@Lotto mancante: imposta una colonna lotto o un lotto di default.r  r]  zFCodice prodotto presente ma associato a piu righe del catalogo locale.r  r  gGz?z>Prodotto gia presente piu volte con la stessa identita locale.r  g
ףp=
?zLNome prodotto coincidente su piu varianti locali: specifica meglio il lotto.g{Gz?c                     | d   S r  rV   r   s    r?   r   z0_preview_supplier_catalog_rows.<locals>.<lambda>  s
    Q rA   T)r   r  gzG?g(\?gzG?g?r     gQ?z/Riconoscimento non abbastanza sicuro: proposta z (rA  z%).gGz?r  matched_r  r  r  r  r  )r  rH   r   )	row_indexr3  r5  r4  source_product_coder  match_label
confidence
importablewarningsr  proposed_product)okr  r   )r   r   rK   rG   rH   r   r   r  r   r   r9  	enumerater   r3  r5  r4  rc   r   r  rg   sortrp   r   create_missingr  r  r)  ))r  r  products_by_codeproducts_by_identityproducts_by_supplierproducts_by_name_and_lotr  normalized_namenormalized_suppliernormalized_lotnormalized_codepreview_rowsr  default_supplier_namer9  indexrh   r3  source_supplier
source_lotr  r  r  r  r  code_candidates	candidatesupplier_filteredidentity_candidatessupplier_candidateslot_candidatesexact_name_candidatesscored_candidatesr  overlap
best_scorebest_overlapbest_candidatesecond_scorefallback_candidatesr  s)                                            r?   _preview_supplier_catalog_rowsr9  9  s3    9DD8IMXY]M^<G<MLWX\L] X1'2F2FG5g6K6KL4W5E5EF1'2F2FG_-44W=2~ />CV!WX__`gh !45<<WE~$o~%FGNNwWX -/L"# G %228b??A006B==?A6 O

s"oo++-33R7LRPRYY[))C-=CJJL
1+>5oF4Z@1#2B2BC *.


OO56OOjkOO^_.22?BGO" &5%!.y/F/FGK^^ %! %
 %&7O?#q("1!"4)
 
_%) hi(
";NSa"6":":O^]p;qsu"v&'1,"5a"8-
!
()A- `a(
";N"6":":;NPR"S/B""+FabkbtbtFu  zH  GHI" " "5 ,:%'=TU^UkUk=lp=	%! % ()Q."7":)
!
*+a/ no(
HJ!!/ JI%=k9KaKa%bNE7%*EiFXFX*Y]k*k #C 6%,,eWi-HI	J
 "&&+?&N;LQ;O8
L.:=>O:PST:T03A6Z]&:+=,RVBV\fiu\uz~[~&4O!.J!&z1!5J4'OOI.JeJeIffhilmrs}  AD  tD  nE  jF  iG  GJ  K "-J"z['@_Yg":">">Q_?`bd"e&'1,"5a"8)
!
&-;;O(11JJN#q(#hzl+,1,;&$%*%ZGDZDZJJJJ1$"JN#q(#%&!+&  1 /-#	  	 	"*(+(@(@#&#6#6'*'7'7(3J?#J2($JYJe#5o#Fko$4	
AO
d  o%8"%s   $!X ;XX&X
X
F	secondarygoalr;  c                   |r|j                   n|j                  }|r|syt        j                  d|xs d      D cg c]%  }|j	                  d      s|j	                  d      ' }}|r/| j
                  j                         t        fd|D              sy|j                  r5|j                  j                         | j                  j                         vryyc c}w )NFz\s*\|\s*|\s*,\s*|\s*;\s*r   z .,-c              3   B   K   | ]  }|j                         v   y wrJ   )r^  )r  termrG   s     r?   r  z _goal_matches.<locals>.<genexpr>  s     JD4::<</Js   T)
secondary_product_matchproduct_matchr_  r  r   rG   r^  anysupplier_matchrH   )r   r<  r;  rA  partproduct_termsrG   s         @r?   _goal_matchesrF    s    4=D004CUCUM46HH=XZgZmkm4n  FDrvr|r|  ~D  sETZZ'  FM  F((..0JMJJt2288:$BTBTBZBZB\\ Fs   CCc                     t        |       dk(  S )Nr  )r   )r   s    r?   _is_pack_lot_coderH    s    &x0D88rA   c                     | j                   | j                   n#| j                  | j                  j                   nd }|y 	 t        |      }|dkD  r|S d S # t        t        f$ r Y y w xY w)Nr9   )r  r  rb   rd   re   )r   r  r  s      r?   _order_item_units_per_packrJ    s    '+':':'F##lplxlx  mET\\MhMh  KOIy) ,a/>9T9 z" s   A A'&A'c                 L    t        | j                        syt        |       xs dS )Nr]  )rH  r   rJ  r   s    r?   _order_item_pack_multiplierrL    s!    T]]+%d+2s2rA   c                     t        | j                  xs d      }|sy|dv xs$ |j                  d      xs |j                  d      S )Nr   Fr  r  r  )rK   
unit_labelr  )r<  rN  s     r?   _goal_counts_order_packsrO    sc    ()>B?JGG  L:K`K`aiKj  Lnx  oD  oD  EK  oL  LrA   c                 j    t        | j                  xs d      }t        |      r|S |t        |       z  S r  )rb   r   rO  rL  )r   r<  r   s      r?   _order_item_goal_quantityrQ  $  s3    T]]'a(H%1$777rA   r  c                 H   | j                   dk(  r| j                  | j                  | j                  d| j                  xs d| j
                  | j                  | j                  | j                  | j                  | j                  | j                  dS | j                   dk(  rd}d}|D ]  }|j                  D ]  }t        |j                  |j                  |j                   |j                   n#|j"                  |j"                  j                   nd       }|a||j$                  z  t'        |      z  }t)        ||       r||z  }t)        || d      s||z  }  i d| j                  d	| j                  d
| j                  ddd| j                  xs dd| j                  xs ddt+        |d      dt+        |d      d| j                  d| j                  xs dd| j
                  d| j                  d| j                  d| j                  d| j                  d| j                  xs dS d}|D ]  }|j                  D ]  }t)        ||       s| j                   dk(  r}t        |j                  |j                  |j                   |j                   n#|j"                  |j"                  j                   nd       }|}|||j$                  z  t'        |      z  z  }|t-        ||       z  }  | j                  | j                  | j                  | j                   | j                  xs dt+        |d      | j                  xs | j                   dk(  rdnd| j                  | j                  xs d| j
                  | j                  | j                  | j                  dS )Nnoter   )r   r6   r&  r   descriptionrA  r@  rC  targetsecondary_targetunitbonusliters_dualr]   Tr:  r   r6   r&  r   target_greyr   target_patronprogress_greyr@  progress_patronrX  rT  rA  r@  rC  rU  rV  rW  Lrg  articoli)r   r6   r&  r   rU  progressrW  rX  rT  rA  r@  rC  rV  )	goal_typer   r6   r&  rT  rA  r@  rC  rU  rV  rN  bonus_labelr   rl  rG   r   r  r  r   rL  rF  rp   rQ  )	r<  r  primaryr;  rK  r   resolved_litersrg  r`  s	            r?   _goal_progressre  +  s   ~~''IIII++1r!//'+'C'C"11kk $ 5 5OO%%
 	
 ~~&	 	(E (":%%MM,0,@,@,LD((swss  tLSWS_S_SoSo  RV#
 #*(4==8;VW[;\\ t,v%G tt<'I(	(
$''
DII
 DII
 M	

 4;;+!
 T227a
 U7A.
 uY2
 T%%
 4++1r
 T//
 &t'C'C
 d11
 dkk
  5 5
  DOO*s!
 	
& H BKK 	BD t,~~)":%%MM,0,@,@,LD((swss  tLSWS_S_SoSo  RV#
 #*Odmm;>YZ^>___5dDAA	BB" gg				++"(A&V4>>X+EC:!!''-2++#'#?#?-- 11 rA   z/healthc                      dddS )Nr  zordini-backend)r   servicerV   rV   rA   r?   health_checkrh    s    '788rA   z
/api/loginc                     	 t        | j                  | j                  | j                        }|j
                  dk(  rd|j                  vrdddS t        |      S # t        $ r ddicY S w xY w)N)
identifierpasswordsession_tokenro  FrM  ordiniz(Questo account non puo accedere a Ordini)ro  r  )r   rj  rk  rl  re   rolepermissionsrw  )r  rm  s     r?   loginrp    sz    "$))%%!//
 ||w873F3F#F ,VWW7##	  "5!!"s   ,A A+*A+z/api/sessionauthc                     d| j                   | j                  | j                  | j                  | j                  xs | j
                  xs | j                  | j                  dS )NT)authenticatedrp  rM  rq  rr  rs  rj  )rp  rt  rq  rr  rs  ru  rv  rj  )rq  s    r?   session_infort    sS     ##''''^^Gt}}G++ rA   z/api/sotto-stockc                 4    t        |       }t        | |       |S rJ   )r   r   )rM   r   s     r?   get_safety_stock_statusrv    s    .r2NN3rA   z/api/sotto-stock/settingsc                     dt        |       iS )Nrk   )rj   rZ   s    r?   get_safety_stock_settingsrx    s    3B788rA   c                 d    t        || j                        }t        ||      }t        ||       |S )Nr   )rs   rk   r   r   )r  rM   rk   r   s       r?   update_safety_stock_settingsrz    s2    
 ,B0D0DEL.rMNN3rA   z/api/prodottic                    t        t              j                  t        j                  j	                  d            j                  t        j                  t        j                  t        j                        }t        | j                  |            }t        |       }|D cg c]=  }t        ||j                  t        |j                  |j                        i             ? c}S c c}w )NT)r  )r   r"   ry  activer  r{  rH   rG   r   r   r}  r  r)  rc   rL   )rM   r~  r  inventory_summaries_by_productr  s        r?   list_productsr~    s    '?  !3!3D!9:CCGDYDY[b[o[oqx  rB  rB  CDBJJt$%H%Fr%J"  	  	<@@&w';';W=R=RS	
	 	 	s    AC%z/api/fornitori/cataloghic           	          t        | j                  t        t              j	                  t        j
                  j                         t        j                  j                                           }d|D cg c]  }t        |       c}iS c c}w )Ncatalogs)	r   r}  r   r%   r{  rn   r|  r   r/  )rM   r  r*  s      r?   list_supplier_catalogsr    sm    


?#,,_-G-G-L-L-NP_PbPbPgPgPij	
H
 XV'4W=VWWVs   5Bz%/api/fornitori/cataloghi/{catalog_id}r2  c           	         |j                  t        |       }|t        t        j                  d      t        |j                  t        t              j                  t        j                  | k(        j                  t        j                  j                         t        j                  j                                           }t        |      |D cg c]  }t!        |       c}dS c c}w )NCatalogo fornitore non trovator  )r*  r   )rc   r%   r   r   HTTP_404_NOT_FOUNDr   r}  r   r&   ry  r2  r{  r6  r  r   r/  r7  )r2  rM   r*  r   r   s        r?   get_supplier_catalogr    s    ff_j1G(A(AJjkk


&'U&11Z?@X)4488:<O<R<R<V<V<XY	
E /w7EJKT248K Ks   C(r  c                     |j                  t        |       }|t        t        j                  d      |j                  |       |j                          t        t        j                        S )Nr  r  r  )	rc   r%   r   r   r  deleterq   r   HTTP_204_NO_CONTENT)r2  rM   r*  s      r?   delete_supplier_catalogr    sQ    ff_j1G(A(AJjkkIIgIIK : :;;rA   z%/api/fornitori/cataloghi/items/searchr   q)defaultaliasP   r9   i,  )r  gelelimitc                    | xs dj                         j                         }t        t        t              j                  t        t        j                  t        j                  k(        j                  t        j                  j                         t        j                  j                         t        j                  j                               }|rd| d}|j                  t        j                  j                  |      t        j                   j                  |      z  t        j"                  j                  |      z  t        j$                  j                  |      z  t        j&                  j                  |      z  t        j(                  j                  |      z        }|j+                  |j-                  |            j/                         }g }|D ]/  \  }}	t1        |      }
t3        |	      |
d<   |j5                  |
       1 d|iS )Nr   %r*  r   )r   r^  r   r&   r%   r   r   r2  r{  rn   r|  r6  r  ry  r3  iliker5  r4  r  r,  rH   rY   r  r   r7  r/  r   )r  r  rM   r`  r~  
like_valuer   r   r   r*  
serializeds              r?   search_supplier_catalog_itemsr    s    g2__$$&F"O4	o115H5S5SS	T	/,,1135H5S5S5W5W5Y[n[q[q[u[u[w	x 	 ]
zz++11*=!66<<ZHI!1177
CD "..44Z@A **00<	=
 ++11*=>
 ::djj'(,,.D%'E !g5d;
 ;G D
9Z ! UrA   c                 .   | j                   D cg c]>  }|j                  j                         r"t        || j                  | j
                        @ }}|st        t        j                  d      | j                  xs |d   j                  d      xs dj                         xs d }| j                  xs dj                         xs) | j                  xs dj                         xs	 |rd| nd}t        ||| j                  xs dj                         xs d t        |      	      }|j                  |       |j                          t!        |d
      D ]  \  }}|j                  t#        |j$                  t'        |j                  d      xs d      j                         |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      |             
 |j)                          |j+                  |       dt-        |      dS c c}w )Nr8  z/Il catalogo fornitore non contiene righe valider  r   r5  r   z	Catalogo zCatalogo fornitore)r,  rH   r-  r.  r9   r  r3  r4  r  r  r  r  r  r  r  r  r  )r2  r3  r4  r5  r  r  r  r  r  r  r  r  r  r6  T)r  r*  )r   r3  r   r=  rH   r9  r   r   r  rc   r,  r-  r%   r   r   flushr  r&   r   ro   rq   refreshr/  )r  rM   rh   normalized_rowsr;  resolved_catalog_namer*  r(  s           r?   create_supplier_catalogr    sL    << ??  " 	(!//$55	
O  (C(CL}~~%33kq7I7M7MNd7ekikrrt|x|				#**, 	f$$*113	f4Ji./0Pd  *,!228b??AIT(	G FF7OHHJq9 

s
":: 6 <"=CCE #(9 :%(WW-C%D WW^4 #(9 :,''+."%''*=">,ggg&"ww'78 #(9 : 	

( IIKJJw#>w#GHHes   AJz/api/prodotti/catalogo/previewc           	         | j                   st        t        j                  d      t	        |j                  t        t              j                  t        j                  j                  d            j                  t        j                  t        j                  t        j                                    }t        | |      S )NzNessuna riga catalogo ricevutar  T)r   r   r   r  r   r}  r   r"   ry  r|  r  r{  rH   rG   r   r9  )r  rM   r  s      r?   preview_supplier_catalogr  J  s    <<(C(CLlmm


7O!!'.."4"4T":;DDWEZEZ\c\p\pry  sC  sC  D	
H
 *'8<<rA   z/api/prodotti/{product_id}r   c           	         |j                  t        |       }|t        t        j                  d      t        |      \  }}}|j                  t        t              j                  t        j                  | k7  t        j                  |k(  t        j                  |k(  t        j                  |k(              }|t        t        j                  d      ||_
        ||_        ||_        t        ||       d|_        	 |j!                          |j'                  |       dt)        |      dS # t"        $ r1}|j%                          t        t        j                  d      |d }~ww xY w)NProdotto non trovator  zCEsiste gia un altro prodotto con lo stesso nome, lotto e fornitore.TzGAggiornamento prodotto in conflitto: controlla nome, lotto e fornitore.)r  r  )rc   r"   r   r   r  r  scalarr   ry  r   rG   r   rH   HTTP_409_CONFLICTr  r|  rq   r   rollbackr  r)  )	r   r  rM   r  rG   r   rH   conflicting_productexcs	            r?   update_productr  W  sE   ffWj)G(A(AJ`aa,G,P)L(M))wJJ*$  L0(!!]2		
 &00X
 	

 (GG)GGW-GN
		 JJw#5g#>??  
00\
 	s   =D, ,	E&5,E!!E&c                    |j                  t        |       }|t        t        j                  d      d|_        	 |j                          d| dS # t        $ r1}|j                          t        t        j                  d      |d }~ww xY w)Nr  r  Fz#Eliminazione prodotto non riuscita.T)r  r   )
rc   r"   r   r   r  r|  rq   r   r  r  )r   rM   r  r  s       r?   delete_productr    s    ffWj)G(A(AJ`aaGN
		 j11  
008
 	s   A 	B,BBc           	         | st        t        j                  d      t        |       }d}d}|D ]  }t	        |      \  }}}|j                  t        t              j                  t        j                  |k(  t        j                  |k(  t        j                  |k(              }	|	2t        |||d      }
t        |
|       |j                  |
       |dz  }t        |	|       d|	_        |dz  } t        |       t        |      z
  }	 |j!                          d|||dS # t"        $ r1}|j%                          t        t        j&                  d      |d }~ww xY w)	NzNessun prodotto ricevutor  r   T)rG   r   rH   r|  r9   zImport prodotti in conflitto: controlla se il file contiene righe duplicate o se lo stesso prodotto e' stato creato in parallelo.)r  createdupdatedduplicate_rows)r   r   r  r  r  r  r   r"   ry  rG   r   rH   r  r   r|  r   rq   r   r  r  )r  rM   normalized_payloadr  r  r  rG   r   rH   existingr  r  r  s                r?   upsert_productsr    se   (C(CLfgg09GG# 0KE0R-h997O!!$$4  H,%%6
 )!+	G $GU3FF7OqLG%01/2 \C(:$;;N
		 7wR`aa  
00 W
 	s   	D   	E),EEz/api/ordini)r  c                     | xs- t        j                  t        j                        j                  }t        ||      D cg c]  }t        |       c}S c c}w rJ   )r   rU   r   r<   r6   r  rZ  )r6   rM   target_yearrK  s       r?   list_ordersr    sA    9(,,x||499K1GUW1XYU#YYYs    Az/api/ordini/yearsc                     dt        |       iS )Nr  )r  rZ   s    r?   list_order_yearsr    s    Z^$$rA   c                    | j                   st        t        j                  d      | j                   D cg c]  }|j                   }}|j                  t        t              j                  t        j                  j                  |      t        j                  j                  d                  D ci c]  }|j                  | }}| j                   D cg c]  }|j                  |vs|j                   }}|rt        t        j                  d|       | j                   D ch c]P  }||j                     j                  j                         r'||j                     j                  j                         R }	}t!        |	      dk(  rt#        |t%        t'        |	                  nd }
|
<t)        t+        | j,                  |j.                              }
|j1                  |
       n3t+        | j,                  |
j,                  xs |j.                        |
_        t3        t4              }| j                   D ]#  }||j                  xx   |j6                  z  cc<   % |j                         D ]  \  }}t9        |
||   |        t;        |
       |j=                          |j?                  |
       |jA                  t        t(              j                  t(        j                  |
j                  k(        jC                  tE        t(        j                                     }|t        t        jF                  d      dtI        |      dS c c}w c c}w c c}w c c}w )	NNessun prodotto selezionator  TProdotti non trovati: r9   )rM  z"Ordine salvato ma non ricaricabiler  rK  )%r   r   r   r  r   r}  r   r"   ry  r   in_r|  r  r  rH   r   r   r  r"  iterr    r  rM  rt  r   r   r   r   r  r  rq   r  r  rz  r   HTTP_500_INTERNAL_SERVER_ERRORrZ  )r  rq  rM   r   product_idsr  r  missingr  supplier_namesrK  aggregated_quantitiesr   r   loaded_batchs                  r?   create_orderr    s    ==(C(CLijj/6}}=t4??=K= zz&/"7"7

{8SU\UcUcUgUghlUm"no 	

GH  ,3==\4DOOS[<[t\G\(A(ALbcjbkJlmm ]]E$$%3399; 	!!"00668N 
 PSSaObfgOg+BT.5I0JKmqE}!1'--ASAS!TU
u&w}}ekk6WTEWEWX3>s3C Be../5>>A/B 5 ; ; = H
H (<hGHU#IIKJJu99VJ/55jmmuxx6OPXXYefpfvfvYwxyL(M(MVz{{!1,!?@@C > ]s   M5MM-M+AMc                    | j                   st        t        j                  d      |j	                  t        t              j                  t        j                  | j                  k(        j                  t        t        j                                     }|t        t        j                  d      | j                   D cg c]  }|j                   }}|j                  t        t              j                  t        j                  j!                  |      t        j"                  j%                  d                  D ci c]  }|j                  | }}| j                   D cg c]  }|j                  |vs|j                   }}|rt        t        j                  d|       t'        | j(                  |j(                  xs |j*                        |_        d}	d}
|j                   j-                          |j/                          | j                   D ]  }||j                     }t1        |j2                  |j4                  |j6                  |j8                  |j:                        }|d}
|	|z  }	|j=                  t?        |j                  |j                  |j@                  |jB                  |jD                  |j2                  |j4                  ||jF                  tI        |j@                  |jB                  |jJ                        	
              |
rtM        |	d
      nd |_'        |jQ                          |j	                  t        t              j                  t        j                  |j                  k(        j                  t        t        j                                     }|t        t        jR                  d      dtU        |      dS c c}w c c}w c c}w )Nr  r  Ordine non trovatoTr  r]   Fr>  )
batch_idr   rG   r   rH   r   rF  rE  r  r  r@  z%Ordine aggiornato ma non ricaricabiler  )+r   r   r   r  r  r   r    ry  r   r  rz  r   r  r   r}  r"   r  r|  r  r  rM  rt  clearr  rC  r   r  r  r  r  r   r!   rG   r   rH   r  rl  r  rp   rN  rq   r  rZ  )r  rq  rM   rK  r   r  r  r  r  batch_total_estimated_amounthas_priced_linesr  r  r  s                 r?   update_orderr    s    ==(C(CLijjIIfZ(..z}}@P@P/PQYYZfgqgwgwZxyzE}(A(AJ^__/6}}=t4??=K= zz&/"7"7

{8SU\UcUcUgUghlUm"no 	

GH  ,3==\4DOOS[<[t\G\(A(ALbcjbkJlmm"7==%++2SASASTEK#& 	KKHHJ 
5++,)NN##''%77%%

 !#(J6(
"::$11 ))%33)0)@)@%/&55 89M9MwO_O_ahaxax y	

6 N^5)Eq#IcgE IIK99VJ/55jmmuxx6OPXXYefpfvfvYwxyL(M(MV}~~!1,!?@@c > ]s   O O$O8Oc                    d }| j                   o|j                  t        t              j	                  t        j
                  | j                   k(        j                  t        t        j                                    }n| j                  r	 t        j                  | j                  j                  dd            }|j                  t        t              j	                  t        j"                  |k(        j                  t        t        j                                    }nt        t        j                   d      |t        t        j$                  d      |j                  D cg c]  }t'        |       }}|j)                  |       |j+                          d|dS # t        $ r!}t        t        j                   d      |d }~ww xY wc c}w )	NZz+00:00zTimestamp ordine non validor  zSpecifica batch_id o timestampr  T)r  removed)r  r  r   r    ry  r   rz  r   r   r   r   fromisoformatrD   re   r   r   r  rO  r  rJ  r  rq   )r  rM   rK  rU  r  r   removed_itemss          r?   delete_orderr  9  sf   #E#		&,22:==GDTDT3TU]]^jkuk{k{^|}~				x++G,=,=,E,Ec8,TUF 		&,22:3J3Jf3TU]]^jkuk{k{^|}~(C(CLlmm}(A(AJ^__7<{{Ct_T*CMCIIeIIK=11  	xF,G,GPmntww	x Ds   /F %G	G	(GG	z/api/ordini/ultimoc                 D   t        t              j                  t        t        j                              j                  t        j                  j                         t        j                  j                               }| j                  |      }|dd iS dt        |      iS )NrK  )r   r    rz  r   r   r{  rO  r|  r   r  rZ  )rM   r~  rK  s      r?   latest_orderr  P  s    *%%l:3C3C&DENNzOfOfOkOkOmoyo|o|  pB  pB  pD  EDIIdOE}%e,--rA   z/api/ordini/confrontoc           	      >   | xs- t        j                  t        j                        j                  }t        ||      }|dz
  }t        ||      }t        t              t        t              }|D ]4  }|j                  D ]#  }|j                  xx   |j                  z  cc<   % 6 |D ]4  }|j                  D ]#  }||j                  xx   |j                  z  cc<   % 6 t        t              t        |      z  fd      }	g }
|	D ]]  }j                  |d      }|j                  |d      }||z
  }d }|rt        ||z  dz  d      }n|rd }|
j                  |||||d       _ ||t!        j#                               t!        |j#                               |
dS )Nr9   c                 .    j                  | d       | fS r  r  )r&  current_totalss    r?   r   z compare_orders.<locals>.<lambda>k  s     ZhZlZlmqstZuYuw{X| rA   r   r   rA  )rG   current_quantityprevious_quantitydeltadelta_percent)r6   previous_yearcurrent_totalprevious_totalr   )r   rU   r   r<   r6   r  r   r   r   rG   r   r   r   rc   rp   r   rU  r  )r6   rM   r  current_batchesr  previous_batchesprevious_totalsrK  r   product_namesr   rG   r  r  r  r  r  s                   @r?   compare_ordersr  Y  s   9(,,x||499K,["=O!OM-mR@%0%5N&1#&6O  ?KK 	?D4,,->-	?? " @KK 	@DD--.$--?.	@@ 3~._1EEK|}ME% 
)--lA>+//a@ #44!5+<#<"CQGM M ,$4%6!.	

( &^2245o4467 rA   z/api/ordine_sospesoc           	          |j                  t        t              j                  t        j                  t        | |j                        k(              }|r|j                  S i S rJ   )r  r   r'   ry  rM  r  rt  r  rM  rq  rM   	suspendeds       r?   get_suspended_orderr    sP     		&066~7K7KO_`egkgygyOz7z{|I )91r1rA   .c                 r   t        |       }|st        t        j                  d      t	        ||j
                        }|j                  t        t              j                  t        j                  |k(              }|t        ||      }|j                  |       n||_        |j                          ddiS )NzNessun prodotto da sospenderer  )rM  r  r  T)r  r   r   r  r  rt  r  r   r'   ry  rM  r   r  rq   )r  rM  rq  rM   rb  target_staffr  s          r?   save_suspended_orderr    s     .g6J(C(CLkll#E4+=+=>L		&066~7K7K|7[\]I"zJ	
y&	IIK$<rA   c           	          |j                  t        t              j                  t        j                  t        | |j                        k(              }|!|j                  |       |j                          t        t        j                        S )Nr  )r  r   r'   ry  rM  r  rt  r  rq   r   r   r  r  s       r?   delete_suspended_orderr    si     		&066~7K7KO_`egkgygyOz7z{|I
		)
		 : :;;rA   z	/api/notec           	      d   t        t              j                  t        j                  j	                         t        j
                  j	                               }| j                  |      D cg c]:  }|j
                  |j                  |j                  t        |j                        d< c}S c c}w )Nr   authorr   r   )
r   r$   r{  r   r  r   r}  r  r   rF   )rM   r~  rS  s      r?   
list_notesr    s    *&&z'<'<'@'@'BJMMDUDUDWXD JJt$  ''kkII$T__5		
  s   +?B-c                 B   t        t        d |j                        t        | j                              }|j                  |       |j                          |j                  |       d|j                  |j                  |j                  t        |j                        diS )N)r  r   rS  r  )r$   r  rt  r  r   r   rq   r  r   r  rF   r   )r  rq  rM   rS  s       r?   create_noter    s~     -dD4F4FGNbcjcocoNpqDFF4LIIKJJt''kkII$T__5	
 rA   z/api/note/{note_id}note_idc                     |j                  t        |       }|t        t        j                  d      |j                  |       |j                          t        t        j                        S )NzNota non trovatar  r  )	rc   r$   r   r   r  r  rq   r   r  )r  rM   rS  s      r?   delete_noter    sP    66*g&D|(A(AJ\]]IIdOIIK : :;;rA   z/api/obiettivi/{goal_id}goal_idc                    |j                  t        |       }|t        t        j                  d      t        |j                  xs d      j                         }|dvrt        t        j                  d      |j                  j                         |_	        ||_        |j                  xs |j                  |_
        |j                  |_        |j                  |_        |j                  |_        |j                  |_        |j                  |_        |j                   |_        |j"                  |_        |j$                  |_        |j                  dk(  rRd |_        d |_        d |_        d |_        d |_        d |_        |j                  s4t        t        j                  d      |j                  dk(  r||j                  r|j                  st        t        j                  d	      |j                  |j                   t        t        j                  d
      |j"                  xs d|_        n|j                  t        t        j                  d      |j                  s'|j                  st        t        j                  d      d |_        d |_        |j"                  xs |j                  dk(  rdnd|_        |j'                          |j)                  |       t+        |j                  |      }dt-        ||      dS )NzObiettivo non trovator  r   >   rS  rg  r   rY  zTipo obiettivo non validorS  z#Per una nota serve una descrizione.rY  zDPer un doppio target servono prodotto principale e secondo prodotto.zCPer un doppio target servono target principale e target secondario.r^  z.Per questo obiettivo serve un target numerico.z8Per questo obiettivo indica almeno prodotto o fornitore.rg  r_  T)r  r<  )rc   r#   r   r   r  ro   ra  r   r  r&  r6   rT  rA  r@  rC  rU  rV  rN  rb  rq   r  r  re  )r  r  rM   r<  ra  r  s         r?   update_goalr    s   66,(D|(A(AJabbG%%+,224IEE(C(CLghh""$DIDN)		DI**D ..D#*#B#BD !00D..DK#44D((DO**D~~!'+$" $F,G,GPuvv	=	(!!)E)E"77]  ;;$"7"7"?"77\  //0S;;F,G,G  QA  B  B""d&9&9"77Q  (,$ $//`T^^x5OcU_IIKJJt$TYY3GtW =>>rA   z/api/obiettivic           	         | xs- t        j                  t        j                        j                  }t        t              j                  t        j                  |k(        j                  t        t        j                  dk(  dfd      j                         t        j                  j                               }t        |j                  |            }t        ||      }|t!        |      |D cg c]  }t#        ||       c}dS c c}w )NrS  r9   r   )else_)r6   	availablegoals)r   rU   r   r<   r6   r   r#   ry  r{  r   ra  r  r   r   r}  r  r  re  )r6   rM   r  r~  r  r  r<  s          r?   
list_goalsr  	  s    9(,,x||499K|	|  K/	0	$..&8!<AFJJLlooNaNaNc	d 	
 D!"E$["5G^<ABD.w/B  Cs   .Dz/storico_ordini.csv_c           	      P   | xs- t        j                  t        j                        j                  }t        ||      }t        j                         }t        j                  |      }|j                  g d       |D ]j  }t        |j                        xs d}|j                  D ]@  }	|j                  ||	j                  |	j                  |	j                   |	j"                  g       B l |j%                  d       dd| di}
t'        t)        |j+                         g      d|
      S )	N)Datar   LOTTO	FORNITOREQuantitar   r   zContent-Dispositionz%attachment; filename="storico_ordini_z.csv"ztext/csv; charset=utf-8)
media_typeheaders)r   rU   r   r<   r6   r  ioStringIOcsvwriterwriterowrF   rO  r   rG   r   rH   r   seekr   r  getvalue)r6   r  rM   r  r  bufferr  rK  r   r   r  s              r?   export_orders_csvr  0	  s     9(,,x||499K$["5G[[]FZZF
OOJK n 2 239r	KK 	nDOOY(9(94==$J\J\^b^k^klm	nn KKN$(Mk]Z_&`aGT6??#4"56C\fmnnrA   rJ   )collectionsr   r   r   r   r  difflibr   rz   r  r   r_  r  zoneinfor   fastapir	   r
   r   r   r   r   r   fastapi.responsesr   
sqlalchemyr   r   r   r   sqlalchemy.excr   sqlalchemy.ormr   r   app.api.depsr   r   r   r   app.core.configr   app.core.databaser   app.core.tenancyr   r   app.models.order_batchr    app.models.order_itemr!   app.models.productr"   app.models.seasonal_goalr#   app.models.shared_noter$   app.models.supplier_catalogr%   r&   app.models.suspended_orderr'   app.schemas.commonr(   r)   r*   r+   r,   r-   r.   r/   r0   r1   r2   app.services.push_notificationsr3   router	protectedra   r   r  r   tupler@   ro   rF   rL   rV  rS   rW   r[   rb   rj   rs   r   r   r   objectr   r   r   r   r   r   r   r   r   r   r   r  r)  r/  r7  r=  rC  rG  rJ  rZ  rh  rl  rw  r  r  r  r  r  r  r  r  rK   r   r  r  r  r  r  r   r  r  r  r  r9  rF  rH  rJ  rL  rO  rQ  re  rc   rh  postrp  rt  rv  rx  putrz  r~  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  include_routerrV   rA   r?   <module>r(     s   # 2 2 
 #  	  	   T T T / 2 2 ) 0  ) 0 < - + & 1 - L 5    > 
G,D$E#FG	 &8 #M* 3 58);#< x$ 3: [t [C$J [SXY\^aYaSb [/g /3 /4 /2# 23G 3 3l( (E (  % &23 2 2QT 2|7 |s |~ LP e' eEDL eTXY\^dYdTe ePc6k!2 s 4S&[(9#: tCy 
LtCy LS Lg $sF{:Kd:R <// / Cy	/
 / / 
/d4 43 4Df%&  	
 
#v+41G 1T#v+=N 1SV 1h@d3i @DcN @} ' } d5c?DQTV\Q\L];]6^ } F 37(,	.. CK(4/. #Y%	.
 
#v+.b	 	T#v+=N 	+> 4VCT . !%#'		 : Dj	
 
#v+8 #&*!22T\2 t|	2
 t|2 dl2 T\2(I %$, ") S&[(9  J 4V+< (S UT\ (3 # PUX\P\ afimam [ T#v+-> " "' "d:6F "'7 'tCy '1C$J 1#* 1 1
	$sCx. 	T#s(^ 	  } sC}9M "T-%8 "T-=P "0W 0] 0t 0"%3: %# %$
sTz 
c 
nx$ n%RZHZB[ n  
UYHY 4u) ug uQT uY] u&iJ i iC iTX iWJ W4 WSd
 Ss3x S 3:  cDj  U5RW<EX   
.S 
.S 
. 	  t^  :	 
 Dj  
#v+ F~*~7m~ 
#v+~B MR 	  T VZ 9d
 9t 9:Y :54< :3i 3E 3L< LD L8I 8\ 8e 8T TZ0@ TT#v+EV Tn I9d38n 9 9 \$< $Df$5 $ $ ~%,-E%F 	{ 	4PSU[P[K\ 	 	 !"*1&/  d3;>O  # *+,3FO 9' 9S&[@Q 9 ,9 *+ &/& 
#v+ ,  ' g Dc6k9J4K     )*)0 Xw XT#v+=N X +X 678? S g DQTV\Q\L]  8$ 9vGaGab;B6? < < <x < c< 672S)raC0&/
 	 
#v+	 8@ *+QXY_Q` 3I%A 3Iw 3Ieijmoujuev 3I ,3Il 01SZ[aSb 	=&C 	= 	=gkloqwlwgx 	= 2	= +,JQRX/ $@s $@] $@ $@^bcfhncn^o $@ -$@N ./29&/ 2s 2 2d3PV;FW 2 02&  @G )bT-0 )bg )bTXY\^dYdTe )b !)bX }#(#6gfo ZcDj ZG ZZ^_cdgiodo_pZq Z Z
 "##*6? % %tCK7H % $%   .&/)A)A
)A 	)A 
#v+	)A )AX }  .&/=A=A
=A 	=A 
#v+	=A =A@ - <CFO 2, 2' 2PTUXZ`U`Pa 2 !2, #$&v .W .4V3D . %. &'&+D&9QW ,t ,w ,]abegmbm]n , (,^ $%d+.&/2:2
2 	2 
#s(^	2 &2 %&"3id+ 89&/	#s(^:  		
 
#v+ '* '(d+ 89&/	<:	<
	< 		< 		< )	< {$V_ 
7 
d3;6G1H 
 
    89&/
 	 
#v+	 & '(,3FO < <' < < )< )*AH 9? 9?z 9?w 9?UYZ]_eZeUf 9? +9?x  "'"5WV_ S4Z 7 Y]^aci^iYj  !  !"T*56&/o
*oo 	o 	o #o&   i  rA   