
    08i<                     .   d Z ddlZddlZddlmZ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mZ ej(                  j+                  ej(                  j-                  ej(                  j-                  ej(                  j-                  ej(                  j-                  e                               dd	lmZmZ e G d
 d             Ze G d d             Zd Zddee   defdZdedededefdZ ddee   fdZ!ddee   fdZ" e       Z#y)a8  
Smart Inventory - Daily Snapshot Task
====================================

Celery task for computing daily inventory snapshots.

This task computes inventory levels by:
1. Taking previous day's snapshot as starting point
2. Applying all inventory movements for the current day
3. Computing final on-hand, inbound, outbound quantities
4. Storing results in inventory_snapshot_daily table

Formula:
--------
today_on_hand = previous_day_on_hand + sum(today_movements)
today_inbound = sum(positive_movements_today)  
today_outbound = sum(abs(negative_movements_today))
    N)datetimedate	timedelta)OptionalDictListTuple)	dataclass)Session)textand_)IntegrityError)SessionLocalenginec                   <    e Zd ZU dZdZeed<   dZeed<   dZeed<   y)MovementSummaryz&Summary of movements for a combination        inbound_qtyoutbound_qtynet_movementN)	__name__
__module____qualname____doc__r   float__annotations__r   r        P/var/www/html/hubwallet-dev/src/smart_inventory/tasks/inventory_snapshot_task.pyr   r   $   s#    0KL%L%r   r   c                   l    e Zd ZU dZdZeed<   dZeed<   dZeed<   dZ	e
ed<   dZeed	<   d
Zee   ed<   y
)SnapshotComputationResultzResult of snapshot computationr   records_processedrecords_createdrecords_updatedr   computation_timeFsuccessNerror_message)r   r   r   r   r"   intr   r#   r$   r%   r   r&   boolr'   r   strr   r   r   r!   r!   +   sG    (sOSOS!e!GT#'M8C='r   r!   c                      	 ddl m}  | j                  dd      d
dt        t           dt
        fd	       }|S # t        $ r
}Y d}~yd}~ww xY w)z<Create the celery task dynamically to avoid circular importsr   )
celery_appzBsrc.smart_inventory.tasks.snapshot_task.compute_inventory_snapshotT)namebindNtarget_datereturnc                     t        | |      S N)compute_inventory_snapshot_impl)selfr/   s     r   compute_inventory_snapshot_taskz;create_celery_task.<locals>.compute_inventory_snapshot_task:   s    24EEr   r2   )src.utils.celery_workerr,   taskr   r*   r   ImportError)r,   r5   es      r   create_celery_taskr:   5   s^    
6	bim	n	Fx} 	FX\ 	F 
o	F /. s   58 	AAr/   r0   c                    t        j                         }| rt        | di       j                  dd      nd}t	        d| d       |r&	 t        j
                  |d      j                         }n!t        j                         t        d      z
  }|t        d      z
  }t	        d| d|        t	        d| d|        t               }	 t        |||      }t        j                         |z
  j                         }	|	|_        |j                  rt	        d| d|	dd       t	        d|j                          t	        d|j                           t	        d|j"                          d|j                  |j                   |j"                  |	|j%                         d|j'                          S t	        d| d|j(                          d
|j(                  |	d|j'                          S # t        $ r d| d}t	        d| d	|        d
|dcY S w xY w# t*        $ r>}
dt-        |
       }t	        d| d	|        d
|dcY d}
~
|j'                          S d}
~
ww xY w# |j'                          w xY w)a3  
    Celery task to compute daily inventory snapshots for a given date.
    
    Args:
        target_date: Date string in YYYY-MM-DD format. If None, uses yesterday.
        
    Returns:
        Dict with computation results and statistics
        
    Raises:
        Exception: If computation fails
    requestidmanualz[Task z,] Starting inventory snapshot computation...%Y-%m-%dzInvalid date format: . Expected YYYY-MM-DDz	] ERROR: F)r&   error   daysz] Target Date: z] Previous Date: z] Computation completed in .2fs   Records processed:    Records created:    Records updated: T)r&   r"   r#   r$   r%   r/   z] Computation failed: )r&   rA   r%   z.Unexpected error during snapshot computation: N)r   nowgetattrgetprintstrptimer   
ValueErrortodayr   r   _compute_snapshots_for_datetotal_secondsr%   r&   r"   r#   r$   	isoformatcloser'   	Exceptionr*   )r4   r/   
start_timetask_idtarget_date_obj	error_msgprevious_datedbresultr%   r9   s              r   r3   r3   C   st    JBFgdIr*..tX>HG	F7)G
HI 	:&//ZHMMOO **,)::#iQ&77M	F7)??*;
<=	F7),]O
<=	B",R-P$LLNZ7FFH"2>>F7)#>?OPS>TTUVW*6+C+C*DEF()?)?(@AB()?)?(@AB  %+%=%=#)#9#9#)#9#9$4.88:, 	
 F7)#9&:N:N9OPQ --$4 	
a  	:/}<QRIF7)9YK89$y99	:T  6DSVHM	wiy45 955 	
6 	
sI   $G* 
CH /*H *%HH	I#III II I1r[   rZ   c                 
   t               }	 t        d| d       ddlm}m} ddlm} | j                  |      j                  |j                  |k(        j                         }i }|D ]A  }	|	j                  |	j                  |	j                  f}
t        |	j                        ddd||
<   C t!        |      dk(  rt        d| d	       | j                  |      j                  |j#                  |j$                        |k        j                         }t        d
t!        |       d|        |D ]U  }|j                  |j                  |j                  f}
|
|vr	dddd||
<   ||
   dxx   t        |j&                        z  cc<   W t        dt!        |       d       t        dt!        |       d       t        d| d       | j                  |      j                  |j#                  |j$                        |k(        j                         }t        d
t!        |       d|        i }|D ]  }|j                  |j                  |j                  f}
|
|vrt)               ||
<   ||
   }t        |j&                        }|dkD  r|xj*                  |z  c_        n|xj,                  t/        |      z  c_        |xj0                  |z  c_         | j                  |      j                  |j                  |k(        j3                         }|dkD  r]t        d| d| d       | j                  |      j                  |j                  |k(        j5                          | j7                          g }t9        j:                         }|j=                         D ]  \  }
}|
\  }}}|j?                  |
dddd      }|d   |j0                  z   } |||||||j*                  |j,                  |      }|jA                  |       t        d| d| d| d|d    d|j0                   d|         |j=                         D ]O  \  }
}|
|vs|
\  }}} ||||||d   dd|      }|jA                  |       t        d| d| d| d|d    d	       Q |r<| jC                  |       | j7                          t        dt!        |       d|        nt        d |        t!        |      t!        |      z   |_"        t!        |      |_#        d|_$        d!|_%        |S # tL        $ rA}| jO                          d"|_%        tQ        |      |_)        t        d#|        |cY d$}~S d$}~ww xY w)%a  
    Core logic to compute inventory snapshots for a specific date.
    
    Step 1: Load previous day's snapshots as baseline
    Step 1b: If no previous snapshots exist, compute cumulative from ALL historical movements
    Step 2: Apply all inventory movements for the target date
    Step 3: Delete existing snapshots for target date (idempotency)
    Step 4: Create new snapshots for target date
    
    Note: Previous day's snapshots are retained for historical data.
    z Loading previous snapshots from z...r   )InventorySnapshotDailyInventoryMovement)funcr   )on_hand_qtyr   r   z No previous snapshots found for z<. Computing cumulative baseline from historical movements...zFound z historical movements before ra   zComputed baseline for z+ product/location combinations from historyzLoaded z baseline combinationszLoading movements for z movements for z	Deleting z existing snapshots for z (idempotency)...)snapshot_date
company_idlocation_id
product_idra   r   r   
created_atzWITH Movement (,z): z + z = zNO Movement (z (carry forward)zCreated z snapshot records for z"No snapshot records to create for TFz$ERROR: Snapshot computation failed: N)*r!   rM   )src.smart_inventory.apps.inventory.modelsr^   r_   
sqlalchemyr`   queryfilterrb   allrc   rd   re   r   ra   lenr   rf   quantity_deltar   r   r   absr   countdeletecommitr   rJ   itemsrL   appendadd_allr"   r#   r$   r&   rU   rollbackr*   r'   )r[   r/   rZ   r\   r^   r_   r`   previous_snapshotsbaseline_datasnapshotkeyhistorical_movementsmovement	movementsmovement_summariessummaryqtyexisting_countrecords_to_insertcurrent_timemovement_summaryrc   rd   re   baselinenew_on_handrecordr9   s                               r   rQ   rQ      s   " '(Fc0sCD 	h#XX&<=DD"00MA

#% 	 * 	H&&(<(<h>Q>QRC$X%9%9:" #"M#	 }"4]OC  A  B $&88,=#>#E#E		+667+E$ce ! F33455RS^R_`a 1 T**H,@,@(BUBUVm+'*'*(+*M#& c"=1U8;R;R5SS1T *3}+=*>>ijk 	M*++ABC 	&{m378 HH./66II'223{B

#% 	 	s9~&ok]CD  ! 	(H&&(<(<h>Q>QRC,,*9*;"3'(-G//0CQw##s*#$$C0$  C' 	(" "89@@"00K?

%' 	 AIn--Ek]RcdeHH+,33&44CfhIIK ||~ &8%=%=%? 	[!C!25/JZ %(("" #/ H #=14D4Q4QQK+)%'%',88-::'	F $$V,OJ<qQzl#hWdNeMffijz  kH  kH  jI  IL  MX  LY  Z  [3	[8 +002 	{MC,,693
K/"-) +) ( 7 #!$+	 "((0j\;-qCPXYfPgOhhxyz!	{& JJ()IIKHS!2344J;-XY6{mDE#&}#5<N8O#O !$%6!7!" 
"1v4QC89s%   P5T CT 	U6UUUc                 n   t        d       t        d|       }|d   r{t        d|j                  dd      dd       t        d	|j                  d
d              t        d|j                  dd              t        d|j                  dd              yt        d|j                  dd              y)z
    Test function for manual snapshot computation (bypasses Celery)
    
    Args:
        target_date: Date string in YYYY-MM-DD format. If None, uses yesterday.
    z+Running manual snapshot computation test...Nr&   "SUCCESS: Computation completed in r%   r   rE   rF   rG   r"   rH   r#   rI   r$   ERROR: Computation failed: rA   zUnknown error)rM   r3   rL   )r/   result_dicts     r   test_snapshot_computationr   L  s     

78 2$DK92;??CUWX3YZ]2^^_`a&{7JA'N&OPQ$[__5F%J$KLM$[__5F%J$KLM+KOOG_,U+VWXr   c                 l   t        d       | r&	 t        j                  | d      j                         }n!t        j
                         t        d      z
  }|t        d      z
  }t        d|        t        d	|        t               }	 t        j                         }t        |||      }t        j                         |z
  j                         }|j                  rYt        d
|dd       t        d|j                          t        d|j                          t        d|j                          nt        d|j                          |j#                          y# t        $ r t        d|  d       Y yw xY w# t         $ r}t        d|        Y d}~Kd}~ww xY w# |j#                          w xY w)z>
    Direct test of core logic without any Celery wrapper
    z!Running direct core logic test...r?   zERROR: Invalid date format: r@   NrB   rC   zTarget Date: zPrevious Date: r   rE   rF   rG   rH   rI   r   zERROR: Unexpected error: )rM   r   rN   r   rO   rP   r   r   rJ   rQ   rR   r&   r"   r#   r$   r'   rU   rT   )r/   rX   rZ   r[   rV   r\   r%   r9   s           r   manual_test_core_logicr   a  s    

-. 	&//ZHMMOO
 **,)::#iQ&77M	M/*
+,	OM?
+,	B\\^
,R-P$LLNZ7FFH>>67G6LANO*6+C+C*DEF()?)?(@AB()?)?(@AB/0D0D/EFG 	
=  	0=RST	4  /)!-../ 	
s<   $E CE= E:9E:=	FFF! FF! !F3r2   )$r   ossysr   r   r   typingr   r   r   r	   dataclassesr
   sqlalchemy.ormr   ri   r   r   sqlalchemy.excr   pathrt   dirname__file__src.utils.dbr   r   r   r!   r:   r*   r3   rQ   r   r   compute_inventory_snapshotr   r   r   <module>r      s$  & 
 
 . . . . ! " ! ) PX@Y0Z [\ ] -    ( ( (Gx} GPT GZvvv v 	vxY8C= Y*( (X 01 r   