
    ]io                     (   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 ddlmZmZmZ ddl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mZmZmZm Z  dedede!dz  ddfdZ"dededdfdZ#dedefdZ$defdZ%dedefdZ&dede'dedefdZ(dede)e   dede)e*   fdZ+dede'de,fdZ-	 	 	 	 	 d9dede'de'dz  d edz  d!e'd"e'de.e)e   e'f   fd#Z/dede'd$e'defd%Z0	 	 	 d:dede'de'dede)e   d&e!d'e1dz  d(e,dd)defd*Z2dede'd$e'ddfd+Z3	 	 d;dede'd$e'de)e   d'e1dz  dd)defd,Z4dede'd$e'd-e'def
d.Z5dede'd$e'd-e'def
d/Z6dede'd$e'd-e'd0e1d1e1dz  defd2Z7dede'd$e'defd3Z8dede'd$e'd-e'd4e1defd5Z9dede'de,fd6Z:dede'dd7de'de)e    f
d8Z;y)<uQ   Operational service — business logic for penjualan (sales shift report) module.    )dateDecimalselect)IntegrityErrorSQLAlchemyError)AsyncSession)LaporanShiftPenjualanNozzleStatusLaporan)ProdukHarga)AksiEnum	ModulEnum)Nozzle)operational_repositoryrole_repository)KasPaymentInputLaporanShiftDetailResponseLaporanShiftResponsePenjualanNozzleInputPenjualanNozzleResponseTellerInitResponsedblaporancreated_by_userNreturnc                   K   ddl m}m} ddlm} ddlm} |j                  xs  |d       |d      z  |j                  xs  |d       |d      z  z   |j                  xs  |d       |d      z  z   |j                  xs  |d       |d	      z  z   |j                  xs  |d       |d
      z  z   |j                  xs  |d       |d      z  z   |j                  xs  |d       |d      z  z   |j                  xs  |d      z   }|j                  xs  |d      |j                   xs  |d      z   |j"                  xs  |d      z   }| j%                  t'        |j)                  t*        j,                              j/                  t*        j0                  |j2                  k(               d{   }	|	j5                         xs  |d      }
| j%                  t'        |      j/                  |j0                  |j2                  k(               d{   }|j7                         }|` ||j8                  |j2                  |j:                  |j<                  |||
|j>                  tA        |dd      	      }| jC                  |       nW|jD                  |j>                  k7  r)|j>                  |_"        d|jF                  xs d |_#        ||_$        ||_%        |
|_&        | jO                          d{    y7 I7 7 
w)zEAuto-create or update the Penyetoran record linked to a LaporanShift.r   )
PenyetoranStatusPenyetoranr   )func0100000500002000010000500020001000Nid)	spbu_idlaporan_shift_idtanggalshift_id
jumlah_kasjumlah_non_kastotal_penjualanstatuscreated_by_idzY[AUTO] Dikembalikan ke Draft karena data penjualan shift ini diubah. Catatan sebelumnya: -)(app.models.penyetoranr   r    decimalr   
sqlalchemyr!   kas_100kkas_50kkas_20kkas_10kkas_5kkas_2kkas_1k	kas_logampembayaran_kartupembayaran_qrpembayaran_instansiexecuter   sumr   nilaiwherer,   r*   scalarscalar_one_or_noner+   r-   r.   DRAFTgetattraddr2   catatanr/   r0   r1   commit)r   r   r   r   r    Dr!   r/   r0   total_resultr1   result
penyetorans                B/var/www/html/spbu.com/backend/app/services/operational_service.py_upsert_penyetoranrS      s    B$ 
			#QsVq{2		"AcFaj0	1		"AcFaj0	1 
	"AcFaj0	1 
	!1S6QvY.		/
 
	!1S6QvY.	/ 
	!1S6QvY.	/ 
			$af	&  
	!	!	+QsV				(!C&	*		$	$	.#	0  txx--./	//7::=	> L #))+5qvO::z  !<!<

!JK F **,JOO$ZZOO%%!)+#))!/4>


 	z  0 6 66 0 6 6J''1'9'9'@S&AC  !+
$2
!%4
"
))+K> s8   F3L5K>6A!LLC L8L9LLLkasc                 z   |j                   | _         |j                  | _        |j                  | _        |j                  | _        |j                  | _        |j
                  | _        |j                  | _        |j                  | _        |j                  | _        |j                  | _	        |j                  | _
        y)z>Copy kas/payment fields from input schema onto the ORM object.N)r8   r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   )r   rT   s     rR   _apply_kas_to_laporanrV   \   s    ||GkkGOkkGOkkGOZZGNZZGNZZGNG"33G--G"%"9"9G    c                    | j                   xs g }t        d |D        t        d            }t        d |D        t        d            }t        d$i d| j                  d| j
                  d| j                  d| j                  r| j                  j                  ndd	| j                  d
| j                  d| j                  r| j                  j                  ndd| j                  d| j                  r| j                  j                  ndd| j                  d| j                   d| j"                  r| j"                  j                  ndd| j$                  d| j&                  r| j&                  j                  ndd| j(                  d|d|dt+        |      d| j,                  d| j.                  xs t        d      d| j0                  xs t        d      d| j2                  xs t        d      d| j4                  xs t        d      d| j6                  xs t        d      d| j8                  xs t        d      d| j:                  xs t        d      d | j<                  xs t        d      d!| j>                  xs t        d      d"| j@                  xs t        d      d#| jB                  xs t        d      S )%z8Build a summary LaporanShiftResponse from an ORM object.c              3   4   K   | ]  }|j                     y wN)volume.0rs     rR   	<genexpr>z*_build_laporan_response.<locals>.<genexpr>n   s     /$Q$   r"   c              3   4   K   | ]  }|j                     y wrZ   rE   r\   s     rR   r_   z*_build_laporan_response.<locals>.<genexpr>o   s     -1qwwr`   r*   r+   r.   
shift_nama r-   r2   submitted_by_nameNsubmitted_atreviewed_by_namereviewed_atcatatan_reviewrecalled_by_namerecalled_atunlocked_by_nameunlocked_attotal_volumetotal_nilainozzle_countsource_foto_urlr8   r9   r:   r;   r<   r=   r>   r?   r@   rA   rB    )"penjualan_nozzlerD   r   r   r*   r+   r.   shiftnamar-   r2   submitted_bynamerf   reviewed_byrh   ri   recalled_byrk   unlocked_byrm   lenrq   r8   r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   )r   rowsrn   ro   s       rR   _build_laporan_responser}   k   s   ##)rD/$/>L--ws|<K :: !! *17==%%B	
  ~~ 8?7K7K'..33QU )) 6=5H5H,,11d '' -- 6=5H5H,,11d '' 6=5H5H,,11d ''  "!"  #$ Y%&  //'( !!1WS\)* /73<+, /73<-. /73</0 ~~-12 ~~-34 ~~-56 ##3ws|78 !11AWS\9: ++;ws|;< $77G73<= rW   c                 <   | j                   }|r|j                  nd}|r|j                  nd}t        di d| j                  d| j
                  d|r|j                  ndd|r|j                  ndd|r|j                  ndd	|r|j                  ndd
|r|j                  ndd| j                  d| j                  d| j                  d| j                  d| j                  d|j                  xs dd| j                  d| j                  d| j                   S )zIBuild an enriched PenjualanNozzleResponse from a PenjualanNozzle ORM row.Nr*   	nozzle_idnozzle_namard   island_nama	produk_idr   produk_namaproduk_kodeteller_awal_manualteller_akhir_manualteller_awal_digitalteller_akhir_digitalflag_reset_tellerprimary_tellermanualr[   
harga_jualrE   rr   )nozzleprodukislandr   r*   r   ru   koder   r   r   r   r   r   r[   r   rE   )rowr   r   r   s       rR   _build_nozzle_responser      s9   ZZF$V]]$F$V]]$F" 66-- $*FKKr $*FKKr	
  &&))1 $*FKKr $*FKKr 11  33  33 !55 // ,,8 zz >>  ii! rW   c                     t        |       }| j                  xs g D cg c]  }t        |       }}t        di |j	                         || j
                  dS c c}w )z>Build a full LaporanShiftDetailResponse including nozzle rows.)nozzlesunlock_reasonrr   )r}   rs   r   r   
model_dumpr   )r   summaryr   nozzle_responsess       rR   _build_detail_responser      sm    %g.G@G@X@X@^\^@^`@^.s3@^`% 



 ++  as   Ar   r-   c                 l  K   ddl m} | j                  t        t              j                  t        j                  |k(  t        j                  |k        j                  t        j                  j                               j                  d             d{   }|j                         }|w| j                  t        |      j                  |j                  |k(               d{   }|j                         }|rd|j                   dnd| }t        d| d| d	      |j                  S 7 7 Kw)
zZFetch the effective harga for a product on a given date (latest berlaku_mulai <= tanggal).r   )Produk   N"zid=zBelum ada harga untuk produk  pada tanggal z<. Silakan set harga produk terlebih dahulu di menu Products.)app.models.productr   rC   r   r   rF   r   berlaku_mulaiorder_bydesclimitrH   r*   ru   
ValueErrorharga)	r   r   r-   r   rP   r   produk_resultr   produk_labels	            rR   _resolve_hargar      s    )::{	{$$	1;3L3LPW3W	X	+++002	3	q	 F 
#
#
%C
{ jj)=)=fii9>T)UVV113-36;;-q)3yk9J+L>y QI J
 	
 99! Ws&   BD4D0AD4&D2'A
D42D4nozzle_inputsc                   K   g }|D ]B  }| j                  t        t              j                  t        j                  |j
                  k(  t        j                  j                  d                   d{   }|j                         }|t        d|j
                   d      |j                  s|j                  |j                  k  r3t        d|j
                   d|j                   d|j                   d      |j                  |j                  k  r3t        d|j
                   d|j                   d|j                   d      |j                  |j                  }nE|j                    t#        | |j                   |       d{   }nt        d|j
                   d	      |j$                  xs d
}|dk(  r|j                  |j                  z
  }	n|j                  |j                  z
  }	|	|z  }
|j'                  |j
                  |j                  |j                  |j                  |j                  |j                  |	||
d	       E |S 7 7 ʭw)uD  
    Validate and enrich each nozzle input into a dict ready for DB insertion.

    Volume is computed from the nozzle's primary_teller setting:
      - 'manual'  → teller_akhir_manual  - teller_awal_manual
      - 'digital' → teller_akhir_digital - teller_awal_digital

    Raises ValueError on validation failure.
    Nz
Nozzle id=z tidak ditemukanz: teller_akhir_manual (z) harus >= teller_awal_manual (z ) kecuali flag_reset_teller=Truez: teller_akhir_digital (z ) harus >= teller_awal_digital (u6    tidak memiliki produk — tidak bisa menentukan hargar   digital)	r   r   r   r   r   r   r[   r   rE   )rC   r   r   rF   r*   r   
deleted_atis_rH   r   r   r   r   r   r   harga_jual_overrider   r   r   append)r   r   r-   r|   inprP   r   r   primaryr[   rE   s              rR   _process_nozzle_inputsr      sK     Dzz6N  cmm!;V=N=N=R=RSW=XY
 
 **,>z#--8HIJJ $$&&)?)??  /FsG^G^F_ `4474J4J3KKkm  ''#*A*AA  /GH`H`Ga b5585L5L4MMmo  "".00J)-b&2B2BGLLJz#--8nopp ''38i--0G0GGF,,s/E/EEF#"%"8"8#&#:#:#&#:#:$'$<$<!$!6!6$

 
	O d Ka
0 Ms&   A2I4I5DIICIIr+   c                   K   |j                   ryt        fd|j                  xs g D        d      }|yt        j                  | |j
                  t        j                  t        j                         d{   S 7 w)z
    Return True if user has penjualan:approve permission for this SPBU.
    Superadmin always can. Regular users must have the permission via their role assignment.
    Tc              3   B   K   | ]  }|j                   k(  s|  y wrZ   )r+   )r]   ar+   s     rR   r_   z$_user_can_approve.<locals>.<genexpr>  s     S#9Qaii7>Rq#9s   NF)
is_superadminnextassignmentsr   has_permissionrole_idr   	penjualanr   approve)r   userr+   
assignments     ` rR   _user_can_approver     sw     
 S4#3#3#9r#9SUYZJ //
J	 3 3X5E5E   s   A5A?8A=9A?r.   r2   skipr   c           	         K   t        j                  | ||||||       d{   \  }}|D 	cg c]  }	t        |	       c}	|fS 7 "c c}	w w)z<Return a paginated list of LaporanShiftResponse for an SPBU.N)r   get_all_laporanr}   )
r   r+   r-   r.   r2   r   r   laporan_listtotalls
             rR   list_laporanr   (  s]      !7 F F
GWhe! L% 1==1#A&=uDD >s   AAAAAA
laporan_idc                 |   K   t        j                  | ||       d{   }|t        d      t        |      S 7 w)z3Return a fully enriched LaporanShiftDetailResponse.NLaporan tidak ditemukan)r   get_laporan_by_idr   r   r   r+   r   r   s       rR   get_laporan_detailr   8  sA      +<<RWUUG233!'** Vs   <:<submitter_userrq   force_draftzKasPaymentInput | Nonec	           
        K   ddl m}	 | j                  t        t              j                   |	t        j                  |k(  t        j                  |k(  t        j                  |k(                     d{   }
|
j                         t        d| d| d      t        | ||       d{   }t        | ||       d{   xr | }	 t        j                  | ||||       d{   }|r||_        |rt!        ||       |rsddlm}m} t        j&                  | |t(        j*                  |j,                  d	       d{   }|j,                  |_        |j1                  |j2                        |_        | j7                          d{    t?        | ||       d{    t        j@                  | |j,                  |       d{   }tC        |      S 7 e7 17 7 7 7 Z# t8        $ r% | j;                          d{  7   t        d
      t<        $ r | j;                          d{  7    w xY w7 7 sw)u  
    Create a new LaporanShift.

    - Operators → saved as DRAFT (status=DRAFT, submitted_by not set yet)
    - Admins (penjualan:approve permission) → saved & immediately APPROVED in one step
      (submitted_by = reviewed_by = the admin, audit trail preserved)

    Raises ValueError if a laporan for the same spbu+shift+tanggal already exists,
    or on any nozzle validation failure.
    r   )and_NzLaporan untuk shift_id=r   z
 sudah adadatetimetimezonez#Auto-approved oleh admin saat inputuser_idrL   Duplicate atau constraint error)"r7   r   rC   r   r   rF   r+   r.   r-   rH   r   r   r   r   create_laporanrq   rV   r   r   update_statusr   APPROVEDr*   submitted_by_idnowutcrf   rM   r   rollbackr	   rS   r   r   )r   r+   r.   r-   r   r   rq   r   rT   r   dupnozzle_rowscan_approver   r   r   s                   rR   r   r   B  s    *  

|""$$/%%1$$/	
 C +%hZ~gYjQ
 	
 /r='JJK*2~wGG\Q\_K.==b'8U\^ijj&5G#!'3/ 32@@G]33&))= G '5&7&7G##+<<#=G iik R.
999 +<<RWUUG!'**k KG k 	 <kkm:;; kkm : Vs   A2H?4G56H?+G,H? G	H?G( 'G"(AG( G$AG( G&G( H? H;!(H?	H=
H?H?H?"G( $G( &G( (H8H+H80H31H88H?=H?c                 P  K   ddl m} ddlm} t	        j
                  | ||       d{   }|t        d      |j                  t        j                  k7  rt        d      |j                  }	 | j                   |t              j                  t        j                  |k(               d{    | j                  |       d{    | j                          d{     ||       d{    y7 7 H7 17 # t         $ r | j#                          d{  7    w xY w7 4w)uT   Hard-delete a DRAFT laporan (and nozzle rows via cascade). Non-draft → ValueError.r   )delete)delete_fileNr   z/Hanya laporan berstatus Draft yang bisa dihapus)r7   r   app.utils.file_uploadr   r   r   r   r2   r   rI   rq   rC   r   rF   r,   rM   r	   r   )r   r+   r   
sql_deleter   r   foto_urls          rR   delete_laporanr     s     /1*<<RWUUG233~~,,,JKK&&HjjO4::?;[;[_i;ijkkkii   iik h
 V 	l  kkm  sv   'D&C5AD&0>C= .C7/C= C9C= C; C= $D&/D$0D&7C= 9C= ;C= =D!DD!!D&c                   K   t        j                  | ||       d{   }|t        d      |j                  |k7  rt        d      |j                  t
        j                  k7  rt        d      t        | ||j                         d{   }	 t        j                  | ||       d{   }|r||_
        |rt        ||       | j                          d{    t!        | |d       d{    t        j                  | |j"                  |       d{   }t%        |      S 7 7 7 7 T# t        $ r% | j                          d{  7   t        d      t        $ r | j                          d{  7    w xY w7 7 mw)z
    Replace nozzle rows on a DRAFT laporan.
    Raises ValueError if laporan not found, wrong SPBU, or not in DRAFT status.
    Nr   zLaporan tidak termasuk SPBU iniz/Hanya laporan berstatus DRAFT yang dapat dieditr   )r   r   r   r+   r2   r   rI   r   r-   update_laporan_nozzlesrq   rV   rM   r   r   r	   rS   r*   r   )r   r+   r   r   rq   rT   r   r   s           rR   update_laporanr     sf     +<<RWUUG233'!:;;~~,,,JKK.r='//RRK.EEb'S^__&5G#!'3/iik R$
/// +<<RWUUG!'**C V S ` 	 <kkm:;; kkm 0 Vs   FD(A-FD+FD1 +D-,.D1 D/D1 F/F0(FFF+F-D1 /D1 1FE+F9E<:FFFr   c                 R  K   ddl m} t        j                  | ||       d{   }|t	        d      |j
                  t        j                  k7  rt	        d      |j                  xs  |d       |d      z  |j                  xs  |d       |d      z  z   |j                  xs  |d       |d	      z  z   |j                  xs  |d       |d
      z  z   |j                  xs  |d       |d      z  z   |j                  xs  |d       |d      z  z   |j                  xs  |d       |d      z  z   |j                  xs  |d      z   |j                   xs  |d      z   |j"                  xs  |d      z   |j$                  xs  |d      z   }t'        d |j(                  xs g D         |d            }t+        ||z
         |d      k\  r2||z
  }|dkD  rdnd}	t	        d|dd|dd|	 dt+        |      dd	      	 t        j,                  | |t        j.                  |       d{   }| j1                          d{    t        j                  | ||       d{   }ddlm}
  |
| |       d{    ddlm}  || ||dd|       d{    | j1                          d{    tA        |      S 7 7 7 ~# t2        $ r% | j5                          d{  7   t	        d      t6        $ r | j5                          d{  7    w xY w7 7 7 7 ow)z(Transition a DRAFT laporan to SUBMITTED.r   r   Nr   z2Hanya laporan berstatus DRAFT yang dapat di-submitr"   r#   r$   r%   r&   r'   r(   r)   c              3   4   K   | ]  }|j                     y wrZ   rb   r\   s     rR   r_   z!submit_laporan.<locals>.<genexpr>  s     K,Jq177,Jr`   1LebihKurangzGrand Total Kas (z,.0fz%) tidak sama dengan Total Penjualan (z). z Rp z". Koreksi data kas sebelum submit.)r   r   )run_penjualan_checks
log_actionsubmitr   r   r+   aksimodul	object_id)!r6   r   r   r   r   r2   r   rI   r8   r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rD   rs   absr   	SUBMITTEDrM   r   r   r	   app.utils.anomalir   app.utils.auditr   r   )r   r+   r   r   rN   r   grand_totalr1   selisihlabelr   r   s               rR   submit_laporanr     s8     %*<<RWUUG233~~,,,MNN
 
			#QsVq{2		"AcFaj0	1		"AcFaj0	1 
	"AcFaj0	1 
	!1S6QvY.		/
 
	!1S6QvY.	/ 
	!1S6QvY.	/ 
			$af	& 
	!	!	+QsV	- 
			(!C&		* 
	$	$	.#
	0  KG,D,D,J,JKQsVTO
;()QsV3/"Q;HD11VWfgkVllogT#g,t,,NP
 	


.<<00'
 
 iik +<<RWUUG 7
r7
+++*
R'P[gq
rrr ))+!'**o V>
 	 <kkm:;; kkm
 V , s s   !L'KG$L'	*K 3K4K K
K L'*L+L'L!L'L#L'5L%6L'K 
K L(K+)+LLLL'!L'#L'%L'c                   K   t        j                  | ||       d{   }|t        d      |j                  t        j
                  k7  rt        d      	 t        j                  | |t        j                  |d       d{   }| j                          d{    ddlm}  || ||d	d
|       d{    t        j                  | ||       d{   }t        |      S 7 7 d7 N# t        $ r% | j                          d{  7   t        d      t        $ r | j                          d{  7    w xY w7 7 jw)z
    Allow an operator to pull a SUBMITTED laporan back to DRAFT.
    Only valid while status is still SUBMITTED (admin has not acted yet).
    Clears submitted_by/submitted_at so it can be corrected and re-submitted.
    Nr   z<Recall hanya bisa dilakukan pada laporan berstatus SUBMITTEDT)r   recallr   r   r   r  r   r   )r   r   r   r2   r   r   r   rI   rM   r   r   r	   r   r   r   )r   r+   r   r   r   r   s         rR   recall_laporanr    s+     +<<RWUUG233~~000WXX
.<<,,gd
 
 iik +
R'P[gq
rrr*<<RWUUG!'**- V
 	 <kkm:;; kkm
 sUs   EC&9E+C, C(C, C*C,  E7D?8EEE(C, *C, ,D<D	+D<4D75D<<EEactionrL   c           
        K   t        j                  | ||       d{   }|t        d      |j                  t        j
                  k7  rt        d      |dk(  rt        j                  nt        j                  }	 t        j                  | ||||       d{   }| j                          d{    ddlm}  || |||d	||rd
|ind       d{    | j                          d{    t        j                  | ||       d{   }t        |      S 7 7 7 m# t        $ r% | j                          d{  7   t        d      t        $ r | j                          d{  7    w xY w7 7 7 lw)z&Approve or reject a SUBMITTED laporan.Nr   z6Hanya laporan berstatus SUBMITTED yang dapat di-reviewr   r   r   r   r   r   rL   r   r+   r   r   r   detail)r   r   r   r2   r   r   r   REJECTEDr   rM   r   r   r	   r   r   r   )	r   r+   r   r   r  rL   r   
new_statusr   s	            rR   review_laporanr	  4  sf     +<<RWUUG233~~000QRR+1Y+>''MDZDZJ
.<<Wg
 
 iik +
R'keo4;Y0G G G
))+*<<RWUUG!'**5 V
 	 <kkm:;; kkm
GUs   E;DAE;=D" DD" 2D 3D" 7E;E5E;-E7.E;E9E;D"  D" "E2>E?+E2*E-+E22E;7E;9E;c                 H  K   t        j                  | ||       d{   }|t        d      |j                  t        j
                  k7  rt        d      	 t        j                  | |t        j                         d{   }| j                          d{    t        j                  | ||       d{   }t        |      S 7 7 H7 2# t        $ r% | j                          d{  7   t        d      t        $ r | j                          d{  7    w xY w7 hw)z,Lock an APPROVED laporan (no further edits).Nr   z3Hanya laporan berstatus APPROVED yang dapat di-lockr   )r   r   r   r2   r   r   r   LOCKEDrM   r   r   r	   r   r   s       rR   lock_laporanr  Z  s      +<<RWUUG233~~///NOO.<<R-J^J^__iik +<<RWUUG!'**# V ` <kkm:;; kkm Vso   D"C9D"(C  C	C CC D"7D 8D"	C C D)C,*+DDDD"alasanc           
      @  K   t        j                  | ||       d{   }|t        d      |j                  t        j
                  t        j                  fvrt        d      	 ddlm}m} t        j                  | |t        j                  |       d{   }||_        |j                  |j                        |_        | j                          d{    ddlm}  || ||d	d
|d|i       d{    | j                          d{    t        j                  | ||       d{   }t+        |      S 7 !7 7 j# t         $ r% | j#                          d{  7   t        d      t$        $ r | j#                          d{  7    w xY w7 7 7 mw)zIReopen an APPROVED or LOCKED laporan back to DRAFT, recording the reason.Nr   zAHanya laporan berstatus APPROVED atau LOCKED yang dapat di-unlockr   r   )r   r   r   unlockr   r  r  )r   r   r   r2   r   r   r  r   r   r   rI   unlocked_by_idr   r   rm   rM   r   r   r	   r   r   r   )	r   r+   r   r   r  r   r   r   r   s	            rR   unlock_laporanr  r  st     +<<RWUUG233~~m44m6J6JKK\]]/.<<,,F
 
 ")&ll8<<8iik +
R'P[gq%v.0 0 0
))+*<<RWUUG!'**7 V

 	 <kkm:;; kkm
0Us   FD>AF'2E E>E EE F7F8FFF.F/FE E F!E$"+FFFFFFc                 8   K   t        | ||       d{   S 7 w)uL   Public wrapper — returns True if user can approve penjualan for this SPBU.N)r   )r   r   r+   s      rR   check_user_can_approver    s     "2tW5555s   r   c                 p  K   ddl m}m} ddlm} ddlm} | j                   ||      j                  |j                  |k(  |j                  j                  d      |j                  j                  d            j                  |j                               d{   }t        |j!                         j#                               }	|	sg S |	D 
cg c]  }
|
j$                   }}
	 |j'                  |      }|dkD  r|	|dz
     j$                  }|}n|	d   j$                  }| |d	      z
  }t+        j,                  | |||       d{   }|D cg c]A  }t/        |d
   |d   |d   n
t1        d      |d   |d   n
t1        d      |d   |d         C c}S 7 c c}
w # t(        $ r d}Y w xY w7 ic c}w w)u2  Return teller_awal pre-fill from the previous shift's submitted/approved laporan.

    Previous shift = shift before shift_id ordered by jam_mulai.
    If shift_id is the first shift of the day → last shift of (tanggal - 1).
    If no qualifying laporan found → is_first_time=True for all nozzles.
    r   )r   	timedeltar   )ShiftTNr   )daysr   teller_terakhir_manualr"   teller_terakhir_digitalr   is_first_time)r   r   r   r   r  )r   r   r  r7   r   app.models.spbur  rC   rF   r+   	is_activer   r   r   	jam_mulailistscalarsallr*   indexr   r   get_teller_initr   r   )r   r+   r-   r.   r   r  	sa_selectr  shift_resultshiftss	shift_idsidxprev_shift_idprev_tanggalr|   r^   s                    rR   r#  r#    s     ).% %	u}}')<)<T)BEDTDTDXDXY]D^	_	%//	" L
 ,&&(,,./F	  &&v!vI&ooh' QwsQw** r
!22'77G\S`aaD 	 A 	n>?@X>Y>eq!9:krsvkw@AB[@\@h"; <nuvynz-.O,	
 	 	7 '   b	sh   BF6F3F6F!F6$F 5AF6F/F6AF1F6F6F,)F6+F,,F61F6)NNNr      )NFN)NN)<__doc__r   r   r6   r   r7   r   sqlalchemy.excr   r	   sqlalchemy.ext.asyncior
   app.models.operationalr   r   r   r   r   app.models.roler   r   r  r   app.repositoriesr   r   app.schemas.operationalr   r   r   r   r   r   objectrS   rV   r}   r   r   intr   r  dictr   boolr   tupler   r   strr   r   r   r   r  r	  r  r  r  r#  rr   rW   rR   <module>r:     s   W    : / O O * / " D < < <W]`dWd <im <~:< :o :$ :$\ $6J $N#: 2L 5O \ c D W ,AA,-A A 
$Z	AP S T . #'EEE Dj	E
 D E E E 4$%s*+E ++"+03++" #'$(K+K+K+ K+ 	K+
 ,-K+ K+ 4ZK+ K+ 
"K+  K+\ \  C  S  T  2 #'$(-+-+-+ -+ ,-	-+
 4Z-+ 
"-+  -+`<+<+"<+03<+>A<+<+~++"+03+>A++B#+#+#+ #+ 	#+
 #+ 4Z#+  #+L++"+03++0++"+03+>A+KN++D6\ 6# 6$ 6
22"2-32?B2	
2rW   