From 590d716eec5664f5ce4cc6b947c9ebe063774805 Mon Sep 17 00:00:00 2001 From: Deena Date: Thu, 24 Jul 2025 18:23:58 +0530 Subject: [PATCH] Fix for Issue #2 --- sos_installation_commision/__manifest__.py | 1 + .../sos_travel_plan.cpython-310.pyc | Bin 6056 -> 6131 bytes .../models/sos_travel_plan.py | 1 + .../security/record_rules.xml | 34 ++ sos_installation_commision/views/menu.xml | 16 +- .../views/sos_travel_plan_view.xml | 2 +- sos_inventory/__manifest__.py | 1 + sos_inventory/models/__init__.py | 3 +- .../__pycache__/__init__.cpython-310.pyc | Bin 2462 -> 2526 bytes .../sos_common_scripts.cpython-310.pyc | Bin 7598 -> 7624 bytes .../sos_dock_audit.cpython-310.pyc | Bin 21160 -> 20128 bytes .../__pycache__/sos_fg_bom.cpython-310.pyc | Bin 6455 -> 6470 bytes .../__pycache__/sos_material.cpython-310.pyc | Bin 4702 -> 5118 bytes .../__pycache__/sos_min.cpython-310.pyc | Bin 17307 -> 17316 bytes .../__pycache__/sos_mrn.cpython-310.pyc | Bin 11694 -> 12326 bytes .../sos_return_fir.cpython-310.pyc | Bin 8486 -> 8507 bytes .../__pycache__/sos_sfg.cpython-310.pyc | Bin 4225 -> 4627 bytes .../__pycache__/sos_sfg_bom.cpython-310.pyc | Bin 6174 -> 6537 bytes .../sos_sfg_quote_generation.cpython-310.pyc | Bin 6800 -> 7125 bytes .../sos_transfer_challan.cpython-310.pyc | Bin 8649 -> 8670 bytes .../models/__pycache__/sos_wo.cpython-310.pyc | Bin 9657 -> 10268 bytes sos_inventory/models/sos_common_scripts.py | 3 +- sos_inventory/models/sos_dock_audit.py | 203 +++---- sos_inventory/models/sos_fg_bom.py | 1 + sos_inventory/models/sos_material.py | 12 + sos_inventory/models/sos_min.py | 4 +- sos_inventory/models/sos_mrn.py | 39 +- sos_inventory/models/sos_return_fir.py | 2 + sos_inventory/models/sos_sfg.py | 12 +- sos_inventory/models/sos_sfg_bom.py | 30 +- .../models/sos_sfg_quote_generation.py | 7 + sos_inventory/models/sos_transfer_challan.py | 4 +- ...s_transfer_challan_return_from_customer.py | 81 +++ sos_inventory/models/sos_wo.py | 25 +- sos_inventory/security/ir.model.access.csv | 3 + sos_inventory/views/sos_dock_audit_view.xml | 2 +- .../views/sos_sfg_quote_generation.xml | 2 +- ...sfer_challan_return_from_customer_view.xml | 115 ++++ .../views/sos_transfer_challan_view.xml | 4 +- sos_inventory/views/sos_wo_view.xml | 18 +- .../sos_case_diary.cpython-310.pyc | Bin 21963 -> 20032 bytes .../sos_proposal_boq.cpython-310.pyc | Bin 43261 -> 52165 bytes .../sos_proposal_builder.cpython-310.pyc | Bin 10252 -> 11083 bytes ...posal_customer_requirement.cpython-310.pyc | Bin 7506 -> 7506 bytes ...s_sales_achievement_report.cpython-310.pyc | Bin 16206 -> 23335 bytes .../sos_sales_action_plan.cpython-310.pyc | Bin 11331 -> 11557 bytes sos_sales/models/sos_case_diary.py | 74 --- sos_sales/models/sos_proposal_boq.py | 265 ++++++++- sos_sales/models/sos_proposal_builder.py | 28 +- .../sos_proposal_customer_requirement.py | 4 +- .../models/sos_sales_achievement_report.py | 339 ++++++++++- sos_sales/models/sos_sales_action_plan.py | 38 +- sos_sales/report/sos_proposal_report_view.xml | 20 +- sos_sales/security/ir.model.access.csv | 6 + sos_sales/security/record_rules.xml | 25 +- sos_sales/views/menu.xml | 2 +- sos_sales/views/sos_case_diary_view.xml | 33 +- sos_sales/views/sos_customers_view.xml | 2 +- sos_sales/views/sos_proposal_boq_view.xml | 541 ++++++++++++++++++ .../sos_sales_achievement_report_view.xml | 4 +- .../views/sos_sales_action_plan_view.xml | 4 +- sos_sales/views/sos_sales_leads_view.xml | 2 +- sos_sales/views/sos_sales_plan_view.xml | 2 +- sos_sales/views/sos_vertical_domain_view.xml | 2 +- .../sos_sales_achievement_wizard_view.xml | 131 ++++- 65 files changed, 1816 insertions(+), 331 deletions(-) create mode 100644 sos_installation_commision/security/record_rules.xml create mode 100755 sos_inventory/models/sos_transfer_challan_return_from_customer.py create mode 100755 sos_inventory/views/sos_transfer_challan_return_from_customer_view.xml diff --git a/sos_installation_commision/__manifest__.py b/sos_installation_commision/__manifest__.py index b423c71..fb123d5 100755 --- a/sos_installation_commision/__manifest__.py +++ b/sos_installation_commision/__manifest__.py @@ -23,6 +23,7 @@ # always loaded 'data': [ 'security/ir.model.access.csv', + 'security/record_rules.xml', 'views/menu.xml', 'views/sos_travel_plan_view.xml', 'views/sos_travel_reimbursement_bills_view.xml', diff --git a/sos_installation_commision/models/__pycache__/sos_travel_plan.cpython-310.pyc b/sos_installation_commision/models/__pycache__/sos_travel_plan.cpython-310.pyc index 6cde4b9e337e7c203a62b3b77406935e3d365e59..7db9c07713262a13c3c40d5ee98821fdca3ba35a 100644 GIT binary patch delta 455 zcmYk2IZFdU7>4t$hLt2kM53v3pPOShho&$Hibta&Xd!N4jC@Npn1f|OwAn%t1XG0h z6IM23VQ*t)BUsp4S=*#^9Jbi0p7)(+z8U6G`_;&R5TA#y?Sy?c8Iv1O$K#0|z%WKJ zg0az*9x>!@6yumcFD7}8@f^n#`bVHAIRCq8o+Ldf%nW87GvzYVj+ql?Mwoe295d@O zbB1h-p#`Dlg<8atqbe@7z`2NJ@stv0AF8NzB&>*&W!|V*6}uYe8LSDeh`uhkD*8pi zHC)2Rtw*mTwWVqRH#jfj=7C4qV$ag&v>F+j#;|P~*gCyx_1ir|<#}LQ=lxF08Yt42 zY#JAB%RrOxAEozl!)vOX*qeMQ!5Urly~7R-`aj^1efy69bhbiX0ZteMcL92AZ}wP% jYxXo}0X)!DXdRlY6WRw7a9_k;<|_bQ`m@la$?)AD9qoVm delta 390 zcmeyYze1lkpO=@50SFdUI%afDg`Dy=;nHihK%dib5}Qlw2x%mVAn03U@DK zlmd{=lOmp?1mrPADFS)2Dat7-P?btZDwUxsRlzD%z$(>J)S)U>kyNTdRce4$s)JP4 zr)Z{VL6vGCDb)nBwNkXfPSFOkxl(jebkmtq^uStmfFimn`e0c-Ae$q_0L<10iyMO3 z24Ha`FxxQ2IK`xeA<8JlG{p=^8>g73SO960l*#=}nk>N#nl77wi zYEEKFYRYD2j&deOhso7k=NP>wdvRZ84BITn6UoRJxw(S(Fe799W*dHAM#h}YT>^1T ojFp>T3Y9Q2c2ABIab~pIyhtR7aWj*cJ|knsWFv9w$@$_f0123Cq5uE@ diff --git a/sos_installation_commision/models/sos_travel_plan.py b/sos_installation_commision/models/sos_travel_plan.py index 59b44e9..312c99e 100755 --- a/sos_installation_commision/models/sos_travel_plan.py +++ b/sos_installation_commision/models/sos_travel_plan.py @@ -44,6 +44,7 @@ class sos_travel_plan(models.Model): ] ) prepared_by_name = fields.Many2one('res.users', string='Prepared by') + reporting_to = fields.Many2one('res.users',related="prepared_by_name.reporting_to", string='Prepared by') prepared_by_image = fields.Image(related="prepared_by_name.signature_image",string='Prepared by Sign',readonly=True) prepared_on = fields.Datetime(string="Approved On") dept_in_charge_name = fields.Many2one('res.users', string='Department In-Charge') diff --git a/sos_installation_commision/security/record_rules.xml b/sos_installation_commision/security/record_rules.xml new file mode 100644 index 0000000..1e44a4d --- /dev/null +++ b/sos_installation_commision/security/record_rules.xml @@ -0,0 +1,34 @@ + + + + + Travel Plan: Own Records - Read Access + + [(1, '=', 1)] + + + + + + + + Travel Plan: All Records - Read Access + +[ +'|', +('create_uid', '=', user.id), +('reporting_to', '=', user.id) +] + + + + + + + + diff --git a/sos_installation_commision/views/menu.xml b/sos_installation_commision/views/menu.xml index 87f4134..98e1a4d 100755 --- a/sos_installation_commision/views/menu.xml +++ b/sos_installation_commision/views/menu.xml @@ -1,14 +1,10 @@ - - - - - - - - + + + + \ No newline at end of file diff --git a/sos_installation_commision/views/sos_travel_plan_view.xml b/sos_installation_commision/views/sos_travel_plan_view.xml index 8ddfd48..512fa6f 100755 --- a/sos_installation_commision/views/sos_travel_plan_view.xml +++ b/sos_installation_commision/views/sos_travel_plan_view.xml @@ -230,6 +230,6 @@ name="action_report_travel_plan"> Print + action="action_travel_plan_list" groups="sos_inventory.sos_ce_user,sos_inventory.sos_ce_head,sos_inventory.sos_finance_user,sos_inventory.sos_management_user,sos_inventory.sos_hr_user,sos_inventory.sos_sales_user,sos_inventory.sos_qc_user,sos_inventory.sos_production_user,sos_inventory.sos_qc_user,sos_inventory.sos_qa_user,sos_inventory.sos_rd_user"/> diff --git a/sos_inventory/__manifest__.py b/sos_inventory/__manifest__.py index f813946..c54744d 100755 --- a/sos_inventory/__manifest__.py +++ b/sos_inventory/__manifest__.py @@ -80,6 +80,7 @@ 'views/sos_serviceprovider_report.xml', 'views/sos_master_customer_property.xml', 'views/sos_service_call_log_report.xml', + 'views/sos_transfer_challan_return_from_customer_view.xml', 'wizard/sfg_bom_bulk_upload_view.xml', 'wizard/mon_bulk_upload_view.xml', 'wizard/missing_component_wizard.xml', diff --git a/sos_inventory/models/__init__.py b/sos_inventory/models/__init__.py index 104356e..fa11e2f 100755 --- a/sos_inventory/models/__init__.py +++ b/sos_inventory/models/__init__.py @@ -56,4 +56,5 @@ from . import sos_mat_outsourcing_vendor_register from . import sos_inventory_customers from . import sos_master_customer_property from . import sos_service_call_log_report -from . import sos_inhouse_validation_reports_files \ No newline at end of file +from . import sos_inhouse_validation_reports_files +from . import sos_transfer_challan_return_from_customer \ 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 e6a7e9cd70a532890ccc0660fc44c24940f5dbc8..95c81f28ab2dcd36bd6eb0b6c781d00049437179 100644 GIT binary patch delta 139 zcmbOyd{3A+pO=@50SJOLsxoRP^2#!v*r>gSNsuAMI)@?GI?9@nA;l(`LDP2g8>X!+ z2AYhwG>h|#<4cMX^NQ0_i{g_r5_57A^WuwAOG=CK;?s)qbK{dsi%arzQ;YmGZ8k4q nS7GEUvH@DKlA*{BNEO*lzQ_^EQU+vBHsH*e?7+#vB)|v&fAA?c delta 77 zcmca7JWrT6pO=@50SNl?k~3T<^2##q*{HpTiPbuoLDOdQ52mdw%zm2IoA0u#FmkSB eD6$2rEV7-<&l$>60%T4u;LMraz{$oWzz6^z;}c~7 diff --git a/sos_inventory/models/__pycache__/sos_common_scripts.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_common_scripts.cpython-310.pyc index 16e163da8536a1464554036bf46201742caf9d93..24caafa54341f99d2f86cbdae974c5e2e7bb3bdb 100644 GIT binary patch delta 336 zcmZ2yeZrbIpO=@50SG)z>oQU%^2##SP1LSqWeR4{NFqAM?>M}BbU=3pmSUeIaUJl{01Cuom?vu$jCJLyo{Jml|pc8 zVQFe!a%#MLYF=tlVo83HUTQ^2QDSmQd|6^nX{si(pP!#5qo1bW>HWd$)(c50=GD9a`RJ4b5iX$n6YZI5~Bg5 z$mC!~RYuXtm5fSkDeOQwvCV54JtVm_nf?6yG#ULg1tvSlR88J5Bg?2Z`L2w5Js)Ec z$n<0;kQGqC2BbNG*cph6vw%bjV=Yq+;{t{hriF~P%r(p|46&NEEHx}Z5oVwWYYAfw zYcpdCOEyc9UKLjjQwdWIYYK}bLo=f}LoHJ{Lm?*%LkV-GE+Yd7)-a`j#Up{@eC2R% zA!iNKX=Fd_Q`Yo%|u2pU%zoSm8U=ARrE*1ABbs`kM@>c5kd@D;8NM&`enB;3F~N!!lnoIlWE-2n zIwx17X&w{#C1sf}7Y#EfcH<9;cZ+?wdx#tz7Z%o%zp*3YA0@TysPL86j0=WKOPvtp zkBYCB9%0`WAC%VT9|6M+cpPw4l>4fk!jua88k|oM*l`G8Sz)!$M6V*dY_+DaLpiBg-%KdVe8`Qjr1usF(qR&u6f}cS61@V3$Fo!;}MB$CPV4%;T!9^F4 z8j3}x>YkQUQ1~oB9^Aptf_@p0of^V$X3K1@{!`8wnl@|)^gez{tO~AUy_vq?pmh^g z8Tm?2ETOBh$nL&KqDzUZ{JYrfI|Lm@&H*LMe-ixfV~snij>-N2yklZrUC{YWkdKIX zUESay$Oi%60Ng_mD&aDA_ktlKavrE5z(v4>R{kc26Uz7{3{5?t-U67qK>Z$&)i+GT zkb5jE4rdA${E~7jbLp0!Gq*IKlb;nw7PhdV%*BOXHYg3_+LY2&y0^5a;Yp+prW16* zRGPm=yBY3w%3D3rrSkL8wF|t0Xpg3+i4{qvql%tLr}%HA?6#Epg)Sx4$A1Ue*8#nN z-vZtsFp86j6j?8(MRXogQkoK#%YThI`(5fGou7m3D;T@Fdw6$RQ~9f6AQZ6wjCkV7 zP?b0rx_=PnH5{9y$FfF%+a}rb7=~E`!g;27vj&v*l-A~$9U?HiTNry|5! z{9;?vLxr+*oTj};$ExdL@j;X39D&Mbq|~8hp?q@)o=l*H;_R{_<`Zu$Yh$OyyPIqM zi%BKV!8SII-6kcP6wV8hz|#(h_4M>;bE! ztTEe&^#Plt?UJ^SOYrc3Wgm+<$}J~JHpa>=w8}By*k_B`e3tI|n3K4!W=qVi+b6io zWAlcY&l2A?^`vWnj&P@C)Vr0}(xLbWKmj}ha0BQf zW`!}>cEj>1YcvY0XMCAq;Gq&UyT9OkM{dLPnit zBTIk*y~aE(k%}i(P1U7h!-=w=(s?%|veg`mN9a5nYP-kotr167tgv69fmq&FG6>`H zzX0TAq|ZOZ@Hn877Vl1M3dAj6x7 zXA31yI5;JgR)!Zj3vr;Zh=y0*o(-FsB5P_W@oKD-!CnKZR=gcvB5Ut@XFV9>QF32P z$7e=~2b%A+(y9jWNy}2R?&fFXsc~XMS!?f>lEmv@BL3A96i>C5O{ujv5hbnIdCn-g zmz0@NV)OdF%rn2(TF4f&d~1I|OKXu>I=Vli^oT%P$<2q4`J$!pG4kj&97|~3Nu@7> z$FLbsG9g9~Ub0eU<7rwb^+5y=8nZy%F{MHwplIf%;;B`5+uK-cW_x=sV@!N~eMP-l zjj)sSyo?68pK3!PG*@A&TpV9tc{|kOXQQ9iN-*BlsP9>Mh3stBDV@zWU>oafKJoYU z4PV1uLe6Y^nUvu&x#6*peOg1|t8s)G68!{R=%FPZtDOnnv5dVuwXxG3roEtL^g3|A z=fyueHqPo=Sq0A0)`p`anO1ajA6X2f^Q4)i-=xc=kED099YT6XCep0EqK(e+I4Vz)TBxS!en%%xB{ACZDQ+o}ra= zjQhA88x%oG-V1$&rljX(49KZzh2bj@mrsE@td_5{0=@t=S_{t>i#%$lme=T-JVZo) zSe)++i3^)cKVSK{fQ1dBv9o24^5KD<-!dg%>D>Ci_LdDe_?%VakMI`yyvIflmRG;j zGHV1)Yb(;QGOFf$uuSSL*}%H-buvTl*N-24)@Z}+UJ$?9vW9J-AS)K`tq)eT; z!?jcGQuuytYsky55Ce~}3S|1EN7zJG@T=kvTWcye(rQ!#4POOri=Ek-$LeMIjBg|j zWtqBdZ?ahpBsY^^hcc~(pz2e=MZjMH|DTV=u~(YdztijFopfZkcw)z`tW#Xtv1`p0 v(qp*j`z}sjIEG`3{PJ-@`E`JNZM4Ej$W<-_1h?j$;=Y}24u9d!QuluW0rm8z delta 5679 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 J3%^k6`WF$bzK;L^ diff --git a/sos_inventory/models/__pycache__/sos_fg_bom.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_fg_bom.cpython-310.pyc index 35db6fdcd737ab4fa9e3b9abf592cabc17c3b4e4..18b37efc20837ef9724d9b3801e69ced1cebebc3 100644 GIT binary patch delta 215 zcmdmPbj*l1pO=@50SH!zHf1zzlLh%jCZFNH z!x%VuB~KNj-((fub=+YYI AfdBvi delta 194 zcmX?RwB3j|pO=@50SNl@k~2a!^6GQzDgk*l3@!|@JhhB9j9Cmo%qR{bnLuPbb0Jd- zLoh>;D^Qsx%j80Cxye(wRe9KeTn;8NMwb6oijx)iMJC_ozQY(Wc?VAwqwi#6-gVre zKm|n+K%&YLBtMBSmN95@9N%`v=*eRI`HT^h+xQnV#%$ISNMmG7**sBjF(V_(W>euK hOpH~Ve~F4SGB!;X5?{&KGkK5rA;!GP^%BPzV*u^{F|z;w diff --git a/sos_inventory/models/__pycache__/sos_material.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_material.cpython-310.pyc index 7a8bb9185abcc8724563f656b5110cc424daacbf..3db2d0196f50dbe9e88e014fac660b9835925166 100644 GIT binary patch delta 816 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 E00t*k6aWAK diff --git a/sos_inventory/models/__pycache__/sos_mrn.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_mrn.cpython-310.pyc index c85dc3cc5869a153f2b2b7a4f0b2d7785a940708..e6baf1ddfcbc29483f6f4012ab86c4f218043335 100644 GIT binary patch delta 3004 zcmbuBYitx%6vyYz&d$!xKDym5+uc5vQu^8!P>G^Z@l_%kwZ^n!h&JoGcPO*8v-IvD z(#*2r0~15Aa6gEqYHQ-7L`h6PsEA^s@rx!#e2)**#Q2sNABZA)&fONO_5*=7^WSst zJ?GqWe{*Jb_uTmS&EY~Qq)YJk$bl_u-@N*n@WE(RH4H;=b;DI`R`}6qvMl92)U!@z z9gdWjC`n2s;*fELD%4BW2~Wu*=9Q#0?sd>ssc%f4ASK0-S4g9z|C5r}@lp*k?1NR` z3aNi!RREF%X>BPa=8#y}36EEc zQ58nf1Wh_2S~uY%((u{CoxrDlojgj|D)5N{q0wnV4N0jyC!!;>5uFC1a~vORyQEUu z|2Wmqs8dF)CqUJJD*}(@=h4P74RO)b$(__uV5>fe7hr`wO;*@5Z0j8z##hYHEzga2 z_*K9r<>LTr&or$0bGH*DyYDn;l~sD8p{|=%{T{F-+9aSM6DeO?;c}c-0<0ulLApRR zR+WJLnTTsX4!fByq%9Mk<56{BVI&a7*fMP$!^a~++vddF>_kLEwa+vZV3rw{Q^Ab( z3}&=vFn2f+AoB-CizZIb)x@J@*jf#s$v8Ypw3BwxMH5P|lwRD!R>LcT^`SI?xane{ zn6X*bDy}hDCbu>_IGD9E%&<2wE3<|bhBCPgMY}L$FjwyDcD;5kV-?ae+layX5I8Yo z4NURs_;#{|kH;@E(~592sp~gwV<=-~hm2{{-n8CuYp1iDR<1B)S_2tc$YB=ujFYY< zGiX{yk$)QBAK8LO=|Q;`mdoMtD;iZUE1aF=-JtXLsR(f~43wG=s1hsH_&(46tqd=DMc7 zQCMLQ;Btr=c_U{7wQR9qv0b<@2$HU5L9}l|Cry-W8?;xjjL=I$~hS73Z!-SS#D zP&rKI*6d)>)huJ90L+in^*8+nsdN$~I{b&>l8HjJW4fY&9V5ET*VZ@PlF$`dfu$f( zk498Q(LHrUzFq!UZ>uRRl$U^NTm`L5~@V|T?t}TO0HxIi%gK?BfTR= zf---j{`}a#7nR%P1In3G!GM?j}$2uNu!H&+%j`MV{y9rIwP1__|a*d6?gm zx{{3Yw^9l92?R9B52gCmXVH9tf4(T8t6=)zDq7s0Kcq_KV3esm+aB9-&_5+N-ATwM zzI8!&*Jt1}DZ8GYLXmv|c3O75xq=DUyxsVLV{8Zah0R{)_cbTU2%l_DlOz1?=9@@6KXc(G(#dx(+@xTy@PjRN{L+>V^)K`<^Fm9b z_b8Z4_>PusQPF7n2FtWF>zSD|*kAmN)`a&@a9GN(Ze2z;?@TxFM_SJ(o4MP10a?c5 zZI`UthpApfc?o4d%F8Gol-E!?Q7}7u1w|$x2hj3>&G>2MVBV4F8Rmgw?~Z7Ksmg=LPUA*Wiqo z@T<~Y<uzJDu+p*h+ zu<=S~zz`FJ!8I{4Q#KPxKtXUJ(L`c2Lsm7s2+A)69)Q0E3)&S5%W+!YXV zPE#6DsKa#XWRwuWl#=cd4-oT3x?oiYm8ol3!is!fz}iNEZ9FC!QK>@R)H7^0(^6D%d$_y43$W#6THPbUq6;jYHI`14AtWn{Qc3~?5LH2Q(V%sO zZc`c}dDd@D43!KD(OMcFwUwq-LxfYo6>DNjoi_hkm<4RzrJ+;7r+@ZQez5q z3Y|(DM(vA*rf3IS3f}>?L=XjmuM2D;Ij&UA<@>8X^5rnmfmnoC&j+jDl2{009Bg-L2R{ zL_8%2i-TC;B|az;iE`b}Z`1}AaZo&|gezb&Zw=3OK=+uvacnT$Ld0=_@2lHQUgw>W z2gq*zawJUN=I=yW3FqUHAbEvfjkMQUhqXMD7iF~8bUf2<*~W(PxNq=8eV2O|hI6AAKS*&q0qkLgQE%}}&8`hH({B%Pw zc+kqSGWb(a!0~uuWm?M^yF~UpuZuR3GrT>zjEH<^w4X>kGOeGi-*z z5bbyb>30ZS+}XG}fY(}3R%djhdll0Y8nfz)Rc9fm@=qFPkpUi$R`9QFGM^lq4ZUY# zkCHOJIrc<;FE08nVjp5Z;yr{7@jhZY!g@XjFuH^|gt!bS*q3N)4YmVAXM4ubR%kch zk}J`hp}K*O%rQ^T#94nq($jIszlxI|Ld4>MbCG1Na{EFY09$5Yz zhTk9xh@*&c#4*GVh~tPK5kDbLAWkBFM&OOIQ;5@uUlC^zzadJNtL!}XFCZ=od|OMv zjY47s`d0-0@r)Vwd`&amdMSTlbQLjyu>7`Mz0F2Us73GzS(dIrT*KEkN5yNx z*pB8hQgh427a=#`yk#Oka$mUfI!^vyt#k3^EmOT{T$5OQfR`=*B=qlbzNcl@T{yQD zk3EDaz2UpJk6)2h34S~X_j6-rBO!cvW}6S+CPOtHFSRM5Iz8ih&l4SnEPtqt$jHdCer5qX$on< zT7`;O;cSX7G>X9oD3Xm(ivNIrL2%*1y&|}A2TA1$5^uUbN0P{Av#0au`k1tXipua+rS%fL>w40)*~#D`Stnz02>&3Me} z_nZ5_D4dcyqB>e8)!7~bf&0VVgw-s91$Ft%u(^~jvN+Q+*p_$TBt~q9jb<3ys^|AmpyAW8BeXo^aV zKdD6uT>CpvVdaLd?g!>6FwKEg-$djxRaXf&2pIxxsb?;i(z#@b&&^S3Dwb7kiJc># z9?Y`%*%yEU{_@q}NVnua4*cDZ$6kgv$h}S2B-|m~B^U_z34X#hp}(YMYy>8iCe>Sn t!P4-1&@Hj&ys_8)5^#uz{&O%Y!2oRGcrXO_a3OdaKH6Fo~~I z&aO|tkv}+s_e9k)6-*35rZxx#OuAsEX?(22u#e~ zw*K`zB4HD*w`FBMa)o0zicY%(!&sN6@tu4J4r1E151X!^(RneHA0sRXBrJS{^l`!> zZo3b|d3^7F5n3Ws;RBP2A*cj;13kMg9zmuo#^kBAmUN~T`5gIlKAyuL;TROq9jU@zV=J;B z#4%q-pG{sS_X=T)aFwu4FcWqO5kiO1zmpp7#%4TCs&@#3JHl_VD0GcqF|Rc9AA1Hx oXU~_-6ty*;scCvyVQNFms(c6M;t9BprT7$l#wT$!AKByn4I>h~Q~&?~ diff --git a/sos_inventory/models/__pycache__/sos_sfg.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_sfg.cpython-310.pyc index 023cb1cbc639813b10438296a8ef48d9a92196e4..0bd559c76225d603281aab818f9740ea06a9e159 100644 GIT binary patch delta 1014 zcmZ8fTTc@~6yBNLE!%Aih(Lm1)PyL-#E5tSB^p7fnkbr@5bI@Jc7}FwyGv)bkeU+W zCGp7^-9J#`6HmtQBYg7*OyaxoM;Om(j1p(F-^@94&UbF}@tF_I-h^zR4#~%olAUSm+%{W@s07CRAxXk%a?d*m-3tZR#$iV ztzj9JD`lg2d;bT$YVG(G>He%9*pc3ZUsV7&X_HN3n|KKxuxD^@9BcHpO^9#b)dQZ|QKG&Y z22qvyHBVNB(m53?rq-%#HLhzb^6ElPLMFu?ZL8*nklNmoK_av%qD`Gq!jpbY(}3$? z=EwDoW+GU;DWn&MEQu2@)FVu_BA+#*AYmIa@CDlnk{X5p&Rdoe;hMHKy-;C32h)kF zf@@PkP9_-Z93;e~@MFnA1HvBBS;qVjycpX{zc~w2@*Jc(gWVeha7dn5)FDTR1D{Li zFUx#UC@+^;d8u@!TgLv$o-7$!0Ap=dMIxu+B+nz1(vmZ7OC(Dh&Pt!Wj@mBFqwY}l zaMw>^cQOaYECyqqo$(DSaPUrSW zCHnTx^Jlt8Q>z_|sQkz!=$q{H~!t)-P=U ze5-0b{hIf)dE(?;;*JjNPZh@K>Qgjf2+t5agjE2YVK6@-B|dRkN0>l$9^Ve69wjW` zQlP$w5aFfMXnIi+BrQ3Lx&}fe{oFS*@^2=82P5CXwg0jI6nU3U^iNEoc%Xp4cG{V% U$GjPes{||*mNG~O%;6`$0k;GQ;Q#;t delta 631 zcmZvYzi-n(6vutGxm?}EBvnB~WT{k%rb3md_z_U4Qd;^WKud{eRR%2AcTFOab2z(| zj6?;3ogX)`Q89I_vN6Db_$NHGFtRZL?^!}+;4FW2@B5zL`#kIM=VNYIC^!b3*D`3A zN8h-wXdR-ce)OSio)?$iU*>ZMgx}!vFO3)E!4+_7e1YFQF!>^1%Dk(5xoK2a20zVN zd+>t|kuy`!A+=f}PAwt#QW^bpjyE& z$3mQ(+zSAHg+oR;EP)^w^zYeYbbY7)=}<(q|^%)7fM;^ zJVcp5J0FC-J|N22>u|M!eig;TBzwH;%eWIK>MVNOC=ESVs+Es_(J|IOq__0j(mArP fKb9sgVEjM+l+E-)zS|YE1S%rjWYiq7PB;GmjD(#i diff --git a/sos_inventory/models/__pycache__/sos_sfg_bom.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_sfg_bom.cpython-310.pyc index 9172a53d139bc96fd64e8b230c3b80530483d053..975df11a3b085754bfc8af708ea87288cfc0ca19 100644 GIT binary patch delta 2494 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 UfTnW@>fS)l|AiD@-w+A^14_{uod5s; diff --git a/sos_inventory/models/__pycache__/sos_sfg_quote_generation.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_sfg_quote_generation.cpython-310.pyc index 8fa844799961b4c72ec5c381a29a55ce93d9bbff..ab6598ee8b763ebd74060a1f815f385753c85a49 100644 GIT binary patch delta 880 zcma))&rcIU6vy{%ZD|S==vrDZn4$=jAFVAQiYO}hGlnRfY+`EZ+Z0-D>1>IZfYeYl zq9A097k|-WLU{CSE-1VGkz$3C0VF331+FOuV_teCF-0+g<7T((BAr zRyq{%q&D*7HGwzI)^gY^^_GvooHgmgHncB6q*33qwiny613QZr3}CRJ%tNF}sQXAQ zs<&GK_6bJAa9xvMP1P)Rz z5NVV4Az?p>r=-1I+DSQ$XQa}BXGazPIkSOR*EEzumD6goSvI0yi?Ni!hQ+;1=R|sv zWfDv`jA%A@!?YQ>SZ>PT!P@$ zQ6;OQA~v)PGZ1T8PQY(rd5UQ_c8dg+4T#CKFg?!uwOuXoaXp@j{(FuW!eLP7?WzxK zpyqdM@x0b%+xGI;RS8#KWM#pZ+XdMm&(>+y>q1`VL)DLLv>7W%aax2WzFGaNeu2a= zp^tEza7Vz@_^M0eK36-u=jUDTV1a{{girjcHfp;^uKT5rS{VGYz_#$Wz%oS-2vmx# z5LUU*9dJDqq3IaYja<}-XPC|w`4#si_{uljKVXrs*T&!{cX~d+WB%E*yYUIFd`bus zo(YKlQM=e6;kmp`Muc0u$$J4h`INUG^8BqgFejJEJ9m-wzt2hL5TS=a-<;8@*mW`VEDv<@f*q delta 628 zcmca=KEaePpO=@50SNl@k~7ZeY~<76X1uo9oI8lIUSWY^idKsDLZ%d*6x|kvX2vL` z6ulJv7KSM0RFIrOieZY;Lgp0X6cezl3Q$xv#dINKidl*|SVRr1&LYJ!#VW-*#U{me zAzO-Fial6P9jw{`sM;~b2`r)kRt*wyPH|~r-~n2wnc^DEpy_r?cJf96+0DVc6-?|! zen7|G;+uS5Af2Zk#AGWjNh~QXp6oBEz_@gBf#5W`2B2_JBZ%;V6W$j0_h-273* zh*1-407L+8KsSih10q0174?FMzR5mfdO{O{%v)SZsl_Gn#mV_asYUIRd&D9c&rg0P z_K~rD@(uAs#y69#B=#}RnEX>h&T=M5=PVGR4r~Z>jBJnqy7K@ diff --git a/sos_inventory/models/__pycache__/sos_transfer_challan.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_transfer_challan.cpython-310.pyc index aac0c0d3a4dd2c1f114551be77d67c7eb16916d9..fbe8824985cdd2604216b39a7500af84bacac7da 100644 GIT binary patch delta 268 zcmW-byH3L}6o&2C;3kcsw3OID2o*4}AYfsFrDE;Eh>#fm0a;u`#OMt004yE}Qt|>^ z)DiIj40(k<3vSMGr1M|C^EaN2<%5(F@iW?l*hMU1xnwn^jY>33gIz3S>EAlMgY6k6| ue;PuUe9px>Hn52lTgXa=?UG%P{gJ!YyFq?DebzsW#_lxDXm5Iz-tvDZRz*Jm delta 275 zcmW-by-EZz6oqpqaWlyz{_HqA$-3jZpn|29t*~HWYiWB09Rzi;%sfRv5J#DL0+DTO z1e+~<2_M1ULNGh`7MH_0ALo8gzoz;|Ye~W!XBU_0n|{sV#ed}I`z3dzln$B%ImRej zin8V{RLrs2Rq#}!G4Us6e5fpGRvZgN4>hjVv;`n{r?^(}!1qHIkS~2)#|_7^?;p$r z7XH)NEOqe{d5$X4r8X@oBh37d*%OO<YYge_5hn5XqpTu=0=fhE!1r@qAWXvw!OkL2m#6 diff --git a/sos_inventory/models/__pycache__/sos_wo.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_wo.cpython-310.pyc index 2070291473740bd7e809244e2b10b21600f88e56..8276c387d87b19cfc4f1fe358792c257cc86315c 100644 GIT binary patch delta 2136 zcmZ`(Yiv|S6uxuszFKL!eb6VZOCN-dloksDRe`p&wDiHNpjL6&?zwEY-QByLd$*;f zuuW)0o<1gqL<_b?BgAMzDnF2z7!u_dCPqPXe_;IK5C3SxPnGC7v&+lG-P~`^W4@U) zXU>_c-LpG$jhvip1%L7Hribn{y_NfsnyX#Da+;;W3T*y>!4_zN)-&3`Q@Uq(6|})t z@Io`{^{8h-J9MDF4fWMh?}RSMI-?FWpwe8x#c%M(Oc$PAu!M200d{0V{D)eEn8s_Eg=ADX_s?! zv>b%6v~<7_M3B8rdWO+60#WJdBug#C&=dzlnz|qXqd0jxa4>P~25XPvPcD3_o%5{K z{HpB?#`HMY?iLz!K#Rjj=yBVz1CjipsA1~1tBnTWZ40o(#aOQx$+>>Og_qfepScNP zN*Pv$*_;Y2tjw!N*pxD-O|f})M4eK%D*K&BG*G9sfMYZdG;n|uT;K-JtOi-L8ithJ zXJ-dPR%A>MM8M=NxZHOP%|Ja<-V+z6Of&`O$q2QS2le5ah94#BitX@QrLOF|j>m(W>^ctA$A z7cFKnf|q485B^nEO@GXB&vkFI$TZAAVBA>!C@I8{pePG9xxX+L5>796h`8vjWkGS% zd$=x)KCUBR{4%Tv%C_4~4i00E_%OML#A11ccs)OtCB?b?ab)Hd9P|?DlA0zBp)7tc zD;4Jpa@cF)lY+afO-4yDVVDLqoxMSPvw)5$1UFnR|O5r<-)e9#v*vb^JZK{C>v&m&GRpFKTlg zqP-@>wW50Vx%jOJFo%6hSCyIn4FP9WqwT5?OBdN!Vy1Z0iX`fOhwbD>5*ti2lQBMl zCi{snH!!%dU^J=oqvDU^685EVm()8>pjRvwl#AUZ7hT<`@Z{U2RW35~1K9);d1F9V|PSR`Lv(!BKK~Beu8}nerD$d6PO0vBa;N&XtCVSeih{v8(Ggne?^Kl z%V<2kMqIaoe1gk;&LZ8;+9Mkc>zBVrYi^Ln2)++-3%ip~i=4{pGFcnWj;Il|^g z2nFH>9~7OH)!q;hPZ30kT`8t>O3NcL>_#3VgPZHIARjULXxiOaur!6yre|>Cy+QCM z!2yC1f&_s@;6Sk5pyMlr&jppD?YUn8JVi5_3FuOI13?qPy9BcY5Bv2&(~4D9+3ciP zUlq-Fd2&4ko_vo7E5?go(ZXj{rqj}cJ! z`ZfMN$v+SrCOAs)aBF%h__qj4n3%4f@|;8wEB=;n)I7_I#g>`|c3UKB4z8C?Aq&dI zZxcx_c^oBMi^MJd6WL~noq42WkDL%WwNE;4qIsEEQ`?j}PqQu%P*3nVf_VaJRsJDC zJ;4_Q^6qYt^f7|1jwWo+kQonz4AA*ivdcg=ko54Bjigc_>GR6C=&JbFiqeoiEB}V{ u9|C9d|`Z-9~mp?5gt>oJQSt_Ttu2?j+I;ajb3~i~b7)*gRDL delta 1440 zcmZ9MU2KzO6vz9tYuAo_u@Ad$Y@Pe0k-EWD*wlTpv9S#XV}lh&>3ZIN(Yr~LC2{crqS2wom}sKry}=7FOuQjPFT61EoOhF;z4*QV^FQZ2 z=Xsy!P2V0_9n9DA@^Vb{TULXSd(G$bubBTZ-?;gTScDGf44a_~x}oQs#rK$Ek8Ok9 z&GS@A-G8b}fLJZ?_U} z5gaR?qt0)OLwVfvo_W1#3_DA(7lj zx=kuUO#)soZL;>!Qm66P((bGfDIBRQN2jyFrtt6(_Bg%b63#e*2LI^X<~qT4*#o#( z)ezprin4p+8s@s%y;Br>vUID|(kkedWO`ci()y;b)RIa6Y#^Ri{@r{G6E3HCAJ4eF zS+i7xAC{Ek53Z}W0Se?4o-VJlu`g42rF=-l@P2uR_$afZVoHc_@Qp1mi3R*Le`}7O zJ*^~@fw1Dirh?KEp%(-a38~SnjU$kAbdVnLJw_^9#X#nA<)Uaac4Z&dR3#OV^U|1e zig)T5RpN95QB9Sv^6*`T8C5}1Q~oH(X*}w#aYfj*_Qkb8N`?&$LBFcW{rIN4rf`HC z=NS{6tHkR?W%!HRR^a0>TPo85c`_-F2g{0&Q zlWhz>c-h2gVVq$s<78tQE>}Cm60TIoH)Y$4?3?ZO9AS579(nYvDD3B|y^KM|5Zb}-hqbX}ij;1Nsww$3dou)2*7}DXV`CQ64Q}f#k`7#HXjy!X z&GU>43}n2{urMw%yo_rMBelow Return-IQI is waiting for your Approval

@@ -147,6 +165,7 @@ class sos__mrn(models.Model): elif eachone == "SFG": for item in self.line_ids_sfg: component = self.env['sos_sfg'].browse(item.component_id.id) + if item.qa_decision == "to_stores": current_qty = getattr(component, 'inhand_stock_qty', 0) new_qty = current_qty + item.quantity @@ -174,9 +193,19 @@ class sos__mrn(models.Model): send_email = self.env['sos_common_scripts'] send_email.send_group_email(self.env,'sos_return_iqi',iqi_record.id,"deenalaura.m@sosaley.in","Return-IQI Inspection Request",body_html,'sos_inventory.sos_qc_user') # Email part ends + if customer_return_record and self.return_type == "customer" and item.qa_decision != "to_stores": + create_vals = { + 'tc_id': customer_return_record.id, + 'item_name': component.name, + 'item_type': 'SFG', + 'return_incoming_doc_ref':iqi_record.id if iqi_record else None + } + new_line = self.env['sos_transfer_challan_return_from_customer_lines'].create(create_vals) + else: for item in self.line_ids_fg: component = self.env['sos_fg'].browse(item.component_id.id) + if item.qa_decision == "to_stores": current_qty = getattr(component, 'inhand_stock_qty', 0) new_qty = current_qty + item.quantity @@ -213,7 +242,15 @@ class sos__mrn(models.Model): send_email = self.env['sos_common_scripts'] send_email.send_group_email(self.env,'sos_return_fir',return_fir_record.id,"deenalaura.m@sosaley.in","Return-BRR Inspection Request",body_html,'sos_inventory.sos_qc_user') # Email part ends - + if customer_return_record and self.return_type == "customer" and item.qa_decision != "to_stores": + create_vals = { + 'tc_id': customer_return_record.id, + 'item_name': component.name, + 'item_type': 'FG', + 'return_fg_incoming_doc_ref':return_fir_record.id if return_fir_record else None + } + new_line = self.env['sos_transfer_challan_return_from_customer_lines'].create(create_vals) + return sequence_util.action_assign_signature( self, 'stores_approved_by', diff --git a/sos_inventory/models/sos_return_fir.py b/sos_inventory/models/sos_return_fir.py index a7ef543..dd9434b 100755 --- a/sos_inventory/models/sos_return_fir.py +++ b/sos_inventory/models/sos_return_fir.py @@ -75,6 +75,8 @@ class Return_FIR_BRR(models.Model): 'return_fg_incoming_doc_ref':self.id, 'department':'Quality Control' }) + if ncmr_record: + self.ncmr_ref = ncmr_record.id ncmr_body_html = f"""

Below NCMR is waiting for your Inspection

""" diff --git a/sos_inventory/models/sos_sfg.py b/sos_inventory/models/sos_sfg.py index 2f293bd..88b25b8 100755 --- a/sos_inventory/models/sos_sfg.py +++ b/sos_inventory/models/sos_sfg.py @@ -53,6 +53,17 @@ class SOS_SFG(models.Model): ) last_batch_no = fields.Char(string="Batch No") last_serial_no = fields.Integer(string="Last Serial No") + def write(self, vals): + assembling_changed = 'assembling_charges' in vals + res = super().write(vals) + + if assembling_changed: + for sfg in self: + bom_records = self.env['sos_sfg_bom'].search([('name', '=', sfg.id)]) + for bom in bom_records: + bom._compute_overall_total() # If you want to force recompute manually + bom._sync_unit_price_with_sfg() + return res @api.onchange('category') def onchange_category(self): if self.category: @@ -62,7 +73,6 @@ class SOS_SFG(models.Model): } prefix = prefix_map.get(self.category, "SO") - # Search all records starting with this prefix matching_records = self.env['sos_sfg'].search([ ('code_no', 'like', prefix + '%') ]) diff --git a/sos_inventory/models/sos_sfg_bom.py b/sos_inventory/models/sos_sfg_bom.py index c6f1aef..b46e5fc 100755 --- a/sos_inventory/models/sos_sfg_bom.py +++ b/sos_inventory/models/sos_sfg_bom.py @@ -38,8 +38,10 @@ class SOS_Sfg_Bom(models.Model): 'material_code' : 'Material Code', 'primary_component_id': 'Material Name', 'quantity': 'Quantity', - 'location':'Location', - 'inhand_stock_qty':'Inhand Qty' + 'inhand_stock_qty':'Inhand Qty', + 'uom':'UOM', + 'unit_price':'Unit Price', + 'total_cost':'Total' } self._write_sheet(workbook, 'Materials', self.sfg_bom_line_ids, headers) @@ -62,12 +64,26 @@ class SOS_Sfg_Bom(models.Model): } def _write_sheet(self, workbook, sheet_name, line_records, headers): - """Write data to each sheet based on specified fields and custom headers.""" worksheet = workbook.add_worksheet(sheet_name) - for col, header in enumerate(headers.values()): - worksheet.write(0, col, header) + + number_format = workbook.add_format({'num_format': '#,##0.00'}) + bold_format = workbook.add_format({'bold': True}) + name_value = getattr(self, 'name', False) + worksheet.write(0, 0, 'Name',bold_format) # Label for the first value + worksheet.write(0, 1, name_value.display_name if name_value else '') # Handle Many2one field - for row, record in enumerate(line_records, start=1): + assembling_charges = getattr(self, 'assembling_charges', 0.0) + worksheet.write(1, 0, 'Assembly Charges',bold_format) # Label for the second value + worksheet.write(1, 1, assembling_charges, number_format) # Assume numeric (float) + + overall_total = getattr(self, 'overall_total', 0.0) + worksheet.write(2, 0, 'Overall Cost (Including assembling charges)',bold_format) # Label for the third value + worksheet.write(2, 1, overall_total, number_format) # Assume numeric (float) + + for col, header in enumerate(headers.values()): + worksheet.write(4, col, header,bold_format) + + for row, record in enumerate(line_records, start=5): for col, field in enumerate(headers.keys()): value = getattr(record, field, '') if isinstance(value, models.Model): @@ -123,7 +139,7 @@ class SOS_Sfg_Bom_Line(models.Model): _description = 'BOM Lines of Semi-Finished Goods' bom_id = fields.Many2one('sos_sfg_bom', string="SFG BOM Reference") - fg_bom_id = fields.Many2one('sos_fg_bom', string="SFG BOM Reference") + fg_bom_id = fields.Many2one('sos_fg_bom', string="FG BOM Reference") primary_component_id = fields.Many2one('sos_material', string='Part No', required=True) location = fields.Char(related="primary_component_id.location") inhand_stock_qty = fields.Float(related="primary_component_id.inhand_stock_qty") diff --git a/sos_inventory/models/sos_sfg_quote_generation.py b/sos_inventory/models/sos_sfg_quote_generation.py index e940e6b..0335a9b 100755 --- a/sos_inventory/models/sos_sfg_quote_generation.py +++ b/sos_inventory/models/sos_sfg_quote_generation.py @@ -162,6 +162,13 @@ class SOS_SFG_Quote_Generation_Line(models.Model): # final_supplier3_qty = fields.Integer(string='Qty') best_supplier = fields.Many2one('sos_service_providers', string="Best Deal", compute='_compute_best_supplier', store=True) available_suppliers = fields.Many2many('sos_service_providers', compute='_compute_available_suppliers') + remarks = fields.Char(string="Remarks") + @api.onchange('required_qty', 'inprogress_qty', 'status') + def _onchange_check_inprogress_qty(self): + for rec in self: + if (rec.inprogress_qty >= rec.required_qty and rec.required_qty != 0) or rec.status == 'close': + rec.inprogress_qty = 0 + @api.depends('required_qty', 'inprogress_qty') def _compute_from_ir(self): for record in self: diff --git a/sos_inventory/models/sos_transfer_challan.py b/sos_inventory/models/sos_transfer_challan.py index 0a1f34e..c4bf71c 100755 --- a/sos_inventory/models/sos_transfer_challan.py +++ b/sos_inventory/models/sos_transfer_challan.py @@ -180,7 +180,7 @@ class TC_Model_Line(models.Model): 'fir_date':self.production_to_qc_transfer_on, 'batch_size':self.production_to_qc_transfer_qty, 'sampling_size':self.production_to_qc_transfer_qty, - 'plan_ref_no':plan_ref_no.id, + 'plan_ref_no':plan_ref_no.id if plan_ref_no else '', 'batch_No':self.batch_no, 'fir_no': sequence_util.generate_sequence('sos_fir_brr','BRR', 'fir_no'), @@ -204,7 +204,7 @@ class TC_Model_Line(models.Model): # Email part ends self.production_to_qc_transfer_by = self.env.user.id sequence_util = self.env['sos_common_scripts'] - if self.tc_id.fg_option: + if self.tc_id.fg_option and self.tc_id.plan_ref_no: week_number = sequence_util.calculate_week_number( self.tc_id.indent_start_date, self.tc_id.indent_target_date, diff --git a/sos_inventory/models/sos_transfer_challan_return_from_customer.py b/sos_inventory/models/sos_transfer_challan_return_from_customer.py new file mode 100755 index 0000000..2b93b59 --- /dev/null +++ b/sos_inventory/models/sos_transfer_challan_return_from_customer.py @@ -0,0 +1,81 @@ +from odoo import models, fields, api +from datetime import date,datetime +from odoo.exceptions import ValidationError,UserError +import re + +class SOS_TC_Return_Customer(models.Model): + _name = 'sos_transfer_challan_return_from_customer' + _description = 'Transfer Challan' + _rec_name="tc_no" + _order = 'tc_no desc' + + + tc_no = fields.Char(string="TC No",default=lambda self: self._generate_id(),readonly= True, required= True) + line_ids = fields.One2many('sos_transfer_challan_return_from_customer_lines', 'tc_id', string="Finished Goods",copy=True, ondelete='cascade') + mrn_ref_no = fields.Many2one('sos_mrn',string="Return Note Reference",readonly= True) + def _generate_id(self): + sequence_util = self.env['sos_common_scripts'] + return sequence_util.generate_sequence('sos_transfer_challan_return_from_customer','TC', 'tc_no') + +class SOS_TC_Return_CustomerLines(models.Model): + _name = 'sos_transfer_challan_return_from_customer_lines' + _description = 'tc Lines' + + tc_id = fields.Many2one('sos_transfer_challan_return_from_customer') + item_name = fields.Char(string="Item Name") + item_type = fields.Selection([ ('FG', 'FG'),('SFG', 'SFG'),('Material', 'Material')], + default='FG' , string="Type") + + return_incoming_doc_ref = fields.Many2one('sos_return_iqi',string="IQI Ref No",readonly=True) + return_fg_incoming_doc_ref = fields.Many2one('sos_return_fir',string="Return FIR ref",readonly=True) + combined_incoming_doc_ref = fields.Reference( + selection=[ + ('sos_return_iqi', 'Return IQI Ref No'), + ('sos_return_fir', 'FIR Ref') + ], + string="Incoming Document Reference", + compute="_compute_combined_incoming_doc_ref", + store=False + ) + stores_handovered_by = fields.Many2one('res.users', string='Stores Handovered By',related="tc_id.mrn_ref_no.stores_approved_by") + stores_handovered_on = fields.Datetime(string="Stores Handovered On",related="tc_id.mrn_ref_no.stores_approved_on") + qc_tested_by = fields.Many2one('res.users', string='QC Tested By',compute="_compute_qc_tested_by") + qc_tested_on = fields.Datetime(string="QC Tested On") + received_qty = fields.Integer(string="Received Quantity") + approved_qty = fields.Integer(string="Approved Quantity") + rejected_qty = fields.Integer(string="Rejected Quantity") + ncmr_ref = fields.Many2one('sos_ncmr',string="NCMR Ref(If any)") + stores_received_by = fields.Many2one('res.users', string='Stores Received By') + stores_received_on = fields.Datetime(string="Stores Received On") + + @api.depends('item_type','return_incoming_doc_ref','return_fg_incoming_doc_ref') + def _compute_qc_tested_by(self): + for record in self: + if record.item_type == "FG": + record.qc_tested_by = record.return_fg_incoming_doc_ref.qc_by_name + record.qc_tested_on = record.return_fg_incoming_doc_ref.qc_tested_on + record.qc_tested_on = record.return_fg_incoming_doc_ref.qc_tested_on + record.received_qty = record.return_fg_incoming_doc_ref.batch_size + record.approved_qty = record.return_fg_incoming_doc_ref.approved_qty + record.rejected_qty = record.return_fg_incoming_doc_ref.rejected_qty + record.ncmr_ref = record.return_fg_incoming_doc_ref.ncmr_ref + record.stores_received_by = record.return_fg_incoming_doc_ref.stores_received_by + record.stores_received_on = record.return_fg_incoming_doc_ref.stores_received_on + else: + record.qc_tested_by = record.return_incoming_doc_ref.qc_by_name + record.qc_tested_on = record.return_incoming_doc_ref.qc_tested_on + record.received_qty = record.return_incoming_doc_ref.received_qty + record.approved_qty = record.return_incoming_doc_ref.approved_qty + record.rejected_qty = record.return_incoming_doc_ref.rejected_qty + record.ncmr_ref = record.return_incoming_doc_ref.ncmr_ref + record.stores_received_by = record.return_incoming_doc_ref.stores_received_by + record.stores_received_on = record.return_incoming_doc_ref.stores_received_on + @api.depends('return_incoming_doc_ref','return_fg_incoming_doc_ref') + def _compute_combined_incoming_doc_ref(self): + for record in self: + if record.return_incoming_doc_ref: + record.combined_incoming_doc_ref = f'sos_return_iqi,{record.return_incoming_doc_ref.id}' + elif record.return_fg_incoming_doc_ref: + record.combined_incoming_doc_ref = f'sos_return_fir,{record.return_fg_incoming_doc_ref.id}' + else: + record.combined_incoming_doc_ref = False \ No newline at end of file diff --git a/sos_inventory/models/sos_wo.py b/sos_inventory/models/sos_wo.py index 4bccfd4..45167a7 100755 --- a/sos_inventory/models/sos_wo.py +++ b/sos_inventory/models/sos_wo.py @@ -61,7 +61,7 @@ class sos__wo(models.Model): total_qty = fields.Integer(string='Total Line Items Count', compute='_compute_total_qty', store=True) received_qty = fields.Integer(string='Received Line Items Count', store=True) payment_method=fields.Selection([('neft', 'NEFT'),('credit', 'Credit'),('credit_card', 'Credit Card')],string="Payment Method") - wo_status = fields.Selection([ ('open', 'Open'),('close', 'Closed')], default='open' , string="Status") + wo_status = fields.Selection([ ('amend', 'Amended'),('open', 'Open'),('close', 'Closed')], default='open' , string="Status") progress = fields.Float(string="Completion Percentage", compute='_compute_progress', store=True) dc_no = fields.Many2one('sos_dc',string="DC Reference No", readonly= True) stores_approved_by = fields.Many2one('res.users', string='Manager Approval By') @@ -82,7 +82,20 @@ class sos__wo(models.Model): # record = super(sos__wo, self).create(vals) # record.action_esign_btn() # return record - + def action_amend(self): + active_ids = self.env.context.get('active_ids', []) + records = self.browse(active_ids) + for record in records: + record.wo_status = 'amend' + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'title': 'Amended', + 'message': 'The selected record(s) have been amended.', + 'sticky': False, + } + } def action_esign_btn(self): sequence_util = self.env['sos_common_scripts'] sequence_util.action_assign_signature( @@ -143,7 +156,13 @@ class sos__wo(models.Model): record.progress = (progress_sum / line_count) * 100 record.wo_status = 'close' if record.progress == 100 else 'open' - + @api.onchange('progress') + def _onchange_progress_status(self): + for record in self: + if record.progress == 100: + record.wo_status = 'close' + else: + record.wo_status = 'open' # @api.depends('total_qty', 'received_qty') # def _compute_progress(self): # print(self.received_qty,self.total_qty) diff --git a/sos_inventory/security/ir.model.access.csv b/sos_inventory/security/ir.model.access.csv index 769e66a..d6e7c17 100755 --- a/sos_inventory/security/ir.model.access.csv +++ b/sos_inventory/security/ir.model.access.csv @@ -193,4 +193,7 @@ access_sos_transfer_challan_summary_lines,sos_transfer_challan_summary_lines acc access_material_backup_export,material_backup_export access,model_material_backup_export,base.group_user,1,1,1,1 access_ncmr_report_wizard,ncmr_report_wizard access,model_ncmr_report_wizard,base.group_user,1,1,1,1 access_sos_parameter_fir,sos_parameter_fir access,model_sos_parameter_fir,base.group_user,1,1,1,1 +access_sos_transfer_challan_return_from_customer_lines,sos_transfer_challan_return_from_customer_lines access,model_sos_transfer_challan_return_from_customer_lines,base.group_user,1,1,1,1 +access_sos_transfer_challan_return_from_customer,sos_transfer_challan_return_from_customer access,model_sos_transfer_challan_return_from_customer,base.group_user,1,1,1,1 + diff --git a/sos_inventory/views/sos_dock_audit_view.xml b/sos_inventory/views/sos_dock_audit_view.xml index aa17bad..f2d52c0 100755 --- a/sos_inventory/views/sos_dock_audit_view.xml +++ b/sos_inventory/views/sos_dock_audit_view.xml @@ -46,7 +46,7 @@ Print --> + confirm="Are you sure to make revision for next phase?" invisible="not top_management_name">Make Revision

Dock Audit




diff --git a/sos_inventory/views/sos_sfg_quote_generation.xml b/sos_inventory/views/sos_sfg_quote_generation.xml index 733cdf2..10cf786 100755 --- a/sos_inventory/views/sos_sfg_quote_generation.xml +++ b/sos_inventory/views/sos_sfg_quote_generation.xml @@ -27,7 +27,7 @@ - + diff --git a/sos_inventory/views/sos_transfer_challan_return_from_customer_view.xml b/sos_inventory/views/sos_transfer_challan_return_from_customer_view.xml new file mode 100755 index 0000000..641e637 --- /dev/null +++ b/sos_inventory/views/sos_transfer_challan_return_from_customer_view.xml @@ -0,0 +1,115 @@ + + + + Transfer Challan + ir.actions.act_window + sos_transfer_challan_return_from_customer + tree,form + + + sos_transfer_challan_return_from_customer.view.tree + sos_transfer_challan_return_from_customer + + + + + + + + + + + + + + Form + sos_transfer_challan_return_from_customer + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + +
diff --git a/sos_inventory/views/sos_transfer_challan_view.xml b/sos_inventory/views/sos_transfer_challan_view.xml index 5b933c7..1283a1d 100755 --- a/sos_inventory/views/sos_transfer_challan_view.xml +++ b/sos_inventory/views/sos_transfer_challan_view.xml @@ -5,7 +5,7 @@ ir.actions.act_window sos_transfer_challan tree,form,kanban - {'group_by': 'plan_ref_no'} +

No Data @@ -245,7 +245,7 @@ If no 'to' is used, values will be stored as entered."/> diff --git a/sos_inventory/views/sos_wo_view.xml b/sos_inventory/views/sos_wo_view.xml index 078391c..c26475a 100755 --- a/sos_inventory/views/sos_wo_view.xml +++ b/sos_inventory/views/sos_wo_view.xml @@ -6,6 +6,15 @@ sos_wo tree,form,kanban + + 📝 Amend + + + code + + action = model.action_amend() + + sos_wo.search sos_wo @@ -38,7 +47,8 @@ - + + @@ -58,9 +68,11 @@ - + + - + +

Work Order




diff --git a/sos_sales/models/__pycache__/sos_case_diary.cpython-310.pyc b/sos_sales/models/__pycache__/sos_case_diary.cpython-310.pyc index 0309ae46dc10e706659852689bd09434b050ec6e..67bf31fdf507c238018ad3cc8556f3930b73bdbc 100644 GIT binary patch delta 5785 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 Z{x)L)K>;P;Wx&~XThf-Cy%IQ&{|}jVWGDat delta 7582 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 delta 721 zcmX|7O>YuW6rDH2N1=A27FsNnuW5k+lvXOX#UhPu6Js<@Of*hn2ymYim4UpW#&%;O zEL_NQ?uY~7g_VK}; z#EE+9DxpPi$|Be`>N%q>k{o@QelL?0-%;}@UaGwdBsKaIQDyJ3yNSD{R$b@5 z_;*s^zvBDR26l?WX7Ty29+h>4ZJ=fa{!n|P+|yV1yF`Vo@!yF(EsTZn)ZMm8yH$3? z3bu6LHoLSz*;&`-=vi`)Xsh-Fhe)^0`a#viz`95S?NAde7UQ4N0k0E1`&tGM>Jg&y zqF$6$!e8shWQqUPJKI}WWhEPK+EBJ(+XlskU4*f-*{b6F9h-Xvub9;qWw-3avi+T4 i4e3|B);WYJ$w3?h*Ft=R)%eeJp42ck&$F2@+5HFm)3!eV diff --git a/sos_sales/models/__pycache__/sos_proposal_customer_requirement.cpython-310.pyc b/sos_sales/models/__pycache__/sos_proposal_customer_requirement.cpython-310.pyc index 5d5672d35b6b321fb73df6469e4990f8cc5ea6dd..dec46a8b441a7fa7493a601c22ac5798057d632d 100644 GIT binary patch delta 33 ncmca)b;*i5pO=@50SLnORBYsaF2u+``LmD)qv>WDVKXiOq#_9( delta 33 ncmca)b;*i5pO=@50SNvmmu=*JF2u++`LmD)qrqkwVKXiOr9lZF diff --git a/sos_sales/models/__pycache__/sos_sales_achievement_report.cpython-310.pyc b/sos_sales/models/__pycache__/sos_sales_achievement_report.cpython-310.pyc index 36986a6530558a2cb62dfe660acef11941989611..e84ce6cf1239dfc458b3fdcf087297078fb04f09 100644 GIT binary patch literal 23335 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 delta 6475 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 P-w^m)9543U1HQilULUBo diff --git a/sos_sales/models/__pycache__/sos_sales_action_plan.cpython-310.pyc b/sos_sales/models/__pycache__/sos_sales_action_plan.cpython-310.pyc index ff71298f2979464a001f2e3709de4f12a7bff27f..48fe35c9319e64c285bd390076fcc409cd1b0e17 100644 GIT binary patch delta 3396 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 Qt}Y(z{yaR_OWhy;2cDlF6951J diff --git a/sos_sales/models/sos_case_diary.py b/sos_sales/models/sos_case_diary.py index 6fb1d13..1ae5fae 100755 --- a/sos_sales/models/sos_case_diary.py +++ b/sos_sales/models/sos_case_diary.py @@ -67,7 +67,6 @@ class sos_case_diary(models.Model): ], string="Service Type") line_ids = fields.One2many('sos_case_diary_line', 'ref_id', string="Action") - accounts_line_ids = fields.One2many('sos_billing_collection', 'ref_id', string="Billed & Collected") status = fields.Selection([('open', 'Open'), ('close', 'Closed without Order'), ('close_order', 'Closed with Order') ],default='open',string='Status') @@ -81,15 +80,7 @@ class sos_case_diary(models.Model): po_copy = fields.Binary(string="PO Copy") po_copy_filename=fields.Char(string="PO DocumentFile Name") order_expected_on = fields.Date(string="Order Expected On") - line_ids_billed= fields.One2many( - 'sos_billing_collection', 'ref_id', - domain=[('action_status', '=', 'Billed')] - ) - line_ids_collected = fields.One2many( - 'sos_billing_collection', 'ref_id', - domain=[('action_status', '=', 'Collected')] - ) @api.depends('end_customer_name', 'quote_no') def _compute_display_name(self): for rec in self: @@ -704,68 +695,3 @@ class SosCaseTransferHistory(models.Model): ) return {'type': 'ir.actions.act_window_close'} -class SosBillingCollection(models.Model): - _name = 'sos_billing_collection' - _description = 'Billing & Collection Details' - - ref_id = fields.Many2one('sos_case_diary', ondelete="cascade") - customer_name = fields.Many2one( - 'sos_customers', - string="Customer Name", - related='ref_id.customer_name', - store=True, - readonly=True -) - sales_person = fields.Many2one( - 'res.users', - string='Sales Executive', related="ref_id.sales_person",store=True) - action_status = fields.Selection([ - ('Billed', 'Billed'), - ('Collected', 'Collected') - ], string='Action') - date_of_action = fields.Date(string="Date") - currency_id = fields.Many2one( - 'res.currency', - string='Currency', - default=lambda self: self.env['res.currency'].search([('name', '=', 'INR')], limit=1).id or False - ) - value = fields.Monetary(currency_field='currency_id',string="Value(In Lakhs)") - def _get_financial_year(self, ref_date=None): - ref_date = ref_date or date.today() - start_year = ref_date.year if ref_date.month >= 4 else ref_date.year - 1 - end_year = start_year + 1 - return f"FY {start_year}-{end_year}" - @api.model - def create(self, vals): - # Get date and convert to datetime if it's a string - date_of_action = vals.get('date_of_action') - if isinstance(date_of_action, str): - date_of_action = datetime.strptime(date_of_action, '%Y-%m-%d').date() - - fy = self._get_financial_year(date_of_action) - month_name = date_of_action.strftime('%B').lower() - action_status = vals.get('action_status', '').lower() - value = vals.get('value', 0.0) - - # Compose the dynamic field - actual_field = f"{action_status}_target_{month_name}" - - # Get sales person from related ref_id - ref_id = vals.get('ref_id') - sales_person = None - if ref_id: - ref = self.env['sos_case_diary'].browse(ref_id) - sales_person = ref.sales_person - - if sales_person: - report = self.env['sos_sales_achievement_report'].search([ - ('financial_year', '=', fy), - ('sales_person', '=', sales_person.id) - ], limit=1) - if report and hasattr(report, actual_field): - current_value = getattr(report, actual_field, 0.0) or 0.0 - report.write({actual_field: current_value + value}) - - return super(SosBillingCollection, self).create(vals) - - diff --git a/sos_sales/models/sos_proposal_boq.py b/sos_sales/models/sos_proposal_boq.py index 6ca61f2..daaa84c 100755 --- a/sos_sales/models/sos_proposal_boq.py +++ b/sos_sales/models/sos_proposal_boq.py @@ -5,6 +5,7 @@ class Battery_Installation_Requirement(models.Model): _name = 'sos_proposal_boq' _description = 'Battery Installation Details' _rec_name="proposal_id" + _order = 'proposal_id asc' _sql_constraints = [ ('unique_proposal_id', 'unique(proposal_id)', 'Proposal ID must be unique!') ] @@ -56,7 +57,7 @@ class Battery_Installation_Requirement(models.Model): warranty_cost = fields.Monetary(string="Warranty Cost", compute='_compute_warranty', store=True, currency_field='currency_id') margin = fields.Monetary(string="Opreational Cost",compute='_compute_margin', currency_field='currency_id') margin_per_battery = fields.Monetary(string="Opreational Cost per Battery", currency_field='currency_id') - warranty_percentage = fields.Integer(string="Warranty(%)") + warranty_percentage = fields.Float(string="Warranty(%)") final_cost = fields.Monetary(string="Final Cost", compute='_compute_final_cost', store=True, currency_field='currency_id') final_cost_per_battery = fields.Monetary(string="Final Cost", compute='_compute_final_cost_per_battery', store=True, currency_field='currency_id') communication_type = fields.Selection([ @@ -87,6 +88,11 @@ class Battery_Installation_Requirement(models.Model): line_ids_fg_ups8 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 8",compute='_compute_line_ids_by_ups',store=False) line_ids_fg_ups9 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 9",compute='_compute_line_ids_by_ups',store=False) line_ids_fg_ups10 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 10",compute='_compute_line_ids_by_ups',store=False) + line_ids_fg_ups11 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 11",compute='_compute_line_ids_by_ups',store=False) + line_ids_fg_ups12 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 12",compute='_compute_line_ids_by_ups',store=False) + line_ids_fg_ups13 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 13",compute='_compute_line_ids_by_ups',store=False) + line_ids_fg_ups14 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 14",compute='_compute_line_ids_by_ups',store=False) + line_ids_fg_ups15 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 15",compute='_compute_line_ids_by_ups',store=False) #SFG Fields line_ids_sfg_ups1 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 1",compute='_compute_line_ids_by_ups',store=False) @@ -99,6 +105,12 @@ class Battery_Installation_Requirement(models.Model): line_ids_sfg_ups8 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 8",compute='_compute_line_ids_by_ups',store=False) line_ids_sfg_ups9 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 9",compute='_compute_line_ids_by_ups',store=False) line_ids_sfg_ups10 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 10",compute='_compute_line_ids_by_ups',store=False) + line_ids_sfg_ups11 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 11",compute='_compute_line_ids_by_ups',store=False) + line_ids_sfg_ups12 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 12",compute='_compute_line_ids_by_ups',store=False) + line_ids_sfg_ups13 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 13",compute='_compute_line_ids_by_ups',store=False) + line_ids_sfg_ups14 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 14",compute='_compute_line_ids_by_ups',store=False) + line_ids_sfg_ups15 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 15",compute='_compute_line_ids_by_ups',store=False) + #Material Fields line_ids_material_ups1 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 1",compute='_compute_line_ids_by_ups',store=False) @@ -111,6 +123,12 @@ class Battery_Installation_Requirement(models.Model): line_ids_material_ups8 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 8",compute='_compute_line_ids_by_ups',store=False) line_ids_material_ups9 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 9",compute='_compute_line_ids_by_ups',store=False) line_ids_material_ups10 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 10",compute='_compute_line_ids_by_ups',store=False) + line_ids_material_ups11 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 11",compute='_compute_line_ids_by_ups',store=False) + line_ids_material_ups12 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 12",compute='_compute_line_ids_by_ups',store=False) + line_ids_material_ups13 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 13",compute='_compute_line_ids_by_ups',store=False) + line_ids_material_ups14 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 14",compute='_compute_line_ids_by_ups',store=False) + line_ids_material_ups15 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 15",compute='_compute_line_ids_by_ups',store=False) + #Installation Kit Fields line_ids_installation_kit_ups1 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 1",compute='_compute_line_ids_by_ups',store=False) @@ -123,6 +141,11 @@ class Battery_Installation_Requirement(models.Model): line_ids_installation_kit_ups8 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 8",compute='_compute_line_ids_by_ups',store=False) line_ids_installation_kit_ups9 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 9",compute='_compute_line_ids_by_ups',store=False) line_ids_installation_kit_ups10 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 10",compute='_compute_line_ids_by_ups',store=False) + line_ids_installation_kit_ups11 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 11",compute='_compute_line_ids_by_ups',store=False) + line_ids_installation_kit_ups12 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 12",compute='_compute_line_ids_by_ups',store=False) + line_ids_installation_kit_ups13 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 13",compute='_compute_line_ids_by_ups',store=False) + line_ids_installation_kit_ups14 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 14",compute='_compute_line_ids_by_ups',store=False) + line_ids_installation_kit_ups15 = fields.One2many('sos_proposal_line_material_installation', 'ref_id', string="Installation Kit UPS 15",compute='_compute_line_ids_by_ups',store=False) #Miscellaneous Kit Fields line_ids_miscellaneous_ups1 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 1",compute='_compute_line_ids_by_ups',store=False) @@ -135,6 +158,11 @@ class Battery_Installation_Requirement(models.Model): line_ids_miscellaneous_ups8 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 8",compute='_compute_line_ids_by_ups',store=False) line_ids_miscellaneous_ups9 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 9",compute='_compute_line_ids_by_ups',store=False) line_ids_miscellaneous_ups10 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 10",compute='_compute_line_ids_by_ups',store=False) + line_ids_miscellaneous_ups11 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 11",compute='_compute_line_ids_by_ups',store=False) + line_ids_miscellaneous_ups12 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 12",compute='_compute_line_ids_by_ups',store=False) + line_ids_miscellaneous_ups13 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 13",compute='_compute_line_ids_by_ups',store=False) + line_ids_miscellaneous_ups14 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 14",compute='_compute_line_ids_by_ups',store=False) + line_ids_miscellaneous_ups15 = fields.One2many('sos_proposal_miscellaneous_items', 'ref_id', string="Miscellaneous UPS 15",compute='_compute_line_ids_by_ups',store=False) #ups totals ups1_total = fields.Float(string="UPS 1 Total Cost",compute='_compute_ups_total',store=True) @@ -147,6 +175,11 @@ class Battery_Installation_Requirement(models.Model): ups8_total = fields.Float(string="UPS 8 Total Cost", compute='_compute_ups_total', store=True) ups9_total = fields.Float(string="UPS 9 Total Cost", compute='_compute_ups_total', store=True) ups10_total = fields.Float(string="UPS 10 Total Cost", compute='_compute_ups_total', store=True) + ups11_total = fields.Float(string="UPS 11 Total Cost", compute='_compute_ups_total', store=True) + ups12_total = fields.Float(string="UPS 12 Total Cost", compute='_compute_ups_total', store=True) + ups13_total = fields.Float(string="UPS 13 Total Cost", compute='_compute_ups_total', store=True) + ups14_total = fields.Float(string="UPS 14 Total Cost", compute='_compute_ups_total', store=True) + ups15_total = fields.Float(string="UPS 15 Total Cost", compute='_compute_ups_total', store=True) extra_lines_cost = fields.Monetary(string="Cost", compute='_compute_extra_lines_cost', store=True, currency_field='currency_id') packing_and_forwarding = fields.Monetary(string="Packing & Forwarding", currency_field='currency_id',store=True) @@ -161,6 +194,11 @@ class Battery_Installation_Requirement(models.Model): line_ids_spare_ups8 = fields.One2many('sos_proposal_line_spare_ups8','ref_id', string="Spare UPS 8") line_ids_spare_ups9 = fields.One2many('sos_proposal_line_spare_ups9','ref_id', string="Spare UPS 9") line_ids_spare_ups10 = fields.One2many('sos_proposal_line_spare_ups10','ref_id', string="Spare UPS 10") + line_ids_spare_ups11 = fields.One2many('sos_proposal_line_spare_ups11','ref_id', string="Spare UPS 11") + line_ids_spare_ups12 = fields.One2many('sos_proposal_line_spare_ups12','ref_id', string="Spare UPS 12") + line_ids_spare_ups13 = fields.One2many('sos_proposal_line_spare_ups13','ref_id', string="Spare UPS 13") + line_ids_spare_ups14 = fields.One2many('sos_proposal_line_spare_ups14','ref_id', string="Spare UPS 14") + line_ids_spare_ups15 = fields.One2many('sos_proposal_line_spare_ups15','ref_id', string="Spare UPS 15") @api.model def create(self, vals): res = super().create(vals) @@ -254,11 +292,16 @@ class Battery_Installation_Requirement(models.Model): 'line_ids_spare_ups7.total_price', 'line_ids_spare_ups7.production_cost', 'line_ids_spare_ups8.total_price', 'line_ids_spare_ups8.production_cost', 'line_ids_spare_ups9.total_price', 'line_ids_spare_ups9.production_cost', - 'line_ids_spare_ups10.total_price', 'line_ids_spare_ups10.production_cost' + 'line_ids_spare_ups10.total_price', 'line_ids_spare_ups10.production_cost', + 'line_ids_spare_ups11.total_price', 'line_ids_spare_ups11.production_cost', + 'line_ids_spare_ups12.total_price', 'line_ids_spare_ups12.production_cost', + 'line_ids_spare_ups13.total_price', 'line_ids_spare_ups13.production_cost', + 'line_ids_spare_ups14.total_price', 'line_ids_spare_ups14.production_cost', + 'line_ids_spare_ups15.total_price', 'line_ids_spare_ups15.production_cost' ) def _compute_ups_total(self): for rec in self: - for i in range(1, 11): + for i in range(1, 16): total = 0 for field_name in [ 'line_ids_fg', @@ -293,6 +336,11 @@ class Battery_Installation_Requirement(models.Model): rec.line_ids_fg_ups8 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 8) rec.line_ids_fg_ups9 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 9) rec.line_ids_fg_ups10 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 10) + rec.line_ids_fg_ups11 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 11) + rec.line_ids_fg_ups12 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 12) + rec.line_ids_fg_ups13 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 13) + rec.line_ids_fg_ups14 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 14) + rec.line_ids_fg_ups15 = rec.line_ids_fg.filtered(lambda l: l.ups_index == 15) rec.line_ids_sfg_ups1 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 1) rec.line_ids_sfg_ups2 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 2) @@ -304,6 +352,11 @@ class Battery_Installation_Requirement(models.Model): rec.line_ids_sfg_ups8 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 8) rec.line_ids_sfg_ups9 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 9) rec.line_ids_sfg_ups10 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 10) + rec.line_ids_sfg_ups11 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 11) + rec.line_ids_sfg_ups12 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 12) + rec.line_ids_sfg_ups13 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 13) + rec.line_ids_sfg_ups14 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 14) + rec.line_ids_sfg_ups15 = rec.line_ids_sfg.filtered(lambda l: l.ups_index == 15) rec.line_ids_material_ups1 = rec.line_ids_material.filtered(lambda l: l.ups_index == 1) rec.line_ids_material_ups2 = rec.line_ids_material.filtered(lambda l: l.ups_index == 2) @@ -315,6 +368,12 @@ class Battery_Installation_Requirement(models.Model): rec.line_ids_material_ups8 = rec.line_ids_material.filtered(lambda l: l.ups_index == 8) rec.line_ids_material_ups9 = rec.line_ids_material.filtered(lambda l: l.ups_index == 9) rec.line_ids_material_ups10 = rec.line_ids_material.filtered(lambda l: l.ups_index == 10) + rec.line_ids_material_ups11 = rec.line_ids_material.filtered(lambda l: l.ups_index == 11) + rec.line_ids_material_ups12 = rec.line_ids_material.filtered(lambda l: l.ups_index == 12) + rec.line_ids_material_ups13 = rec.line_ids_material.filtered(lambda l: l.ups_index == 13) + rec.line_ids_material_ups14 = rec.line_ids_material.filtered(lambda l: l.ups_index == 14) + rec.line_ids_material_ups15 = rec.line_ids_material.filtered(lambda l: l.ups_index == 15) + rec.line_ids_installation_kit_ups1 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 1) rec.line_ids_installation_kit_ups2 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 2) @@ -326,6 +385,11 @@ class Battery_Installation_Requirement(models.Model): rec.line_ids_installation_kit_ups8 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 8) rec.line_ids_installation_kit_ups9 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 9) rec.line_ids_installation_kit_ups10 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 10) + rec.line_ids_installation_kit_ups11 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 11) + rec.line_ids_installation_kit_ups12 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 12) + rec.line_ids_installation_kit_ups13 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 13) + rec.line_ids_installation_kit_ups14 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 14) + rec.line_ids_installation_kit_ups15 = rec.line_ids_installation_kit.filtered(lambda l: l.ups_index == 15) rec.line_ids_miscellaneous_ups1 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 1) rec.line_ids_miscellaneous_ups2 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 2) @@ -337,6 +401,11 @@ class Battery_Installation_Requirement(models.Model): rec.line_ids_miscellaneous_ups8 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 8) rec.line_ids_miscellaneous_ups9 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 9) rec.line_ids_miscellaneous_ups10 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 10) + rec.line_ids_miscellaneous_ups11 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 11) + rec.line_ids_miscellaneous_ups12 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 12) + rec.line_ids_miscellaneous_ups13 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 13) + rec.line_ids_miscellaneous_ups14 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 14) + rec.line_ids_miscellaneous_ups15 = rec.line_ids_miscellaneous.filtered(lambda l: l.ups_index == 15) @api.model @@ -362,10 +431,14 @@ class Battery_Installation_Requirement(models.Model): self.communication_type = self.proposal_id.communication_type self.specific_requirements = self.proposal_id.specific_requirements multiplier = max(1, math.ceil(self.proposal_id.number_of_batteries / 20)) - self.engineers_nos = 1 - self.no_of_days = multiplier - packing_calculation = 1200 - packing_kg_12V=100 + if self.proposal_id.number_of_batteries < 100: + self.engineers_nos = 1 + self.no_of_days = multiplier + else: + self.engineers_nos = 2 + self.no_of_days = multiplier / 2 + packing_calculation = 1200 + packing_kg_12V = 100 * self.proposal_id.number_of_ups direction = self.proposal_id.direction if direction == "North": forwarding_calculation = 20 * packing_kg_12V @@ -375,8 +448,9 @@ class Battery_Installation_Requirement(models.Model): forwarding_calculation = 23 * packing_kg_12V else: forwarding_calculation = 13 * packing_kg_12V - base_amount = 0.20 * (packing_calculation + forwarding_calculation) - self.packing_and_forwarding = base_amount * 0.18 + base_amount = 1.20 * (packing_calculation + forwarding_calculation) + self.packing_and_forwarding = base_amount * 1.18 + # Clear all lines self.line_ids_fg = [(5, 0, 0)] self.line_ids_sfg = [(5, 0, 0)] @@ -424,6 +498,7 @@ class Battery_Installation_Requirement(models.Model): material_lines.append((0, 0, { 'component_id': material_record.id, 'uom': material_record.uom, + 'singet_set_qty':single_set_qty, 'unit_price': material_record.unit_price, 'description': material_record.description, 'ups_index': ups_index, @@ -778,7 +853,7 @@ class sos_proposal_Material_installationkit(models.Model): def _compute_set_wise(self): for record in self: record.quantity = record.singet_set_qty * record.total_set - @api.depends('unit_price','quantity') + @api.depends('unit_price','quantity','production_cost') def _compute_total_price(self): for record in self: if record.production_cost: @@ -1153,6 +1228,176 @@ class sos_spare_material10(models.Model): _name = 'sos_proposal_line_spare_ups10' _description = 'Spare Material 10' + ref_id = fields.Many2one('sos_proposal_boq', ondelete="cascade") + component_id = fields.Many2one('sos_material', string="Material Name", required=True) + uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") + currency_id = fields.Many2one('res.currency', string='Currency') + material_code = fields.Char(related="component_id.material_code",string="Material Code") + material_name = fields.Char(related="component_id.part_no",string="Material Name") + singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) + total_set = fields.Integer(string="Total Set",default=1) + quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",readonly=False) + unit_price = fields.Monetary(store=True,currency_field='currency_id',string="Unit Price",related="component_id.unit_price") + total_price = fields.Monetary(string="Total",compute="_compute_total_price") + description = fields.Char(string="Description") + production_cost = fields.Boolean(string="Include in Costing",default=True) + ups_index = fields.Integer(string="UPS Index",store=True) + @api.onchange('component_id') + def _onchange_component_id(self): + for record in self: + if record.component_id: + record.unit_price = record.component_id.unit_price + @api.depends('singet_set_qty','total_set') + def _compute_set_wise(self): + for record in self: + record.quantity = record.singet_set_qty * record.total_set + @api.depends('unit_price', 'quantity', 'production_cost') + def _compute_total_price(self): + for record in self: + if record.production_cost: + record.total_price = record.unit_price * record.quantity + else: + record.total_price = 0.00 +class sos_spare_material11(models.Model): + _name = 'sos_proposal_line_spare_ups11' + _description = 'Spare Material 11' + + ref_id = fields.Many2one('sos_proposal_boq', ondelete="cascade") + component_id = fields.Many2one('sos_material', string="Material Name", required=True) + uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") + currency_id = fields.Many2one('res.currency', string='Currency') + material_code = fields.Char(related="component_id.material_code",string="Material Code") + material_name = fields.Char(related="component_id.part_no",string="Material Name") + singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) + total_set = fields.Integer(string="Total Set",default=1) + quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",readonly=False) + unit_price = fields.Monetary(store=True,currency_field='currency_id',string="Unit Price",related="component_id.unit_price") + total_price = fields.Monetary(string="Total",compute="_compute_total_price") + description = fields.Char(string="Description") + production_cost = fields.Boolean(string="Include in Costing",default=True) + ups_index = fields.Integer(string="UPS Index",store=True) + @api.onchange('component_id') + def _onchange_component_id(self): + for record in self: + if record.component_id: + record.unit_price = record.component_id.unit_price + @api.depends('singet_set_qty','total_set') + def _compute_set_wise(self): + for record in self: + record.quantity = record.singet_set_qty * record.total_set + @api.depends('unit_price', 'quantity', 'production_cost') + def _compute_total_price(self): + for record in self: + if record.production_cost: + record.total_price = record.unit_price * record.quantity + else: + record.total_price = 0.00 +class sos_spare_material12(models.Model): + _name = 'sos_proposal_line_spare_ups12' + _description = 'Spare Material 12' + + ref_id = fields.Many2one('sos_proposal_boq', ondelete="cascade") + component_id = fields.Many2one('sos_material', string="Material Name", required=True) + uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") + currency_id = fields.Many2one('res.currency', string='Currency') + material_code = fields.Char(related="component_id.material_code",string="Material Code") + material_name = fields.Char(related="component_id.part_no",string="Material Name") + singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) + total_set = fields.Integer(string="Total Set",default=1) + quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",readonly=False) + unit_price = fields.Monetary(store=True,currency_field='currency_id',string="Unit Price",related="component_id.unit_price") + total_price = fields.Monetary(string="Total",compute="_compute_total_price") + description = fields.Char(string="Description") + production_cost = fields.Boolean(string="Include in Costing",default=True) + ups_index = fields.Integer(string="UPS Index",store=True) + @api.onchange('component_id') + def _onchange_component_id(self): + for record in self: + if record.component_id: + record.unit_price = record.component_id.unit_price + @api.depends('singet_set_qty','total_set') + def _compute_set_wise(self): + for record in self: + record.quantity = record.singet_set_qty * record.total_set + @api.depends('unit_price', 'quantity', 'production_cost') + def _compute_total_price(self): + for record in self: + if record.production_cost: + record.total_price = record.unit_price * record.quantity + else: + record.total_price = 0.00 +class sos_spare_material13(models.Model): + _name = 'sos_proposal_line_spare_ups13' + _description = 'Spare Material 13' + + ref_id = fields.Many2one('sos_proposal_boq', ondelete="cascade") + component_id = fields.Many2one('sos_material', string="Material Name", required=True) + uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") + currency_id = fields.Many2one('res.currency', string='Currency') + material_code = fields.Char(related="component_id.material_code",string="Material Code") + material_name = fields.Char(related="component_id.part_no",string="Material Name") + singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) + total_set = fields.Integer(string="Total Set",default=1) + quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",readonly=False) + unit_price = fields.Monetary(store=True,currency_field='currency_id',string="Unit Price",related="component_id.unit_price") + total_price = fields.Monetary(string="Total",compute="_compute_total_price") + description = fields.Char(string="Description") + production_cost = fields.Boolean(string="Include in Costing",default=True) + ups_index = fields.Integer(string="UPS Index",store=True) + @api.onchange('component_id') + def _onchange_component_id(self): + for record in self: + if record.component_id: + record.unit_price = record.component_id.unit_price + @api.depends('singet_set_qty','total_set') + def _compute_set_wise(self): + for record in self: + record.quantity = record.singet_set_qty * record.total_set + @api.depends('unit_price', 'quantity', 'production_cost') + def _compute_total_price(self): + for record in self: + if record.production_cost: + record.total_price = record.unit_price * record.quantity + else: + record.total_price = 0.00 +class sos_spare_material14(models.Model): + _name = 'sos_proposal_line_spare_ups14' + _description = 'Spare Material 14' + + ref_id = fields.Many2one('sos_proposal_boq', ondelete="cascade") + component_id = fields.Many2one('sos_material', string="Material Name", required=True) + uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") + currency_id = fields.Many2one('res.currency', string='Currency') + material_code = fields.Char(related="component_id.material_code",string="Material Code") + material_name = fields.Char(related="component_id.part_no",string="Material Name") + singet_set_qty = fields.Integer(string="Single Set Quantity",default=1) + total_set = fields.Integer(string="Total Set",default=1) + quantity = fields.Integer(string="Quantity",compute="_compute_set_wise",readonly=False) + unit_price = fields.Monetary(store=True,currency_field='currency_id',string="Unit Price",related="component_id.unit_price") + total_price = fields.Monetary(string="Total",compute="_compute_total_price") + description = fields.Char(string="Description") + production_cost = fields.Boolean(string="Include in Costing",default=True) + ups_index = fields.Integer(string="UPS Index",store=True) + @api.onchange('component_id') + def _onchange_component_id(self): + for record in self: + if record.component_id: + record.unit_price = record.component_id.unit_price + @api.depends('singet_set_qty','total_set') + def _compute_set_wise(self): + for record in self: + record.quantity = record.singet_set_qty * record.total_set + @api.depends('unit_price', 'quantity', 'production_cost') + def _compute_total_price(self): + for record in self: + if record.production_cost: + record.total_price = record.unit_price * record.quantity + else: + record.total_price = 0.00 +class sos_spare_material15(models.Model): + _name = 'sos_proposal_line_spare_ups15' + _description = 'Spare Material 15' + ref_id = fields.Many2one('sos_proposal_boq', ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") diff --git a/sos_sales/models/sos_proposal_builder.py b/sos_sales/models/sos_proposal_builder.py index 7f5620b..ab345ed 100755 --- a/sos_sales/models/sos_proposal_builder.py +++ b/sos_sales/models/sos_proposal_builder.py @@ -18,7 +18,7 @@ class SOS_Proposal_Builder(models.Model): string='Currency', default=lambda self: self.env['res.currency'].search([('name', '=', 'INR')], limit=1).id or False ) - total_cost = fields.Monetary(string="Total Cost", currency_field='currency_id') + total_cost = fields.Float(string="Total Cost", compute='_compute_total_cost', store=True) buffer_in_percentage = fields.Integer(string="Buffer(%)",default=0,store=True) total_with_buffer = fields.Monetary(string="Total with Buffer", compute='_compute_total_with_buffer', currency_field='currency_id', store=True) #Proposal builder @@ -197,6 +197,32 @@ class SOS_Proposal_Builder(models.Model): for rec in self: buffer_percent = rec.buffer_in_percentage or 0.0 rec.total_with_buffer = rec.total_cost * (1 + buffer_percent / 100.0) + @api.depends('proposal_id') + def _compute_total_cost(self): + for rec in self: + boq = self.env['sos_proposal_boq'].search( + [('proposal_id', '=', rec.proposal_id.id)], + limit=1, order='id desc' + ) + rec.total_cost = boq.final_cost if boq else 0.0 + @api.model + def create(self, vals): + if vals.get('proposal_id') and not vals.get('total_cost'): + boq = self.env['sos_proposal_boq'].search( + [('proposal_id', '=', vals['proposal_id'])], limit=1, order='id desc' + ) + if boq: + vals['total_cost'] = boq.final_cost + return super().create(vals) + + def write(self, vals): + if vals.get('proposal_id') and not vals.get('total_cost'): + boq = self.env['sos_proposal_boq'].search( + [('proposal_id', '=', vals['proposal_id'])], limit=1, order='id desc' + ) + if boq: + vals['total_cost'] = boq.final_cost + return super().write(vals) class SOS_Technical_Diagrams(models.Model): _name = 'sos_proposal_diagrams' diff --git a/sos_sales/models/sos_proposal_customer_requirement.py b/sos_sales/models/sos_proposal_customer_requirement.py index 3d04d42..b921509 100755 --- a/sos_sales/models/sos_proposal_customer_requirement.py +++ b/sos_sales/models/sos_proposal_customer_requirement.py @@ -147,8 +147,8 @@ class Battery_Installation_Requirement(models.Model): @api.onchange('number_of_ups') def _onchange_number_of_ups(self): if self.number_of_ups is not None: - if self.number_of_ups > 10: - raise ValidationError("Number of UPS cannot be more than 10.") + if self.number_of_ups > 15: + raise ValidationError("Number of UPS cannot be more than 15.") lines = [(5, 0, 0)] # clear all for i in range(self.number_of_ups): diff --git a/sos_sales/models/sos_sales_achievement_report.py b/sos_sales/models/sos_sales_achievement_report.py index f1f225c..ff9fdb3 100755 --- a/sos_sales/models/sos_sales_achievement_report.py +++ b/sos_sales/models/sos_sales_achievement_report.py @@ -1,8 +1,9 @@ from odoo import models, fields, api -from datetime import date +from datetime import date, timedelta,datetime import re import calendar +from odoo.exceptions import UserError class SOS_Sales_Achievement_Report(models.Model): @@ -20,13 +21,13 @@ class SOS_Sales_Achievement_Report(models.Model): planned_target_april = fields.Float(string="Planned For April") actual_target_april = fields.Float(string="Actual For April") billed_target_april = fields.Float(string="Billed For April") - yet_to_billed_target_april = fields.Float(string="Yet to Billed For April") + yet_to_billed_target_april = fields.Float(string="Yet to Billed For April",compute="_compute_yet_to_billed_april") collected_target_april = fields.Float(string="Collected For April") achievement_percentage_april = fields.Char(string="Achievement Percentage For April", compute="_compute_achievement_percentage", store=True) planned_target_may = fields.Float(string="Planned For May") actual_target_may = fields.Float(string="Actual For May") billed_target_may = fields.Float(string="Billed For May") - yet_to_billed_target_may = fields.Float(string="Yet to Billed For May") + yet_to_billed_target_may = fields.Float(string="Yet to Billed For May",compute="_compute_yet_to_billed_targets") collected_target_may = fields.Float(string="Collected For May") achievement_percentage_may = fields.Char(string="Achievement Percentage For May", compute="_compute_achievement_percentage", store=True) planned_target_june = fields.Float(string="Planned For June") @@ -108,7 +109,50 @@ class SOS_Sales_Achievement_Report(models.Model): ytd_billed = fields.Float(string="YTD Billed", store=True,compute="_compute_ytd_billed") ytd_collected = fields.Float(string="YTD Collected", store=True,compute="_compute_ytd_collected") line_ids = fields.One2many('sos_sales_achievement_report_brief', 'ref_id',copy=True) - + billing_collection_line_ids = fields.One2many( + 'sos_billing_collection', + 'ref_id', + string="Billing Collection Lines" + ) + @api.depends('opening_balance', 'actual_target_april', 'billed_target_april') + def _compute_yet_to_billed_april(self): + for rec in self: + rec.yet_to_billed_target_april = (rec.opening_balance or 0.0) + \ + (rec.actual_target_april or 0.0) - \ + (rec.billed_target_april or 0.0) + + @api.depends( + 'yet_to_billed_target_april', # link to April + 'actual_target_may', 'billed_target_may', + 'actual_target_june', 'billed_target_june', + 'actual_target_july', 'billed_target_july', + 'actual_target_august', 'billed_target_august', + 'actual_target_september', 'billed_target_september', + 'actual_target_october', 'billed_target_october', + 'actual_target_november', 'billed_target_november', + 'actual_target_december', 'billed_target_december', + 'actual_target_january', 'billed_target_january', + 'actual_target_february', 'billed_target_february', + 'actual_target_march', 'billed_target_march', + ) + def _compute_yet_to_billed_targets(self): + month_order = [ + 'may', 'june', 'july', 'august', 'september', + 'october', 'november', 'december', + 'january', 'february', 'march' + ] + + for rec in self: + prev_yet_to_bill = rec.yet_to_billed_target_april or 0.0 + for month in month_order: + actual = getattr(rec, f'actual_target_{month}', 0.0) or 0.0 + billed = getattr(rec, f'billed_target_{month}', 0.0) or 0.0 + result = prev_yet_to_bill + actual - billed + setattr(rec, f'yet_to_billed_target_{month}', result) + prev_yet_to_bill = result + + + @api.depends( 'yet_to_billed_target_april', 'yet_to_billed_target_may', 'yet_to_billed_target_june', 'yet_to_billed_target_july', 'yet_to_billed_target_august', 'yet_to_billed_target_september', @@ -137,41 +181,52 @@ class SOS_Sales_Achievement_Report(models.Model): def action_view_billed_lines(self): self.ensure_one() - # Extract the month from context - month = int(self.env.context.get('month', 0)) - if not month: - month = 4 # fallback to April - - # You must extract year (hardcoded or dynamic based on financial year logic) - # Assuming your main model has `financial_year = 'FY 2025-2026'` - match = re.search(r'FY\s*(\d{4})', self.financial_year or '') - if match: - year = int(match.group(1)) + month = int(self.env.context.get('month', 4)) # default April + action = self.env.context.get('action', 'Collected') + if action == 'Billed': + view_id = self.env.ref('sos_sales.view_sos_billed_collection_wizard_form_billed').id else: - year = date.today().year # fallback + view_id = self.env.ref('sos_sales.view_sos_billed_collection_wizard_form_collected').id - # Get month boundaries + # Extract year from financial_year string like 'FY 2025-2026' + match = re.search(r'FY\s*(\d{4})', self.financial_year or '') + year = int(match.group(1)) if match else date.today().year + + # Get month date range last_day = calendar.monthrange(year, month)[1] - from_date = f'{year}-{month:02d}-01' - to_date = f'{year}-{month:02d}-{last_day:02d}' - # Fetch Billed lines + from_date = date(year, month, 1) + to_date = date(year, month, last_day) + + # Use the actual related record's value (not the related field) + sales_person_id = self.sales_person.id or self.ref('sales_person').id + + # If sales_person is still None, raise a warning + if not sales_person_id: + raise UserError("Sales person is missing in this record.") + + # Search filtered billing lines billed_lines = self.env['sos_billing_collection'].search([ - ('sales_person', '=', self.sales_person.id), - ('action_status', '=', self.env.context.get('action')), + ('sales_person', '=', sales_person_id), + ('action_status', '=', action), ('date_of_action', '>=', from_date), ('date_of_action', '<=', to_date), ]) + wizard = self.env['sos_billed_collection_wizard'].create({ + 'main_parent_id': self.id, + 'billed_line_ids': [(6, 0, billed_lines.ids)], + 'action_status': action, + }) + return { 'name': f"{self.env.context.get('action')} Items", 'type': 'ir.actions.act_window', 'res_model': 'sos_billed_collection_wizard', 'view_mode': 'form', + 'view_id': view_id, 'target': 'new', - 'context': { - 'default_billed_line_ids': [(6, 0, billed_lines.ids)], - 'default_parent_id': self.id, - } + 'res_id': wizard.id, } + def action_view_brief_lines(self): self.ensure_one() domain = [('ref_id', '=', self.id)] @@ -204,6 +259,7 @@ class SOS_Sales_Achievement_Report(models.Model): } } + @api.depends( 'collected_target_april', 'collected_target_may', 'collected_target_june', 'collected_target_july', 'collected_target_august', 'collected_target_september', @@ -500,13 +556,107 @@ class SOS_Sales_Achievement_Report_Brief(models.Model): _order = 'action_date desc' ref_id = fields.Many2one('sos_sales_achievement_report', string="Financial Year", ondelete="cascade") customer_name = fields.Many2one('sos_customers',string="Customer Name", required=True) - action_date = fields.Date(string="QP No") + action_date = fields.Date(string="Date") currency_id = fields.Many2one( 'res.currency', string='Currency', default=lambda self: self.env['res.currency'].search([('name', '=', 'INR')], limit=1).id or False ) - proposal_value = fields.Monetary(currency_field='currency_id',string="Proposal Value(In Lakhs)") + proposal_value = fields.Monetary(currency_field='currency_id',string="PO Received(In Lakhs)") + billed_date = fields.Date(string="Billed Date") + billed_amount = fields.Monetary(currency_field='currency_id',string="Billed Value(In Lakhs)") + def open_line_form(self): + self.ensure_one() + return { + 'type': 'ir.actions.act_window', + 'name': 'Edit Line', + 'res_model': self._name, + 'res_id': self.id, + 'view_mode': 'form', + 'target': 'new', # Opens as a popup + } + def _get_financial_year(self,current_date): + start_year = current_date.year if current_date.month >= 4 else current_date.year - 1 + end_year = start_year + 1 + return f"FY {start_year}-{end_year}" + + def write(self, vals): + for rec in self: + # Previous values + old_billed_date = rec.billed_date + old_billed_amount = rec.billed_amount + report = rec.ref_id + # New values + new_billed_date = vals.get('billed_date', old_billed_date) + new_billed_amount = vals.get('billed_amount', old_billed_amount) + + if isinstance(new_billed_date, str): + new_billed_date = datetime.strptime(new_billed_date, '%Y-%m-%d').date() + + # Adjust billed target + if report and old_billed_date and new_billed_date: + old_month_billed = old_billed_date.strftime('%B').lower() + new_month_billed = new_billed_date.strftime('%B').lower() + if old_month_billed != new_month_billed or old_billed_amount != new_billed_amount: + old_field_billed = f"billed_target_{old_month_billed}" + new_field_billed = f"billed_target_{new_month_billed}" + if hasattr(report, old_field_billed): + report.write({ + old_field_billed: max((getattr(report, old_field_billed, 0.0) or 0.0) - old_billed_amount, 0.0) + }) + if hasattr(report, new_field_billed): + report.write({ + new_field_billed: (getattr(report, new_field_billed, 0.0) or 0.0) + new_billed_amount + }) + # Optionally create billing collection entry (if needed) + if new_billed_amount > 0: + self.env['sos_billing_collection'].create({ + 'ref_id': report.id, + 'customer_name': vals.get('customer_name', rec.customer_name.id), + 'sales_person': report.sales_person.id, + 'action_status': 'Billed', + 'date_of_action': new_billed_date, + 'value': new_billed_amount + }) + + return super(SOS_Sales_Achievement_Report_Brief, self).write(vals) + + @api.model + def create(self, vals): + action_date = vals.get('action_date') + billed_date = vals.get('billed_date') + customer_name = vals.get('customer_name') + + if isinstance(action_date, str): + action_date = datetime.strptime(action_date, '%Y-%m-%d').date() + if isinstance(billed_date, str): + billed_date = datetime.strptime(billed_date, '%Y-%m-%d').date() + + month_name = action_date.strftime('%B').lower() + value = vals.get('proposal_value', 0.0) + actual_field = f"actual_target_{month_name}" + + ref_id = vals.get('ref_id') + if ref_id: + report = self.env['sos_sales_achievement_report'].browse(ref_id) + sales_person = report.sales_person + if sales_person and hasattr(report, actual_field): + current_value = getattr(report, actual_field, 0.0) or 0.0 + report.write({actual_field: current_value + value}) + + # Instead of also summing billed_value here, just create billing line + if billed_date: + self.env['sos_billing_collection'].create({ + 'ref_id': report.id, + 'customer_name': customer_name, + 'sales_person': report.sales_person.id, + 'action_status': 'Billed', + 'date_of_action': billed_date, + 'value': vals.get('billed_amount', 0.0) + }) + + return super(SOS_Sales_Achievement_Report_Brief, self).create(vals) + class SOS_Sales_Achievement_Report_Brief_Wizard(models.TransientModel): _name = 'sos_sales_achievement_report_brief_wizard' @@ -520,13 +670,144 @@ class SOS_Sales_Achievement_Report_Brief_Wizard(models.TransientModel): string="Brief Lines", readonly=True ) + + + def action_add_new_brief_line(self): + self.ensure_one() + return { + 'type': 'ir.actions.act_window', + 'name': 'Add Brief Line', + 'res_model': 'sos_sales_achievement_report_brief', + 'view_mode': 'form', + 'target': 'new', + 'context': { + 'default_ref_id': self.parent_id.id, + 'default_currency_id': self.env.ref('base.INR').id, + } + } class SosBilledCollectionWizard(models.TransientModel): _name = 'sos_billed_collection_wizard' _description = 'Billed Collection Lines Wizard' - parent_id = fields.Many2one('sos_billing_collection') # adjust accordingly + main_parent_id = fields.Many2one('sos_sales_achievement_report', string="Sales Achievement Report") billed_line_ids = fields.Many2many( 'sos_billing_collection', string="Billed Lines", readonly=True, - ) \ No newline at end of file + domain="[('ref_id', '=', main_parent_id)]" + ) + action_status = fields.Selection([ + ('Billed', 'Billed'), + ('Collected', 'Collected') + ], string='Action Status', readonly=True) + @api.model + def default_get(self, fields_list): + res = super(SosBilledCollectionWizard, self).default_get(fields_list) + main_parent_id = self.env.context.get('active_id') + if main_parent_id and self.env.context.get('active_model') == 'sos_sales_achievement_report': + res['main_parent_id'] = main_parent_id + # Populate billed_line_ids with related sos_billing_collection records + billing_lines = self.env['sos_billing_collection'].search([('ref_id', '=', main_parent_id)]) + res['billed_line_ids'] = [(6, 0, billing_lines.ids)] + return res + + def action_add_new_collection_line(self): + self.ensure_one() + if not self.main_parent_id: + raise UserError("No Sales Achievement Report found.") + if self.action_status == "Collected": + form_title="Collection" + view_xml_id="view_sos_billing_collection_minimal_form_collection" + else: + form_title="Billed" + view_xml_id="view_sos_billing_collection_minimal_form_billed" + return { + 'type': 'ir.actions.act_window', + 'name': f'Add {form_title}', + 'res_model': 'sos_billing_collection', + 'view_mode': 'form', + 'view_id': self.env.ref(f'sos_sales.{view_xml_id}').id, + + 'target': 'new', + 'context': { + 'default_ref_id': self.main_parent_id.id, + 'default_action_status': self.action_status, + 'default_sales_person': self.main_parent_id.sales_person.id if self.main_parent_id.sales_person else False, + } + } +class SosBillingCollection(models.Model): + _name = 'sos_billing_collection' + _description = 'Billing & Collection Details' + + ref_id = fields.Many2one('sos_sales_achievement_report', ondelete="cascade", required=True) + customer_name = fields.Many2one('sos_customers', string="Customer Name") + sales_person = fields.Many2one( + 'res.users', + string='Sales Executive', + related="ref_id.sales_person", + store=True + ) + action_status = fields.Selection([ + ('Billed', 'Billed'), + ('Collected', 'Collected') + ], string='Action') + date_of_action = fields.Date(string="Date") + currency_id = fields.Many2one( + 'res.currency', + string='Currency', + default=lambda self: self.env['res.currency'].search([('name', '=', 'INR')], limit=1).id or False + ) + value = fields.Monetary(currency_field='currency_id', string="Value (In Lakhs)") + customer_name = fields.Many2one('sos_customers',string="Customer Name") + po_no = fields.Char(string="PO No") + invoice_no = fields.Char(string="Invoice No") + products = fields.Selection( + [ + ('BHMS 1.2V', 'BHMS 1.2V'), + ('BHMS 2V', 'BHMS 2V'), + ('BHMS 12V', 'BHMS 12V'), + ('BHMS 48V', 'BHMS 48V'), + ('BMS-HV', 'BMS-HV'), + ('BMS-LV 100A', 'BMS-LV 100A'), + ('BMS-LV 40A', 'BMS-LV 40A'), + ('SBMS 55A', 'SBMS 55A'), + ('MC 250W', 'MC 250W'), + ('HeartTarang', 'HeartTarang') + ], + string="Products") + quantity = fields.Integer(string="Quantity") + def _get_financial_year(self, current_date): + start_year = current_date.year if current_date.month >= 4 else current_date.year - 1 + end_year = start_year + 1 + return f"FY {start_year}-{end_year}" + + @api.model + def create(self, vals): + if not vals.get('ref_id'): + raise UserError("Cannot create record without a valid Sales Achievement Report.") + + action_date = vals.get('date_of_action') + action_status = vals.get('action_status').lower() + if isinstance(action_date, str): + action_date = datetime.strptime(action_date, '%Y-%m-%d').date() + + fy = self._get_financial_year(action_date) if action_date else False + month_name = action_date.strftime('%B').lower() if action_date else False + final_value = vals.get('value', 0.0) + actual_field = f"{action_status}_target_{month_name}" if month_name else False + + record = super(SosBillingCollection, self).create(vals) + + # Update the related sos_sales_achievement_report by adding value + if vals.get('ref_id') and month_name: + report = self.env['sos_sales_achievement_report'].search([ + ('id', '=', vals.get('ref_id')), + ('financial_year', '=', fy), + ]) + if report and hasattr(report, actual_field): + current_value = getattr(report, actual_field, 0.0) or 0.0 + new_value = current_value + final_value + report.write({actual_field: new_value}) + + return record + diff --git a/sos_sales/models/sos_sales_action_plan.py b/sos_sales/models/sos_sales_action_plan.py index d883847..4772bb8 100755 --- a/sos_sales/models/sos_sales_action_plan.py +++ b/sos_sales/models/sos_sales_action_plan.py @@ -24,6 +24,14 @@ class sos_sales_action_plan(models.Model): string="End Customer/Quote No", domain="[('customer_name', '=', customer_name), ('quote_no', '!=', False)]" ) + ce_product_type = fields.Selection( + [ + ('Sales', 'Sales'), + ('Service', 'Service'), + ('Spare', 'Spare'), + ('Cloud', 'Cloud') + ], + string="Service Type") product = fields.Selection( [ ('BHMS 1.2V', 'BHMS 1.2V'), @@ -80,7 +88,7 @@ class sos_sales_action_plan(models.Model): ('Engaged to Negotiation', 'Engaged to Negotiation'), ('Negotiation to Order', 'Negotiation to Order') ], - string="Action Category",requierd=True) + string="Action Category",required=True) action_plan = fields.Text(string="Action Plan") result = fields.Text(string="Result") status = fields.Selection( @@ -101,9 +109,15 @@ class sos_sales_action_plan(models.Model): ], string='State', default='draft', readonly=True) def _get_customer_domain(self): - if self.env.user.has_group('sos_inventory.sos_management_user'): + if ( + self.env.user.has_group('sos_inventory.sos_management_user') or + self.env.user.has_group('sos_inventory.sos_ce_head') or + self.env.user.has_group('sos_inventory.sos_ce_user') + ): return [] # no filter, show all return [('responsible', '=', self.env.uid)] + + @api.onchange('quote_no_selector') def _onchange_quote_no_selector(self): if self.quote_no_selector: @@ -436,21 +450,23 @@ class sos_sales_action_plan(models.Model): } } else: - casediary_record = self.env['sos_case_diary'].create({ + vals = { 'customer_name': self.customer_name.id, - 'end_customer_name':self.end_customer_name, + 'end_customer_name': self.end_customer_name, 'customer_city': self.location, 'sales_person': self.sales_executive.id, 'products': self.product, 'proposal_value': self.value, 'status': self.status, - 'quote_no':self.quote_no, - 'quantity':self.quantity, - 'po_no':self.po_no, - 'po_copy':self.po_copy, - 'po_copy_filename':self.po_copy_filename - - }) + 'quote_no': self.quote_no, + 'quantity': self.quantity, + 'po_no': self.po_no, + 'po_copy': self.po_copy, + 'po_copy_filename': self.po_copy_filename + } + if self.ce_product_type: + vals['ce_product_type'] = self.ce_product_type + casediary_record = self.env['sos_case_diary'].create(vals) self.env['sos_case_diary_line'].create({ 'ref_id': casediary_record.id, 'action_plan_date': self.date, diff --git a/sos_sales/report/sos_proposal_report_view.xml b/sos_sales/report/sos_proposal_report_view.xml index 91e9356..c902d37 100755 --- a/sos_sales/report/sos_proposal_report_view.xml +++ b/sos_sales/report/sos_proposal_report_view.xml @@ -35,24 +35,24 @@
-



-

1. INTRODUCTION

-

ABOUT SOSALEY

+



+

1. INTRODUCTION

+
ABOUT SOSALEY

-

2. PROPOSAL OBJECTIVE

+

2. PROPOSAL OBJECTIVE

-

3. PROPOSAL OVERVIEW

+

3. PROPOSAL OVERVIEW

-

4. ARCHITECTURE

+

4. ARCHITECTURE



-

PARAMETERS MONITORED

+
PARAMETERS MONITORED


-

5. QUOTATION

+

5. QUOTATION

@@ -74,9 +74,9 @@
Customer Details
Billing Address
-

6. PAYMENT TERMS

+

6. PAYMENT TERMS

-

7. TERMS AND CONDITIONS

+

7. TERMS AND CONDITIONS

diff --git a/sos_sales/security/ir.model.access.csv b/sos_sales/security/ir.model.access.csv index ff410dd..0f4ffdb 100755 --- a/sos_sales/security/ir.model.access.csv +++ b/sos_sales/security/ir.model.access.csv @@ -51,9 +51,15 @@ access_sos_proposal_line_spare_ups7,sos_proposal_line_spare_ups7 access,model_so access_sos_proposal_line_spare_ups8,sos_proposal_line_spare_ups8 access,model_sos_proposal_line_spare_ups8,base.group_user,1,1,1,1 access_sos_proposal_line_spare_ups9,sos_proposal_line_spare_ups9 access,model_sos_proposal_line_spare_ups9,base.group_user,1,1,1,1 access_sos_proposal_line_spare_ups10,sos_proposal_line_spare_ups10 access,model_sos_proposal_line_spare_ups10,base.group_user,1,1,1,1 +access_sos_proposal_line_spare_ups11,sos_proposal_line_spare_ups11 access,model_sos_proposal_line_spare_ups11,base.group_user,1,1,1,1 +access_sos_proposal_line_spare_ups12,sos_proposal_line_spare_ups12 access,model_sos_proposal_line_spare_ups12,base.group_user,1,1,1,1 +access_sos_proposal_line_spare_ups13,sos_proposal_line_spare_ups13 access,model_sos_proposal_line_spare_ups13,base.group_user,1,1,1,1 +access_sos_proposal_line_spare_ups14,sos_proposal_line_spare_ups14 access,model_sos_proposal_line_spare_ups14,base.group_user,1,1,1,1 +access_sos_proposal_line_spare_ups15,sos_proposal_line_spare_ups15 access,model_sos_proposal_line_spare_ups15,base.group_user,1,1,1,1 access_sos_sales_achievement_report_brief,sos_sales_achievement_report_brief access,model_sos_sales_achievement_report_brief,base.group_user,1,1,1,1 access_sos_sales_achievement_report_brief_wizard,sos_sales_achievement_report_brief_wizard access,model_sos_sales_achievement_report_brief_wizard,base.group_user,1,1,1,1 access_sos_billing_collection,sos_billing_collection access,model_sos_billing_collection,base.group_user,1,1,1,1 access_sos_billed_collection_wizard,sos_billed_collection_wizard access,model_sos_billed_collection_wizard,base.group_user,1,1,1,1 +access_sos_business_performance_wizard,sos_business_performance_wizard access,model_sos_business_performance_wizard,base.group_user,1,1,1,1 diff --git a/sos_sales/security/record_rules.xml b/sos_sales/security/record_rules.xml index 53faec2..77969c5 100755 --- a/sos_sales/security/record_rules.xml +++ b/sos_sales/security/record_rules.xml @@ -68,6 +68,17 @@ + + Sales Action Plan: CE Head Reads CE User Records + + + + + + + + + Sos sales action plan: All Records - Read Access @@ -89,7 +100,8 @@ [(1, '=', 1)] @@ -127,7 +139,16 @@ - + + Case Diary: CE Head Reads CE User Records + + + + + + + + Sos Case Diary: All Records - Read Access diff --git a/sos_sales/views/menu.xml b/sos_sales/views/menu.xml index 402d5cc..335ec9f 100755 --- a/sos_sales/views/menu.xml +++ b/sos_sales/views/menu.xml @@ -1,7 +1,7 @@ - + \ No newline at end of file diff --git a/sos_sales/views/sos_case_diary_view.xml b/sos_sales/views/sos_case_diary_view.xml index c18591f..15c0924 100755 --- a/sos_sales/views/sos_case_diary_view.xml +++ b/sos_sales/views/sos_case_diary_view.xml @@ -164,36 +164,7 @@ - -
- -
-

Billed

-

- - - - - - - -
-
-
-

Collected

-

- - - - - - - -
-
-
+ @@ -310,7 +281,7 @@ - +
- + diff --git a/sos_sales/views/sos_proposal_boq_view.xml b/sos_sales/views/sos_proposal_boq_view.xml index cd26653..5d11f3a 100755 --- a/sos_sales/views/sos_proposal_boq_view.xml +++ b/sos_sales/views/sos_proposal_boq_view.xml @@ -1117,6 +1117,541 @@ + + + +

Finished Goods

+ + + + + + + + + + + + + + + +

Semi-Finished Goods

+ + + + + + + + + + + + + + + +

Materials

+ + + + + + + + + + + + + + + +

Installation Kit

+ + + + + + + + + + + + + + + +

Spare/Additional Materials

+ + + + + + + + + + + + + + +

Miscellaneous

+ + + + + + + + + + +
+ +

Finished Goods

+ + + + + + + + + + + + + + + +

Semi-Finished Goods

+ + + + + + + + + + + + + + + +

Materials

+ + + + + + + + + + + + + + + +

Installation Kit

+ + + + + + + + + + + + + + + +

Spare/Additional Materials

+ + + + + + + + + + + + + + +

Miscellaneous

+ + + + + + + + + + +
+ +

Finished Goods

+ + + + + + + + + + + + + + + +

Semi-Finished Goods

+ + + + + + + + + + + + + + + +

Materials

+ + + + + + + + + + + + + + + +

Installation Kit

+ + + + + + + + + + + + + + + +

Spare/Additional Materials

+ + + + + + + + + + + + + + +

Miscellaneous

+ + + + + + + + + + +
+ +

Finished Goods

+ + + + + + + + + + + + + + + +

Semi-Finished Goods

+ + + + + + + + + + + + + + + +

Materials

+ + + + + + + + + + + + + + + +

Installation Kit

+ + + + + + + + + + + + + + + +

Spare/Additional Materials

+ + + + + + + + + + + + + + +

Miscellaneous

+ + + + + + + + + + +
+ +

Finished Goods

+ + + + + + + + + + + + + + + +

Semi-Finished Goods

+ + + + + + + + + + + + + + + +

Materials

+ + + + + + + + + + + + + + + +

Installation Kit

+ + + + + + + + + + + + + + + +

Spare/Additional Materials

+ + + + + + + + + + + + + + +

Miscellaneous

+ + + + + + + + + +
- + diff --git a/sos_sales/views/sos_sales_leads_view.xml b/sos_sales/views/sos_sales_leads_view.xml index b8fdf2a..f607b39 100755 --- a/sos_sales/views/sos_sales_leads_view.xml +++ b/sos_sales/views/sos_sales_leads_view.xml @@ -99,5 +99,5 @@ - + diff --git a/sos_sales/views/sos_sales_plan_view.xml b/sos_sales/views/sos_sales_plan_view.xml index a11bd41..03ea63f 100755 --- a/sos_sales/views/sos_sales_plan_view.xml +++ b/sos_sales/views/sos_sales_plan_view.xml @@ -257,5 +257,5 @@ name="action_report_sales_plan_btn"> Print Report - + diff --git a/sos_sales/views/sos_vertical_domain_view.xml b/sos_sales/views/sos_vertical_domain_view.xml index e3f53da..86d532e 100755 --- a/sos_sales/views/sos_vertical_domain_view.xml +++ b/sos_sales/views/sos_vertical_domain_view.xml @@ -39,5 +39,5 @@ - + diff --git a/sos_sales/wizard/sos_sales_achievement_wizard_view.xml b/sos_sales/wizard/sos_sales_achievement_wizard_view.xml index 1ff9c81..a66042f 100644 --- a/sos_sales/wizard/sos_sales_achievement_wizard_view.xml +++ b/sos_sales/wizard/sos_sales_achievement_wizard_view.xml @@ -1,19 +1,32 @@ + sos_sales_achievement_report_brief_wizard.form sos_sales_achievement_report_brief_wizard
+
+ + + - - + + + + +