From bca3ccc8647f8e324faa1254dd60344f46eb1654 Mon Sep 17 00:00:00 2001 From: Jadowyne Ulve Date: Sat, 23 Aug 2025 07:14:25 -0500 Subject: [PATCH] Fixed a conversion uom bug in the planner --- .../database_items.cpython-313.pyc | Bin 62278 -> 61946 bytes .../__pycache__/items_API.cpython-313.pyc | Bin 35889 -> 35818 bytes .../items_processes.cpython-313.pyc | Bin 11383 -> 11063 bytes application/items/database_items.py | 3 -- application/items/items_API.py | 2 -- application/items/items_processes.py | 17 ++++------ .../meal_planner_api.cpython-313.pyc | Bin 9160 -> 9142 bytes .../meal_planner_database.cpython-313.pyc | Bin 14331 -> 15375 bytes .../meal_planner_processes.cpython-313.pyc | Bin 2597 -> 3646 bytes application/meal_planner/meal_planner_api.py | 5 +-- .../meal_planner/meal_planner_database.py | 30 ++++++++++++++++++ .../meal_planner/meal_planner_processes.py | 22 +++++++++++-- .../sql/selectPlanEventsByMonth.sql | 22 ++++++------- .../__pycache__/receipts_api.cpython-313.pyc | Bin 21270 -> 21945 bytes .../receipts_processes.cpython-313.pyc | Bin 9480 -> 10156 bytes application/receipts/receipts_api.py | 12 +++++++ application/receipts/receipts_processes.py | 20 ++++++++++++ .../receipts/static/js/receiptHandler.js | 17 +++++++--- logs/database.log | 5 ++- 19 files changed, 118 insertions(+), 37 deletions(-) diff --git a/application/items/__pycache__/database_items.cpython-313.pyc b/application/items/__pycache__/database_items.cpython-313.pyc index ff16a8e24cc82ddce97e60b2167cec297eb2c72e..2fcfacd68026a63133765d676091c14cb9538f62 100644 GIT binary patch delta 3144 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 diff --git a/application/items/__pycache__/items_API.cpython-313.pyc b/application/items/__pycache__/items_API.cpython-313.pyc index bf6c8b4546036291b384bb48142d5bfc03e36452..18f42d6597a8293cba1d554a21965bdfb5221342 100644 GIT binary patch delta 2002 zcma)7drXs86z6{JM`&Sjb7zkSK~%em+L?z!ij zd+xmhyQEt?rI7m}A-Vwk!cQDqH#iWYHLyIGY%rHTuEr?JifvvX$X^)-&>QkUIUXIZoyj16&+n4YhzMX#IicT3<%e_hdJ zI8?F=$J>;q*+J?^jv`-7P)P6;K@)7x$&@`P?pDs^gsGVuF62EI-byw>T~Cr18VaJp zo^Oyh;P9BzpWmVq%tDx7kignu^}>vBErwLYZ4Gueryz!uBL!B8`T9-IvU;$YOzIBQ z!hy<(Fl5rpTXAp>W)&yFd9z0O-Q;I;eW>D11jOXY1W^Q?2xk5QiCYks@e&g23Azbh z1Z{DGybZ-sWma(=E(&`}<_30=tq(4jJk7SiH1kx}19Q!p!M#FF&<}2NmhKf4zr)}C z1&mfsf(6BT<-9pgrKTFdnOTt_FI>S|F~wr}HB|ko9A0=?((XZ#rxS%T+FKeX@58|# z%0Q`JGWp1uhu{yYTIZ~@uW{PBSoYtX3~FKL`-v%%B)ggKrtubdw73MLEiOw96og)I zm!<0tqKz>O^dJSQ43}x7WFPVS5d7)}TfM`taeLM_w>CNqDxu|v$bJ}ZEset(1X*&? ztI3kWI$)i}ARk3zr1Gl8C{6GYkD~LdJsynq5L{iJs1em}OM_5LJfxP-!^t(}@oWcl zmuJZ*k({i&Uv88pipe6~K#!|lBnx_L#@O_S$#Bm(36@#ogL`NZ4Z(5PXw9CygG4$D z26=4X2T0KipIEcyQz+&PuH4ITGxx13#OS|YWyAntD$>~ym@86r?;&G8m18BABSqO) zv6jX9$iWbS*nCRpm?XA|cR_4rYP86R52D_n;c6nzC+LC7O7gq4(kOp`iY3bDl@D0D zk8C0_Z6kM7JH3<}IpuW(rxDC;ab>~;3D)R;3YI7`PP9?S721{tpCNLYmjZml%Hz6)5_1H>AIKf`t`-OXkTg_7ehxO-r^}zA z=!9WglJcqjTNddfi#SulbrlUy!#mX(==w%=AqF_3W-)7m=9(wvuh7_{oUD1o0>`Go zpfeA7x1G7;wl1SKFXHjmsmI)p!undH?i+N`L3`3ET6DBltztXjVtpqrVQnzzF46h~ z+m)9Zw9?pqiOA>-VAF~!k<2?_pfL+qzuvf3zKn{!%A%$!Rj`k2Vn!dl+ng6kz0ZFj z_>tfW!A}tAd3o}26#ZdEHeThjJKSZq);gEXjyrwAGYwn#OHZl%8#3Nh;#*cQ$;;qE zjDgwum!`q_CE5L6O>iJu#b=RWcta}8DT#y{ZxjoGjoy4%@O-RFyJ`Yl@*YU=A#Loq zQP&xy$MRUDS7BG{^ptDFx`FTv|Cz*_1iv5{wBtJQdh5)P+hntmO~rRWOxsM|T^yXH z$_~JyHY40=kAWj?)v@78MG*lb5xSy$)kthaQI2XPlaZVw7v(E6H(X)iK5`|hB&v25 zqTBy}ENj}w$I^$fOofx}Ve)-+dr>*tzFHMNJ{x`wW^eAD@Br=jVBuBd_DgOje*~kO zOJpr(a8sGmk;Q@^Qe1x#Fj&#~20IRac2;bnCycuY=uP7E+=$nN(|f_`isy7+bGnH+ z-ME}?MShfkZX|w+fUX8k=a|z`<8&rCbvLK}6#d7kr8qSJr^<3lhie&p-4)9wDR;Wk iB-q>?r{s3`sG~wz6T7bpkfsvk-c{51?sT}gwc>Bpb}YXD delta 2172 zcmZ`)du&r>6u;kXZ?|=nmd74280`dVMRUm8UdueVzaSnyw%nMwg3T7mP7sWO zBQ8P-Lb2e8e@HJ&gw|D~;Z&+A;c5CA-UQH3*~@frWQr{+Ecv;|7lgqn#oE>Ar5WFV z78Y7}Mn&s3dwz(XAP-opRFWU%o$`y*qt$T%BzYmhe1c2@4hHKp&@n4ksz-L0yla+T z&4SQtTWx40y<)zOs0Nsqp9q=h7HK`Qhh%Shy-Km14=M9Z>@~3EPc_6;yMx)>>2n2m z3tAnQTj!OCtQ9U~RxlqtpOwYhpeZXw>Okcg(B@2%zsee5b6b(+oS= zCIDEHm!^Fi$&2^~z5#uXQ9hJ6Ud0;W?4mkETYiqT6Lr_*mi&t%+YMy}snQ-4+?G2E zhKX59$~NS~(Uq$_wXRn^F0S|=O5UR8r007Hlxj$y$9ECG34Sch#k7)(QZ@>Ag zfZ?PY?ePWNJZN8BT*Tc~o^`>Hzt+vS!OG=n(qS|(%R825h@%u|N?$agI5jU@A3BpQ6b^xuCR@jZ@+tr>~XaQ#l`s+^PuRc3Em-d zKhhz77Wp!0c1@B`IPbHuN{U~ij4KY5u|0@zu5vO)__uP7`B8_c>-=+aso`#KUA>!s zK@#c~KLfA0jMCRg*2vAS`z%iJt=u5RZ6z6nPK zM)f_WiF^iIJvOvEj> z8-~zLPlRNv!NAW`5(Hgjc^8&WPlm1OdU=QMJT-WYe=MHG4u2Yk{>;Bp`Ux%HlP9mK zRK+T3DTVaFTR~f#a^QaA?ahu zfL_^t0rCf_eh_nei5a4g&g>aQZKBTK=3CKBuM3XnYH=rSyO3jy)Ry diff --git a/application/items/__pycache__/items_processes.cpython-313.pyc b/application/items/__pycache__/items_processes.cpython-313.pyc index 68e845490313ea158971a2b816e768ebbbfad0e5..a9c1524cc9ec8411212c02cf61c82630a9997afb 100644 GIT binary patch delta 452 zcmew!u|16MGcPX}0}z<3TbZ$2b0c4#08<$A8>= z1}OxCAil{B%%YQhg;XbZ2q}vS!o)+_Oc^2UXu-(`ghGJY1sR1V*D=XYE)>?9ypu_k zC4wtRa`HwQ>B;AXc^DZcTg%8#))kRu31tnE1qw^CC@_SwPF^n~vw4@uG)6{&$$?^8 zo14UV8M*3!1{Z^{=j55<_ay}6W~8j}yr^P!!NThze^?jGM@0rv!!H_>S4j9Wec+fR znJ*&4z$Gz*WkKdeIfDyEE*Cii8eE=Co+#64;)0WHwY~xkG1i`J*9GJk^#F-mEGe1EB}H){KF9}P6N(mqSXv;W9z?_f ziCY{tx%nxjIjMF<%O|tw_^CQFG75flV~PX@!itcu3?TYL850Mi2W zi-946F<6Kd$cbnT7Pe%`V~ys8$)Ko5h_WF}@l9i3;0Bon)4~uWFu8$QbTYS)su+?% zoCqzG4TO|Mg< zldmYaGB!+>Qhdl*I{A;HFJsAMFQpBPEt7vM*)euawo)$O0{Ny0MC{(YMcJR3v0*cd z`g}&l{>e);LRc39#l`Kh`AgY{zoQzRp!z>1Ks3?TYL850MisZZAA zRyNWAYAMnL61P}W%Tn`7inKujIzU2`qlg8>)&&vlAVMER7)-9?R%bH;G0i5g=GJ0Y z1u~0EL6*u+{>dH9XtFt!r-F&w9HfE?M5s@`!KZ46u!y}VH94~&wfGiuYF-MGecb5w z>49`ZEw$!1W;B|d&+ox#w0Q@=FeA{KGXmL6AxPGMR67C*O_m}g%YdFr$uBA{at28w zJcrk^Zec^9WqXC4xxu=;Kw3>UbBj!6W>lZNP+U<4Za$KUJW%IPz9*gu)a@Z*$r!S^ zNkSgv)J2kpjEd?YW1>Ms460k$VLHD^X#;gCNb4}>PWF{925LMg9n2_g22_5Ft+XH| zu_RTK=@v_AX=X}M7RU_s$@;P?LI_{MO-hwDfW^^lSyjgB$p>XyfyTMZDKfHwj05V- zlUKv0bD2C`=N)-P#*WGVLWHg@auBgst0n%)B=A9Ovx`y#BZ~=89RQV|rg8uP delta 819 zcmaKq&rj1}7{~jxwe9GBm0>omT`3N>GC;ObahD~q1ICl4qQs$zuq6)3SUN_)6BnbN zGzKfn;e!RSFzwX{fzC+u;-h{rVqQM9(ab9bRUAaC1oLrf+r@Akgy1OYY!NF5g5W* zPfY!+gl-C7mA+3(?t_wBUwMD#+{WNXWr{T2N1kO6oj7qg2@K0e(aiI|eZ(|U-CNM)Ex3g_jxkfG%$K9u{#7%6LYir4VFTmZ|>dzV@H1f8I_CZKoz z-dqbLI;GiiwNz_xrAo1lC;!VkM%_)Q8OT5eF9uFR%6$?D0l~ZtUS-d=Vd(T25tDb? zVB}K81*hiZ>2d3F|AnoDQUvxql$Xb;>l78s{S~^$K>}}wjU#*cZHeCI`nVM?6Zi2* z7Hqc~(dnvp4yC|I(3k?1X)3K<#9imN!%5=ws{_J3nW)X-Pd$p4)YBwkO|?NCCEbQl zuNE&amQ1$6*X!k?Ge^S`sA;jzeIjjbc=u!7(t6<ERRK{VOr;Y6{H{G)eyhSj-0fdgK At^fc4 diff --git a/application/meal_planner/__pycache__/meal_planner_database.cpython-313.pyc b/application/meal_planner/__pycache__/meal_planner_database.cpython-313.pyc index 81b57f1a60e6b063e0697ed93973997388c78051..4c8bad4599874cddd15bc55aa13479498d3f77ab 100644 GIT binary patch delta 600 zcmeyJ-(SJ^nU|M~0SMgJuFPQ7oyaG__-LZKlDR-IvlK%XV-ZWRU@%JzYcOjJn+Z!W z8&He|D9Vl^$_^Ff2o{{!AX<;CffFjlg`$BAD$0!_$_*9e0gCbf*^EWJKo&2U#Rpf( z4|E0}RHXn=lpicFn9isv^b+I`zm5NrB^iHBPLlFqTFE@4HG*;GP@$*sr}sMxKD8%P%E0f{Pu_~iV&vecsD%>2A!g>VnoAXkOVlGNPz%oGJ% z1=V5&M?V*Z(tJ4II>fKYYw{~81#TpLlND5@ChJR!%8C`I=An#-PdX zRjOFSfCA4q=c%?p1f(YOYK5~!0R@>EH)m-HF*1g4uGLOvVNC`K$!~tDU%<+m0c6^3 zjxw!fWE7fw!_3yl2Pgn`LJ`RLB9M_qAR}(Eq+}+S6oIrBfi!`GjCneb45Re|;SUTzYDMYfJ?7RdIY2o8FDjTO delta 412 zcmeCL_?^%9nU|M~0SKN%tjI{xoX97^cxIxyk~x1cvlK%XV-ZWRKrl-TYcOjJn+Z!W z8&He|D9Vl^$_^Ff2o{*wAexM((YL HX+SOjA|_vI diff --git a/application/meal_planner/__pycache__/meal_planner_processes.cpython-313.pyc b/application/meal_planner/__pycache__/meal_planner_processes.cpython-313.pyc index 8bfe9668304dfda697f3644b97a698b0e7df5fe0..e7d07d1e3b377a51e21b0df900d3b17566c8b89e 100644 GIT binary patch delta 1665 zcmZ8hUrbw77(e%4Z~xu4(87??LXiQ@gv|jibc~4(GDKkEwsT2i>K#2m2fc-JZ>Nok z^u>sYSxU|pF}jQgO}4k0_<%7n#;3*j(5~X@1*0!M7+;vg*Tr*gDK>s-zjMy_`~KeZ zo$m|Zw{5ONNwNb%w;n!N;+>nW7UuG1PsGc&0%Vmfvd{`{FvzyZgvCwuG?3v0B{G$jLOAp7?@-67~8bY#MnW0h^>lMF2;Gm<+}i=yv)XUnd>0{S$To11o?;{ zLQIeadX_=tZ2*$QcG^X>1ldBRHS`#31E4M{PgLp%&$8mWAd5$qriZ$GEHTTRSf_rp zm94VvIA<|#t7(wfcIs(})Jv%j5o@wO2dTk&?S0u!Yoi+LrY?wCYbteSg6ybw7`c5^ z@CT%PXYB(`-vYn^I>7Y3>Kfy^KvbHJ!+2(uV6uOHp<6ESg9vX*lLH>dnN0GOuUQpR_=OThnufXDv%qQ+h6u zQ4>pwnv8}8L~q?Vp}`e6uU}bF)bX1%=qtJDjH)jg%~jx4;twJ%1v9D^&91IMgIk2U zAuOz96g_M+Y#IrjP?a<^_#9M_A*4-n3pBkMg1H)w|0+ovcA6x0no*HNl0a_4G9Q2fPwX|E*bpkG&TI%pS5L{> zTk&^n2Y>RP*_f)hTel)5clZ6SU3dS(^Tms^rGYEOXrlPmjZ$=ZcVKxxaP~=H@^N7D zQMh=0xpZ}xa`MU-K(B#3Wge8~a(= zJ8V^5_+u`_xbW9p#2NS0+|G598R4^3t??pvT5`u}!Y0ji(E-A^iOus~PfYARk}Dw+ zg`4Za-*BzCofnv}xx2`J*hCOu*c4rdY7#=t;O8@%j(_Ca+Yy-{Aj~4_#1P>-t0@Gv zu+`x8+$uy}*e?VGvzPD%K^}U6XrV#M+9~TGjC3A?iVl;B>p3(;r7ux-jxsty!cF*l zp&%k3*&7_5wJdcv7(DH8G(bgSR)Z*!N}^6`aqJd_@UNB*rVBr_1nh`T3^PUS7Xu^c zIdar!Gk5%-5E**Fa4X4VR9S|zS>1eqC`zO))Myv~ApRWs-Qz37OP)}Ea^K-8_zDY~ zZDmLBGi`hL)Ave_zWgP;Z9OAwXG>Ba{>8e9*KGa%elgzHbQS=5u>FCgcgdK1U!|VY!`TYSRzk$I$ApLETn8tsCBaFwi F{}=gSf}a2Y delta 714 zcmYjPzi-n(6!tZae1Gz(&2 zfQ{$|_y>@R#DIiY7+_##U}3l-F?C>qDq=+9o|_7u?C-w!?t7n~b@!qC@W`tc`NV(ACjW%}hITN!mhG+eEf9it0yY5KY1mYf8N1hi|$385yno;ZCE(_Lbsl zwwZN|v?w~JBQ=qe11?r8spSQmPFUJ0oSt%KE^5Bf0@EZKWwx&tk-_@P;;hj+epqiB zE9ih%B(|q4us5oVa_pUY#x(!yt|Z+ibhB-Bw$N0UCl2m{7$VhJWPwsrDnP41*#qsV ztP2e*>hle*yHP}ZOi1_xKF8&55JvVCEkdG_?SV&0Xlq=Kh66%jYOZ!%+6^$_x)+gt zJB~ffW#8=+p1KzeS*$zf3PMLu0;m8Qv}L-KxDmna&XCSSwE`f9lwL{p4Ev)$W6v`L zTU-u>FP#$`T#Z9Q+a9KHX#cz@%+K|Z^fubv!1uX@-N@~@A%S$m+dLT5qNGc_LDU|& z!(QNGu1*SUD?3-yI8 z)n8l~^>*Sf<_i01jMQ(k{-pZ&CVOO_m>vtEWTQ1(r&Yn|GJ9>-)|P%lWO0k^ShGyTdtve()t%bTdK_f diff --git a/application/meal_planner/meal_planner_api.py b/application/meal_planner/meal_planner_api.py index c5d6163..8d9d440 100644 --- a/application/meal_planner/meal_planner_api.py +++ b/application/meal_planner/meal_planner_api.py @@ -28,8 +28,9 @@ def getEventsByMonth(): site_name = session['selected_site'] year = int(request.args.get('year', 2025)) month = int(request.args.get('month', 1)) - events = () - events = meal_planner_database.selectPlanEventsByMonth(site_name, (year, month)) + + events = meal_planner_processes.selectPlanEventsByMonth(site_name, year, month) + return jsonify(status=201, message="Events fetched Successfully!", events=events) return jsonify(status=405, message=f"{request.method} is not an allowed method on this endpoint!", events=events) diff --git a/application/meal_planner/meal_planner_database.py b/application/meal_planner/meal_planner_database.py index 6b2a9b1..bec38b0 100644 --- a/application/meal_planner/meal_planner_database.py +++ b/application/meal_planner/meal_planner_database.py @@ -167,6 +167,36 @@ def selectPlanEventByUUID(site: str, payload: tuple, convert=True, conn=None): except Exception as error: raise postsqldb.DatabaseError(error, payload, sql) +def selectConversionsTuple(site: str, payload: tuple, convert=True, conn=None): + """payload=(event_uuid,)""" + self_conn = False + conversions = () + + sql = f"SELECT * FROM {site}_conversions WHERE item_id = %s AND uom_id = %s;" + + try: + if not conn: + database_config = config.config() + conn = psycopg2.connect(**database_config) + conn.autocommit = True + self_conn = True + + with conn.cursor() as cur: + cur.execute(sql, payload) + rows = cur.fetchone() + if rows and convert: + conversions = postsqldb.tupleDictionaryFactory(cur.description, rows) + if rows and not convert: + conversions = rows + + + if self_conn: + conn.close() + + return conversions + except Exception as error: + raise postsqldb.DatabaseError(error, payload, sql) + def insertPlanEventTuple(site: str, payload: tuple, convert=True, conn=None): self_conn = False event_tuple = () diff --git a/application/meal_planner/meal_planner_processes.py b/application/meal_planner/meal_planner_processes.py index 460614c..5249e63 100644 --- a/application/meal_planner/meal_planner_processes.py +++ b/application/meal_planner/meal_planner_processes.py @@ -5,6 +5,22 @@ from application.meal_planner import meal_planner_database from application import postsqldb, database_payloads import config + +def selectPlanEventsByMonth(site_name, year, month): + events = () + events = meal_planner_database.selectPlanEventsByMonth(site_name, (year, month)) + for event in events: + event['has_missing_ingredients'] = False + for recipe_item in event['recipe_items']: + if recipe_item['item_uom'] != None and recipe_item['ingrediant_uom'] != recipe_item['item_uom']: + conversion = meal_planner_database.selectConversionsTuple(site_name, (recipe_item['item_id'], recipe_item['ingrediant_uom'])) + conv_factor = conversion.get('conv_factor', 1) + qty = float(recipe_item['qty']) / float(conv_factor) + recipe_item['qty'] = qty + if float(qty) > float(recipe_item['quantity_on_hand']): + event['has_missing_ingredients'] = True + return events + def addTakeOutEvent(site, data, user_id, conn=None): event_date_start = datetime.datetime.strptime(data['event_date_start'], "%Y-%m-%d") event_date_end = datetime.datetime.strptime(data['event_date_end'], "%Y-%m-%d") @@ -31,6 +47,9 @@ def addTakeOutEvent(site, data, user_id, conn=None): print(receipt) + attendees = data['attendees'] + cost = float(data['cost'])/int(attendees) + receipt_item = database_payloads.ReceiptItemPayload( type = 'custom', receipt_id=receipt['id'], @@ -39,7 +58,7 @@ def addTakeOutEvent(site, data, user_id, conn=None): name=data['event_shortname'], qty=data['attendees'], uom=1, - data={'cost': data['cost'], 'expires': False} + data={'cost': cost, 'expires': False} ) receipt_item = meal_planner_database.insertReceiptItemsTuple(site, receipt_item.payload(), conn=conn) @@ -57,7 +76,6 @@ def addTakeOutEvent(site, data, user_id, conn=None): ) event = meal_planner_database.insertPlanEventTuple(site, event_payload.payload(), conn=conn) - print(event) if self_conn: conn.commit() conn.close() diff --git a/application/meal_planner/sql/selectPlanEventsByMonth.sql b/application/meal_planner/sql/selectPlanEventsByMonth.sql index 751f8d1..8812530 100644 --- a/application/meal_planner/sql/selectPlanEventsByMonth.sql +++ b/application/meal_planner/sql/selectPlanEventsByMonth.sql @@ -8,22 +8,22 @@ sum_cte AS ( GROUP BY mi.id ), cte_recipe_items AS ( - SELECT rp_item.rp_id, rp_item.qty, COALESCE(sum_cte.total_sum, 0) as quantity_on_hand FROM %%site_name%%_recipe_items rp_item + SELECT items.id AS item_id, rp_item.rp_id, rp_item.qty, rp_item.uom AS ingrediant_uom, item_info.uom AS item_uom, COALESCE(sum_cte.total_sum, 0) as quantity_on_hand FROM %%site_name%%_recipe_items rp_item LEFT JOIN sum_cte ON sum_cte.item_uuid = rp_item.item_uuid - ), -recipe_missing_items AS ( - SELECT - rp_id, bool_or(qty > quantity_on_hand) AS has_missing_ingredients - FROM cte_recipe_items - GROUP BY rp_id -) - + LEFT JOIN %%site_name%%_items items ON rp_item.item_uuid = items.item_uuid + LEFT JOIN %%site_name%%_item_info item_info ON items.item_info_id = item_info.id + ) + SELECT events.*, COALESCE(row_to_json(recipes.*), '{}') as recipe, - COALESCE(recipe_missing_items.has_missing_ingredients, FALSE) AS has_missing_ingredients + COALESCE(ritems.recipe_items, '{}') as recipe_items FROM %%site_name%%_plan_events events LEFT JOIN %%site_name%%_recipes recipes ON recipes.recipe_uuid = events.recipe_uuid -LEFT JOIN recipe_missing_items ON recipe_missing_items.rp_id = recipes.id +LEFT JOIN LATERAL ( + SELECT array_agg(row_to_json(ri.*)) AS recipe_items + FROM cte_recipe_items ri + WHERE ri.rp_id = recipes.id +) ritems ON TRUE WHERE event_date_end >= make_date((SELECT year FROM arguments), (SELECT month FROM arguments), 1) AND diff --git a/application/receipts/__pycache__/receipts_api.cpython-313.pyc b/application/receipts/__pycache__/receipts_api.cpython-313.pyc index 84790515f9d0859874e60c7680bf5ff2aea8a67a..ce4980bb1f0b298788dfbd8ac5beaca8e478a247 100644 GIT binary patch delta 570 zcmbQXjB)2`M!wIyyj%=GAoFrX28aDbJ_*L0jq0InlP@sKPoB+IIk|>SezGyU=wt&-swkw%OwCoi)M1CoC&4H=hC*0<^s7S~TK$kZ=N zEzZv=OASsfD$7jX++iWh$W*jw@+nIdXYPXh;u45>Y7slo*rFvsqL>9pC;&l`ERb;@4Bfy6ED{L+$w(vtXs#FC7n{UBjG5V2vhovR7!c_341bGhps zMv0w3W)&we7?M*n3rdPLS&BG7>JClLb~op`0%V$j+^0Qxy@%-JgYI(~cTSG?kmo)G zQo{)%E>7AZBdKbuap8UuA38TT}hd!pl$3Uu10*PB}1qDT!c_l?# zCTsd0S6K=Y2L)9TC=`l79xej8s|aLi5y-%zyOa6-q`030nLsx%6brL%Hu2lS%&oJb aY(vHcMxhIg_LKJnN-#MvZoV4m$Or)aai*65 delta 409 zcmdnFnsM4PM!wIyyj%=GFm=O%jMFv~`6L(>HmZlRahNiKL>U++J1~n+p3PP{`2w^2 zWMg(wmUJdf%gr;`BaIj}Cx5aG1CpLrhK!3RS6g*$mbbmk$hdU!XFCnH}r)5C-B6c95$z2o* zVs8c!J3z!v5U~wJ>;V$DxbsU(3Q9}j3ld8*igtm7?Lfrp$xGZ#SWf|&Vw>-}-(i&4 z0%TTk>KCOZr)CzE6l<~+ae&nAoqW;Lob^1AsWq9`YdhnX$w$59x%YykI6=gj$?v^n zST6#ZhMNVveVMs#0GZ|>mtUJa&qil*tC8&F4Sv%Y^(VXgn+hKUX*mKUZm|^<6lLa> z6s@1!?|)o=F-RN~3Pm7~7lE8r1hTUTWN^`q$yEVT+>d}vP&gOgX4yPHU<>o+?hrjj E04@tG+_IzWv@W zlXnU#YZbEt*$NO)qyS{!;x5Q9E(uO8D$7hxEy@9kOatQLUWUo(a^{l4D%XW=E(zQ0 z2st5n(EoyS=!KYsi^7QwK9lb%x@>k4iDhFg$^@#Pyh`dSW69(O=`6N#Ah)P;@&{=< zuA(duI~z!Bc95CP$W{#E7EXRBE6Z3v`M+!|E6A#qn-k^!v9QhqGDRk*C}%K=Pd=-x z!q_4=fSjCz>hDnf7;EUSi H2Pzr>)$w*L delta 244 zcmZ4E-{HmgnU|M~0SG+jP0!e(GLcV$ao0rkEN$LkRw;%o#v;C8zF;;miyz2h2eSl# zEDkVBForouW%5C8QBlrdE=$HD;b86}kzgJvh9c2)Mos>WAF_ove-{g2mN=i)I2@MKeIeoXOJavRsRS VOhzCsj-BkJZp{?MG`U4x0|2%_K}G-o diff --git a/application/receipts/receipts_api.py b/application/receipts/receipts_api.py index f5dd547..21790f1 100644 --- a/application/receipts/receipts_api.py +++ b/application/receipts/receipts_api.py @@ -252,6 +252,18 @@ def resolveLine(): return jsonify({'error': False, "message": "Line Saved Succesfully"}) return jsonify({'error': True, "message": "Something went wrong while saving line!"}) +@receipt_api.route('/api/resolveServiceLine', methods=["POST"]) +@access_api.login_required +def resolveServiceLine(): + if request.method == "POST": + line_id = int(request.get_json()['line_id']) + site_name = session['selected_site'] + user_id = session['user_id'] + payload = {'line_id': line_id} + receipts_processes.postService(site_name, user_id, payload) + return jsonify({'error': False, "message": "Line Saved Succesfully"}) + return jsonify({'error': True, "message": "Something went wrong while saving line!"}) + @receipt_api.route('/api/postVendorUpdate', methods=["POST"]) @access_api.login_required def postVendorUpdate(): diff --git a/application/receipts/receipts_processes.py b/application/receipts/receipts_processes.py index f49ae11..34a3057 100644 --- a/application/receipts/receipts_processes.py +++ b/application/receipts/receipts_processes.py @@ -146,6 +146,26 @@ def linkItem(site, user_id, data, conn=None): return conn + +def postService(site, user_id, data, conn=None): + self_conn = False + if not conn: + database_config = config.config() + conn = psycopg2.connect(**database_config) + conn.autocommit = False + self_conn = True + + receipt_item = receipts_database.selectReceiptItemsTuple(site, (data['line_id'],), conn=conn) + + receipts_database.updateReceiptItemsTuple(site, {'id': receipt_item['id'], 'update': {'status': "Resolved"}}, conn=conn) + + if self_conn: + conn.commit() + conn.close() + return False + + return conn + def postLine(site, user_id, data, conn=None): self_conn = False if not conn: diff --git a/application/receipts/static/js/receiptHandler.js b/application/receipts/static/js/receiptHandler.js index 610f146..c43c56e 100644 --- a/application/receipts/static/js/receiptHandler.js +++ b/application/receipts/static/js/receiptHandler.js @@ -67,7 +67,11 @@ async function replenishLinesTable(receipt_items) { label_color = 'purple' } if(receipt_items[i].type == 'PLU SKU'){ - label_color = 'blue' + label_color = 'light blue' + } + if(receipt_items[i].type == 'take out'){ + console.log(receipt_items[i]) + label_color = 'brown' } typeCell.innerHTML = `${receipt_items[i].type}` @@ -76,7 +80,6 @@ async function replenishLinesTable(receipt_items) { let operationsCell = document.createElement('td') - let linkOp = document.createElement('a') linkOp.style = "margin-right: 5px;" linkOp.setAttribute('class', 'uk-button uk-button-small uk-button-default') @@ -98,7 +101,7 @@ async function replenishLinesTable(receipt_items) { resolveOp.setAttribute('class', 'uk-button uk-button-small uk-button-default') resolveOp.setAttribute('uk-icon', 'icon: check') resolveOp.onclick = async function(){ - await resolveLine(receipt_items[i].id) + await resolveLine(receipt_items[i].id, receipt_items[i].type) } let denyOp = document.createElement('a') @@ -244,8 +247,12 @@ async function addSKULine(item_id) { } -async function resolveLine(line_id) { - const response = await fetch(`/receipts/api/resolveLine`, { +async function resolveLine(line_id, type) { + let url = '/receipts/api/resolveLine' + if(type==="take out"){ + url = '/receipts/api/resolveServiceLine' + } + const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', diff --git a/logs/database.log b/logs/database.log index 1271c8a..bbcfd87 100644 --- a/logs/database.log +++ b/logs/database.log @@ -655,4 +655,7 @@ sql='SELECT items.item_uuid as item_uuid, items.item_name as item_name, units.fullname AS fullname, units.id AS unit_id, items.links AS linksFROM main_items itemsLEFT JOIN main_item_info item_info ON item_info.id = items.item_info_idLEFT JOIN units ON item_info.uom = units.idWHERE items.search_string LIKE '%%' || %s || '%%' AND items.inactive IS false AND item_info.safety_stock > 0ORDER BY items.item_name LIMIT %s OFFSET %s;') 2025-08-21 18:44:41.870684 --- ERROR --- DatabaseError(message='column "name" does not existLINE 1: SELECT * FROM test_vendors ORDER BY name ASC LIMIT 10 OFFSET... ^', payload=(10, 0), - sql='SELECT * FROM test_vendors ORDER BY name ASC LIMIT %s OFFSET %s;') \ No newline at end of file + sql='SELECT * FROM test_vendors ORDER BY name ASC LIMIT %s OFFSET %s;') +2025-08-23 07:01:48.754381 --- ERROR --- DatabaseError(message='column rp_item.type does not existLINE 11: ... SELECT items.id AS item_id, rp_item.rp_id, rp_item.ty... ^', + payload=(2025, 8), + sql='WITH arguments AS ( SELECT %s AS year, %s AS month),sum_cte AS ( SELECT mi.item_uuid, SUM(mil.quantity_on_hand)::FLOAT8 AS total_sum FROM main_item_locations mil JOIN main_items mi ON mil.part_id = mi.id GROUP BY mi.id ),cte_recipe_items AS ( SELECT items.id AS item_id, rp_item.rp_id, rp_item.type, rp_item.qty, rp_item.uom AS ingrediant_uom, item_info.uom AS item_uom, COALESCE(sum_cte.total_sum, 0) as quantity_on_hand FROM main_recipe_items rp_item LEFT JOIN sum_cte ON sum_cte.item_uuid = rp_item.item_uuid LEFT JOIN main_items items ON rp_item.item_uuid = items.item_uuid LEFT JOIN main_item_info item_info ON items.item_info_id = item_info.id ) SELECT events.*, COALESCE(row_to_json(recipes.*), '{}') as recipe, COALESCE(ritems.recipe_items, '{}') as recipe_itemsFROM main_plan_events eventsLEFT JOIN main_recipes recipes ON recipes.recipe_uuid = events.recipe_uuidLEFT JOIN LATERAL ( SELECT array_agg(row_to_json(ri.*)) AS recipe_items FROM cte_recipe_items ri WHERE ri.rp_id = recipes.id) ritems ON TRUEWHERE event_date_end >= make_date((SELECT year FROM arguments), (SELECT month FROM arguments), 1) AND event_date_start < (make_date((SELECT year FROM arguments), (SELECT month FROM arguments), 1) + INTERVAL '1 month');') \ No newline at end of file