From ceb5e58e3ef806e10a07df50f8b235a5db2a48c6 Mon Sep 17 00:00:00 2001 From: Deena Date: Wed, 17 Sep 2025 15:08:29 +0530 Subject: [PATCH] Reference #11 --- sos_inventory/__manifest__.py | 9 +- .../__pycache__/controllers.cpython-310.pyc | Bin 3075 -> 3275 bytes sos_inventory/controllers/controllers.py | 4 +- sos_inventory/models/__init__.py | 4 +- .../__pycache__/__init__.cpython-310.pyc | Bin 2571 -> 2639 bytes .../__pycache__/sos_ccrf.cpython-310.pyc | Bin 6314 -> 8100 bytes .../sos_common_scripts.cpython-310.pyc | Bin 7624 -> 7625 bytes .../models/__pycache__/sos_dc.cpython-310.pyc | Bin 11056 -> 11122 bytes .../sos_deliverables_config.cpython-310.pyc | Bin 4983 -> 5147 bytes .../sos_departments.cpython-310.pyc | Bin 535 -> 1144 bytes .../sos_disposal_register.cpython-310.pyc | Bin 4988 -> 4989 bytes .../sos_dock_audit.cpython-310.pyc | Bin 20283 -> 20875 bytes .../__pycache__/sos_fg_plan.cpython-310.pyc | Bin 22643 -> 23533 bytes .../__pycache__/sos_fir_brr.cpython-310.pyc | Bin 9165 -> 9187 bytes .../__pycache__/sos_grn.cpython-310.pyc | Bin 9263 -> 13467 bytes .../models/__pycache__/sos_ir.cpython-310.pyc | Bin 13422 -> 13437 bytes ...utsourcing_vendor_register.cpython-310.pyc | Bin 4268 -> 4841 bytes .../__pycache__/sos_mon.cpython-310.pyc | Bin 19814 -> 21870 bytes .../__pycache__/sos_mrn.cpython-310.pyc | Bin 13048 -> 13635 bytes .../__pycache__/sos_ncmr.cpython-310.pyc | Bin 25667 -> 32901 bytes .../sos_order_delivery_plan.cpython-310.pyc | Bin 9914 -> 9915 bytes ...vendor_monitoring_register.cpython-310.pyc | Bin 4624 -> 5189 bytes .../models/__pycache__/sos_po.cpython-310.pyc | Bin 10964 -> 10965 bytes .../__pycache__/sos_prf.cpython-310.pyc | Bin 5229 -> 3738 bytes .../sos_quote_generation.cpython-310.pyc | Bin 8783 -> 8605 bytes .../sos_sales_order.cpython-310.pyc | Bin 5493 -> 5545 bytes ...os_service_call_log_report.cpython-310.pyc | Bin 1860 -> 2342 bytes .../__pycache__/sos_sfg.cpython-310.pyc | Bin 4627 -> 4611 bytes ...utsourcing_return_register.cpython-310.pyc | Bin 1758 -> 1873 bytes .../models/__pycache__/sos_wo.cpython-310.pyc | Bin 10865 -> 10866 bytes sos_inventory/models/sos_budget_plan.py | 159 ++++++ sos_inventory/models/sos_ccrf.py | 54 +- sos_inventory/models/sos_common_scripts.py | 2 +- sos_inventory/models/sos_dc.py | 5 +- .../models/sos_deliverables_config.py | 9 +- sos_inventory/models/sos_departments.py | 32 +- sos_inventory/models/sos_disposal_register.py | 2 +- sos_inventory/models/sos_dock_audit.py | 18 +- sos_inventory/models/sos_fg_plan.py | 65 ++- sos_inventory/models/sos_fir_brr.py | 1 + sos_inventory/models/sos_grn.py | 214 +++++++- sos_inventory/models/sos_ir.py | 39 +- .../sos_mat_outsourcing_vendor_register.py | 18 +- sos_inventory/models/sos_mon.py | 79 ++- sos_inventory/models/sos_mrn.py | 14 + sos_inventory/models/sos_ncmr.py | 242 ++++++++- .../models/sos_order_delivery_plan.py | 2 +- ..._outsourcing_vendor_monitoring_register.py | 17 +- sos_inventory/models/sos_po.py | 2 +- sos_inventory/models/sos_prf.py | 79 +++ sos_inventory/models/sos_quote_generation.py | 45 +- sos_inventory/models/sos_sales_order.py | 1 + .../models/sos_sequence_generator.py | 2 +- .../models/sos_service_call_log_report.py | 12 +- sos_inventory/models/sos_sfg.py | 2 +- .../sos_sfg_outsourcing_return_register.py | 4 + sos_inventory/models/sos_wo.py | 2 +- .../report/Unconfirmed 666526.crdownload | 0 sos_inventory/report/sos_boq_labels.xml | 513 +++++++++--------- .../report/sos_budget_plan_summary.xml | 91 ++++ sos_inventory/report/sos_mon_items_report.xml | 7 +- sos_inventory/security/ir.model.access.csv | 14 +- sos_inventory/security/record_rules.xml | 22 +- sos_inventory/security/security.xml | 21 +- sos_inventory/static/src/css/style.css | 7 + .../static/src/js/pareto_chart_widget.js | 344 ++++++++++++ .../static/src/xml/pareto_chart_template.xml | 65 +++ sos_inventory/views/menu.xml | 5 +- .../views/pareto_chart_widget_view.xml | 8 + sos_inventory/views/sos_budget_plan_view.xml | 74 +++ sos_inventory/views/sos_ccrf_view.xml | 120 +++- sos_inventory/views/sos_dc_view.xml | 11 +- .../views/sos_deliverables_boq_view.xml | 2 +- .../views/sos_deliverables_config_view.xml | 4 +- sos_inventory/views/sos_departments.xml | 16 +- sos_inventory/views/sos_dock_audit_view.xml | 4 +- sos_inventory/views/sos_fg_plan_view.xml | 27 +- sos_inventory/views/sos_fg_view.xml | 3 + sos_inventory/views/sos_fir_view.xml | 2 +- .../views/sos_master_customer_property.xml | 3 +- sos_inventory/views/sos_min_view.xml | 4 +- sos_inventory/views/sos_mon_view.xml | 10 +- sos_inventory/views/sos_mrn_view.xml | 9 +- sos_inventory/views/sos_ncmr_view.xml | 161 ++++-- sos_inventory/views/sos_prf_view.xml | 144 +++++ sos_inventory/views/sos_sales_order_view.xml | 4 + .../views/sos_service_call_log_report.xml | 9 +- ...s_sfg_outsourcing_return_register_view.xml | 9 +- sos_inventory/views/sos_wo_view.xml | 3 +- .../mon_bulk_upload_wizard.cpython-310.pyc | Bin 2982 -> 2982 bytes 90 files changed, 2394 insertions(+), 460 deletions(-) create mode 100755 sos_inventory/models/sos_budget_plan.py create mode 100755 sos_inventory/models/sos_prf.py create mode 100755 sos_inventory/report/Unconfirmed 666526.crdownload create mode 100755 sos_inventory/report/sos_budget_plan_summary.xml create mode 100755 sos_inventory/static/src/js/pareto_chart_widget.js create mode 100755 sos_inventory/static/src/xml/pareto_chart_template.xml create mode 100755 sos_inventory/views/pareto_chart_widget_view.xml create mode 100755 sos_inventory/views/sos_budget_plan_view.xml create mode 100755 sos_inventory/views/sos_prf_view.xml diff --git a/sos_inventory/__manifest__.py b/sos_inventory/__manifest__.py index 5408d67..693eeaa 100755 --- a/sos_inventory/__manifest__.py +++ b/sos_inventory/__manifest__.py @@ -11,7 +11,7 @@ 'version': '17.0.1.0.0', # any module necessary for this one to work correctly - 'depends': ['base','web','mail'], + 'depends': ['base','web','mail','one2many_search_widget'], # always loaded 'data': [ @@ -19,6 +19,7 @@ 'security/record_rules.xml', 'security/ir.model.access.csv', 'data/cron_jobs.xml', + 'views/pareto_chart_widget_view.xml', 'views/sos_audit_log_view.xml', 'views/menu.xml', 'views/sos_quote_generation.xml', @@ -26,6 +27,7 @@ 'views/sos_fg_view.xml', 'views/sos_sfg_view.xml', 'views/sos_material_view.xml', + 'views/sos_budget_plan_view.xml', 'views/sos_material_bom_view.xml', 'views/sos_sfg_bom_view.xml', 'views/sos_fg_bom_view.xml', @@ -81,6 +83,8 @@ 'views/sos_service_call_log_report.xml', 'views/sos_transfer_challan_return_from_customer_view.xml', 'views/sos_shelflife_register_view.xml', + 'views/sos_prf_view.xml', + 'wizard/sfg_bom_bulk_upload_view.xml', 'wizard/mon_bulk_upload_view.xml', 'wizard/missing_component_wizard.xml', @@ -115,6 +119,7 @@ 'report/sos_boq_labels.xml', 'report/shelflife_report.xml', 'report/sos_boq_report.xml', + 'report/sos_budget_plan_summary.xml', 'data/send_indent_plan_email_template.xml', 'data/selection_item.xml' @@ -130,6 +135,8 @@ 'sos_inventory/static/src/components/**/*.js', 'sos_inventory/static/src/components/**/*.xml', 'sos_inventory/static/src/components/**/*.scss', + 'sos_inventory/static/src/js/pareto_chart_widget.js', + 'sos_inventory/static/src/xml/pareto_chart_template.xml', diff --git a/sos_inventory/controllers/__pycache__/controllers.cpython-310.pyc b/sos_inventory/controllers/__pycache__/controllers.cpython-310.pyc index 4af816c595d484cd1c4421c63b7fdd8219ae06b2..ce169042c568a73c2c5565a5c873a8471f717ca5 100644 GIT binary patch delta 627 zcmZuuJ#Q015WU^|@cHb61SC5N5E2O`vSM+#GKG~QX@VjVAv!maxjDy9*51?JS&7o5 z2yF^$5iKUAIuZBL*e#p?qaS0F~m#gX&AG5l+9YU)+ka zNt%jbqN2W3Bjcr$S7I19m~ncOd=N9L`D<}JiSOgi90Xu!!=Im5_YxswbL~_r0q;>V zPL_zi;U}l6gn0$rJd0$SM-rrLwSOPFY5QcB>+xq~cF(w#-2pW%&pj8^tLIevTh?Qx=aeGOOmu%QOu@z#gAnTtH z%li|8was>xf{m4}Gb%PN?8EHLJMX^Fm08(mzV9e-ZYR;OdFS7^HsBE}T|$+v8fzn+ zk^!MA)u?`>QG=S-%8YakYMm&7Eo-7@)x-zsm{JcfvSEIpa;-K87SfuAJnKyuM|)|f z{Xs8cH0EypVw4E+#JgE9J}7}I)z+5OIJ@K(Q1Xg6Cmqk(p=VJRvGH^_$oH&s(w>K5 zK%|jo;LD3BEg+T<3y2b85wQ$-Gq5V>ul6y4bZMOQMcX+f>*C58)z@GswTLCs9L6EU z;w#^sahUza!0oCixK(0{mit6Z@#$`F9%1_@=U-LDN(Y#5Q-rOEQ?K4=;GhYR&OV!D QoFxf-gvx&w;?Z0E0v*d+4gdfE diff --git a/sos_inventory/controllers/controllers.py b/sos_inventory/controllers/controllers.py index d281927..625b1ad 100755 --- a/sos_inventory/controllers/controllers.py +++ b/sos_inventory/controllers/controllers.py @@ -4,7 +4,9 @@ import io import xlsxwriter class MaterialBackupExportController(http.Controller): - + @http.route('/supplier/form', auth='public') + def index(self, **kw): + return "Hello, world" @http.route(['/download/material/backup//'], type='http', auth='user') def download_backup_by_year(self, year, item_type, **kwargs): # Safely map table names diff --git a/sos_inventory/models/__init__.py b/sos_inventory/models/__init__.py index 3537e14..f507b75 100755 --- a/sos_inventory/models/__init__.py +++ b/sos_inventory/models/__init__.py @@ -58,4 +58,6 @@ from . import sos_master_customer_property from . import sos_service_call_log_report from . import sos_inhouse_validation_reports_files from . import sos_transfer_challan_return_from_customer -from . import sos_shelflife_register \ No newline at end of file +from . import sos_shelflife_register +from . import sos_budget_plan +from . import sos_prf \ No newline at end of file diff --git a/sos_inventory/models/__pycache__/__init__.cpython-310.pyc b/sos_inventory/models/__pycache__/__init__.cpython-310.pyc index e4b259808be200444ddc747200f029fe9e7970f3..39fff9217dfb685e8bb99c5cb55a8a26337e15a5 100644 GIT binary patch delta 138 zcmeAcIWNMS&&$ij00eXXEz7tzkyn=S%|`7jOtK6qwmA&Bwo$f>3@HpLc0jgWlpT<5 zAIzZXu$hJV4~wEE<1PN;{Nnhe(v-r88xJE7qW~iS(R(FM delta 70 zcmX>v(k;T9&&$ij00i;Q6EYS}IIRF3v diff --git a/sos_inventory/models/__pycache__/sos_ccrf.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_ccrf.cpython-310.pyc index 57c09abae07ca1a64a40cbc4fc0ba8feafa0c8ee..74d05d9cf8cff9eb8cb814ab85e61c06d18bb5c7 100644 GIT binary patch delta 2978 zcmb7GO>A4o5#~}PMLqtC`l0+2o3d=DtkUSGmhH&4EQ*vYMIyzJvSibVU!J%tkuv!n zvyZYM6)p`#KnpZR<7|rrO@XF>n<8yd!11A{0tI^Nq0Oy_cMH&7d+H@Rb!Hz$)3tpF z3C_-ZGqdyF?942GH}>di&kYa} z*TC_{16N^QLN@^^G?4{~+ydn7Ch{g*{A`K7^J_wHQ+40*J}IQ>yHwkE6f$(37GYhc zlrmVebc1ff`W7wGGORheMeo3xrxjX-b%pBG*za-_uG1Q%_`N4nt|>yk5ck|yNuT($ zyU}#=$x5P=VRlm{Ddugr91|}$#&q}#Z?}&0nbc2|GoKDK4^>Ash1M0gFvcB=~6woIL1ECu8Fiqig((1T5b?(|CPFGY`N@T9t-`9PKO0-s zDrKtG+4H96!9eQ5WR|nLV2SULW5sRQPA@WXUpYy}o_wZo(%2hVVOkZH#-?7z7_sjx zRJBbOw<4xts>LGTP>WhkQ!8biS)EcY)4f14kxj&w0E;b9Gw$SJ$fM;d8ns>Pc+0U4 zd#f7;ybtayx7dryfO9r@9pW8sVhy(ZYTQ_dcT_1ei@aQW>U=zFYv4p$nx`9dZfvT$ zR)rS~9u*V*Lf@9U3opk9+Rf#y{$wYuoUj-LDKf_@}{n?*Y$nd<3i+0 zo5#J#kwcGPMqc&&#J2fcV!3aa ztcV}{o_OxpY|Uk?}|V5r+U}Xx$`|u#TVv9kT?^e=wM?56>l7yjq78hzXFhI_rr~F< z0AY>-p^k!+l0pY{7F^7|<)Iza1tZ!6H$^ANUcBnymg)jtflCf~pX3$E`z7y_e1Q64 z{syexWHL9WrVYv(6%{*I#irxuA>y9W>SU950dNpRW0(jVOil~vdCe?plzq``a!3qi z6;@}Kd%-lf8Se!z{yLHoB%?qw@gOguP)4$ayuMZG|>uim4A$>9%&Zw|V+%J1S zx#gLq*|eIP%_nmU*{A0*2@k(_B+DD}MtSbuc;Tt+g_0HcI}pp);cCV6un)+SEg5yg zv|MW?t!}y3O3)xEFx~2azW_)Kt7G2S+4BO4;l#?sdzyXFfahp$1Qh@82)6;VLPZR% znyt{-5tgUc480>m@7SSXfzUe`dIv+7j2+7hM3uubfFW8${50wr`4XT%!p}Skq`e00 tW@@z*+GXMaadBYAhczP$gntRm7!?l&Lj4iIdL6cT#OY{6`XWld@;{XlFPi`W delta 1239 zcmY*ZOHUhD80ES!9@}8!2N-I=<2Z%7P71gop$RWP0tRg3#Kbs5f;0FVuq)$nuT3P7 zDyu3|E2XJGw^F;Q+DctjYNgaw*Hxr0yQ{izwq553uG3Y=gLt@920{$8(5z+8WMZ z$NBTfeUQ*O&s%7q;D@AcUc4};kQwA9-MRtki>1T5^PcXEAdbQy+}E8k_3n4ekolg# zCOkOl`h>_UkcF+2E;$Z4c!+%!WZ1^O29Mw|_I22SJoW^PJ^=+m5_X}0Jp}+N_6^v> zd)jZl>|P)wz=*I&Tr4a!8Y6h60mHd55>IBNP?nCixv2AL6vjG*8?#yJZ3{vqnYkX% zQmIWXoF=l;^wd73FByCSpDo2u5FRE0EY6sP_QmWKz5>*Ro>8T3R9@P${da+cK z(o}=PLcOF_Bzjn30r3TSr};_@lB*MQ)rGC%k>sDAo2)Kel29jkkEP6?k00Bk8pY^3 zMoVEm>)4*A>QlASA+aTkmt1c?u~5Rk>HBD49FNfwYlpk}`cYLqC-Z?G8e)^yZL-0h zS^puktZFNe9Q(`m72ePs{R)XOoBbLpbM{fP!eo1ZsO-d^GOhA!=}yrYdu6{V zB#_Y+=61X*lsVjB>yC)^KM!Bq!%j^e_M2nu(%f={gj(C|a4vTQD$Z+{9@*|;KRd0$ zaohLOIsf+mLVG?`^1DZ^UTlT3R#PFbRp`ZLCR`K3$L)EWt~(w1U%O^6^Z#~D3ZJz- zmVqEivs(kNNr;UPHpv=m4F<_N6Wpgl1}&{IJizc!=|I_6=_VJX`21% zmdHK!+U;h+A&F#JV#q_bSaB%kddSU2++wY?U!gKz?h*Ta$d`P~2TV!)c0vbO=xsjK z%|%hG6pHwzsdSEOQC=*(qoQU{@^(r{NfssMCMIVj=A{%R=IIqV6z3Nw=A>5YW#(<( IC?UZL0KCufBt*s%zy5^SO2?S3|K7T z0)Le8$E|VsH^eXSaC{|QcgfUdCZ$BY2Hrdc^#M)qRCW#RCI^Rsl#xSy!e#L8(VTMb zRFF!|$=94J?i?o7np41?LUM#VHKbN^inN+K?i?lcn&TnINJF3CEhde`+b2lgy`+g8 z=SB%RK~C~@A8971_`09SwL)f#I;>a29KDexfo^(Qp;DFHsq`8vYNV=wS{E?}P|oz0 zeyCwHmNM{aY~kF@ibOxOsbgXeK(RU>)dX->EsVaagNy1?j2qy#YIj@#7-EC5EAU9Y z9+wO7RDBXZ2{6HKB|Jz>pmL||YnAe&vc95YG^^Y(R=PPH?%(8q=ISM&zG`{kC{s%x}ly)SlK>-$6N zfapfJ5i^MQhz|&yppMR=tYjZ8c9!BaMbmkF|AhFA_{NIUV#2XBorj>`S&sYMh7&s% zc}*e)wR5o^)D9w8!K4>~E@~$copB+3qr`Xwqq>kjsC0$&wMrMCU(Gm^yu|J7f9JP@ z4d@c{WZp^nUo-lXf6BY)vTmjg+I@9Rr_)&pS^rfbjRBEO+W;ym{UO_QTu38&GA}a_I z>OfE}wAv(56n7O27!gDoW*?M|85NplAQ`%A(K)Y0i|j3a=kR;?{og(J{;a)UYdc}J zMric(wKX;e^Dfz@;r4??pWd@^V3XK!1H?|Tt5-V%fz3^9O39Roa>Hyf%x*FjVvk|+ z$mEMkGF775Fa^e%y=45N#xPsOK2h7N1q#J}ae!)(s1pII#iCvuq`FNU5{G-W@W6I) z#II!^RS(0|3UzwrJ%BRIwe~?Z4p~c~&R_%4iN|ei(4r=6>i~*WRCGN+yK0TOt3$VP z#$^IrQN{6R0s8T2!Xi9U!Nm0dPt<~A3}6HwCk4TYJ;{lBOB-HIz6s+hKP5wlSv=-0 zf)aJh{RZ&7rx`l&ho?>t*HvX|0l+J~nC6LkM+cX!hs;$CjjbJWTm{p-V4fst!71;B z=qc)?iSdjviK8Bed6?Q?cs<<bZHS!}7 z%f0Rx`HAIc#uvskE?8qDcu@xJKz_xp%#+KH`i<5kp(D$MsXjOQv$}oD?TDuw)I(t% zO`V}Ie^V!oxRllInj^jT-x1@$4sy;Iu|NCVs{aMb@ANq(mE>GD&r`brCvu!Hk4rgg h;`s(7pP=LoO8$|Yr@KkSiq$EWQ}%ef#U7hr`3>ea=cE7t diff --git a/sos_inventory/models/__pycache__/sos_deliverables_config.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_deliverables_config.cpython-310.pyc index 709054c3939dc974da097018ccc0807a7674cbf6..9c378dc741ce769f9000db9fc39d7802c5410088 100644 GIT binary patch delta 1995 zcmb`HO>7%Q6vubg>-A>6{#rX}^T{?OO(LNXkf2I2C9V5G)Fd==5Hv-&8}Hb4yIF@> zJ8dErOFeMQp_*fn5FAh~apTMZPMkQy3QkBIK;nWBQYeV`#*Q7pL5hT}`Rncf&F635 z>~E(ZO~(BzImSoCi8)blba0|h+(|e| zM|Dzr%DN#O6P$G0i3ukIPJi2p3ugeF6Ky9UoRi=Tww)w6DQ5^)A?qf@eJN*HJfuH; zpV*|)BrFY^oC(dy`8ujB|McXcs~wYIZGgS21u3#D?wp>73cwl`cp8Tyr2YxDUd+(={t4m z6)78p$EMPh_l;%SuTj?C`~uqYeqV0QTCO^Em$C~j$7t=jZC-4diA4{FdbD=X`7-!{ zf(K&@q6?DLr6A(al3jOeyf5+^S>@LwqhyWWjf|RaKrgn6qe8D&H=8nBWd@h<9 zd*qL(nrf=og4NBHN_H2+zP zkt~0r{lLF7^oE#EkO;F^u=jZoc(Jhyb`1`;W96!Kuf{epl|#9Nas_1pBD4+|EQlwUX2bfR=`m$Rv6txu~EdF6r&PK5v8*P8^gy6%54+{ zB+#l}@s{lY{5pEQ2;YIkyd+Iaz6DXMC=FRBimL7>BXMGo4751>HE8S(&>!U?Bbay^ zXPiLkya(pu;~~JD#HOwae1hh`8A`hbqyB8M&KT77PN3!5(UE9JW?2@F^N6zJ#KJxJ%F`Qsq}1Z@b=h`WRO zo)VFw;G zA1a?;Oj+c<0QMlYM^5vkd1|2pEKu-X2THE$*IM_w7s0<@=9QTge>U3R^InRtm*T;k z3~MA%ia4>jl(UHCCW^SS;!<{NQ$(Ub--RykLGuSd4vGPbz#wq@W`9ys|IXF8p{ delta 1862 zcmbu9&u<$=6vs36c(ZoaYkQr9*h!Q$4M_|N2Lw`5N}&pkRMCV~2~f-rv+PbBll5+S z>mVW_87^=NQZ*7BI2V*2NiX~XJ@7A#xKtHfIQCEp#EGyK!r4>-y+5`&ahUwLccyzO|REriJlw#?Sh;pYshrzsIWs+9{yp zbRA1OMRW$cPF6cZ=nQuqTRTsoGtzZ(=;Zy9U*2QYf{sUZ?D%8reU))_aKNf;2!=4R z{R9;8ruu!c>FxxrgWaUb`uCZ3<(GVj73Ft4l!esi#sW@+1u0Xtsb?@W`#95A!eHDo z?s7Z9@cM@*jlUf(%f_AdC_OPw>zlFoWJiRafEn!W^Gf1RYsHOQ0w&koPz3NY+GwVi zHYQghegq-Pgi3i) zBZyUMiEfpIN(GG;2)NW4O>Ebd`FbOW>fknMbj|g)V|W8cffi87H=`!9D$CPmV}6$G zIg$zq!GLE;k|?U5a;pn~m&lrzKbvd07xlnqz2-%}fH66eo+@>4(i|NvQgjAoO0K7$ zW@ltAH!i&)nem0!D7-+jM6ygm$-^4SWfFsAon(XL zEt0DIH*7Bp;D*6lF%Cx8;V2bep^`H$?CNI1fi&z!p!UbSl$IWEf8wf8`CE zS!@uSjhBfHJPr3pOUYU$Q$7Lf_3Ug}!_;gaCMti=p2|Oh=Gb!}Fb&uw*&=C>bQ8x& zziaw4ACezP*Is-goQDt(!P09~1Kth*9=qLI!+#W8Xi@@{$?^l~_1-sxII@B*oBYiU5 zBW$ynh%SH_Q>x3`g;^HsdYp0g*tERqoND*bDZc79h2l$5+yY&LSoTLw{{QK$RtoUA zXH$Qdc!+xdRgU5wZS=f8ne(*t6%u`J^~pRe;lmnf;gq)gsyM+~@`vKw3Vp+X&ZDj# mpnnN8=LiJs5(8zPZR)T6IflL1Mj7mL63&F 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 delta 5245 zcmbtXd2pN65!aI~S&`4kc5KVH9ow;;_>7a-j^o>j<0E!%?1E7Iz9@2R$$nB2oCy^} zG6Ur5z*3GvAx8xa=`!Jj7)jUS z#%*#5(@T)fkQp*lW+5LllF7Us`E2I1n9o5zmw7w$dC2E8pUr$hWIc!Z!U&&>e1gj$ zi_VCEEXFOykvtUT%cV$*kpiYmm@Y)xB1@SrV!Dj!Vx%+VGBjzH<+9>L?8s7-kkQIB zLN1ppWEDDI5+$osVHYGOKKrZFr<{q#n7I zvR!sy#5yrH4anPMpo{%k6;|zL)zz%pBiDyj*Rbja)@%%G_OfOZYi^W%Va;aN4B1>8 z*6e4^7S5<9tlG}1n_07iHMhvEtl5cNlH7)R+wq27 z$XVnL*6T((LGF~-VFE_vD958mTR*bG7hc&V=i55K4%N91vDLIWR zTcnac{M{=3av%O~yUh@57}>tXP`*Eyv}My4N0)bO@7&F%HO6>ruV=s4J*E{5dgtDc zi?N7pa~~$>3UL5Ti_Z!l%r3ql4$Wycw-5oin7S1z?TL__nF-I^%*E1lv+i!R%^DSVfj6r(98a`R03wB>n94X{ST;xm_N|F284%#P=h> z;_OVY*^l4>_uBK~kCXhwH^%5eSGfY>~}@oX;L~vaF*al z1dkA$BY2eHF@nPgv&NvYs^+e|Gzg|Ah_}I>_g;YZ2jh0T9AjRoG2wAeYS*+Aw77i^ z-;`5nihM7RSNq92d+{@(eok;rFP@-Paz*`^Aklz~aVOCdui zbib?=GAq_a*s=b?ot>O{PC5s|q@E(jpC-_k<|iS_A{oqv4+~*?FnO1IV#4ilIh;}| z&F2fI`1ZJ`rshk`E}!4w@dlHooHLV}$M5j@o&J5kVB*+5pWlmxr(s4)>(frKtx<{sY=+8PmeDhe-BAlG&YO zW8Qrpzt7?1#?_?0^C)TE0q>M-Zh4i+$O-B-Vk3st>%>NEs^1eE+Dz0%*i*Vwl+L|S z`hmd7bZ%L{uy9Dt>M8iV{8ljzH&+ac9dNPYKs8@6uGiz&&~*-U(CQ9NHw=*a6&eg$ zx}1K^@5Zpa2;Z&DS^66mZt`e#lTOc!dYKOWEx|#8mk53b&sN&=UqCV#yH&f%ubw68 zbHv9@?Nd`;pQfIN&nk1_-Q2YJ3$*x4f@h$9`O%JxMBYk3@l|>-D1`HFPf-rVM!!7= z;{o_$dEe4IY56{a2MHb~c!l6ig0~6Y1J8;YoP!UqD1%p4xJA<3%Bm)#NCIz7?vlk= zpyfDx_PTpn1+=%Pn)1->gK)II)y#A59BSw0)KD|Tqf4_fq4B5JJnu>_MTJwOREKb|7G7=0 zh4m|6vhxv=?!xnvCpc;t)GRD(=nzKO+fX7Nfjb-W5zjZY1>UE{4+#E5@MnS#31SHT zN>D<;6Y?)e1rwy(H#Om$2{pyXw0N4JklfK{!6zh(zH!hp;Pq&Jr<#e(^z~Q)9bWH* z=Je=ePc@RMSTbNBstO?(C$%ZfBYlbjrs)3a3)0w2AmG!EOsf%vx8OhDN_eP07yh*> z8!z12k~>$u`hZA}p)IRPJC>+)f+cWaO;LP2kx2w;@X?xzHCaSj2(k${oH<105)_jO zb|RlxzIG8Wz{bYB{1PJBy)vSf5nM-GMhMDby0;J>Ypg1*#D(&hP+TeVL7UU((Cy>_Etrt{oN~A7M!^#+7;i`q>ty9k;{%Hy_~sBw~Y62;+P3-2~(2m@SdZeDOfaoo77 z^b(@_Qu=r9DkY@a=urJ4{Do*IS@_#ji{w?xM|F_SHA}}tcXbv^KQpRdKb#nO7;~%$0=#&$UjQm(z-#^sV0McNlSF9sIGa zO3(WIBB_rUworQQq*+e3gBYZCy8DG zocs!Lt)n_Sp3Z1M30YB5=Qb)3>7ukE@4?QKKm#1p}`rAd|im7U% zEoOwRs)%9}M?8 z6yUQ2Up=4o0t?UMGTdSygA~rM8_0BnC*l77W-$P7_21RIk@ir51miYqlTNkQH&~va z-X}LcAo%LnOQbE--{FaY!t6n`W{Sa=LIUo!7-B`Nuo@FYico`C+L?2)gD;B(hl`Cb zA}2T?hl%yUk_G Jv29sm`5*X?_K^Sp diff --git a/sos_inventory/models/__pycache__/sos_fg_plan.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_fg_plan.cpython-310.pyc index 9eb078c85ae60cfef7e1c274e1e5d67b1d994b50..503f044945a9eaeec374346617a2513e8d61dc47 100644 GIT binary patch delta 4991 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 delta 4349 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 delta 980 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 diff --git a/sos_inventory/models/__pycache__/sos_ir.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_ir.cpython-310.pyc index 1cb55d4d457740040442d6e35405c488e850e1cb..c701614a93d506815521d890456a385351a0e367 100644 GIT binary patch delta 346 zcmaEt@i&7npO=@50SL_OPh}X#Zsb!DXWTK_SUiT&fAR!zNk);)tHftBa`R;IqzGlR zOkgasoa`dm&uBUMilnM=Z4E<~VisGCNS0C-XBi_wTGcWxY$l+ZgFrS|zc@pU09gNq$s44+8Ko!x0h1om!Hf}`=ScgrGs;bVqtwX4!@|Wl zIbT_wc_mNe=9$WxjM7p?iMff%8Hsr*MTvQOMGnRJ#fdqom3qnfxs&gxEN86Q+@kuN zk+FMoj(P$!qw(gmT2ai58zyV$buez5yixBnxRUYkW-kp5Icp|H~kcOBP00t*((f|Me delta 291 zcmeyH@h*cepO=@50SG)ZreqwA*~q6N&bVf>v3Lxl=i~|El8k(tSBcMNoE#|G$7nqH zfuyQ%c@0CBVisGCNS0C-XBp!J#-j4c5>m>7^MK+iK;B#+tvZ3Rc7={_Ko0lYb~RGI6m?u2oiNUd0o!dAYJCBctTxiz?zwnR%06t1M@% z-aJ|LIU{4&=4$l>W=5mUceJ9I8P`uX*Xv;1I{AR!XU18Zx9IOJ ZGK`EbCtDe>VZ1Z>x$#6+F(C~xDF92-TqFPh diff --git a/sos_inventory/models/__pycache__/sos_mat_outsourcing_vendor_register.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_mat_outsourcing_vendor_register.cpython-310.pyc index 090f2dba1e29a8ed55d65d5deb88e2da698baa2e..68491d9816f70e05f570c33ad96916c93aa9f062 100644 GIT binary patch delta 1118 zcmZ{jOH30{6o%)_OzA)$R9e#Vro4-Qh@g>|L>_8_!~~*HHDl8|lt*dHZ83qA5F?2z z7Um`{TtVW7#Kb7Napl^?g&P;Mc7qEy?!|L1plEQK`^~xk{m8!L7J8|IlI-Em-j!MzAbBhp0lg9WvvwWPBwV z!)A{OqN1rI(@Uu+}Sndh3J#$rVFJ`yB`7%F)zfkXJ^O z`>u7!E894x1;C~5;E+shS!K$kvI`RtonJ;L??W(*7Rq@FgDs9JrHrWD% zp$0%dSnHvRM3rF_ow&4qX99-A3um~T52E#-?m0EtE512zi+jd&C-1;*MEg?#AEKPo z5}Wa0P<%DsbWx=;!`3pHrBlsqXc;9Njbp9jxX!&Fg)S9F#er)qKuz23SSG{Mcw^>r zZk6|m8F!zb_v1-KwH>p`bS%dQa3@~5o8W=?;!a}nuxH#QCw3E0Fz30a90tTY&r|3T z*Sy!^ig@JnpD8xesrXzhm9WfA+DxU##ar(>G>ER^?u{8roFhyV5(KK&cHT(ktc1l6 z=W+Ob(j8;6lp!((30Dat1S*f4gcu=Cke5pT72C@F0@c&gCvcHa6nB^6B{%^lcq8QR+rsnx{%ap zFww-58hwfJC`S`7!dYYdGbUc}#@T6H$$t+U65{q*5uAvI;TvL)|(M~UKE>mj{ij$G-$*f_&m5xY9ABD@>fkn zyUg7Z1DtL8oN`O{-N!hlX^AQ{68GT9sKN831wRurBd1hqTjvW{;vi~>I*??6)L}Gv zlvNhjg&qVuYAK(o%I_;!xhU~$7KSpVycV=VE zCbw-(#I{_&9g6hsUfb=2z1B{fKkdRFvqJ8Io^j<*g3MY)^|XwKU<<;a%RF)LTku5xP`kPBGwQO5K9swe$xxtHsk$^ zFQZq7#8$Dh{tyai=Md_qE0~&yb;Nx{R6@il3z$c{YQ%gBJ&s2hK3F+p;1LQ-4m1x} VbAz(I>p44-(ozIpLxY#O&VP-)ne6}o diff --git a/sos_inventory/models/__pycache__/sos_mon.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_mon.cpython-310.pyc index e58ea797cb0c10f15f7e6b86d32592e1bcbea42e..cb4f6faa7fedc912ca5de81fada4d0b2f642a1e0 100644 GIT binary patch delta 8049 zcmb6;3v^W1aeLo>wAvr~{{;*Bu|f!akPsk=pIAT$Fdu_08!xN9PhzG0ad%fBA-u-M z2JC`A*Vw^vFp6t8vfb0hY8qqvG>+TYZBOeoN$caj(_@o3ZjzofagUocaj@ykywys` zpVOkV^X|-@nLBr8?!9v_|NaE~)pN`hbvkVZ`1kCkHxIv%`lc(3F(HfCnUs?k^Ahen zr}XEmS;JOd3T@V30Bt8P)q7hgzNF<>Qp5qEP7UwqEkUkZ2`UqV{S zp>5?=)UF_@YF^e;^dwveEQ1Y7yav|#-l!DY~H;BCBpNa3q^ z2VV__F9%uXSTgA8XZD5Sj-*E%BnmEgNFW=7lV8AtiuZ5uQ z08Kjq?*ts;zYEX~eiPr#b59xgo^$5@E)v|!_wk$gexe=#Q@Vk=j^Dy><^3RG;kN}sqF`BfCr#&liG86Gv||xt9rpFTad&b z;gT3`C6O7QJjyQ+wVyx69|yy3<6q$y;d?uOf`1jh2lL#(aTfJP{46 zB0lcily16r`orqvcV=>iZ6n5C2G*ciN8x!TwlozuXIXnuH zMH3LFU&^jx1)HJukpjSBm@hRckzNj9tuu@h{<&|^60 zI%`N6DJc|gJY}6=J+Kb$VP_0J(-9jtK-5e-$4hSrR3l<((`2lxFx849ECg^8#yDsL z%^*K)7>0314f_qua6~~(A`e)=-rexgvWG-88H4b1%^2k115Igc(u_kvKE*VPPy-Mo zQ4E}-gxEWW)QEa4Cc19{G;Rf;++{MjnC<#_Y84s;Sruvg66ZB`hN1y~DBj(eQROj< zd{k}}>Y(VRmOnD4<$c!k5TYXN&xUF1hU>QN2cqzzh2kavd*BzxSUQZR>sF(KDa>)* zbbY+~|6-u@lq^jJ7)a0j!^oN7w+Vi69Eu`Vdx8xaPAC&>*dSaJiXKsB033`YT$yBq z8^uDxjf5+rhMO*%CZIRMxOsy4%z9irmYte)2PBvXru-q{fq}#_03Wjk@03Lxgr;Wk z$6{)Pi#xE>hZNIrG#C+$(1ehZbHI%O%^dTKL|peyCVXNAu-yi~cmV*bVqz9%%lwL% z>38E5PE4VLz)9-;zn*dh3Rh` zHe-4dP4BaCbEeOd?z5!jvf%ufk;_W=W$~;G%>=ZRt_-r9){1rKzA57`%wUtiKoYni zq_~A-!*4JAK3WQ32$xLG3C2MIh7^9Ve15n9Wi7_z(Lrf`RAAB@ZC>T-aMMkrAhJx_~s_YH} zQykZ*#h_SCzc(@c&vMOjeSFPq21g@-!~V#SO1p4s?luhe%vog_y`OPF7K}j-a6^L} z;JDENFmYvO;$S_x5Q?OvOfYvei(b5CsO{P!Kbjzof>t8swh@*G{ zfv!z1F33NKno@H#nN8QeP}58p#V`nD!Xwa&B7$Jn-cdwjI6?|XxDS3aj?OZDJlD}4 zE3LQLbtZ;@SwZYe9y=Jw**KGZRCCifK_`T_a@!Bs)j(LhT zXE4GcZDp@xsu;K1abKB2-aHa;FOU&W`bjWkg z_3UB!mh&a+Vn96>F(J>pTAU{Vfh575NE|>{n>(O+S$^R9QSsfxs2SsGLOg&Bdk~zF z|FWQs9gy}M4|{I9EvJ%|UjVun&Z4ZNeh~>qhBWi2Ka^BGCUHTAbNkqf^5xuTD(*z- zb_AF!=~G0Y0buCyyfV=FSYDm^5)fXKujhSV(PMAMqwDYFOZnbHaTJ=G12$C=J?5h^ z#QkLSHt2Xmt}gf~yIU?ST+XnXD3*c30`~XvSmE;(--LdW)>pzfppbhs>mzb^VZJ<6 zRLI_*9xWaadUPj@e;DrilB8njp!8w0RVEcB*@;C_R`<@G2OiS5v;(e z(uORn5WI|_9svfMk^-hnR7@C%{$J0~=a_|?3o*^OW|j1p)v@1BpDp7oMP9L?SJF+0@ z6MunVexQ-|Ed+mw;M?+rg`Ee;jh|<9KJaL!c#=owg;~6U(qCk^po8yKGHuVIg-Sh> zV$qAGxKdz|JcXiG)NDQ~f>3Q7m0j-Q>H|prA%Y_aCJ_`PC_(T806lE_nEM*brWNN0 zf;_&&Q~fq}XaWa|}vX(9c zQ)clVvd-?^G})_2`v!n?zm^kGkKUN-8D-+Ce4}ceouW_kYLq$E%UW=i=%&u|IF>~E zuJjJHw5(WC#G+8yzb(Vn?!wQpR=h92UfpETeJ0wZ1mg&^`N}V(`+|0u)~5NTRz;BFTd}pu)m0?1HgE-e5$2bzUy(yvikL4 z;%)U2rV!tU4OaOUxDz1z34a=91+dst#=7N%$QZ;)Z%Ex?%6XB4c znaK|uO4xU&vzMDud_m)I;o~UsJkHG$PXq%aV<7sxJm1(`N*YT*nPv_}hk}u`PEjHM ztFe>)KsK(p0y=)aqD?7ea#7RL-Xi36CZe&hKjI%!!*B%7oEd17p2X$YLem$wHINXsFxv+96Zuz7e*z;6Hb2*cszot^8~|`k;mW0%!X5(kx_(*lsbPOG zq-!_L(@sj4DJ>t#lP&8Rm#?=B@5cp&H-gAm3)Go{RvI3gTGqyBG^F|?;t|A5T#Y3( z=ghU;7lFIF_yzVj;8^3yKtd#=|WuMbX}xtk!GDK#>8>tumz$}&j~+Nb>d!> z>%fv!lwtF02rePOGC}+~f)^3Ij^KL;-a_zC05r3{7vK&mXaT@Q+#rky>@&gLm{7hpv_S*iHb@P;3keWeEdJ;^KGT_^|qQa=3+U_!Ayz* zcV6XFlhN{t%j80;yxz8|#DrA%vwUJT+nB>@V^*7u+3ICSyQ;jwWbW1)`8Vy)rmA=m zyeAf`W_Yr!<|cTyt>txmDLfE*;MuQ)==dhvz?T!X5grIjfm#MHu1&<>43u)Bv~YM% z1#K08Rq{M|K+Oegp}Od@o9Do@SUX>J3g7$|6Qu(vt5bXpk(L0dimwGyC+{LkHBq|x zI(PaQhMr9}@=frdS4-_4z8Tte)P|>0XfFjh4@fb5EG4OW8m<>8@H|SCW%NMS z0C&8i9a=7AlCKY|ef>rb7xHE~(Xp7d%S#<)Y`MJB;a>SJIDg!_EwUWeL0|-m96Xvd z<4*Oc=GZU_Yu!H(4B_<;8AStvi_*Dz4?LnBTHU~EWE7>SFZELhXLXuNQ4QP+s?D73y-gJQ2(Bb)mQWS8CQ5NmOyJOrKi z2xci!pt(*yzQ&!i9;q7;Y(%hWR;UMY655PH_Hq>3g2b(|Xzc+fE-;v4IZ}G%_}XaA z?U44=d@&xynk^X#Ca^*TjwINjm+h7aG*>9{-LAH5 zqGB~b=WToU(wq!MJdI;fp>K(T#7brQbaypNwIDegK@I|{YVO2VI|969=vGoV=anWu z#@_c4;M~Md5NH7QiJt=W*s-Fe8)77&;u8SuEx$w_^pa*75YeOYK~*pFx{>}X1V2YW z1>1fw6E3B6B>f0QjBr~KXs~93#~NSyrS38c`~kr=1d|A6t2k8Gp-ext-p^9==0#-_ zO^N0}Geq7r^hj;mL{)}%`~BTny#V}+Wc;q#}XvtMCdX}m6GPbVlMM! z^1i&du|ePMW@mtk_D=un#`4chV4lU9sd#LkYwA@TI>V%I=CcN-Pv-;3bQyq_1Ld5W zfSYLA(Qz@~vP-}=Do^)3XD0_(P!uw(vv5J+uo@W2%_h>p=wvQ0XlQ+T?$3El(Z9W-jzhWs5`DJ`BL4{03e4 z`nSB|5kfU3>=hEbx!w)?pW&@3@#rk`2%r~qX5)sVL*g;LZQ2ly#l_=*h+zaMq3`x1 z*m8vsh7n+Dz;;xcD^4PMH-dW*&|YLizg)&`_g?vL+m=w0R66d%{?iD~F!|w{VjDW{ z8RWWOZtHCr{_+f&%?nC2N(o8& zYm^5mA`9`dxgOciLyxCivu93D?-sFA?%Q6oYc?Q@fpI(wB8UH>v`;*QLubMx9!B)@ zT=@U;;LExP7xXRuG7o-7_u%n95BmyEY{3&S_@5#1B3ki;{D;0BcFaP7GY0&<-eS3S c$AX1e0Tw7$sg=hietx?E#Ft-E54niK9bmuTP3MbwVxe1wxsMQC9xAw z)4HUAx~18)rIbQau5rth6mzu0F_g9x1`6dEI(!UMn&D`H0ftg2g;L&opB=lQz#k-& zpWgoVz4z_DefxGdzkith>O(9o>U7!+@aHd=&mFm2eJm}NF{8|8w)+(TY+LALTOBT?? z`P53|Mc}0vtO}sLiEm4i>gMIn5>oX*%f(B%cliTbpuO^eLNY5OtF6mc_SX>84$OAaG5c$Y*_i}t$1+t1l#_Sx zP8wxBv>JF9?}i~5{f%#HHIb&9_wZic2Ls#=?H#aq{orXAw414aH?->c9)2C)FmK=k z3n~5<;s^NLzj&FFu!r$a4Yk71J}b3USd4J-$hI>F+pH%;vr)Cfa&KP7==&F8#Sjd@kxGU-s;~?24U!);z!9~51-~U^9KKQWEg>-D34Lk05Qja5nLr^keE0y34WZI zAz}^zbAq2FW|){+VCML#`6P~euhKcSj|Op?zkA*a%zk9}dw7yeM#$u5eum$2$;5Bv z^Tdww+xUB7U}O9&za4%L@N@iq@H@`m&+mZW>-hq|6Mk>tckvIvubBj(RJMl_LMV~YY#_`6RbNyzFWL#W~}aHZcgo8>~$X!LO*3fvmm^q^PY~R3#`vN5J{xS%p^3 zB9u^6aQR|Z2OE%{?8mJhQ1x2Gp!|7ut#dy#7L6hs&Br9`&PZth@t|yS{jgw!6g88o z#KmEdwRMvsnuw`5bidr2TzzmZBzNitw6NhH)jgB;^<=oRVpI-z)JNHDhJ9W(HM7xX_ru zjULvuPAU=QWK6Wr%fIIJZPhlQ77S1g%mm|#2nVM%M=%x>(UXDW!Rdq|4$&n0!1#=u z%Krr$k;4TQtmS-fj=Z;EBfCv57CcgRJAUO9e!zMx5sbvc@mbAr)w4P=32RRwJ1J{Q zGUTnBve?~A_ixH$Rg0!qQqY*KfM!>tY5+_EH$`UzhE%Kxi+o|T$5VwLa)hEYv1mkz z#9{PW%CT4=64guzusJ8wJYG4pzBHSLv?hq;twkR44s*FMwu&*((t) zr6L4@|1e=srVp2~r znJCO;k1d@lmAop~gjoOEjs!7Zn)4YLL0bD!WhKS^R4+PEFi}Kp$AMvdDb^;ckTU@*~??$0?NW zG-w>JW>ynCs_zbRhFe5DfbgHjEhyC=53d^V;mriibj5vs5Di>I-f1i*fI zS9!LbQk#PDw7gut(@qOc)A7kS%FAmhVl>7zBSSBl2w1|zmjJZXSVF|2sv@3{<33Lo zefKHsUH!nb@(y2hEBVGyX?CcgilE`Dnp0JdC7_5afkZq!EigXXx|wh!FatB37Am^( z$=7{{*$whQMLSEC_f%YRye(Yc9?6%(l><$hb#S>(i4rvPB76Y=Dl|<3^K&)FHS<&y z_N-4nR@uhJ!1d{Rp-6+6&bp6c0xu;w94leswmRlrLBBHU7pRn`>(9zeTUVL-->poU6%Coq-K1 zUNy*1*BoJAlv%YA_A>R|SL+`9r9PKF~Z2Zu>M(%8!G zkS{kr0X`mTYB2u8Ab-+Sy5~*Qb;hHynP4P1smwr;T{(qzkppP zV6{{=anqC%iVLSqYc4m|JSb0Y{}g<}v*Y0&^ez60@K>}o>ybydP*tGt2I$NTC^JFG z6moCA#yxrUu}5V~a|gRoo^GD%#~jAYh|Jc)kw6KipTMbI(de`ij0goa%v_1Z#d9b+ z;E3aiP&^O`&M0(25N{b|YfA}(y3pdu{}SnsDktMwni`J^MGXiTlQ^o1_3~m%u00*6 zZ$rqG&$Mh!W})~RT4gQk(=mEn;Q=VtlZyBY_N^OHrXetxGITaj%C1&qtP+}aIHJ@- zHvks~=sr8k>+N z!FWQ|bNIL-%t+co(TExs!Ei(s<4B}J%wSnmf%hDdi_f_a!7Kp?`(aD+qr=_%p)a5X>0NG=vNU7l7sr1VYn6RShZA z(}BR6i%lFYirt7UR<-GkD(@4umuWth%CHex}2-@ktQpth*x>uvtP!p#Uf4OC2sd(xMDu zTADid!|UNdr;ioMTRZo_#s0gU1#l<-9pGMR>#DJfM$qgNO@MNe^!xD&Syj4uzFetEV#THFm9 znw=|ZNQ7g!m+`KBRDoJHjY@Qs?3Z~xjmDocInq;O#*sy; zAokN~e)aARH@uJ{o;}}NZoI-|Mem(12|AiB5edif`UjndaGZ2Iw~T@K8zz6-+h8H~ zoW$d@tIwORH_`oZ1YP|AsQ-a2UFa)f<5fu0x}>8-mHnDq8IA5q?8PyxIrE>v=CcS? zeZGOxR{%!EH|6?W?j&wPiiT#nNkmV;{b4^cSk%Q25Wa&T5ZYi!UaMZ{KM#avg4c(@ z!D+S`$Ups2rr#7^M1!9r(9UVz6BA?Drvhk>h;kyZ@>~+n%8%~x zWnMEQbd%a$>NNN%`R5L^?(E0`}j7aPRqEw=5rWv0m9d)ZOof z_=p^YT!cJ?d;}9J*P-+|lnPOz&{v~G^Vy6NZ8<5Q8!AZBdeN7jTKOCt-Z3Q7nFDIE=6Z0XLk$ZKS6#t@p87)ZUKdQG^&m zD*|OG0WB}(Dkl8bn0#Qkm^tK=!;P#>zCQeXvKoBMtsm*@Ut3i5{aJ$U+tJ@n1pL~Z z6*Y(81~a;-|L2NuqE-(oYyfF-o#;n-7{F_M4P*NC&-aO0YHG%rJ~4;g*Xi9x!#;!I zyNlw~s`gQ6p4PQZohK&6yLH*zITKUGd!QlqA)tj`w)dknf-s7Jm8c;72#R5ZDFmuQ zHVo21BQ&Swm3@U~OcSV)IZiY{X74pE0=2BM{NSr{IS64=y#OD7Myo4UStkEt1D|mBy@Xm~SElK<=&1wA^5T~%` xX5`MuAB+yBV_FKFtiWDSg#WHtZ*7H(TVh(lsTowa+&7kC-PmeKZrqTa`!Dkw1Ze;O diff --git a/sos_inventory/models/__pycache__/sos_mrn.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_mrn.cpython-310.pyc index 50a8b9d601e6e3d77cf0aa8d699c7c210917fc93..bacd314c5ed5d5930dae286f863306a152c8256f 100644 GIT binary patch delta 2777 zcmcIlYiv~27Cw94oz6_BLrZI)15+$Rp#v2G6-sSODQH`33oVs$9A+PeQ`>W9_L(Zw zYEe)SpRm*)J|V`KYBb^`YN9cs(SItwlcWC7Uq0`R-m8+Bd+SxGS zyz4mQ8+rEuWj`BPiOhw36Ed6mWs+GXeJ)3)hxbZmwPgB`xq|mgW{r%xk`M5~<4(SX zZ~`ViOgh9Q*}#CY3ih<2{k3OWKQE#k&c29-MKf~u_3wz*Wymmj2jjSf>H$AU+`8Z zbq>eEvJMIrMd*SBcHqM< zN(*x`W2ri~ojSMT4%^YZ+;*mQKFe&6&{C%0B8Z+MB;D7hHACBz5v^?6o8Rt8LsN0<>O)`z%yiD5e`p zS&?W*i)6H@zJSv;=W_;_g9YYXb5jj}P*Cu9{mXayGc49m8LuQ5L_m3#kS$qB1VtZw zT-+Hx>o*{sp(*eTTc5WBusu}i5S!p+(L8q> z(&KO>beLTOH6<-91AQgSi?<*vwh|115wC?ON_bdu+s;|24tKLD;Nef%t#E0n?G~5e zB19u2>@Zv(`GQU6cgzbib_B-D9xk7uz)1ox!9IeUpsu{D_+~P1Avgs63+I)VBvU!v zG}LTT)hs=2Jd%gQJ#rMCZ9leI#rCO&DGbo7+6%&vRDz~LOv6i6O~nt8 zS=dhg`zkDFAIw#^MomiLrS4d}(s7?S$BhCW%#YTrW}ausehMC_eIt@VGwu?P5c4R( zG04_+58pv_jT|Pi7;W2aWybZKxQ1M=Bf?WSc5=$Zuw-@$^Ey1D)JVG+x5>4XZsC?~ zZ(7SGb2%Xfp|rko+r#AGGLjRTxD`z?Lhv{NjfU+b1vp*+;ws{137(^cpwPy&R1Vci zTBadR(8584c&VIau?KFhKc5|i+4>>RZM1k8JkfskbbdH`3;Tmk{ji|BLgsK4aunhy zcn@~1iLHkl7PhiBczNM?_*JBBUk{$B783`t57xx$**h>Ct1CN2O97!}Op()#w3;); zemESf@*JR4&%=|k>X{eFyptSDQJiEZBg|_xuIdxXv?lH%-rH`P<66=<(^&E!BED!q z8^?{Kl!XRJNn~4meTLRDffdOX6qJ;zjZ^SSf_0R^*JF+v*aWdx=tTAqxM;=8wTxzP zOP+VzXBw&9NdpVg$fJ#589|PKzBS@Tg4+r1CU~3RJq4N*74S?$5zgU@4MSlU-W2rn z{Kx0^GoLSCy66?g?uAq5cLaaJh*^j2>@_WM8lsK0>=$TlywTxi@JeG<_2+W=%-xPt zlT7WN(2U%yL)-`dYK*fIs9n6B?S!etdzl9RMjXVmydgY~VIlIE?4pv!G3AlgBD%KBgE!i44_bP&H^L*IQRLQciqp5A?eaig- z!G{DN5qwNQpB?cT!P)!GrdN6OeMuJGYqo1p+mjO~$@FeAavDl4tHztyG`LPpwmt2- zfvvLLh1qzCf(yNrz4)5mW%+Wa)JE|Q0qs`MX2iGjS_#V%mHzM096-)m1AU2VIJk6y z<2wbii5hrw={M1TkmElI9z&S&4Rmdc_TtGL6yFp11H8MeBK0$wKN9?x;531g{tbTm z6u}4_1TF$Eft#R+z)$cwMHG`2BnT0d5QGUxZaC#UFCfb4bv{7_WST4em1rKK*Yn_L z^U}X8zLZ^5Q$jf?HDuKi)DcLXrJ4o#hznBXX8_hEeC~Q=r(knp5v$K<5)oE)R>3FG zcglNKKzL|*-Hs?_`8#E+f|eDr5Q&E0bUC>L*xu#}H;MNs%&b`TCv-bO+onrb{5H9N qUOZTn2)bif%{|c7(#T?9v~(2HSPBwT#BfY2;Qf}UyEoD}fBvsMdb|Yy delta 2291 zcmbu9T})I*6vuaVm)(VBaan=2hzQDp3!?6dpjMFp0-|8;Qc<*SuR8;*Ecepct9;ao zAK1j=gY?vz7+cXaX?duz-88mo?MtgoZEezzG|i3HXzhn-)uf53{fOzDp%EYSMeoD! zo_o%jb7%f%Wo26+kSBgnIzQ*Cs;m}B$K}O%cR$v|sj0S1VF+ywU@*&e6(l(z3 zM$2fO@YK@==~*B>D}<+!u9Ti~;R(`Jw23w!v(VM_3F)n%Yv_|hrnZGNL|epr5q*lT z74OBgm97)-$LV_7Cf-Zv2D(wam(r(0CbNH2;-ux2EwM9IBQtBo1o?7Ay@21si_w-| z>2UFC@TAqcC-UlKGPI|iAb~{Yq)cKp%yZ_!Tz6)wk-VgXsjRPuS1Qoxt}kCHa*b4_ zr-y5O;cZH6D;qQORCL-ni)fs37gm!KF z^dkCTjknI(kLGs7ARPD3BnJ{_z1yuencD#kIn|zhB50&^b2Th}5LU$s;7CsOxH_m8 zcOc?$Bd5eUg68WVag)W zcvMpjdk51MUFWjtMp7@2>dbJ)qACkVX*?WN`O8?+sw&-#KaT~Q5JwQWK@0~3L3n!hIPEg_&6M_!caj83BbvMN>T|o3u5k5!fiO36tzF7sZ8wNF5h%=7KVMf z8J}V(m9rj=>ru5MtZRG#PW!TL&ta*z;G%D;?F5=baL4Bz+>7b zgYk7H(MQ8hSr1cbT%HSFig{ZQDTu9z-G~z(rvx6iy7JWp>FiiE= zxUP%vnAxy2YjJ)Py8P3~AF$8AqvBuTH)Lea*VW%6tQ2FNM|=w zb&<0lDvSNZ2A#zlNei4Q?kBCVtfZgRi}N`RzAKqED}{&x@<^=5QelMaF63cP7AYH` zaQ6PWc)J)WTh*u@?%~l0<8t)<#yG^7FkGHpPHN$q`8iNly4ZQo-2^`*d*MLo6cT~4 z(yF!R@Q0rxzCfHue2K6izC{!xWQDKLl2_p+wD6uYtSzih=kK9uU!m$ubcWZ%vN^eJ z?_kc|Zt~0cDQ7L0i{0cuB5;u$XU(tR=OnZybdZ)5KI2@P?U(d-mUp2vp zfgDJm``h48IQD16VSxchsIES*Sscz5{wq4KA&LaXEPm1BIMWSFi0S+W`hQ2s(2-yP{Pet2>NF#75c?zz106*Pu zao+5~N9}^tpL?*N+)$Iz%0OfyWGAHH_g7eG%%#LxB0B~L13r?K_#ogR*%PY1Ce}G% zpAZ#(3FdC_V)aK8P84{MZdEQ+%x@mwe05^yK8C3yaBhD2Lr5ksTD*bz-QD}}x_LyI liLIF}rnMVJ%8E!fykA!1#I4FvOr8z)1rXD6y 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 DN^{_5 diff --git a/sos_inventory/models/__pycache__/sos_order_delivery_plan.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_order_delivery_plan.cpython-310.pyc index 02db84d2920b5837d6e73ab013140e9254c08052..c13fab9ec45df9f318544819e4338d815f3a7974 100644 GIT binary patch delta 55 zcmdnxyW5vHpO=@50SG3xZp+xWkvBw6TB;~9H!(RQF)yVkF;B0^p*X)dF(jRKD-17RKonF6f{9V_QDRIDHnr#SEPdQ5B*mI8WJ_YW zi5oYvGHgr?J6CSp$Um5camycYi|5=LK^`-?-<W52;YdOSShAYH1Mq80=gRAIz4F;5~9R?$sJ>-UE ze|dOkz!TKZxV5oFdO5R_<1uG;F1r#>F68oZ+&fTA7<8<^mx)h$zk|z}Mkp{~ONQtI zy`UG^c@6YBEu_6Mz$h3dN|%_Z2OTj4W<+Bec>eM2P=@?P@G9PlXh4f$X5~|YVeCCX zDDJ%=vx(p_L6qPe0o7YHBG{&DIy^b+T7oC|!YT){7I`9v7RxG43Bss$L$O3WnOI52 z@vwhS8e5KwC8q~>ojL@IRk0doGJU_suhYXaOtvqO2VwhkA!43SE&$ccGi7mrpr3D;0hv>t- zAzV%wf~D7an7O}p1(WRb9qQq#caDw8pWfC6aT|3nR+$4=b1EgQ-|U!}~Ihihaq%O{F^Q8Gy~D$iOs<+#)8%j;}XeyA9%qXM`U@k~af zv3apBnmytsZpya6b@ocW2rS=tKw*fpb@7n=EZ|A(xyXx0v_%7P&}{J( zUlT+{FkpD}n0HWcCzDP&7$LYf_o=J<`>CRj^BiP0s4T&0W1ygoN zOv>HhGrt;w`?NVCdn>~paSLtvyfVrLRRbkVm_Y24`$`B>UzJRpS1>;Ga+-;c2$s7sM}&bzmHjl{8YX02aTR3 AxBvhE delta 801 zcmZ{iPiqrF7{)W3h9sMRO(G_mL`_>w6C0D(SW|?yDl~YhG{LH=5SPp}rfzn(v)e+H z5=2jeD7;_5;;9!wdi3H&5WVy$ix+SD6+Aib28vj^3%_}IX5MFZ-+_ zGvhcpI=L&+JS{lhnSZ>CbjtD03hx{(ipop0k<<*mS1 zf2U9sUumZ~+hA?0t7|QT@ix;erNdgZYZ|K3-;?YSld0>V`jei5SYCvlT!&x2A{@xI zVm%F3#I-!|3rc&ZiHNK{X{%MKLSzqyRf|Zhtx0 zmq-=9gs+@%ii3(_aDAK6)~40x6^KTzx%bF2tVF8h4!n%?<`ytvQ6Mkz>te8dl&Rfq z#{2vxPW`v(lJHj1uZgVmB0o|d=FBv7%@h$DGtFZ|?jDBB9S!kvX6W2HzWUy<`sZj; z{OzC7)qvB=d2}nV7R^NL(B_t+cCCJ^r|`!n>_nTQv)`jP$PA=n<75FAVo%8!e2i5F z4J=zh)DaI6*jU?pOS4#q@!>%Y)6w@Vsk&kf4=sVKONgt8`-moD4ej} delta 54 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 diff --git a/sos_inventory/models/__pycache__/sos_quote_generation.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_quote_generation.cpython-310.pyc index 7992cd268a525edcd008095e15e9c19ae0a8369c..72171225c2f4535c381dcf88597c80e356f3118b 100644 GIT binary patch delta 1054 zcma)6OH30{6rER?>9lo9E6{f86iWRhh>-w(5)3hl5seWNqtu0_skCBA>E}^3#Azhx zLW8)u_=(m~{46w*h!qk15;ZPd7~{$=G)6aWj5`;)@ZMG+E=-){op!KmUijhuSBUO)|4WhwNijz~$!S$uhkpYaA1{2>Z9~Go+=oQ5SlIP^l`U zWnIq7Ar=xt(pX8_q_eC^H>J#3%b1``J&SNCIIK9zLdJ|V#?ofpi2E!}TXX|z&8V@2 zWL21-ZGU__&L&krgv%y(NoTS#_rR24mc_gt6XmNAU{rNL++x+r4@P3aXrS+KA`y** zc|#zX>d$LM5{4~KSiI;5+XiOEQ)(EnsnDT#SZS_TQ5e(Vn6-t`)bh2?chjiwQe(m1@PgkM_}g!SpHXQGB}0g9pG_0T}d*Pg;Vi@d4j|{-RsylIO*>2KctXHg^)R2V<34r zo(hKo2_ESRFT^8{4RXxMn*Jd}KGhH3-JjYD$uzLvRs9Zvz{K_1;zOIU)+z zDsGL&gDL)>H5H4XCKM}qLDn=(c%8NMVmLhwPJPVF@mSZPV5~dL9}`Cfa;kv81KFoZ mJcIUiD6cunGB8vVQ7PlRF%XS+V+d~}CH)C_24DLo=Kc+QV=nFh delta 1193 zcmaKsS!fec6o%(!I+ID#X`*eGY15`Is4c}UE~V8L7hE2!;?nw{glJ-IsabAfRhY3N zD2gcJ5frVGSSnUu)Syzawgul6q*UWm#aGc+5z%v|HUUL5+;7hP&wnoW+&kpfhSwX_ zxT@L({9TS6JZyWUu2a}a*sjcF?ZB0$KE0&d%C`~?Ntbl7m+|IKK^JvtjY&<&h?p(G zq2RDZ#C|c$n1HdJM~Q{Hj(^lS&{aB9mvri4M$HNvh5cLhS&Tl}u!U!=YQyYe$bGqG&?l z?fE_T;@hSPNV~~G3{5tNcq!SP+hXfyt9^V49u#jt!TOrL+lG$BPeM(9OAOXbw&!UEGab4x`pZLV05R}Vx}>CnuzadQV_ zWEq7+Rdd(~oU2-l=lQH^f%FjN@9?qe2m{#RZ&e0xj)w$r&EG6Nz)2-c`p4C~7!Aqh zSH?$RusX~FV6FKi-9x<|zSgw4Z(_vz3AYF<2)AKZU>PoaCeY9}OagV0mp1jp!)adZ z`M=Ff?|zi3#|W$6PYzu7;hF}X*JJAc}4xKhs$2;%UAzf|EgDvJ?Fo) zRP#oA$JjSs)(fFS{3mL={HuP+PWYlx3Lc^O$Uhm2+7Iza7UicXXZ+5{gti2p^Mv_Y zs|!34S6{vr}%oBsfe CzqP3V delta 619 zcmY+BNlU{(7=}C5wsA=vo5aRlTWj0Yy4GEPfH&7mJc*wRB8uY4gGCTUrJxKV9z;+P z>Us!x^x#RnDR}X3hp3JAOODkOR(E_gpXQ)J zAj9nPIp2~3I&lD*gF&nz>rg>#AQvyVAb82Z1O-Yn1$ITwRidlPxga_ds;Rl{N@_K^ zRzAI;bVEwLm9y;ocM;BZ-|u zH%)6rZi61;c4P&5i94VVwEi8J-3bFQi1#iSnsCL3oliHooe_^uVSUb+TEy70nD!@F zO6>WM9INb&v2pRk!;V?L#n^>74J5tS_=nfe#e3j|WyQXh^4y@<6|dS9zm-dhj5`?* zBC1EdhY}yfq`txP!(ljA6vusz;~3+(O+f;QwsF#?jSI|VqCzc01`28h)CkG4e3!(bI*WHs5mu!R zbY-Y+VxvMr%82*|h=s4<1t#Wx0VLizjoOK`-rqml_kZty@(=gRlABbkwub9h_>)SkdcjS$_Gz8A&I#S1o2S}) z(r?i=^-s0_2Homu{(X5)KGvsX&nLMP3>jw-rYwl*l;nnBhl8mGjy%x+tSn$0sG(%; zPQueLO1&2hM8bUn3-VRz;^Z!V%*|dJrW4`ou%ryimAfJl0ZpRUK{%mtn$>oZy(fyj zeKzp+lI+&Y5Fq5~yLOj*&#?bU_?g}1M@bwpwZWP5F6PT?SKR_&gMcRyIl)o$MG$nX z9W3zx;PdqKjZQOJkv+R-n=)^USSE>pLOOGG5f8GxD%o{~FC8cGb5+?wZwrh2E^ oTx(qnDf*Z3gEEMY{AxaQUE&m%g-3D9^0(Ppyb3gP$#!M=ABY#aY5)KL delta 272 zcmZ1`bcByDpO=@50SNl@k~4(aCh|>Y`o%DD@dtqvg%rgWhA7z-rCz;gbJA8a6mdkL z$)1^)kzZPzTE*d+r|SV`aR;TA=NDxwgj5!!7D)r0Fgc!O0i*0BR%1q~$tJA-_-}C+ rfmOtpfK+fyUdJXr*_(}v(QI-Un>HT{BNGVzV`FCf%fm9cnJpRs&-g$j delta 93 zcmcb}caN7ZpO=@50SNl@k~8X9C-QYO9-BC8FJFpEifRi(lthYJFoUN0=4!@YOp|xA tEMSzJ9K~u3B>PzZF%@x4R%93FE@B00X9MD5t;u`Yw3&DqCx2s$1_0%&8CL)R diff --git a/sos_inventory/models/__pycache__/sos_wo.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_wo.cpython-310.pyc index 1b151b5e6b8cee9716ceb09ae4e1b23ca48eb909..d82393effb343eacdcb5b2aab309da102c1db973 100644 GIT binary patch delta 59 zcmewu@+pKjpO=@50SG3xZp&D)k@uX4v{X@IZensqVqQv7VxC@+Lvem_VoqwMUUGi! NWI<7>&HSQCq5y1c6e|D# delta 59 zcmewq@-c)rpO=@50SK6xW@jwl$a_viMzSa|H!(RQF)yVkF;B0^p*X)dF( 0: + pack_count = ceil(raw_to_purchase / pack) + to_purchase = pack_count * pack + else: + pack_count = 0 + to_purchase = raw_to_purchase + materials.append({ + 'material_name': rec['name'], + 'needed_quantity': rec['needed'], + 'inhand_quantity': rec['inhand'], + 'actual_needed': raw_to_purchase, + 'std_packing_qty': pack, + 'packs_to_buy': pack_count, + 'to_purchase': to_purchase, + 'price': rec['price'], + 'cost': round(to_purchase * rec['price'], 2), + }) + + if not materials: + raise UserError("No materials need to be purchased.") + + # Optional ordering: most to purchase first + materials.sort(key=lambda r: (-r['to_purchase'], r['material_name'])) + + total_cost = sum(m['cost'] for m in materials) + + action = self.env.ref('sos_inventory.action_material_budget_summary') + return action.report_action( + self, + data={ + 'fg_name': label_name, # shown as header label + 'total_quantity': self.quantity, + 'materials': materials, + 'total_cost': total_cost, + 'currency_symbol': self.env.company.currency_id.symbol or '', + } + ) \ No newline at end of file diff --git a/sos_inventory/models/sos_ccrf.py b/sos_inventory/models/sos_ccrf.py index 07f3a75..3ad23c7 100755 --- a/sos_inventory/models/sos_ccrf.py +++ b/sos_inventory/models/sos_ccrf.py @@ -41,7 +41,7 @@ class SOS_CCRF(models.Model): batch_release_date = fields.Date(string="Invoice Date") brcoa_no = fields.Char(string="BRCOA No") brcoa_date = fields.Date(string="BRCOA Date") - other_complaints = fields.Text(string="Details of any other Complaints received from this Production run") + other_complaints = fields.Text(string="Defective Details/Symptom") data_collected_by = fields.Many2one('res.users', string='Data Collected By') data_collected_image = fields.Image(related="data_collected_by.signature_image",string='Data Collected Sign',readonly=True) data_collected_on = fields.Datetime(string="Data Collected On") @@ -56,12 +56,17 @@ class SOS_CCRF(models.Model): investigation_carriedout_image = fields.Image(related="investigation_carriedout_by.signature_image",string='Investigation Carried Out Sign',readonly=True) investigation_carriedout_on = fields.Datetime(string="Investigation Carried Out On") root_cause = fields.Html(string="Root Cause", - default="

Why #1

Why #2

Why #3

") + default="

Why #1 :

Why #2 :

Why #3 :

Why #4 :

Why #5 :

") + #team_formation = fields.Html(string="Team Formation", + #default="

Name :


Department :


Roles :

") + #problem_description = fields.Html(string="Problem Description", + #default="

Clear Statement :


Photo :


What :


Where :


When :


Why :


Who :


How :


How many :

") rootcause_carriedout_by = fields.Many2one('res.users', string='Root Cause Carried Out By') rootcause_carriedout_image = fields.Image(related="rootcause_carriedout_by.signature_image",string='Root Cause Carried Out Sign',readonly=True) rootcause_carriedout_on = fields.Datetime(string="Root Cause Carried Out On") - corrective_action = fields.Html(string="Corrective Action") - preventive_action = fields.Html(string="Preventive Action") + corrective_action = fields.Html(string="D5:Permanent Corrective Action") + implement_validate_corrective_action = fields.Html(string="D6:Implement & Validate Corrective Actions") + preventive_action = fields.Html(string="D7:Preventive Recurrence") capa_status = fields.Selection([ ('open', 'OPEN'),('close', 'Close')], default='open' , string="Status") status_reviewed_by = fields.Many2one('res.users', string='Status Reviewed By') status_reviewed_image = fields.Image(related="status_reviewed_by.signature_image",string='Status Reviewed Out Sign',readonly=True) @@ -76,6 +81,11 @@ class SOS_CCRF(models.Model): rootcause_verifiedout_image = fields.Image(related="rootcause_verifiedout_by.signature_image",string='Root Cause Verified By Sign',readonly=True) rootcause_verifiedout_on = fields.Datetime(string="Root Cause Verified On") helper_field = fields.Many2many('sos_fg', string="Helper Field") + team_recognition = fields.Html(string="Team Recognition (Image)") + capa_line_ids = fields.One2many('sos_ccrf_capa_line', 'ccrf_id', string="CAPA Line Ids",copy=True) + team_formation_line_ids = fields.One2many('sos_ccrf_team_formation_line', 'ccrf_id', string="Team Formation Line Ids",copy=True) + problem_description_line_ids = fields.One2many('sos_ccrf_problem_description_line', 'ccrf_id', string="Problem Description Line Ids",copy=True) + @api.onchange('fg_name') def _onchange_fg_name(self): if self.fg_name: @@ -140,4 +150,38 @@ class SOS_CCRF(models.Model): 'rootcause_verifiedout_by', 'rootcause_verifiedout_on' ) - \ No newline at end of file + +class CCRF_Model_CAPA_Line(models.Model): + _name = 'sos_ccrf_capa_line' + _description = 'CAPA Lines' + + ccrf_id = fields.Many2one('sos_ccrf', string="CCRF Reference", ondelete="cascade") + issue = fields.Char(string="Issue") + corrective_action = fields.Html(string="D5:Permanent Corrective Action") + implement_validate_corrective_action = fields.Html(string="D6:Implement & Validate Corrective Actions") + preventive_action = fields.Html(string="D7:Preventive Recurrence") + +class CCRF_Model_TEAM_FORMATION_Line(models.Model): + _name = 'sos_ccrf_team_formation_line' + _description = 'Team Formation Lines' + + ccrf_id = fields.Many2one('sos_ccrf', string="CCRF Reference", ondelete="cascade") + name = fields.Char(string="Name") + department = fields.Char(string="Department") + role = fields.Char(string="Role") + + +class CCRF_Model_PROBLEM_DESCRIPTION_Line(models.Model): + _name = 'sos_ccrf_problem_description_line' + _description = 'Problem Description Lines' + + ccrf_id = fields.Many2one('sos_ccrf', string="CCRF Reference", ondelete="cascade") + clear_statement = fields.Text(string="Clear Statement") + photos = fields.Html(string="Photos") + what = fields.Text(string="What") + where = fields.Text(string="Where") + when = fields.Text(string="When") + why = fields.Text(string="Why") + who = fields.Text(string="Who") + how = fields.Text(string="How") + how_many = fields.Text(string="How many") \ No newline at end of file diff --git a/sos_inventory/models/sos_common_scripts.py b/sos_inventory/models/sos_common_scripts.py index b6b30f6..bce4650 100755 --- a/sos_inventory/models/sos_common_scripts.py +++ b/sos_inventory/models/sos_common_scripts.py @@ -288,7 +288,7 @@ class Sequence_Generator(models.AbstractModel): reporting_user = env['res.users'].search([('id', '=', users.reporting_to.id)]) email_to = reporting_user.login else: - email_to = "ramachandran.r@sosaley.in" + email_to = "ramachandran.r@sosaley.com" mail_values = { 'subject': subject, 'body_html': body_html, diff --git a/sos_inventory/models/sos_dc.py b/sos_inventory/models/sos_dc.py index 69703f4..48a3276 100755 --- a/sos_inventory/models/sos_dc.py +++ b/sos_inventory/models/sos_dc.py @@ -60,7 +60,8 @@ class sos__dc(models.Model): dept_in_charge_image = fields.Image(related="dept_in_charge_name.signature_image",string='Department In-Charge Sign',readonly=True) dept_in_charge_approved_on = fields.Datetime(string="Approved On") remarks = fields.Text(string="Remarks") - + courier = fields.Char(string="Courier Name") + lr_no = fields.Char(string="LR No") @api.onchange('dock_audit_no') def _onchange_dock_audit_no(self): if self.dock_audit_no: @@ -220,7 +221,7 @@ class sos__dc(models.Model): """ subject = f"Delivery Challan Approval Request - {self.dc_no}" send_email = self.env['sos_common_scripts'] - send_email.send_direct_email(self.env,"sos_dc",self.id,"ramachandran.r@sosaley.in",subject,body_html) + send_email.send_direct_email(self.env,"sos_dc",self.id,"ramachandran.r@sosaley.com",subject,body_html) # Email part ends sequence_util = self.env['sos_common_scripts'] sequence_util.action_assign_signature( diff --git a/sos_inventory/models/sos_deliverables_config.py b/sos_inventory/models/sos_deliverables_config.py index 07b66f2..33159f8 100755 --- a/sos_inventory/models/sos_deliverables_config.py +++ b/sos_inventory/models/sos_deliverables_config.py @@ -22,7 +22,12 @@ class SosTestingParameters(models.Model): communication_type = fields.Selection([ ('wired', 'Wired'), ('wireless', 'Wireless') - ], string="Communication Type", default='wired') + ], string="Communication Type") + slave_type = fields.Selection([ + ('15S Individual Slave', '15S Individual Slave'), + ('90S Electrical Panel', '90S Electrical Panel'), + ('60S Electrical Panel', '60S Electrical Panel') + ], string="Slave Type") fg_ids = fields.One2many('sos_fg_deliverables', 'ref_id', string= 'FG Deliverables',copy=True) sfg_ids = fields.One2many('sos_sfg_deliverables', 'ref_id', string= 'SFG Deliverables',copy=True) material_ids = fields.One2many('sos_material_deliverables', 'ref_id', string='Material Deliverables',copy=True) @@ -57,6 +62,7 @@ class SOS_SFG_Deliverables(models.Model): item_type = fields.Selection([ ('Master Panel', 'Master Panel'), ('CT Module', 'CT Module'), + ('Battery Count', 'Battery Count'), ('Slave Module', 'Slave Module'), ('Internet Module', 'Internet Module') ], string="Type",default="Master Panel") @@ -82,6 +88,7 @@ class SOS_Material_Deliverables(models.Model): item_type = fields.Selection([ ('Master Panel', 'Master Panel'), ('CT Module', 'CT Module'), + ('Battery Count', 'Battery Count'), ('Slave Module', 'Slave Module'), ('Internet Module', 'Internet Module') ], string="Type",default="Master Panel") diff --git a/sos_inventory/models/sos_departments.py b/sos_inventory/models/sos_departments.py index 69cd10e..7996278 100755 --- a/sos_inventory/models/sos_departments.py +++ b/sos_inventory/models/sos_departments.py @@ -8,4 +8,34 @@ class sos_department(models.Model): name = fields.Char(string="Department Name") - \ No newline at end of file + short_form = fields.Char(string="Short Text") + process_incharge = fields.Many2one('res.users', string='Process Incharge') + users_line_ids = fields.One2many('sos_departments_user_lines','ref_id', string='Users') + + _sql_constraints = [ + ('uniq_department_name', 'unique(name)', 'Department name must be unique.'), + ] +class sos_department_line(models.Model): + _name = 'sos_departments_user_lines' + _description = 'Users in department' + + ref_id = fields.Many2one('sos_departments', string="Departments", ondelete="cascade") + users = fields.Many2one('res.users', string='Users') + # @api.onchange('users') + # def _onchange_users(self): + # if self.users: + # domain = [('users', '=', self.users.id)] + # if self.id and isinstance(self.id, int): # Only add if it's a real ID + # domain.append(('id', '!=', self.id)) + + # existing_line = self.env['sos_departments_user_lines'].search(domain, limit=1) + # if existing_line: + # return { + # 'warning': { + # 'title': 'User Already Assigned', + # 'message': f"This user is already assigned to {existing_line.ref_id.name}." + # } + # } + + + \ No newline at end of file diff --git a/sos_inventory/models/sos_disposal_register.py b/sos_inventory/models/sos_disposal_register.py index 5d6fa02..6e0bca2 100755 --- a/sos_inventory/models/sos_disposal_register.py +++ b/sos_inventory/models/sos_disposal_register.py @@ -96,7 +96,7 @@ class sos_Disposal_Register(models.Model):

Below Item is waiting for your approval to Dispose

""" - sequence_util.send_direct_email(self.env,"sos_disposal_register",self.id,"ramachandran.r@sosaley.in","Disposal Approved",body_html) + sequence_util.send_direct_email(self.env,"sos_disposal_register",self.id,"ramachandran.r@sosaley.com","Disposal Approved",body_html) # Email part ends return sequence_util.action_assign_signature( self, diff --git a/sos_inventory/models/sos_dock_audit.py b/sos_inventory/models/sos_dock_audit.py index 83d6754..6f56144 100755 --- a/sos_inventory/models/sos_dock_audit.py +++ b/sos_inventory/models/sos_dock_audit.py @@ -30,7 +30,9 @@ class SOS_Dock_Audit(models.Model): ], string="Product Type",required=True) quantity = fields.Integer(string="Quantity") + warranty = fields.Integer(string="Warranty(In Months)") invoice_no = fields.Char(string="Invoice No") + invoice_date = fields.Date(string="Invoice Date") customer_name = fields.Char(string="Customer Name") lead_time = fields.Datetime(string="Lead Time") customer_po_no = fields.Char(string="PO No") @@ -140,6 +142,18 @@ class SOS_Dock_Audit(models.Model): }) def action_acc_esign_btn(self): + required_fields = ['payment_status', 'invoice_date','invoice_no', 'billing_address', 'gst_no', 'shipping_address'] + missing_fields = [] + + for field in required_fields: + if not self[field]: # Check if field is empty/False + missing_fields.append(field) + + # If any fields are missing, show warning + if missing_fields: + warning_msg = "Please fill the following required fields before proceeding:\n" + warning_msg += "\n".join([f"👉 {field.replace('_', ' ').title()}" for field in missing_fields]) + raise UserError(warning_msg) sequence_util = self.env['sos_common_scripts'] sequence_util.action_assign_signature( self, @@ -151,7 +165,7 @@ class SOS_Dock_Audit(models.Model): body_html = f"""

Below Dock Audit is waiting for your Approval

""" - sequence_util.send_direct_email(self.env,"sos_dock_audit",self.id,"ramachandran.r@sosaley.in","Dock Audit Approval",body_html) + sequence_util.send_direct_email(self.env,"sos_dock_audit",self.id,"ramachandran.r@sosaley.com","Dock Audit Approval",body_html) # Email part ends def action_auditor_esign_btn(self): sequence_util = self.env['sos_common_scripts'] @@ -206,7 +220,7 @@ class SOS_Dock_Audit(models.Model): self.shipping_address = self.deliverables_boq_id.sales_id.shipping_address self.gst_no = self.deliverables_boq_id.sales_id.gst_no self.payment_status = self.deliverables_boq_id.sales_id.payment_status - self.customer_name = self.deliverables_boq_id.sales_id.customer_name + self.customer_name = self.deliverables_boq_id.sales_id.customer_name.customer_name self.fg_name = self.deliverables_boq_id.sales_id.fg_name self.quantity = self.deliverables_boq_id.sales_id.qty self.lead_time = self.deliverables_boq_id.sales_id.lead_time diff --git a/sos_inventory/models/sos_fg_plan.py b/sos_inventory/models/sos_fg_plan.py index 8a0972a..04d977c 100755 --- a/sos_inventory/models/sos_fg_plan.py +++ b/sos_inventory/models/sos_fg_plan.py @@ -30,6 +30,11 @@ class SOS_FG_Plan(models.Model): prepared_by = fields.Many2one('res.users', string='Planned By') prepared_image = fields.Image(related="prepared_by.signature_image",string='Prepared By Sign',readonly=True) prepared_on = fields.Datetime(string="Planned On") + + accounts_approved_on = fields.Datetime(string="Accounts Approved On") + accounts_approved_name = fields.Many2one('res.users', string='Accounts Sign') + accounts_approved_by_image = fields.Image(related="accounts_approved_name.signature_image",string='Accounts Sign',readonly=True) + blowup = fields.Boolean(string="Blowup Done",default=False) target_date = fields.Date(string="Target Date",required=True) indent_start_date = fields.Date(string="Indent Start Date", default=lambda self: fields.Date.context_today(self)) @@ -116,29 +121,45 @@ class SOS_FG_Plan(models.Model): month = today.strftime('%m') base_sequence_prefix = f"SOS/{form_name}/{fy}/{month}/" + # Search for latest record for this fiscal year (not just this month) records = self.env[model_name].sudo().search( - [(field_name, 'like', f"{base_sequence_prefix}%")], + [(field_name, 'like', f"SOS/{form_name}/{fy}/%")], order=f"{field_name} desc", limit=1 ) if records: last_sequence = records[0][field_name] - last_suffix = last_sequence.split('/')[-1] - if last_suffix.isdigit(): - new_suffix = f"{last_suffix}a" + parts = last_sequence.split('/') + last_month = parts[-2] + last_suffix = parts[-1] + + # Extract numeric part only (ignore trailing alphabet) + numeric_part = ''.join(filter(str.isdigit, last_suffix)) + + if last_month != month: + # New month: increment numeric part, no suffix + new_number = int(numeric_part) + 1 + new_suffix = f"{new_number:03d}" else: - base_num = last_suffix[:-1] - last_alpha = last_suffix[-1] - next_alpha = chr(ord(last_alpha) + 1) if last_alpha < 'z' else 'a' - new_suffix = f"{base_num}{next_alpha}" + # Same month: check for alphabet suffix + alpha_part = ''.join(filter(str.isalpha, last_suffix)) + if alpha_part: + next_alpha = chr(ord(alpha_part) + 1) if alpha_part < 'z' else 'a' + new_suffix = f"{numeric_part}{next_alpha}" + else: + # First duplicate in same month + new_suffix = f"{numeric_part}a" else: - new_suffix = '016' + # No previous records at all + new_suffix = '001' return f"{base_sequence_prefix}{new_suffix}" + + def _get_default_lines(self,model,column): products = self.env[model].search([]) @@ -170,9 +191,10 @@ class SOS_FG_Plan(models.Model): def send_indent_plan_email(self, email_ids): + valid_emails = [email for email in email_ids if email] template = self.env.ref('sos_inventory.send_indent_plan_email_template') if template: - template.email_to = ','.join(email_ids) + template.email_to = ','.join(valid_emails) template.send_mail(self.id, force_send=True) def get_unique_emails(self): group_refs = [ @@ -290,7 +312,22 @@ class SOS_FG_Plan(models.Model): else: worksheet.write(row, 1, value) - + def action_acc_approver_esign_btn(self): + sequence_util = self.env['sos_common_scripts'] + body_html = f""" +

Below Indent Budget is waiting for your Approval

+ """ + + send_email = self.env['sos_common_scripts'] + send_email.send_direct_email(self.env,"sos_fg_plan",self.id,"ramachandran.r@sosaley.com","Indent Budget Approval",body_html) + result = sequence_util.action_assign_signature( + self, + 'accounts_approved_name', + 'accounts_approved_on', + 'sos_inventory.sos_finance_user' + ) + + def action_top_approver_esign_btn(self): sequence_util = self.env['sos_common_scripts'] result = sequence_util.action_assign_signature( @@ -334,11 +371,9 @@ class SOS_FG_Plan(models.Model): body_html = f"""

Below Indent Budget is waiting for your Approval

""" - send_email = self.env['sos_common_scripts'] - send_email.send_direct_email(self.env,"sos_fg_plan",self.id,"ramachandran.r@sosaley.in","Indent Budget Approval",body_html) - sequence_util = self.env['sos_common_scripts'] - result = sequence_util.action_assign_signature( + send_email.send_group_email(self.env,'sos_fg_plan',self.id,"deenalaura.m@sosaley.in","Indent Budget Approval",body_html,'sos_inventory.sos_finance_user') + result = send_email.action_assign_signature( self, 'prepared_by', 'prepared_on' diff --git a/sos_inventory/models/sos_fir_brr.py b/sos_inventory/models/sos_fir_brr.py index a7d26c6..dd245f6 100755 --- a/sos_inventory/models/sos_fir_brr.py +++ b/sos_inventory/models/sos_fir_brr.py @@ -125,6 +125,7 @@ class FIR_BRR(models.Model): sos_record.target_date , date.today() ) + week_number = min(week_number, 8) field_name = f'qc_week_{week_number}' fgplan_field_name = f'planned_week_{week_number}' # FG Plan update diff --git a/sos_inventory/models/sos_grn.py b/sos_inventory/models/sos_grn.py index 76c8f44..2e5d3b8 100755 --- a/sos_inventory/models/sos_grn.py +++ b/sos_inventory/models/sos_grn.py @@ -77,6 +77,7 @@ class sos__grn(models.Model): print(f"Failed to find report action: {e}") def action_report_esign_btn(self): + sequence_util = self.env['sos_common_scripts'] sequence_util.action_assign_signature( self, @@ -84,6 +85,7 @@ class sos__grn(models.Model): 'stores_approval_on', 'sos_inventory.sos_scg_group_user' ) + self.generate_supplier_service() if self.received_goods_type == "Materials": for item in self.line_ids: component = self.env['sos_material'].browse(item.component_id.id) @@ -148,7 +150,180 @@ class sos__grn(models.Model): def _compute_sequence(self): sequence_util = self.env['sos_common_scripts'] return sequence_util.generate_sequence('sos_grn','GRN', 'grn_no') + def generate_supplier_service(self): + grn = self.env['sos_grn'].browse(self.id) + + if self.received_goods_type == "Materials": + # Check for existing register line + already_created = self.env['sos_mat_outsourcing_vendor_register_lines'].search([ + ('ref_id.supplier_name', '=', grn.supplier_name.id), + ('po_no', '=', grn.po_no.id) + ], limit=1) + # Get or create the main register + outsource = self.env['sos_mat_outsourcing_vendor_register'].search( + [('supplier_name', '=', grn.supplier_name.id)], limit=1) + if not outsource: + outsource = self.env['sos_mat_outsourcing_vendor_register'].create({ + 'supplier_name': grn.supplier_name.id, + }) + ir_records = self.env['sos_ir'].search([('po_no', '=', grn.po_no.id)]) + iqi_records = self.env['sos_iqi'].search([('ir_id_unique_id', 'in', ir_records.ids)]) + grn_records = self.env['sos_grn'].search([('po_no', '=', grn.po_no.id)]) + grn_line_records = self.env['sos_grn_line'].search([('grn_id', 'in', grn_records.ids)]) + + # Prepare material_names list + mat_record = [line.component_id.id for line in grn_line_records if line.component_id and line.component_id.part_no] + material_names = [(6, 0, mat_record)] + + # Sum all GRN line quantities including current + total_received_qty = sum(grn_line_records.mapped('received_qty')) #+ new_received + total_approved_qty = sum(grn_line_records.mapped('approved_qty')) #+ new_approved + total_rejected_qty = sum(grn_line_records.mapped('rejected_qty')) #+ new_rejected + + delivery_values = grn_records.mapped('delivery') + delivery_numbers = [float(value) for value in delivery_values if value] + existing_count = len(delivery_numbers) + + responsive_values = grn_records.mapped('responsiveness') + responsive_numbers = [float(value) for value in responsive_values if value] + + reports_values = grn_records.mapped('reports') + reports_numbers = [float(value) for value in reports_values if value] + + avg_delivery_marks = sum(delivery_numbers) / (existing_count) + delivery = ( + 30 if 27.5 < avg_delivery_marks <= 30 else + 25 if 22.5 < avg_delivery_marks <= 27.5 else + 10 if avg_delivery_marks < 20 else + 0 + ) + + avg_report_marks = sum(reports_numbers) / (existing_count) + report = ( + 30 if 27.5 < avg_report_marks <= 30 else + 25 if 22.5 < avg_report_marks <= 27.5 else + 10 if avg_report_marks < 20 else + 0 + ) + + avg_responsiveness_marks = sum(responsive_numbers) / (existing_count) + + responsiveness = ( + 10 if 5 <= avg_responsiveness_marks <= 10 else + 5 if avg_responsiveness_marks < 5 else + 0 + ) + if already_created: + updated_vals = { + 'received_qty': total_received_qty, + 'approved_qty': total_approved_qty, + 'rejected_qty': total_rejected_qty, + 'delivery_marks': delivery, + 'responsiveness_marks': responsiveness, + 'report_marks': report, + 'iqi_references': [(6, 0, iqi_records.ids)], + 'grn_references': [(6, 0, grn_records.ids)], + 'material_names': material_names, + } + already_created.write(updated_vals) + else: + self.env['sos_mat_outsourcing_vendor_register_lines'].create({ + 'ref_id': outsource.id, + 'po_no': grn.po_no.id, + 'received_qty': total_received_qty, + 'approved_qty': total_approved_qty, + 'rejected_qty': total_rejected_qty, + 'iqi_references': [(6, 0, iqi_records.ids)], + 'grn_references': [(6, 0, grn_records.ids)], + 'material_names': material_names, + 'delivery_marks': delivery, + 'responsiveness_marks': responsiveness, + 'report_marks': report, + }) + + elif self.received_goods_type == "SFG": + + # Check for existing register line + already_created = self.env['sos_outsourcing_vendor_monitoring_register_lines'].search([ + ('ref_id.service_provider_name', '=', grn.service_provider_name.id), + ('wo_no', '=', grn.wo_no.id) + ], limit=1) + + # Get or create the main register + outsource = self.env['sos_outsourcing_vendor_monitoring_register'].search( + [('service_provider_name', '=', grn.service_provider_name.id)], limit=1) + if not outsource: + outsource = self.env['sos_outsourcing_vendor_monitoring_register'].create({ + 'service_provider_name': grn.service_provider_name.id, + }) + # Related documents + ir_records = self.env['sos_ir'].search([('wo_no', '=', grn.wo_no.id)]) + iqi_records = self.env['sos_iqi'].search([('ir_id_unique_id', 'in', ir_records.ids)]) + dc_records = self.env['sos_dc'].search([('wo_no', '=', grn.wo_no.id)]) + grn_records = self.env['sos_grn'].search([('wo_no', '=', grn.wo_no.id)]) + + grn_line_records = self.env['sos_grn_line_sfg'].search([('grn_id', 'in', grn_records.ids)]) + + # Prepare material_names list + sfg_ids = [line.component_id.id for line in grn_line_records if line.component_id and line.component_id.name] + + # Include current line component manually if not yet saved in DB + current_component_id = self.line_ids.component_id + if current_component_id and current_component_id not in sfg_ids: + sfg_ids.append(current_component_id) + + sfg_names = [(6, 0, sfg_ids)] + + total_received_qty = sum(grn_line_records.mapped('received_qty')) + total_approved_qty = sum(grn_line_records.mapped('approved_qty')) + total_rejected_qty = sum(grn_line_records.mapped('rejected_qty')) + + delivery_values = grn_line_records.mapped('delivery') + delivery_numbers = [float(value) for value in delivery_values if value] + existing_count = len(delivery_numbers) + + responsive_values = grn_line_records.mapped('responsiveness') + responsive_numbers = [float(value) for value in responsive_values if value] + + reports_values = grn_line_records.mapped('reports') + reports_numbers = [float(value) for value in reports_values if value] + + avg_delivery_marks = sum(delivery_numbers) / (existing_count) + avg_responsiveness_marks = sum(responsive_numbers) / (existing_count) + avg_report_marks = sum(reports_numbers) / (existing_count) + + if already_created: + #print(f" sfg_names : if {sfg_names}") + updated_vals = { + 'received_qty': total_received_qty, + 'approved_qty': total_approved_qty, + 'rejected_qty': total_rejected_qty, + 'delivery_marks': avg_delivery_marks, + 'responsiveness_marks': avg_responsiveness_marks, + 'report_marks': avg_report_marks, + 'iqi_references': [(6, 0, iqi_records.ids)], + 'dc_references': [(6, 0, dc_records.ids)], + 'grn_references': [(6, 0, grn_records.ids)], + 'sfg_names': sfg_names, + } + already_created.write(updated_vals) + else: + #print(f" sfg_names : else {sfg_names}") + self.env['sos_outsourcing_vendor_monitoring_register_lines'].create({ + 'ref_id': outsource.id, + 'iqi_references': [(6, 0, iqi_records.ids)], + 'dc_references': [(6, 0, dc_records.ids)], + 'grn_references': [(6, 0, grn_records.ids)], + 'sfg_names': sfg_names, + 'wo_no': grn.wo_no.id, + 'received_qty': total_received_qty, + 'approved_qty': total_approved_qty, + 'rejected_qty': total_rejected_qty, + 'delivery_marks': avg_delivery_marks, + 'responsiveness_marks': avg_responsiveness_marks, + 'report_marks': avg_report_marks, + }) class sos_grn_line(models.Model): _name = 'sos_grn_line' _description = 'GRN Material Lines' @@ -169,14 +344,19 @@ class sos_grn_line(models.Model): @api.depends('received_qty', 'rejected_qty') def _compute_quality(self): for record in self: - if record.rejected_qty != 0: - record.quality_marks = (100 - ((record.rejected_qty / record.received_qty) * 100)) - if record.quality_marks >= 80 and record.quality_marks <=99: - record.quality_marks = 25 + record.quality_marks = self._calculate_quality_marks(record.received_qty, record.rejected_qty) + + + def _calculate_quality_marks(self, received, rejected): + if received != 0: + q = 100 - ((rejected / received) * 100) + if 91 <= q <= 100: + return 30 + elif 80 <= q <= 90: + return 25 else: - record.quality_marks = 10 - else: - record.quality_marks = 100 + return 10 + return 0 @api.model def write(self, vals): @@ -295,14 +475,20 @@ class sos_grn_line_sfg(models.Model): @api.depends('received_qty', 'rejected_qty') def _compute_sfgquality(self): for record in self: - if record.rejected_qty != 0: - record.quality_marks = (100 - ((record.rejected_qty / record.received_qty) * 100)) - if record.quality_marks >= 80 and record.quality_marks <=99: - record.quality_marks = 25 + record.quality_marks = self._calculate_quality_marks(record.received_qty, record.rejected_qty) + + + + def _calculate_quality_marks(self, received, rejected): + if received != 0: + q = 100 - ((rejected / received) * 100) + if 91 <= q <= 100: + return 30 + elif 80 <= q <= 90: + return 25 else: - record.quality_marks = 10 - else: - record.quality_marks = 100 + return 10 + return 0 class sos_grn_line_fg(models.Model): _name = 'sos_grn_line_fg' diff --git a/sos_inventory/models/sos_ir.py b/sos_inventory/models/sos_ir.py index 6a19daa..8f043a0 100755 --- a/sos_inventory/models/sos_ir.py +++ b/sos_inventory/models/sos_ir.py @@ -276,25 +276,26 @@ class SOS_IR(models.Model): else: - iqi_record = self.env['sos_iqi'].create({ - 'iqi_no': sequence_util.generate_sequence('sos_iqi', 'IQI', 'iqi_no'), - 'material_option':True, - 'sfg_option':False, - 'supplier_name': self.supplier_name.id, - 'batch_no':item.batch_no, - 'received_qty':item.qty, - 'uom': item.component_id.uom, - 'material_name': item.component_id.id, - 'material_code': item.component_id.material_code, - 'in_tact':self.boxes_sealing, - 'invoice_no':self.dc_no_char, - 'invoice_date':self.dc_date, - 'ir_id_unique_id':self.id, - 'from_origin':"Vendor", - 'unit_price':item.unit_price - + if item.qty > 0: + iqi_record = self.env['sos_iqi'].create({ + 'iqi_no': sequence_util.generate_sequence('sos_iqi', 'IQI', 'iqi_no'), + 'material_option':True, + 'sfg_option':False, + 'supplier_name': self.supplier_name.id, + 'batch_no':item.batch_no, + 'received_qty':item.qty, + 'uom': item.component_id.uom, + 'material_name': item.component_id.id, + 'material_code': item.component_id.material_code, + 'in_tact':self.boxes_sealing, + 'invoice_no':self.dc_no_char, + 'invoice_date':self.dc_date, + 'ir_id_unique_id':self.id, + 'from_origin':"Vendor", + 'unit_price':item.unit_price + - }) + }) # Email part body_html = f"""

Below IQI is waiting for your Approval

@@ -383,7 +384,7 @@ class SOS_IR(models.Model): """ subject = f"Inward Approval Request - {self.ir_no}" send_email = self.env['sos_common_scripts'] - send_email.send_direct_email(self.env,"sos_ir",self.id,"ramachandran.r@sosaley.in",subject,body_html) + send_email.send_direct_email(self.env,"sos_ir",self.id,"ramachandran.r@sosaley.com",subject,body_html) # Email part ends sequence_util = self.env['sos_common_scripts'] return sequence_util.action_assign_signature( diff --git a/sos_inventory/models/sos_mat_outsourcing_vendor_register.py b/sos_inventory/models/sos_mat_outsourcing_vendor_register.py index c046edd..f01db23 100755 --- a/sos_inventory/models/sos_mat_outsourcing_vendor_register.py +++ b/sos_inventory/models/sos_mat_outsourcing_vendor_register.py @@ -35,12 +35,26 @@ class SOS_Mat_Oursourcing_Monitor_Lines(models.Model): rejection_percentage = fields.Float(string="Rejected Percentage", compute="_compute_rejected_percentage", store=True) rejection_percentage_display = fields.Char('Rejection Percentage', compute='_compute_rejected_percentage_display') ppm = fields.Integer(string="PPM",compute="_compute_ppm") - - quality_marks = fields.Float(string="Quality Marks") + quality_marks = fields.Float(string="Quality Marks",compute="_compute_sfgquality") delivery_marks = fields.Float(string="Delivery Marks") responsiveness_marks = fields.Float(string="Responsiveness Marks") report_marks = fields.Float(string="Report Marks") + def _calculate_quality_marks(self, received, rejected): + if received != 0: + q = 100 - ((rejected / received) * 100) + if 91 <= q <= 100: + return 30 + elif 80 <= q <= 90: + return 25 + else: + return 10 + return 0 + @api.depends('received_qty', 'rejected_qty') + def _compute_sfgquality(self): + for record in self: + record.quality_marks = self._calculate_quality_marks(record.received_qty, record.rejected_qty) + @api.depends('rejection_percentage') def _compute_rejected_percentage_display(self): for record in self: diff --git a/sos_inventory/models/sos_mon.py b/sos_inventory/models/sos_mon.py index 29e8f49..2fce647 100755 --- a/sos_inventory/models/sos_mon.py +++ b/sos_inventory/models/sos_mon.py @@ -16,6 +16,7 @@ class sos__mon(models.Model): filled_by = fields.Many2one('res.users', string='Filled By', readonly=True,required=True,default=lambda self: self.env.user) logged_inuser_group=fields.Boolean(string='Group Name',compute='compute_user_grp',store=True) dept = fields.Many2one('sos_departments',string="Department") + customer_name = fields.Many2one('sos_inventory_customers',string="Customer Name") purpose = fields.Char(string="Purpose") product_name = fields.Many2one('sos_fg', string='Material/Product Name & No') indent_ref_no = fields.Many2one('sos_fg_plan',string="Indent Reference No") @@ -33,7 +34,7 @@ class sos__mon(models.Model): top_management_name = fields.Many2one('res.users', string='Top Management Approver') top_management_approval_image = fields.Image(related="top_management_name.signature_image",string='Top Management Approval',readonly=True) top_management_approved_on = fields.Datetime(string="Approved On") - + deliverables_boq_id = fields.Many2one('sos_deliverables_boq', string="Load From Deliverables/BOQ Id") stores_approved_by = fields.Many2one('res.users', string='Stores Approved By') stores_approved_image = fields.Image(related="stores_approved_by.signature_image",string='Stores Approval Sign',readonly=True) stores_approved_on = fields.Datetime(string="Approved On") @@ -43,9 +44,9 @@ class sos__mon(models.Model): ('fg', 'FG') ], string='Auto Load Items' ,default=False) material_option = fields.Boolean('Materials', default=True) - sfg_option = fields.Boolean('Semi-Finished Goods') - fg_option = fields.Boolean('Finished Goods') - order_type = fields.Char(string='order_type',copy=True) + sfg_option = fields.Boolean('Semi-Finished Goods', default=False) + fg_option = fields.Boolean('Finished Goods', default=False) + order_type = fields.Char(string='order_type',copy=True,compute="_compute_order_type") line_ids_material = fields.One2many('sos_mon_line_material', 'mon_id', string="Materials",copy=True) line_ids_sfg = fields.One2many('sos_mon_line_sfg', 'mon_id', string="Semi-Finished Goods",copy=True) line_ids_fg = fields.One2many('sos_mon_line_fg', 'mon_id', string="Finished Goods",copy=True) @@ -73,6 +74,74 @@ class sos__mon(models.Model): approx_value = fields.Monetary(compute='_compute_approx_value', string="Approximate Value", currency_field='currency_id', readonly=True,store=True) status = fields.Selection([ ('open', 'Open'),('close', 'Closed')], default='open' , string="Status") active = fields.Boolean(default=True) + is_ce_user_created = fields.Boolean( + compute='_compute_is_ce_user_created', + store=True, + string='Created by CE User' + ) + @api.depends('create_uid') + def _compute_is_ce_user_created(self): + ce_groups = [ + self.env.ref('sos_inventory.sos_ce_user').id + ] + for record in self: + record.is_ce_user_created = any( + gid in record.create_uid.groups_id.ids for gid in ce_groups + ) + @api.depends('material_option', 'sfg_option', 'fg_option') + def _compute_order_type(self): + for rec in self: + parts = [] + if rec.material_option: + parts.append('Material') + if rec.sfg_option: + parts.append('SFG') + if rec.fg_option: + parts.append('FG') + rec.order_type = ",".join(parts) if parts else False + @api.onchange('deliverables_boq_id') + def _onchange_deliverables_boq_id(self): + self.material_option = True + self.sfg_option = True + self.fg_option = True + if self.deliverables_boq_id: + self.line_ids_material = [(5, 0, 0)] # Clear existing records + self.line_ids_material = [ + (0, 0, { + 'component_id': line.component_id, # Replace 'field1' with the actual field names + 'uom': line.uom, + 'material_code': line.material_code, + 'quantity': line.quantity + + # Add other fields to copy here + }) for line in self.deliverables_boq_id.line_ids_installation_kit + ] + self.line_ids_fg = [(5, 0, 0)] # Clear existing records + self.line_ids_fg = [ + (0, 0, { + 'component_id': line.component_id, # Replace 'field1' with the actual field names + 'quantity': line.quantity + }) for line in self.deliverables_boq_id.line_ids_fg + ] + self.line_ids_sfg = [(5, 0, 0)] # Clear existing records + self.line_ids_sfg = [ + (0, 0, { + 'component_id': line.component_id, # Replace 'field1' with the actual field names + 'quantity': line.quantity + # Add other fields to copy here + }) for line in self.deliverables_boq_id.line_ids_sfg + ] + self.line_ids_material = [ + (0, 0, { + 'uom': line.uom, + 'material_code': line.material_code, + 'component_id': line.component_id, + 'quantity': line.quantity + # Add other fields to copy here + }) for line in self.deliverables_boq_id.line_ids_material + ] + + @api.constrains('indent_ref_no', 'auto_load_fg_items') def _check_duplicate_fg_items_per_indent(self): for record in self: @@ -461,7 +530,7 @@ class Mon_Line_Material(models.Model): uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], string="Uom") specifications = fields.Char(string="Specifications") quantity = fields.Float(string="Quantity",required=True,default=1) - location = fields.Char(string="Location") + location = fields.Char(string="Location",related='component_id.location') company_id = fields.Many2one('res.company', store=True, copy=False, string="Company", default=lambda self: self.env.user.company_id.id) diff --git a/sos_inventory/models/sos_mrn.py b/sos_inventory/models/sos_mrn.py index 756d2b2..0a584a1 100755 --- a/sos_inventory/models/sos_mrn.py +++ b/sos_inventory/models/sos_mrn.py @@ -46,6 +46,20 @@ class sos__mrn(models.Model): default=lambda self: self.env.user.company_id.currency_id.id) approx_value = fields.Monetary(compute='_compute_approx_value', string="Approximate Value", currency_field='currency_id', readonly=True) + is_ce_user_created = fields.Boolean( + compute='_compute_is_ce_user_created', + store=True, + string='Created by CE User' + ) + @api.depends('create_uid') + def _compute_is_ce_user_created(self): + ce_groups = [ + self.env.ref('sos_inventory.sos_ce_user').id + ] + for record in self: + record.is_ce_user_created = any( + gid in record.create_uid.groups_id.ids for gid in ce_groups + ) @api.onchange('min_no') def _onchange_min_no(self): if self.min_no: diff --git a/sos_inventory/models/sos_ncmr.py b/sos_inventory/models/sos_ncmr.py index 3f71652..ee892cf 100755 --- a/sos_inventory/models/sos_ncmr.py +++ b/sos_inventory/models/sos_ncmr.py @@ -52,7 +52,8 @@ class NCMR_Model(models.Model): finished_fg_assy = fields.Char() finished_fg_assy_responsibility = fields.Text(string="Production Assy FG Responsibility") description_of_nc = fields.Html(string="Description of Non-Conformities") - root_cause_of_nc = fields.Html(string="Root Cause of Non-Conformities") + root_cause_of_nc = fields.Html(string="Root Cause", + default="

Why #1 :

Why #2 :

Why #3 :

Why #4 :

Why #5 :

") containment_action_of_nc = fields.Html(string="Containment Action to close the Non-Conformities") comments_on_capa = fields.Html(string="Comments on Corrective / Preventive Action ") qa_comments=fields.Text(string="QA Comments") @@ -104,6 +105,14 @@ class NCMR_Model(models.Model): rework_rd_approval_by = fields.Many2one('res.users',string='Rework - R&D In-Charge',readonly=True) rework_rd_approval_sign = fields.Image(related="rework_rd_approval_by.signature_image",string='Rework - R&D In-Charge',readonly=True) rework_rd_approval_on = fields.Datetime(string="Approved On") + + responsible_department = fields.Many2one('sos_departments', string='Department') + responsible_name = fields.Many2one('res.users',string='Responsible Person',domain="[('id', 'in', allowed_user_ids)]") + allowed_user_ids = fields.Many2many('res.users', compute='_compute_allowed_users') + rca_responsible_department = fields.Many2many('sos_departments', string='Department') + rca_responsible_name = fields.Many2many('res.users',string='Responsible Person',relation='sos_ncmr_rca_responsible_name_rel',domain="[('id', 'in', rca_allowed_user_ids)]") + rca_allowed_user_ids = fields.Many2many('res.users', compute='_rca_compute_allowed_users') + combined_incoming_doc_ref = fields.Reference( selection=[ @@ -120,8 +129,155 @@ class NCMR_Model(models.Model): supplier_name = fields.Many2one('sos_suppliers',string="Supplier Name",compute="_get_supplier_name") service_provider_name = fields.Many2one('sos_service_providers',string="Service Provider Name",compute="_get_service_provider_name") customer_name = fields.Many2one('sos_inventory_customers', string="Customer Name",compute="_get_customer_name") - outsourcing_return_ref_no = fields.Many2one('sos_sfg_outsourcing_return_register',string="Outsourcing Return Ref No") + + problem_description_line_ids = fields.One2many('sos_ncmr_problem_description_line', 'ncmr_id', string="Problem Description Line Ids",copy=True) + + @api.depends('responsible_department') + def _compute_allowed_users(self): + for rec in self: + rec.allowed_user_ids = rec.responsible_department.users_line_ids.mapped('users') + + @api.depends('rca_responsible_department') + def _rca_compute_allowed_users(self): + for rec in self: + rec.rca_allowed_user_ids = rec.rca_responsible_department.users_line_ids.mapped('users') + + @api.model + def get_service_suppliers_by_goods_type(self,goods_type=False,startDate=False, endDate=False): + + if goods_type == 'Material': + + query = """ + SELECT id,supplier_name + FROM sos_suppliers + WHERE id IN ( + SELECT b.supplier_name + FROM sos_ncmr a, sos_iqi b + WHERE a.incoming_doc_ref = b.id + AND a.material_option = 't' + AND a.ncmr_date BETWEEN %s AND %s + ) + """ + elif goods_type == 'SFG': + + query = """ + SELECT id,service_provider_name + FROM sos_service_providers + WHERE id IN ( + SELECT b.service_provider_name + FROM sos_ncmr a, sos_iqi b + WHERE a.incoming_doc_ref = b.id + AND a.sfg_option = 't' + AND a.ncmr_date BETWEEN %s AND %s + ) + """ + + self.env.cr.execute(query,(startDate, endDate)) + rows = self.env.cr.fetchall() + result = [{'id': '', 'supplier_name': 'Select Supplier/Service'}] + result += [{'id': row[0], 'supplier_name': row[1]} for row in rows] + + return result + + + @api.model + def get_pareto_data(self, start_date=False, end_date=False, goodstype=False, categoryId=False, servicesupplier=False): + + if not start_date or not end_date: + raise ValueError("Start date and end date must be provided.") + + base_where_clause = "a.ncmr_date BETWEEN %s AND %s" + where_params = [start_date, end_date] + base_groupby_clause = "d.name" + + if goodstype == 'Material': + join_clause = """ + JOIN sos_material_defective_line_sos_ncmr_line_rel c ON b.id = c.sos_ncmr_line_id + JOIN sos_material_defective_line d ON c.sos_material_defective_line_id = d.id + JOIN sos_material_configuration e ON a.material_category = e.id + """ + if categoryId and categoryId != 'Select Category': + join_clause += " JOIN sos_material f ON a.material_name = f.id JOIN sos_material_types g ON f.material_type_id = g.id" + base_where_clause += " AND g.name = %s" + #base_groupby_clause += ",g.name" + where_params.append(categoryId) + + if servicesupplier and servicesupplier !='Select Supplier/Service' and servicesupplier !='undefined': + join_clause += " LEFT JOIN sos_iqi h ON a.incoming_doc_ref = h.id LEFT JOIN sos_suppliers i ON h.supplier_name = i.id" + base_where_clause += " AND h.supplier_name = %s" + base_groupby_clause += ",h.supplier_name" + where_params.append(servicesupplier) + + elif goodstype == 'SFG': + join_clause = """ + JOIN sos_ncmr_line_sos_sfg_defective_line_rel c ON b.id = c.sos_ncmr_line_id + JOIN sos_sfg_defective_line d ON c.sos_sfg_defective_line_id = d.id + JOIN sos_sfg_configuration e ON a.sfg_category = e.id + """ + if categoryId and categoryId != 'Select Category': + join_clause += " JOIN sos_sfg f ON a.sfg_name = f.id" + base_where_clause += " AND f.category = %s" + base_groupby_clause += ",f.category" + where_params.append(categoryId) + + if servicesupplier and servicesupplier !='Select Supplier/Service' and servicesupplier !='undefined': + join_clause += " LEFT JOIN sos_iqi g ON a.incoming_doc_ref = g.id LEFT JOIN sos_service_providers h ON g.service_provider_name = h.id" + base_where_clause += " AND g.service_provider_name = %s" + base_groupby_clause += ",g.service_provider_name" + where_params.append(servicesupplier) + + elif goodstype == 'FG': + join_clause = """ + JOIN sos_defectives_sos_ncmr_line_rel c ON b.id = c.sos_ncmr_line_id + JOIN sos_defectives d ON c.sos_defectives_id = d.id + JOIN sos_testing_parameters f ON a.fg_category = f.id + JOIN sos_fg e ON e.id = f.fg_name + """ + + if categoryId and categoryId != 'Select Category': + base_where_clause += " AND e.fg_type = %s" + base_groupby_clause += ",e.fg_type" + where_params.append(categoryId) + + # Build the full SQL query dynamically + + query = f""" + SELECT + defect_name, + count, + ROUND(count * 100.0 / total, 2) AS individual_percent, + ROUND(SUM(count) OVER (ORDER BY count DESC ROWS UNBOUNDED PRECEDING) * 100.0 / total, 2) AS cumulative_percent + FROM ( + SELECT + d.name AS defect_name, + COUNT(*) AS count, + SUM(COUNT(*)) OVER () AS total + FROM + sos_ncmr a + JOIN sos_ncmr_line b ON a.id = b.ncmr_id + {join_clause} + WHERE + {base_where_clause} + GROUP BY + {base_groupby_clause} + ) AS sub + ORDER BY + count DESC; + """ + + self.env.cr.execute(query, tuple(where_params)) + result = self.env.cr.fetchall() + + data = [] + for row in result: + data.append({ + 'defect_name': row[0], # defect_name + 'count': row[1], # count + 'cumulative_percent': row[3], # cumulative_percent + }) + + return data #Excel Write def action_ncmr_report_orm_btn(self, from_date, to_date,force_download=True): output = io.BytesIO() @@ -559,17 +715,18 @@ class NCMR_Model(models.Model): 'sos_inventory.sos_qa_user' ) else: - if all_closed or record.aodr_no: self.status = 'closed' if self.rework_action == "inhouse": + s_no_list = self.line_ids.mapped('s_no') # Collect all s_no values + s_no_str = ', '.join(map(str, s_no_list)) iqi_record = self.env['sos_iqi'].create({ 'iqi_no': send_email.generate_sequence('sos_iqi', 'R-IQI', 'iqi_no'), 'material_option':self.material_option, 'sfg_option':self.sfg_option, 'received_qty': self.rejected_qty, 'iqi_type':'rework', - 'material_name': self.material_name, + 'material_name': self.material_name.id, 'material_code': self.material_name.material_code, 'sfg_name': self.sfg_name.id, 'sfg_code': self.sfg_name.sfg_code, @@ -577,7 +734,9 @@ class NCMR_Model(models.Model): 'service_provider_name':self.incoming_doc_ref.service_provider_name.id, 'old_iqi_ref': self.incoming_doc_ref.id, 'ir_id_unique_id':self.incoming_doc_ref.ir_id_unique_id.id, - 'in_tact':self.incoming_doc_ref.in_tact + 'in_tact':self.incoming_doc_ref.in_tact, + 'ncmr_ref':self.id, + 'serial_no':s_no_str # 'test_report':self.incoming_doc_ref.test_report, # 'test_report_no':self.incoming_doc_ref.test_report_no, # 'test_report_doc':self.incoming_doc_ref.test_report_doc, @@ -585,7 +744,7 @@ class NCMR_Model(models.Model): }) - + print(iqi_record) # Rework Iteration starts sos_record = self.env['sos_iqi'].search([('id', '=', self.incoming_doc_ref.id)], limit=1) if sos_record: @@ -622,7 +781,27 @@ class NCMR_Model(models.Model): 'sos_inventory.sos_scg_group_user' ) if self.rework_action == "inhouse": - # Email part + if self.material_option: + orr_record = self.env['sos_sfg_outsourcing_return_register'].create({ + 'orr_no': orr_no, + 'iqi_no':self.incoming_doc_ref.id, + 'iqi_date':self.incoming_doc_ref.iqi_date, + 'material_name':self.incoming_doc_ref.material_name, + 'goods_type':'Materials', + 'returned_qty':self.incoming_doc_ref.rejected_qty, + 'rework_type':'inhouse' + }) + else: + orr_record = self.env['sos_sfg_outsourcing_return_register'].create({ + 'orr_no': orr_no, + 'iqi_no':self.incoming_doc_ref.id, + 'iqi_date':self.incoming_doc_ref.iqi_date, + 'sfg_name':self.incoming_doc_ref.sfg_name, + 'goods_type':'SFG', + 'returned_qty':self.incoming_doc_ref.rejected_qty, + 'rework_type':'inhouse' + }) + self.outsourcing_return_ref_no = orr_record.id body_html = f"""

Below NCMR is waiting for your Action

""" @@ -636,7 +815,8 @@ class NCMR_Model(models.Model): 'material_name':self.incoming_doc_ref.material_name, 'supplier_name':self.incoming_doc_ref.supplier_name.id, 'goods_type':'Materials', - 'returned_qty':self.incoming_doc_ref.rejected_qty + 'returned_qty':self.incoming_doc_ref.rejected_qty, + 'rework_type':'outsourcing' }) else: if self.material_option: @@ -647,7 +827,8 @@ class NCMR_Model(models.Model): 'material_name':self.incoming_doc_ref.material_name, 'supplier_name':self.incoming_doc_ref.supplier_name.id, 'goods_type':'Materials', - 'returned_qty':self.incoming_doc_ref.rejected_qty + 'returned_qty':self.incoming_doc_ref.rejected_qty, + 'rework_type':'outsourcing' }) else: orr_record = self.env['sos_sfg_outsourcing_return_register'].create({ @@ -657,7 +838,8 @@ class NCMR_Model(models.Model): 'service_provider_name':self.incoming_doc_ref.service_provider_name, 'sfg_name':self.incoming_doc_ref.sfg_name, 'goods_type':'SFG', - 'returned_qty':self.incoming_doc_ref.rejected_qty + 'returned_qty':self.incoming_doc_ref.rejected_qty, + 'rework_type':'outsourcing' }) self.outsourcing_return_ref_no = orr_record.id @@ -685,6 +867,26 @@ class NCMR_Model(models.Model): ) def action_qa_esign_btn(self): + if self.responsible_department: + if self.material_option: + material = self.material_name.part_no + elif self.sfg_option: + material = self.sfg_name.name + else: + material = self.fg_name.name + result_col = f"NCMR Ref No :{getattr(self, 'ncmr_no', '')}" + + new_action_record = self.env['sos_brm_action'].create({ + 'cross_dept_action': 'cross_dept', + 'department': 3, + 'responsible_person': getattr(self.responsible_name, 'id', False), + 'assigned_by': getattr(self.qa_by, 'id', False), + 'assigned_from_dept': 3, + 'assigned_to_dept': getattr(self.responsible_department, 'id', False), + 'name': f"NCMR Assigned : {material}", + 'result': result_col + }) + if self.action_group: sequence_util = self.env['sos_common_scripts'] sequence_util.action_assign_signature( @@ -767,8 +969,9 @@ class NCMR_Model_CAPA_Line(models.Model): ncmr_id = fields.Many2one('sos_ncmr', string="NCMR Reference", ondelete="cascade") issue = fields.Char(string="Issue") - corrective_action = fields.Html(string="Corrective Action") - preventive_action = fields.Html(string="Preventive Action") + corrective_action = fields.Html(string="D5: Permanent Corrective Action") + implement_validate_corrective_action = fields.Html(string="D6:Implement & Validate Corrective Actions") + preventive_action = fields.Html(string="D7:Preventive Recurrence") class NCMR_Model_Line(models.Model): _name = 'sos_ncmr_line' @@ -897,3 +1100,18 @@ class NCMR_Model_Line(models.Model): def _compute_fg_defective_count(self): for record in self: record.fg_defective_count = len(record.fg_defectives) + +class NCMR_Model_PROBLEM_DESCRIPTION_Line(models.Model): + _name = 'sos_ncmr_problem_description_line' + _description = 'Problem Description Lines' + + ncmr_id = fields.Many2one('sos_ncmr', string="NCMR Reference", ondelete="cascade") + clear_statement = fields.Html(string="Clear Statement") + photos = fields.Html(string="Photos") + what = fields.Text(string="What") + where = fields.Text(string="Where") + when = fields.Text(string="When") + why = fields.Text(string="Why") + who = fields.Text(string="Who") + how = fields.Text(string="How") + how_many = fields.Text(string="How many") \ No newline at end of file diff --git a/sos_inventory/models/sos_order_delivery_plan.py b/sos_inventory/models/sos_order_delivery_plan.py index 1bcf6ec..17be091 100755 --- a/sos_inventory/models/sos_order_delivery_plan.py +++ b/sos_inventory/models/sos_order_delivery_plan.py @@ -182,7 +182,7 @@ class SOS_Order_Delivery_Plan(models.Model):

Below Order Delivery Plan is waiting for your Approval

""" send_email = self.env['sos_common_scripts'] - send_email.send_direct_email(self.env,"sos_order_delivery_plan",self.id,"ramachandran.r@sosaley.in","Order Delivery Plan",body_html) + send_email.send_direct_email(self.env,"sos_order_delivery_plan",self.id,"ramachandran.r@sosaley.com","Order Delivery Plan",body_html) # Email part ends sequence_util = self.env['sos_common_scripts'] return sequence_util.action_assign_signature( diff --git a/sos_inventory/models/sos_outsourcing_vendor_monitoring_register.py b/sos_inventory/models/sos_outsourcing_vendor_monitoring_register.py index d06a4b8..e5e1c94 100755 --- a/sos_inventory/models/sos_outsourcing_vendor_monitoring_register.py +++ b/sos_inventory/models/sos_outsourcing_vendor_monitoring_register.py @@ -36,12 +36,25 @@ class SOS_Oursourcing_Monitor_Lines(models.Model): rejection_percentage = fields.Float(string="Rejected Percentage", compute="_compute_rejected_percentage", store=True) rejection_percentage_display = fields.Char('Rejection Percentage', compute='_compute_rejected_percentage_display') ppm = fields.Integer(string="PPM",compute="_compute_ppm") - - quality_marks = fields.Float(string="Quality Marks") + quality_marks = fields.Float(string="Quality Marks",compute="_compute_sfgquality") delivery_marks = fields.Float(string="Delivery Marks") responsiveness_marks = fields.Float(string="Responsiveness Marks") report_marks = fields.Float(string="Report Marks") + def _calculate_quality_marks(self, received, rejected): + if received != 0: + q = 100 - ((rejected / received) * 100) + if 91 <= q <= 100: + return 30 + elif 80 <= q <= 90: + return 25 + else: + return 10 + return 0 + @api.depends('received_qty', 'rejected_qty') + def _compute_sfgquality(self): + for record in self: + record.quality_marks = self._calculate_quality_marks(record.received_qty, record.rejected_qty) @api.depends('rejection_percentage') def _compute_rejected_percentage_display(self): for record in self: diff --git a/sos_inventory/models/sos_po.py b/sos_inventory/models/sos_po.py index d4b3849..3c21e00 100755 --- a/sos_inventory/models/sos_po.py +++ b/sos_inventory/models/sos_po.py @@ -143,7 +143,7 @@ class sos__po(models.Model): """ subject = f"Purchase Order Approval Request - {self.po_no}" send_email = self.env['sos_common_scripts'] - send_email.send_direct_email(self.env,"sos_po",self.id,"ramachandran.r@sosaley.in",subject,body_html) + send_email.send_direct_email(self.env,"sos_po",self.id,"ramachandran.r@sosaley.com",subject,body_html) # Email part ends sequence_util = self.env['sos_common_scripts'] return sequence_util.action_assign_signature( diff --git a/sos_inventory/models/sos_prf.py b/sos_inventory/models/sos_prf.py new file mode 100755 index 0000000..2e05e1d --- /dev/null +++ b/sos_inventory/models/sos_prf.py @@ -0,0 +1,79 @@ +from odoo import models, fields, api + +class SOS_prf(models.Model): + _name = 'sos_prf' + _description = 'Purchase Requisition Form' + _rec_name = 'prf_no' + _order = 'id desc' + + prf_no = fields.Char(string="PRF No", readonly= True, required= True, default=lambda self: self._generate_id()) + prf_date = fields.Date(string="PRF Date", required=True, default=fields.Date.today) + line_ids = fields.One2many('sos_prf_lines', 'ref_id', string="PRF Lines",copy=True) + requested_by_name = fields.Many2one('res.users', string='Requested by') + requested_by_image = fields.Image(related="requested_by_name.signature_image",string='Requested by Sign',readonly=True) + requested_on = fields.Datetime(string="Requested On") + dept_in_charge_name = fields.Many2one('res.users', string='Department In-Charge') + dept_in_charge_image = fields.Image(related="dept_in_charge_name.signature_image",string='Department In-Charge Sign',readonly=True) + dept_in_charge_approved_on = fields.Datetime(string="Approved On") + top_management_name = fields.Many2one('res.users', string='Top Management Approver') + top_management_approval_image = fields.Image(related="top_management_name.signature_image",string='Top Management Approval',readonly=True) + top_management_approved_on = fields.Datetime(string="Approved On") + status = fields.Selection([('open', 'Open'),('close', 'Closed')], default='open' , string="Status") + + def action_top_esign_btn(self): + sequence_util = self.env['sos_common_scripts'] + subject = f"PRF Approved - {self.prf_no}" + body_html = f""" +

Below PRF got approved

+ """ + sequence_util.send_direct_email(self.env,"sos_prf",self.id,"praveenkumar.m@sosaley.com",subject,body_html) + sequence_util.action_assign_signature( + self, + 'top_management_name', + 'top_management_approved_on', + 'sos_inventory.sos_management_user' + ) + def action_dept_esign_btn(self): + # Email part + body_html = f""" +

Below PRF is waiting for your Approval

+ """ + sequence_util = self.env['sos_common_scripts'] + subject = f"PRF Approval Request - {self.prf_no}" + sequence_util.send_direct_email(self.env,"sos_prf",self.id,"ramachandran.r@sosaley.com",subject,body_html) + # Email part ends + sequence_util.action_assign_signature( + self, + 'dept_in_charge_name', + 'dept_in_charge_approved_on', + 'sos_inventory.sos_scg_group_manager' + ) + def action_stores_esign_btn(self): + # Email part + body_html = f""" +

Below PRF is waiting for your Approval

+ """ + sequence_util = self.env['sos_common_scripts'] + sequence_util.send_group_email(self.env,'sos_prf',self.id,"deenalaura.m@sosaley.in","PRF Approval Request",body_html,'sos_inventory.sos_scg_group_manager') + # Email part ends + sequence_util.action_assign_signature( + self, + 'requested_by_name', + 'requested_on', + 'sos_inventory.sos_scg_group_user' + ) + def _generate_id(self): + sequence_util = self.env['sos_common_scripts'] + return sequence_util.generate_sequence('sos_prf','PRF', 'prf_no') + +class SOS_prf_Lines(models.Model): + _name = 'sos_prf_lines' + _description = 'Purchase Requisition Form Lines' + + ref_id = fields.Many2one('sos_prf', string="PRF", ondelete="cascade") + com_type = fields.Selection([('exits', 'In-stock'),('new', 'New')], string="Availability", default='exits') + component_id = fields.Many2one('sos_material', string="Material Name") + new_component_id = fields.Char(string="New Part No") + qty = fields.Integer(string="Required Qty") + req_date = fields.Date(string="Required Date") + mon_ref_no = fields.Many2one('sos_mon',string="MON Ref No") diff --git a/sos_inventory/models/sos_quote_generation.py b/sos_inventory/models/sos_quote_generation.py index 66825a5..d01b68b 100755 --- a/sos_inventory/models/sos_quote_generation.py +++ b/sos_inventory/models/sos_quote_generation.py @@ -68,35 +68,35 @@ class SOS_Quote_Generation(models.Model): supplier_dict = {} for record in self.line_ids: - if record.supplier1_name: - supplier = record.supplier1_name + if record.final_supplier1_name: + supplier = record.final_supplier1_name if supplier not in supplier_dict: supplier_dict[supplier] = [] supplier_dict[supplier].append({ 'name': record.material_name, - 'product_qty': record.supplier1_qty, - 'price_unit': record.supplier1_quoted_price + 'product_qty': record.final_supplier1_qty, + 'price_unit': record.final_supplier1_quoted_price }) - if record.supplier2_name: - supplier = record.supplier2_name - if supplier not in supplier_dict: - supplier_dict[supplier] = [] - supplier_dict[supplier].append({ - 'name': record.material_name, - 'product_qty': record.supplier2_qty, - 'price_unit': record.supplier2_quoted_price - }) + # if record.supplier2_name: + # supplier = record.supplier2_name + # if supplier not in supplier_dict: + # supplier_dict[supplier] = [] + # supplier_dict[supplier].append({ + # 'name': record.material_name, + # 'product_qty': record.supplier2_qty, + # 'price_unit': record.supplier2_quoted_price + # }) - if record.supplier3_name: - supplier = record.supplier3_name - if supplier not in supplier_dict: - supplier_dict[supplier] = [] - supplier_dict[supplier].append({ - 'name': record.material_name, - 'product_qty': record.supplier3_qty, - 'price_unit': record.supplier3_quoted_price - }) + # if record.supplier3_name: + # supplier = record.supplier3_name + # if supplier not in supplier_dict: + # supplier_dict[supplier] = [] + # supplier_dict[supplier].append({ + # 'name': record.material_name, + # 'product_qty': record.supplier3_qty, + # 'price_unit': record.supplier3_quoted_price + # }) for x, y in supplier_dict.items(): sequence_util = self.env['sos_common_scripts'] po_no = sequence_util.generate_sequence('sos_po','PO', 'po_no') @@ -111,6 +111,7 @@ class SOS_Quote_Generation(models.Model): 'quantity': components['product_qty'],'unit_price': components['price_unit'], 'total_price': components['product_qty'] * components['price_unit'] }) message = 'Purchase Order(s) successfully generated.' + return { 'type': 'ir.actions.client', diff --git a/sos_inventory/models/sos_sales_order.py b/sos_inventory/models/sos_sales_order.py index 3ee5d5b..6215783 100755 --- a/sos_inventory/models/sos_sales_order.py +++ b/sos_inventory/models/sos_sales_order.py @@ -26,6 +26,7 @@ class SOS_SalesOrder(models.Model): string="Product Name",required=True) line_ids = fields.One2many('sos_sales_order_line', 'ref_id',copy=True) customer_name = fields.Many2one('sos_inventory_customers',string="Customer Name") + customer_location = fields.Char(string="Customer Location") lead_time = fields.Datetime(string="Lead Time") customer_po_no = fields.Char(string="PO No") customer_po_date = fields.Datetime(string="PO Date") diff --git a/sos_inventory/models/sos_sequence_generator.py b/sos_inventory/models/sos_sequence_generator.py index 4ec2559..f517455 100755 --- a/sos_inventory/models/sos_sequence_generator.py +++ b/sos_inventory/models/sos_sequence_generator.py @@ -106,7 +106,7 @@ class Sequence_Generator(models.AbstractModel): reporting_user = env['res.users'].search([('id', '=', users.reporting_to.id)]) # email_to = reporting_user.login else: - # email_to = "ramachandran.r@sosaley.in" + # email_to = "ramachandran.r@sosaley.com" print("test") mail_values = { 'subject': subject, diff --git a/sos_inventory/models/sos_service_call_log_report.py b/sos_inventory/models/sos_service_call_log_report.py index 30c4d51..0857698 100755 --- a/sos_inventory/models/sos_service_call_log_report.py +++ b/sos_inventory/models/sos_service_call_log_report.py @@ -23,7 +23,17 @@ class SOS_Service_Call_Log_Report(models.Model): action_taken = fields.Text(string="Action taken or required action to be taken") Date_of_action_Completed = fields.Datetime(string="Date of action completed") status = fields.Selection([('open', 'Open'),('close', 'Closed')], default='open' , string="Status") - + dock_audit_ref_no = fields.Many2one('sos_dock_audit',string="Dock Audit Ref No") + warranty = fields.Integer(string="Warranty(In Months)") + invoice_no = fields.Char(string="Invoice No") + invoice_date = fields.Date(string="Invoice Date") + + @api.onchange('dock_audit_ref_no') + def _onchange_dock_audit_ref_no(self): + if self.dock_audit_ref_no: + self.warranty = self.dock_audit_ref_no.warranty + self.invoice_no = self.dock_audit_ref_no.invoice_no + self.invoice_date = self.dock_audit_ref_no.invoice_date def _generate_id(self): sequence_util = self.env['sos_common_scripts'] return sequence_util.generate_sequence('sos_service_call_log_report','SCLR', 'ref_no') \ No newline at end of file diff --git a/sos_inventory/models/sos_sfg.py b/sos_inventory/models/sos_sfg.py index 88b25b8..cf54fd8 100755 --- a/sos_inventory/models/sos_sfg.py +++ b/sos_inventory/models/sos_sfg.py @@ -111,6 +111,6 @@ class SOS_SFG_Line(models.Model): ir_no = fields.Many2one('sos_ir', string="Material Inward Ref No") min_no = fields.Many2one('sos_min', string="Material Issue Ref No") mrn_no = fields.Many2one('sos_mrn', string="Material Return Ref No") - iqi_no = fields.Many2one('sos_iqi', string="In-house Inspection Ref No") + iqi_no = fields.Many2one('sos_iqi', string="IQI Ref No") diff --git a/sos_inventory/models/sos_sfg_outsourcing_return_register.py b/sos_inventory/models/sos_sfg_outsourcing_return_register.py index 504fd7b..11ce688 100755 --- a/sos_inventory/models/sos_sfg_outsourcing_return_register.py +++ b/sos_inventory/models/sos_sfg_outsourcing_return_register.py @@ -22,6 +22,10 @@ class sos_Outsourcing_Return(models.Model): material_name = fields.Many2one('sos_material',string="Material Name",related="iqi_no.material_name") returned_qty = fields.Integer(string="Returned Quantity",related="iqi_no.rejected_qty") remarks = fields.Text(string="Remarks") + rework_type = fields.Selection([ + ('outsourcing', 'Out-Sourcing'), + ('inhouse', 'In-House') + ], string='Rework Type',default="outsourcing",copy=True) def _generate_id(self): sequence_util = self.env['sos_common_scripts'] return sequence_util.generate_sequence('sos_sfg_outsourcing_return_register','ORR', 'orr_no') diff --git a/sos_inventory/models/sos_wo.py b/sos_inventory/models/sos_wo.py index b3f4610..0fabd85 100755 --- a/sos_inventory/models/sos_wo.py +++ b/sos_inventory/models/sos_wo.py @@ -138,7 +138,7 @@ class sos__wo(models.Model): """ subject = f"Work Order Approval Request - {self.wo_no}" send_email = self.env['sos_common_scripts'] - send_email.send_direct_email(self.env,"sos_wo",self.id,"ramachandran.r@sosaley.in",subject,body_html) + send_email.send_direct_email(self.env,"sos_wo",self.id,"ramachandran.r@sosaley.com",subject,body_html) # Email part ends sequence_util = self.env['sos_common_scripts'] return sequence_util.action_assign_signature( diff --git a/sos_inventory/report/Unconfirmed 666526.crdownload b/sos_inventory/report/Unconfirmed 666526.crdownload new file mode 100755 index 0000000..e69de29 diff --git a/sos_inventory/report/sos_boq_labels.xml b/sos_inventory/report/sos_boq_labels.xml index c7a8ea7..6de0995 100755 --- a/sos_inventory/report/sos_boq_labels.xml +++ b/sos_inventory/report/sos_boq_labels.xml @@ -9,269 +9,296 @@ report -