
    ]i!                    b   d Z ddlmZ ddlmZ ddlmZ ddlmZm	Z	 ddl
mZmZ ddlmZ ddlmZmZ dd	lmZmZ dd
lmZmZ ddlmZmZ ddlmZ ddlmZmZm Z m!Z! ddZ"	 d	 	 	 	 	 	 	 	 	 ddZ#	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 ddZ$	 	 	 	 	 	 	 	 	 	 ddZ%	 	 	 	 	 	 	 	 ddZ&	 	 	 	 	 	 	 	 	 	 	 	 ddZ'y)uP   End-to-End reconciliation service — business logic for actual losses tracking.    )annotations)date)Decimal)funcselect)IntegrityErrorSQLAlchemyError)AsyncSession)EndToEndCycleStatusEndToEnd)LaporanShiftPenjualanNozzle)
PenerimaanPenerimaanItem)NozzleTangki)end_to_end_repository)EndToEndCloseEndToEndCreateEndToEndDetailResponseEndToEndResponsec           	     H   t        di d| j                  d| j                  d| j                  d| j                  r| j                  j
                  ndd| j                  rLt        | j                  d      r6| j                  j                  r | j                  j                  j
                  ndd| j                  d	| j                  d
| j                  d| j                  d| j                  d| j                  d| j                  d| j                  d| j                   d| j"                  d| j$                  d| j&                  r| j&                  j(                  ndd| j*                  r| j*                  j(                  ndd| j,                  d| j.                  S )z-Build an EndToEndResponse from an ORM object.idspbu_id	tangki_idtangki_namaNproduk_namaprodukstatustanggal_mulaitanggal_selesaidead_stock_awaldead_stock_akhirtotal_penerimaantotal_penjualantotal_pemindahan_intotal_pemindahan_outlosses_aktual
losses_pctstarted_by_nameclosed_by_name
created_at
updated_at )r   r   r   r   tangkinamahasattrr   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   
started_byname	closed_byr,   r-   )cs    A/var/www/html/spbu.com/backend/app/services/end_to_end_service.py_build_responser7      s    44		 ++ &'XXAHHMM4	
 -.HH89TYZYaYaYhYhAHHOO((nr xx oo )) )) ++ ++ )) 11 33 oo  <<!" ./\\))t#$ ,-;;q{{''D%& <<'( <<)     Nc                  K   |xs t        j                         }t        t        j                  t        j
                  t        j                        t        d                  j                  t        t        j                  t        j                  k(        j                  t        j                  |k(  t        j                  |k\  t        j                  |k        }| j!                  |       d{   }|j#                         xs t        d      }t        t        j                  t        j
                  t$        j&                        t        d                  j                  t(        t$        j*                  t(        j                  k(        j                  t,        t$        j.                  t,        j                  k(        j                  t,        j                  |k(  t(        j                  |k\  t(        j                  |k        }| j!                  |       d{   }	|	j#                         xs t        d      }
||
t        d      t        d      dS 7 d7 =w)zCalculate live totals from penerimaan and penjualan data.

    Returns dict with keys: running_penerimaan, running_penjualan,
    running_pemindahan_in, running_pemindahan_out.
    0Nrunning_penerimaanrunning_penjualanrunning_pemindahan_inrunning_pemindahan_out)r   todayr   r   coalescesumr   volume_diterimar   joinr   penerimaan_idr   wherer   tanggalexecute
scalar_oner   volumer   laporan_shift_idr   	nozzle_id)dbr   
start_dateend_dateeffective_endpen_q
pen_resultr<   jual_qjual_resultr=   s              r6   _calculate_running_totalsrU   7   s     ,

M 	t}}TXXn&D&DEws|TU	j.66*--G	H	$$	1*,-/

 
 zz%((J#..0@GCL 	t}}TXXo&<&<=ws|LM	lO<<O	P	fo//699<	=		)  J.  M1

	  

6**K#..0@GCL 1.!(")#,	 % ) +s%   C-I/I0D(II;IIc                   K   t        j                  | |||||       d{   \  }}|D cg c]  }t        |       c}|fS 7 "c c}w w)z0Return paginated list of E2E cycles for an SPBU.)r   r   skiplimitN)r   get_allr7   )	rM   r   r   r   rW   rX   rowstotalr5   s	            r6   list_cyclesr\   l   sY      .55
Gyd% KD% )--1OA-u44 .s   AAAAAAc           
       K   | j                  t        |j                         d{   }||j                  |k7  rt	        d      |j
                  du rt	        d      t        j                  | |j                         d{   }|&t	        d|j                   d|j                   d      	 t        j                  | ||j                  t        j                  t        j                         |j                  |d       d{   }| j!                          d{    t)        |      S 7 7 7 ,7 # t"        $ r% | j%                          d{  7   t	        d	      t&        $ r | j%                          d{  7    w xY ww)
z!Start a new E2E cycle for a tank.Nz%Tangki tidak ditemukan untuk SPBU iniFzTangki tidak aktifzTangki 'z:' sudah memiliki siklus E2E yang sedang berjalan (dimulai ))r   r   r   r    r"   started_by_idz!Siklus E2E konflik atau sudah ada)getr   r   r   
ValueError	is_activer   get_open_by_tangkir0   r    creater   OPENr   r@   r"   commitr   rollbackr	   r7   )rM   r   user_iddatar/   existingcycles          r6   start_cyclerl   {   sj     66&$..11F~72@AA5 -.. +==b$..QQHv{{m $ ../q2
 	

+22"!^^(--!%#'#7#7!(

 

 iik 5!!C 2 R

 	 >kkm<== kkmsw   $F	D-AF	D0,F	1AD6 D2D6 D4D6 "F	0F	2D6 4D6 6FE+F>F?FF	c                  K   t        j                  | ||       d{   }|t        d      t        |      }|j                  t
        j                  k(  r*t        | |j                  |j                         d{   }n/|j                  |j                  |j                  |j                  d}t        di |j                         |S 7 7 Qw)z4Get full detail of an E2E cycle with running totals.NSiklus E2E tidak ditemukanr;   r.   )r   	get_by_idra   r7   r   r   re   rU   r   r    r$   r%   r&   r'   r   
model_dump)rM   r   cycle_idrk   basetotalss         r6   get_cycle_detailrt      s      (11"hHHE}5665!D||~***0!4!4
 
 #("8"8!&!6!6%*%>%>&+&@&@	
 " 
//

 ) I
s#   CCAC;C<ACCc                B  K   t        j                  | ||       d{   }|t        d      |j                  t        j
                  k7  rt        d      t        | |j                  |j                         d{   }|d   |d   z   }|d   |d   z   }|j                  |j                  z
  }	||z
  |	z
  }
|d   dkD  r|
|d   z  d	z  n
t        d
      }	 t        j                  | |t        j                  t        j                         |j                  |d   |d   |d   |d   |
||d
       d{   }| j!                          d{    t'        | ||j(                         d{   S 7 P7 7 @7 *# t"        $ r | j%                          d{  7    w xY w7 4w)z<Close an open E2E cycle, freeze totals and calculate losses.Nrn   zSiklus sudah ditutupr<   r>   r=   r?   r   d   r:   )
r   r!   r#   r$   r%   r&   r'   r(   r)   closed_by_id)r   ro   ra   r   r   re   rU   r   r    r#   r"   r   updateCLOSEDr   r@   rf   r	   rg   rt   r   )rM   r   rq   rh   ri   rk   rs   total_in	total_outdead_stock_deltar(   r)   updateds                r6   close_cycler~      s     (11"hHHE}566||~***/00 -
EOOU00 F *+f5L.MMH*+f5M.NNI,,u/D/DDy(+;;M &'!+ 
 45	5	;S\ -44(//#'::<$($9$9$*+?$@#)*=#>'-.E'F(./G(H!.( '
 
  iik
 ""gwzz:::Y I 
  	 kkm ;sx   FE-AF;E0<AFAE6 1E22E6 	E4
E6 F(F)F0F2E6 4E6 6FFFF)r5   r   returnr   )N)
rM   r
   r   intrN   r   rO   zdate | Noner   dict)NNr   2   )rM   r
   r   r   r   z
int | Noner   z
str | NonerW   r   rX   r   r   z"tuple[list[EndToEndResponse], int])
rM   r
   r   r   rh   r   ri   r   r   r   )rM   r
   r   r   rq   r   r   r   )rM   r
   r   r   rq   r   rh   r   ri   r   r   r   )(__doc__
__future__r   datetimer   decimalr   
sqlalchemyr   r   sqlalchemy.excr   r	   sqlalchemy.ext.asyncior
   app.models.end_to_endr   r   app.models.operationalr   r   app.models.penerimaanr   r   app.models.spbur   r   app.repositoriesr   app.schemas.end_to_endr   r   r   r   r7   rU   r\   rl   rt   r~   r.   r8   r6   <module>r      sa   V "   # : / ? @ < * 2 < !	... . 	.
 
.p !555 5 	5
 5 5 (5)")")" )" 	)"
 )"X  	@4;4;4; 4; 	4;
 4; 4;r8   