
    ]iHL                       d Z ddlmZ ddlmZ ddl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mZ dd	lmZ dd
lmZ ddlm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"m#Z#m$Z$ ddl%m&Z& ddl'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0 ddl1m2Z2m3Z3 d"dZ4d#dZ5	 	 	 	 	 	 	 	 d$dZ6	 	 	 	 	 	 	 	 d%dZ7d&dZ8	 	 	 	 	 	 	 	 d'dZ9	 	 	 	 	 d(	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d)dZ:	 	 	 	 	 	 	 	 d*dZ;	 	 	 	 	 	 	 	 	 	 d+dZ<	 	 	 	 	 	 	 	 	 	 	 	 d,dZ=	 	 	 d-	 	 	 	 	 	 	 	 	 	 	 d.dZ>	 	 	 	 	 	 	 	 d/dZ?	 	 	 	 	 	 	 	 	 	 d0dZ@	 	 	 	 	 	 	 	 	 	 d1d ZA	 	 	 	 	 	 	 	 	 	 	 	 d2d!ZBy)3uL   Penyetoran service — business logic for the per-shift cash deposit module.    )annotations)defaultdict)datedatetimetimezoneDecimal)Optional)funcselect)IntegrityErrorSQLAlchemyError)AsyncSession)selectinload)Expense)LaporanShiftPenjualanNozzleStatusLaporan)
PenyetoranPenyetoranBatchStatusPenyetoranStatusPenyetoranBatch)IslandNozzleShift)penyetoran_repository)	BatchReviewRequestDailySummaryPenyetoranBatchCreatePenyetoranBatchResponsePenyetoranResponsePenyetoranUpdateProductTotalShiftProductSummaryShiftSummary)save_uploadUploadContextc           	        d}| j                   6| j                   j                   | j                   j                  j                  }t        di d| j                  d| j
                  d| j                  d| j                  d| j                  d|d| j                  d	| j                  d
| j                  d| j                  d| j                  dt        | j                  t               r| j                  n| j                  j"                  d| j$                  d| j&                  r| j&                  j(                  ndd| j*                  d| j,                  S )z9Build a PenyetoranResponse from an ORM Penyetoran object.Nidspbu_idlaporan_shift_idtanggalshift_id
shift_nama
jumlah_kasjumlah_non_kastotal_penjualancatatan	bukti_urlstatusbatch_idcreated_by_name
created_at
updated_at )laporan_shiftshiftnamar!   r)   r*   r+   r,   r-   r/   r0   r1   r2   r3   
isinstancer4   strvaluer5   
created_bynamer7   r8   )pr.   s     A/var/www/html/spbu.com/backend/app/services/penyetoran_service.py_build_responserD   &   sI    !%J"q'<'<'H__**//
 44		 ++ 			
   << '' )) 		 ++ &ahh4qxx!((..  ./\\))t <<  <<!     c                b   t        | j                  | j                  | j                  | j                  | j
                  | j                  t        | j                  t              r| j                  n| j                  j                  | j                  r| j                  j                  nd| j                  | j                  r| j                  j                  nd| j                  | j                   | j"                  xs g D cg c]  }t%        |       c}| j&                  | j(                        S c c}w )zCBuild a PenyetoranBatchResponse from an ORM PenyetoranBatch object.N)r)   r*   tanggal_from
tanggal_tototal_amountr2   r4   submitted_by_namesubmitted_atreviewed_by_namereviewed_atcatatan_reviewitemsr7   r8   )r    r)   r*   rG   rH   rI   r2   r=   r4   r>   r?   submitted_byrA   rK   reviewed_byrM   rN   rO   rD   r7   r8   )batchrB   s     rC   _build_batch_responserS   A   s    "88''##'')%,,<u||%,,BTBT5:5G5G%,,11T''383D3D**//$%%++,1KK,=2,=?,=aq!,=?####  @s   <D, c           	       K   | j                  t        t              j                  t        j                  |k(  t        j
                  |k(        j                  t        t        j                        t        t        j                        j                  t        j                        j                  t        j                        t        t        j                        j                  t        j                        j                  t        j                              j                  t        j                                d{   }t#        |j%                         j'                         j)                               S 7 9w)z
    Load all LaporanShift for the given SPBU + date, eagerly loading the
    nozzle rows and their related produk/island/shift for aggregation.
    N)executer   r   wherer*   r,   optionsr   r;   penjualan_nozzler   nozzler   produkislandorder_byr)   listscalarsuniquealldbr*   r,   results       rC   _get_daily_sales_datard   V   s      ::|	|##w.0D0D0O	P	++,667DD&&l6==)667DD&&l6==)

 
,//	" F  '')--/00s   D;E9=E7>:E9c           	     d  K   | j                  t        t        j                  t        j                  t
        j                        d            j                  t
        j                  |k(  t
        j                  |k(               d{   }t        t        |j                                     S 7 &w)z/Sum all Expense.jumlah for a given SPBU + date.r   N)rU   r   r   coalescesumr   jumlahrV   r*   r,   r	   r>   
scalar_onera   s       rC   _get_daily_expenses_totalrj   p   sy      ::t}}TXXgnn5q9:	w')7??g+E	F F 3v((*+,,	s   BB0B.'B0c                   t        d       }| j                  xs g D ]  }|j                  }|r|j                  nd}|r|j                  nd}||   }||d<   |r|j
                  nd|d<   |r|j                  nd|d<   |j                  |d<   |j                  r/|d	xx   |j                  z  cc<   |d
xx   |j                  z  cc<   nH|d	xx   |j                  |j                  z
  z  cc<   |d
xx   |j                  |j                  z
  z  cc<   |dxx   |j                  z  cc<   |dxx   |j                  z  cc<   " |j                         D cg c]-  }t!        |d   |d   |d   |d	   |d
   |d   |d   |d         / }}t#        d |D              }	t#        d |D              }
t#        d |D              }t#        d |D              }t%        | j                  | j&                  | j(                  r| j(                  j
                  ndt+        | j,                  t.              r| j,                  n| j,                  j0                  ||	|
||	      S c c}w )zEBuild a ShiftSummary by aggregating PenjualanNozzle rows per product.c            	     r    t        d      t        d      t        d      t        d      t        d      ddddS N0 r   )volume_digitalvolume_manualvolume_finalnilai
harga_jualproduk_namaproduk_kode	produk_idr   r9   rE   rC   <lambda>z"_aggregate_shift.<locals>.<lambda>~   s3    !#, cl	7rE   Nr   rw   ro   ru   rv   rt   rp   rq   rr   rs   rw   ru   rv   rp   rq   rr   rs   rt   c              3  4   K   | ]  }|j                     y wNrp   .0rB   s     rC   	<genexpr>z#_aggregate_shift.<locals>.<genexpr>   s     6X1##X   c              3  4   K   | ]  }|j                     y wr{   rq   r}   s     rC   r   z#_aggregate_shift.<locals>.<genexpr>   s     5Hq1??Hr   c              3  4   K   | ]  }|j                     y wr{   rr   r}   s     rC   r   z#_aggregate_shift.<locals>.<genexpr>   s     48a1>>8r   c              3  4   K   | ]  }|j                     y wr{   rs   r}   s     rC   r   z#_aggregate_shift.<locals>.<genexpr>   s     ,8a!''8r   )	r+   r-   r.   r4   productstotal_volume_digitaltotal_volume_manualtotal_volume_finaltotal_nilai)r   rX   rY   rZ   r)   r<   kodert   flag_reset_tellervolumeteller_akhir_digitalteller_awal_digitalteller_akhir_manualteller_awal_manualrs   valuesr$   rg   r%   r-   r;   r=   r4   r>   r?   )laporan
per_produkrowrY   rZ   rw   entryvr   total_vdtotal_vmtotal_vftotal_ns                rC   _aggregate_shiftr   {   sP    #. 	/ 	#J ''-2-"(d!'FIIQ	9%&k.4v{{"m.4v{{"m!nnl    "#szz1#/"cjj0""#s'?'?#BYBY'YY#/"c&=&=@V@V&VV"n+g#))#3 .L ""$ %A 	n-(-(-.O,>*G*		
 %   6X66H5H55H4844H,8,,G !!)07==%%B!+GNNC!@w~~gnnFZFZ%$#
 
's   2Ic                  K   t        | ||       d{   }t        | ||       d{   }|D cg c]  }t        |       }}t        d       }|D ]  }|j                  D ]  }	||	j
                     }
|	j
                  |
d<   |	j                  |
d<   |	j                  |
d<   |	j                  |
d<   |
dxx   |	j                  z  cc<   |
dxx   |	j                  z  cc<   |
d	xx   |	j                  z  cc<   |
d
xx   |	j                  z  cc<     |j                         D cg c]-  }t        |d   |d   |d   |d   |d   |d	   |d
   |d         / }}t        d |D              }t        d |D              }t        d |D              }t        d |D              }||z
  }t!        j"                  | ||       d{   }t%        ||||||||||r|j&                  nd|r|j(                        S d      S 7 7 c c}w c c}w 7 Kw)z
    Aggregate all laporan_shift + penjualan_nozzle data for a date into a DailySummary.
    Also checks for an existing penyetoran record and includes its id/status.
    Nc            	     r    t        d      t        d      t        d      t        d      t        d      ddddS rm   r   r9   rE   rC   rx   z#get_daily_summary.<locals>.<lambda>   s3    !#, cl	9rE   rw   ru   rv   rt   rp   rq   rr   rs   ry   c              3  4   K   | ]  }|j                     y wr{   r|   r}   s     rC   r   z$get_daily_summary.<locals>.<genexpr>   s     <^1##^r   c              3  4   K   | ]  }|j                     y wr{   r   r}   s     rC   r   z$get_daily_summary.<locals>.<genexpr>   s     ;Nq1??Nr   c              3  4   K   | ]  }|j                     y wr{   r   r}   s     rC   r   z$get_daily_summary.<locals>.<genexpr>   s     :>a1>>>r   c              3  4   K   | ]  }|j                     y wr{   r   r}   s     rC   r   z$get_daily_summary.<locals>.<genexpr>   s     2>a!''>r   )r,   shiftsproducts_totalgrand_total_volume_digitalgrand_total_volume_manualgrand_total_volume_finalgrand_total_nilaitotal_expensessuggested_setorexisting_penyetoran_idexisting_penyetoran_status)rd   rj   r   r   r   rw   ru   rv   rt   rp   rq   rr   rs   r   r#   rg   r   get_by_tanggalr   r)   r4   )rb   r*   r,   laporan_listr   lsr   cross_produkr;   rB   er   r   grand_vdgrand_vmgrand_vfgrand_n	suggestedexistings                      rC   get_daily_summaryr      sA     /r7GDDL4R'JJNAM!N2"22"6F!N %0 	1 	%L AQ[[)A[[AkN }}Am }}AmllAlO1#3#33o!//1n/gJ!''!J   . $$& 'A 	n-(-(-.O,>*G*		
 '   <^<<H;N;;H:>::H2>22G.(I +99"gwOOH%#+"*!)!%!.6x{{D6>8??  EI g EJ!N2* PsJ   HG9HG<HG?CH"2HA)H=H	><H<H?HNc           	        K   t        j                  | ||||||       d{   \  }}|D 	cg c]  }	t        |	       c}	|fS 7 "c c}	w w)z:Return a paginated list of PenyetoranResponse for an SPBU.)rG   rH   r4   N)r   get_allrD   )
rb   r*   skiplimitrG   rH   r4   rowstotalrB   s
             rC   list_penyetoranr     s^      .55
GT5!	 KD% )--1OA-u44 .s     AAAA AAc                |   K   t        j                  | ||       d{   }|t        d      t        |      S 7 w)zDReturn a single PenyetoranResponse, raising ValueError if not found.NPenyetoran tidak ditemukan)r   	get_by_id
ValueErrorrD   )rb   r*   penyetoran_idrB   s       rC   get_penyetoran_detailr   (  sA      $--b-IIAy5661 	J   <:<c                >  K   t        j                  | ||       d{   }|t        d      |j                  t        j
                  k7  rt        d      i }|j                  |j                  |d<   |st        |      S 	 t        j                  | ||       d{   }| j                          d{    t        |      S 7 7 )7 # t        $ r% | j                          d{  7   t        d      t        $ r | j                          d{  7    w xY ww)z%Update catatan on a DRAFT penyetoran.Nr   z2Hanya penyetoran berstatus DRAFT yang dapat dieditr2    Constraint error pada penyetoran)r   r   r   r4   r   DRAFTr2   rD   updatecommitr   rollbackr   )rb   r*   r   bodyrB   update_dicts         rC   update_penyetoranr   2  s     $--b-IIAy566xx#)))MNNK||!%Iq!!	'..r1kBBiikq!!! 	J C =kkm;<< kkmsd   DCA#DC
 CC
 4C5C
 DC
 C
 
D&C)'+DDDDc                4  K   t        j                  | ||       d{   }|t        d      |j                  t        j
                  k7  rt        d      d}t        |      |kD  rt        d      d|v r#|j                  dd      d   j                         nd	}|d
vrt        d      ddl	m
}  || |j                         d{   }	t        |	d|j                        }
t        |||
       d{   }	 t        j                  | ||       d{   }| j!                          d{    t#        |      S 7 7 v7 L7 .7 # t$        $ r% | j'                          d{  7   t        d      t(        $ r | j'                          d{  7    w xY ww)zLSave proof-of-transfer image/PDF and store the URL on the penyetoran record.Nr   z/Bukti hanya bisa diupload pada penyetoran DRAFTi   z)Ukuran file melebihi batas maksimum 10 MB.   ro   >   jpgpdfpngjpegz5Tipe file tidak didukung. Gunakan PDF, JPG, atau PNG.r   )get_spbu_code
penyetoranr   )r   r   r   r4   r   r   lenrsplitlowerapp.utils.file_uploadr   r*   r'   r,   r&   update_buktir   rD   r   r   r   )rb   r*   r   
file_bytesfilenamerB   	max_bytesextr   	spbu_codectxurls               rC   upload_buktir   R  sq     $--b-IIAy566xx#)))JKK I
:"DEE14(//#q
!"
%
+
+
-bC
//PQQ3#B		22I
	<
;CJ#6
6C	'44RC@@iikq!!+ 	J 3
6@ =kkm;<< kkms   FD:B(FD=+F2D?3F8E EE *E+E 9F=F?FE E F!E$"+FFFFc                   K   t        j                  | ||||       d{   \  }}|D cg c]  }t        |       c}|fS 7 "c c}w w)z2Return paginated PenyetoranBatch list for an SPBU.)r4   N)r   get_all_batchesrS   )rb   r*   r   r   r4   r   r   bs           rC   list_batchesr   |  sR      .==b'4QV_effKD%.23d!!$d3U:: g3s   A
AA
AA
A
c                |   K   t        j                  | ||       d{   }|t        d      t        |      S 7 w)zIReturn a single PenyetoranBatchResponse, raising ValueError if not found.NBatch tidak ditemukan)r   get_batch_by_idr   rS   )rb   r*   r5   rR   s       rC   get_batch_detailr     sA      (77HgNNE}011 '' Or   c                  K   |j                   st        d      g }|j                   D ]|  }t        j                  | ||       d{   }|t        d| d      |j                  t
        j                  k7  rt        d| d|j                   d      |j                  |       ~ t        d |D              }|j                  |j                  ||j                  t        j                  d}	 t        j                  | ||       d{   }	|D ]<  }t        j                  | ||	j                  t
        j                   d	       d{    > | j#                          d{    t        j$                  | |	j                  |       d{   }	t'        |	      S 7 U7 7 W7 ?7 # t(        $ r% | j+                          d{  7   t        d
      t,        $ r | j+                          d{  7    w xY ww)u  
    Create a PenyetoranBatch from a list of DRAFT penyetoran IDs.

    Validates all penyetoran belong to spbu_id and are DRAFT.
    Sets their status to SUBMITTED and links them to the new batch.
    Does NOT set submitted_by_id on the batch — that's set by submit_batch().
    zPilih minimal satu penyetoranNzPenyetoran id=z tidak ditemukan di SPBU iniz berstatus z , hanya DRAFT yang bisa di-batchc              3  4   K   | ]  }|j                     y wr{   )r1   r}   s     rC   r   zcreate_batch.<locals>.<genexpr>  s     B/Qq((/r   )rG   rH   rI   r2   r4   )r5   r4   z#Constraint error saat membuat batch)penyetoran_idsr   r   r   r4   r   r   appendrg   rG   rH   r2   r   create_batchr   r)   	SUBMITTEDr   r   rS   r   r   r   )
rb   r*   user_idr   penyetoran_listpidrB   rI   
batch_datarR   s
             rC   r   r     s     899 )+O""'11"c7CC9~cU2NOPP88'--- [
:Z[  	q! # B/BBL ))oo$<<'--J+88WjQQ !A'..r1!HH*447    ! iik+;;B'RR$U++A D( R
 	R @kkm>?? kkms   AG8FB'G8.F% F	>F% FF% !F!"(F% 
F#F% G8F% F% !F% #F% %G5G+G5-G0.G55G8c           	     P  K   t        j                  | ||       d{   }|t        d      |j                  t        j
                  k7  rt        d      	 t        j                  | |t        j                  |t        j                  t        j                        d       d{   }| j                          d{    t        |      S 7 7 )7 # t        $ r% | j                          d{  7   t        d      t         $ r | j                          d{  7    w xY ww)zq
    Submit a DRAFT batch to Manager for approval.
    Sets status=SUBMITTED, submitted_by_id, submitted_at.
    Nr   z0Hanya batch berstatus DRAFT yang dapat di-submit)r4   submitted_by_idrK   z"Constraint error saat submit batch)r   r   r   r4   r   r   update_batchr   r   nowr   utcr   rS   r   r   r   )rb   r*   r5   r   rR   s        rC   submit_batchr     s      (77HgNNE}011||,222KLL+88U+55&$LL6E
  
 iik$U++ O
 	 ?kkm=>> kkmsd   D&C9D&AC %C&C =C>C D&C C D#/C20+D#DD##D&c           	     n  K   t        j                  | ||       d{   }|t        d      |j                  t        j
                  k7  rt        d      |j                  dk7  rt        d      	 t        j                  t        j                        }t        j                  | |t        j                  |||j                  d       d{   }|j                  xs g D ]1  }t        j                  | |dt         j                  i       d{    3 | j#                          d{    t        j                  | ||       d{   }t%        |      S 7 :7 7 M7 57 # t&        $ r% | j)                          d{  7   t        d      t*        $ r | j)                          d{  7    w xY ww)	u   
    Manager approves a SUBMITTED batch.
    On approve: batch→APPROVED, all linked penyetoran→APPROVED.
    Only action='approve' is supported (PenyetoranBatch has no REJECTED status).
    Nr   z:Review hanya bisa dilakukan pada batch berstatus SUBMITTEDapprovezAction harus 'approve')r4   reviewed_by_idrM   rN   r4   z"Constraint error saat review batch)r   r   r   r4   r   r   actionr   r   r   r   r   APPROVEDrN   rO   r   r   r   rS   r   r   r   )rb   r*   r5   r   r   rR   r   rB   s           rC   review_batchr    s     (77HgNNE}011||,666UVV{{i122ll8<<(+88U+44%"11	E
   ""A'..r1*337    #
 iik+;;B'RR$U++5 O 	R ?kkm=>> kkms   F5EAF52AE" EAE" EE" (E)E" E E" F5E" E" E"  E" "F2>F?+F2*F-+F22F5)rB   r   returnr!   )rR   r   r  r    )rb   r   r*   intr,   r   r  zlist[LaporanShift])rb   r   r*   r  r,   r   r  r	   )r   r   r  r%   )rb   r   r*   r  r,   r   r  r   )r   2   NNN)rb   r   r*   r  r   r  r   r  rG   Optional[date]rH   r	  r4   Optional[str]r  z$tuple[list[PenyetoranResponse], int])rb   r   r*   r  r   r  r  r!   )
rb   r   r*   r  r   r  r   r"   r  r!   )rb   r   r*   r  r   r  r   bytesr   r>   r  r!   )r   r  N)rb   r   r*   r  r   r  r   r  r4   r
  r  z)tuple[list[PenyetoranBatchResponse], int])rb   r   r*   r  r5   r  r  r    )
rb   r   r*   r  r   r  r   r   r  r    )
rb   r   r*   r  r5   r  r   r  r  r    )rb   r   r*   r  r5   r  r   r  r   r   r  r    )C__doc__
__future__r   collectionsr   r   r   r   decimalr	   typingr
   
sqlalchemyr   r   sqlalchemy.excr   r   sqlalchemy.ext.asyncior   sqlalchemy.ormr   app.models.expensesr   app.models.operationalr   r   r   app.models.penyetoranr   r   r   r   app.models.spbur   r   r   app.repositoriesr   app.schemas.penyetoranr   r   r   r    r!   r"   r#   r$   r%   r   r&   r'   rD   rS   rd   rj   r   r   r   r   r   r   r   r   r   r   r  r9   rE   rC   <module>r     s   R " # - -   # : / ' ' O O f f 1 1 2
 
 
 =6*111 1 	14--"--1--FZFF"F-1FF` #'!% 555 5 	5
 !5 5 5 *5&"36  	
 @### # 	#
 # #Z  	;	;	; 	; 		;
 	; /	;(("(.1((999 9  	9
 9x  	
 @,,, , 	,
 , ,rE   