From d56fa82f1473dab156a4680eb7135cd8b3ebc6b9 Mon Sep 17 00:00:00 2001 From: anhduy-tech Date: Mon, 26 Jan 2026 12:51:17 +0700 Subject: [PATCH] changes --- api/__pycache__/settings.cpython-313.pyc | Bin 3451 -> 3451 bytes app/__pycache__/models.cpython-313.pyc | Bin 139107 -> 139167 bytes .../workflow_utils.cpython-313.pyc | Bin 30136 -> 30481 bytes .../0366_payment_schedule_batch_date.py | 18 +++++++++ app/models.py | 1 + app/workflow_utils.py | 37 +++++++++++++----- 6 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 app/migrations/0366_payment_schedule_batch_date.py diff --git a/api/__pycache__/settings.cpython-313.pyc b/api/__pycache__/settings.cpython-313.pyc index a174e29b5979e868434e44211ef6187ee9e6b3e9..6f12e0ef4d71c68776703c497d5472ef16e5f9ab 100644 GIT binary patch delta 19 Zcmew@^;?STGcPX}0}!cX7U%acA219ID060TH9-y2g9@7F$4Vh$$1Fb}w-3{4pmCWaIrPqem0Mz^ z+ZvrCzPntv=m>dsOBYi!nTq5?lgO+vEelORU0W>^KXS`f+k4;1I$86_Z{GKL@BKZ` z{XO@&&pp-@v#vQN{(OAAEsB5lzg_PC&+_=~@o275e~8w->28`m0t5A1+6IINy@1Q0 zDR;naj+p>0m0ItEySf@yz4gNss#%9PdU73ZApHfTnupwH$-hlMJKCxD7Mtk$YD}fr zT5P~(+E$ARYO_VJt9Ox)kV#|fK=w{sp*K`i?0LW&^3mQpcvK_w*?R|vXTOL9IFeik zlhQs)N~;a+OUkIYEj)icNMRd&^AG$fq16%<)frn_99Zo01VV&-q*>gisHj$p?!C)J zJN}8V&B^bYz_ynje+ht-ycU%bUi&h9P`fR9T3!mdH=+<7v~(keSq8CbhegK|E=oOx zG(GbU8-2AA1&&l964=eN2J7{l=8Wp)F#W9pX6pX|VyW_9Sb|jQS&tOzb-}OCK6o=_ z`*5>8c5cw8d2&iigZ=}QxCtf6oyN+`WZ28Y!<07Iq^Es7)I5wQ=%lwcA4}WE^9n*Io_=u9Tok0yU6~pYW>PE00mDh#i3J!#`*vcaWd>W1u^LIpNz|Xl z@4{$42#a zz!bBrdfi-?o>|zRwv-{+YH$}ANtS7wCld)wr&ssjG0cnX!v|j=Q%`Luq(krFT@+OB z=PhX7i@9<0Wfn`Jw`ftBoWMb5cAamfEm?5Wg70{eYJeI`GHX5@C-Ha$<6x#TT=?jA$vm3%d8~46033vDDpxJ8cVvU%*S*`_O=e z#)ebEM>vZBFSiV3RK6dR%%yBoMh*K>Wm_yh0s)$HfU|OOq&RdPz=KeaSoMdz*HOtQ zD8N(H@(IRR9%j?0topt@7bPASCraLOtU>M^a4*)ZztB`@kkEO ztXWGF55umAU7yXT=MJL}YG~78WSalX)-{pb9ktY%vO*XHNK`A4v^8>fMMRv>p1~Zw z;`&s*TZ^GLKgU+Aqmm;C;AJ{|gxMSJkS{2E=JG$Wl z>dDsw4_>3)Js4$K!&a|Z^{n$Q{lg#n(}<%OfE6_3C|8Ho!Xi*l&m6^HusX7wk;l-A zF!df|k{vYrIFqbpqa6kb)f~s&wrcSd2-B70oF~;kd2Xi>Cy5L;@{BG?0Q{AP3J!qTyU$0PLX=C-D+KrjJkZkzUWHAOCcu zZ;CVgjq3a;6`sN<457p;TrpOcC);X;TVM~hpTcXXjnGzqiFv@MbnYvxKsP;n8WYU* zY}HK-r}3O^gLnyiO80)vH|7Sz>z7xF!=4-P%v!S8rv;1srT$~ox0kEMNvi0@Wb-!m zJxM!zvC_6hxCD+-{#lf%EhfEUkvrUTmV?CU@Zj^jqluT~Y{e`IXp0t>1eRzGwEO}} z%uVcdiOyX>BYvP)zQL<#C+|hLZ4JUHaGIXHh|Op)qz~WzU%Ua!>pbpP;kfUR2j0Rt zm+-#3j>k4A?Ow^cabRc^hPO<5j?YaqzsD3VAywa_ADXHDd(5-!l+U}2$@K0Fv-udm z_oGq&L*vxl@~MqsShUtG&$kNc33+;lA;|1esajtdZ0GmRJ_R9PX--kdA6Pun;|Yc| zk0*^rUdBB+d&DPN44VWbo=$6SPC;(Y)Vv7wG#NLjjY(F?>wDsLx5V&oYQKzh1nJCW zq++kJ=~opJ5i|isGp^uU^?F40`9Giv7_$A0+6Yqzf2P*+a9*#4#k_~1(>gcgFY$*S z(cYAyvDa#KMyYYvO^#thlU7#Z<8I-&c*V+#rzr4%Pdi7s(JJd#3SMNh$y5`q>L;A! zM;1>UBjSB4ProUiJ)e26%9cyZO={lcYh*Jb{ZbeVLPIix@EXb3B1#KVidkh|qt!Wa z78pV+%<2%%g}E<#6qXA-CUwj6uViY8Rb%7k zvrO6*`F^3=rktvk(=FF!HkA z{+tRiOsDZAQQ8?=8>c2-6PyI02~48|yXwG&$Wi&$u2up*T9%-OqmDKvsG0otU4qKx zzsU|Y!V)m9q}t=GFyj60wmBM?ia!X;>fetKi)D81oTYe;x^r6r88XPRGVOJ4+go{YA%v#5Unyp1hXvK$?3ZmY$zg-$NV0aqk9HG%bZi^YFcPpycdBP(zcku<3S9^>FjWCJ@0 zpCg8zUxm@m18i7h&6+sTuMaAUx3^&519lyMb<>?yc*pg)5DM%N!Zl2oR6HHl`O{#d ziq)8g$EoogJk;QZPk-+4Q`9>fPf?%G5Q=IV@ELLp!T1%_m;!0~< z8)iL1w?0F96LXdd5v8S-$|K>XQ6-3TCCKCg)iU`j`p8vJ(7F-~K!QYb-PL4pe%82g zUdH?azpqxJnizUU=4;}Y5k0wgYg>EvKSL33!J~T{Bb|xDDNsvwpW}5Tn(H_6)*;i1 z3$$$m=DSY5d&SY^GxL_K%TY6}2IcG$& zl|mPxhqIS32t-m?1;(J4!2$p(&Y`zRZ>=vW>q=Ey(9D_O;NU~^v;5;Fc6&N|Bslbl zn@OHDVGxL86Kx$Qp%x{Arv)OIycH=xTPoRxk?2fe+c~fLvvp_cvmN6?O>c99ZqUhc zv~>0pI)S!yd^_@tDl=ur| zQruTqhfzk=SC|5fqW)EQC1iXc5dW)kMr^OJ-FOM4$eAsE0;A~7uThF@qtiEV0uyAu z7{aB@G1aZddfimYVeG6st^mzqNJnvC#IT< zquQhRw<>0@4>IY{F*L(Mx^N81_L*$CQ1UEVPkt-XGef)uiY3=_B+blRn-K_c>T$FK zKBkqmyd^6rx{ewC#?~tw`qu1d>XV7)`n=vYnpuY^`)k7W0wD-V&e_ry_?QmY@v3GA zGG_J(xPjHQ>?FMSf>4i+wj#Frg0`IIQ(twjIr-`liy1Vlo)7Vd!XmJmcGqJzKBPgX zP=iuRI?eu@XwGT&Cm!D<{u7<^#a^J4=AGku_tF`pV!k+iMZU8LM}>H1(4MorQ9G&j zEN|2zHs2Z8s1D~a)VV-71S*7M6c!kqpOb+~@?F3R9HfYgeBeG|gM)J5x=8$b{7h?X zjWaiIY<7-!LRN0JRxV1KROV5fLLXn`BGk%CSyzzgS|W1@R7x@|r^2rhO)V~guq2?< zH#(Suv|6E3Q+iJG2qpO#(z`0WV1rAg36?}@7rq_d&y@79`dK%b(9Gs_3 z4d`WC&o1ZbZUbgI*9wI|JuW2?oKYL>8 zn0#N}gbrS>KVS2DXuMp{Y$8fG{jZ_$< zIz6Q34L0jZ-v+5Q-OqEAg%rntkT<3EyFxa}WZwG{K24jgYIv^)Bs7D*C=4c{DW6IB zfP8FW(KH%jQ^^nN)+pWrt!S%F9YtfHP?g$M7VOvfyD!~{4OV>|K$YhzXKVZGQP9l7CMT>WY>bvS!RsIM zYW7%8f%^ftB2*NG zZQpF!vLD-itxcBA>?TY9G^xqHvSf>fwp!XO-O^-BmUU+BmS#=5ovWg@*^gx>;oSF} z^PKm6-sgSq<;pMk!hKxyps=t2(Q)?Ce7q)hq3BMr+KtdS9`Ab-5j2Srn!;dAs<~pU zEoZJHxKL67BNav153`CI{2|y&IvBPdOezh$QCSsc8$$KGKYozlhn2$ z))pcgdlX@F(+K>ayW95~cHFavHW3tU4;4Tsqixk7WIzFJ01sMO2XXkH+wie-CiX4Q zjUx=PvyH^&KMLQO%Y-Hxwvx|-`(Td&%bhy{I76d+0Qjl02s`1=N~6>n&#%aJdwrP;D+caYDHI2fQT-!@A&X&51(yjs)w$P_4y$tWsH&*H}wjfun7QVYs@? zLe25E!w5yDXv%K$rr&5W4Kk4n5}44@EZ`NhM%zSeyHKBxO4z(3ljcyE&qS!CKAItX zKy`+=bBc_}LX$a1q?xz_TDM?h&00uP$hviA$=#?gr0$yz^dclhRK6xEhbs{FP+;Wp zdQIi)B#!VTwkbzklya_mLdxS=PWJ!CiPo=~GLzH#eOcR&U7)a(7q|kEb&;e99AZro z<@5adn)XI$f(u&?VB7-NbY;Lc7;!6{w{KW&P+jK{dJHHOh5L=hs$-;et3~&cz5W++ z$!|aX)36{aDSX+ENE>OfV;^q9u;5g|-8#wccG8}!P=t!KL)doW;Y9U=mv&Zh>?%S5wNr4h*ahc>LU1;|g}dRK z#`40xkRhj-pXK#}LT3?R*Dh#qYHLQsQ(aNflvF#@G8g$4vB8jH!L|1;r<%9IAFn9x@m=< z2dwxug<7Cvunynhjt@$N_*d@a!P5+`g5Ug8xSb0IgxD(bjf{GShO&7x@l-mSH=Rnb zS>a3~5=~|01A&oYUu-fFjrAmxi6lfu=W#!`I?Ccv2@ju$y*Qi9%3?FI6ESvkB~3?? zQ?c~Kx;sTOmP*Xb$D$LPm?TG4%PMm>(us+Uyt9ItR2q&Sx+?0Y08lj&J8^jA-(yM zWT82u^PC%8mFt$}6{`l*c`1KjeEX%0&U$W;+NSzTV^^9p#_lCq**&>-NoV<}dqr+v zmfP2uJZ0-`m2uTv_esI!f+c5n#_U^GRjr9pm3v81epjYhkr|d1GQ*P5eqH8R-DOyk z86JwcAESHn&rB8}^)P<4HYC7G(=EO6@mg;lDlJ>lSeG@{2M8-$SIsRM>W!YaK32O7l{cn5in)ujs1%k#tyJijsxBxZQs)Y_D6L3QL|Jsz3W@-!Rgq}lcVdT%O{IS6zxVHb z=iYnn@P6R|eDWJ8A1f3a2zwSnvy+cU3d)tL^8rGJV5sNnqfRS2Z8q$0Qles$1I}P~ zL%dQK8YCpc;asB`+AjDTRa;XaIuIY)mP%luUxzuUFnI{ymf}_q#G~LEj5ktaf?}qx zR=KsLvk+>uVWGZB_+yI+Fy&B!=tz%U%}Vg#{${h%!|7$rnT=2n7nfnC){gVd_sY;l zeBZtS=N&b8!+smQXsOfUhb?yS6~FGc479YT+R9|Shao6gl^Dqv_@5nRs&PH_aW5CM ztsx}kEE|_IVO)INP!TcCGHiFOK}I(*e6ob+jv83@wIsNvDCKM;oSyfKCwpRq@PX%O zNCT-sF@2eaxeZ(h*0;2mtok>mQYFtcK-)QeP`WDfF6zf2r{3v5&`U@SVKwy^84iaT zAaj`z))7@P-Vre#ZO2Pa?F*qi|0z_zga%kZ6>Fr?wU`0YNXE2jnQr8&UDhw#Bd3)z9&XR zsG57zOK1lTdLaheAd$tXT?P{$qM=e7G783Ey;vc-T}ZdZfpI9Y2{Sgv3m#d`|D_S8 zuIFeNg?Bt=fDpSKumio-TKw7TP<1`m;Luus*`Ux6>u=)@+Eq&1_HWYc1jl?H*-P}L zM5CCafep+xLQb>!XN1Uj--Dqz&~^8Z8%)weWCH6G=w#d%siF69Dd2136yB?_~C; zL<`MMO4fN(l6VDu2Wl}A(BYK77LNxs(p`KQ)e^1$jdJuD4VNN}vLuo*8+(t5HxAZI zl#CTiq{Djw+2(Q+lgyTb(!`5)tauQ{dnz|ZgT2s$=Yp*|3o(=36@AVwshNy{mE8m; zOZ%+Cv*0d`YSU2KmdWL^{Ak+Y*y<8eySo9V@Vz}x;4>`jO~dE-VDA8Yfj#@u@FgCM zyYc2exBM$cFh7fLh3sgHyWwkgFaX~$s0(k!Tj5*bS-e^XD?-(w*CkMgZ*$|&Dg4UG zKvr>ba(V_0bQXGr0_CB(W+sy#&(0hb^>-?>C$p!r{LCHcNhVc`x}(|Ga(U#EpF%Hc z2KQikupZ`x{NUYRy5?$D3@r;43x_UOUePWYI_D}^ zwAM@R4`yy_1Glt+ zNgDd#&xiY^pt1b4+5Gh3K{;sjcj|OcADUJ_{+iy-?%_?ZIXdC4_@$vaI^iXY1L0^x zbfSYSrYuoObRt3)C%kMANEatM*uI195lM8iLb!hFZwY*a*K>MU#N}KU1cZjEC6KQ$ zpZWXvdtMI%LiKb`VlQfLiRvY`OpAXwi^Yu>Szp#hgz7 diff --git a/app/migrations/0366_payment_schedule_batch_date.py b/app/migrations/0366_payment_schedule_batch_date.py new file mode 100644 index 00000000..355fc2da --- /dev/null +++ b/app/migrations/0366_payment_schedule_batch_date.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.7 on 2026-01-26 03:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('app', '0365_payment_schedule_penalty_paid_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='payment_schedule', + name='batch_date', + field=models.DateField(null=True), + ), + ] diff --git a/app/models.py b/app/models.py index ecb2c9c6..6a11d0cc 100644 --- a/app/models.py +++ b/app/models.py @@ -1700,6 +1700,7 @@ class Payment_Schedule(AutoCodeModel): updater = models.ForeignKey(User, null=False, related_name='+', on_delete=models.PROTECT) entry = models.JSONField(null=True) detail = models.JSONField(null=True) + batch_date = models.DateField(null=True) ovd_days = models.IntegerField(null=True) penalty_amount = models.DecimalField(null=True, max_digits=15, decimal_places=2) penalty_paid = models.DecimalField(null=True, max_digits=15, decimal_places=2) diff --git a/app/workflow_utils.py b/app/workflow_utils.py index c183069a..430c7618 100644 --- a/app/workflow_utils.py +++ b/app/workflow_utils.py @@ -321,17 +321,34 @@ def resolve_value(expr, context): # ============================================= # $append(list, element) if re.match(r'^\$append\(', expr, re.IGNORECASE): - match = re.match(r'^\$append\((.*)\)$', expr, re.IGNORECASE) + match = re.match(r"^\$append\(([^,]+),\s*(.+)\)$", expr, re.DOTALL) if match: - args = split_args(match.group(1)) - if len(args) == 2: - target_list = resolve_value(args[0], context) - element = resolve_value(args[1], context) - if not isinstance(target_list, list): - target_list = [] - result = list(target_list) - result.append(element) - return result + list_expr = match.group(1).strip() + element_expr = match.group(2).strip() + + # 1. Resolve the list + target_list = resolve_value(list_expr, context) + if target_list is None: + target_list = [] + + # Ensure it's a copy so we don't modify the original context variable directly + target_list = list(target_list) + + # 2. Resolve the element + resolved_element = resolve_value(element_expr, context) + + if isinstance(resolved_element, str): + try: + import json + element_to_append = json.loads(resolved_element) + except json.JSONDecodeError: + element_to_append = resolved_element + else: + element_to_append = resolved_element + + target_list.append(element_to_append) + return target_list + # $first(list), $last(list) if re.match(r'^\$(first|last)\(', expr, re.IGNORECASE):