From e7cbc694f87a4e56ced5f3ab35e5f70acada863d Mon Sep 17 00:00:00 2001 From: projectsodoo Date: Sat, 19 Dec 2020 09:19:59 +0530 Subject: [PATCH 1/8] Project to sale order wizard updated --- cor_custom/__init__.py | 1 + cor_custom/__manifest__.py | 1 + .../__pycache__/__init__.cpython-36.pyc | Bin 239 -> 0 bytes .../__pycache__/__init__.cpython-36.pyc | Bin 193 -> 0 bytes .../__pycache__/controllers.cpython-36.pyc | Bin 160 -> 0 bytes .../__pycache__/__init__.cpython-36.pyc | Bin 344 -> 0 bytes .../__pycache__/analytic.cpython-36.pyc | Bin 1483 -> 0 bytes .../__pycache__/crm_lead.cpython-36.pyc | Bin 1093 -> 0 bytes .../models/__pycache__/models.cpython-36.pyc | Bin 150 -> 0 bytes .../models/__pycache__/product.cpython-36.pyc | Bin 984 -> 0 bytes .../models/__pycache__/project.cpython-36.pyc | Bin 3045 -> 0 bytes .../project_overview.cpython-36.pyc | Bin 5983 -> 0 bytes cor_custom/models/project.py | 2 +- .../__pycache__/__init__.cpython-36.pyc | Bin 214 -> 0 bytes ...ofitability_report_analysis.cpython-36.pyc | Bin 24835 -> 0 bytes cor_custom/wizard/__init__.py | 4 + .../wizard/project_create_sale_order.py | 106 ++++++++++++++++++ .../project_create_sale_order_views.xml | 16 +++ .../__pycache__/__init__.cpython-36.pyc | Bin 216 -> 0 bytes .../__pycache__/__init__.cpython-36.pyc | Bin 199 -> 0 bytes .../__pycache__/controllers.cpython-36.pyc | Bin 3859 -> 0 bytes .../__pycache__/__init__.cpython-36.pyc | Bin 189 -> 0 bytes .../models/__pycache__/models.cpython-36.pyc | Bin 1016 -> 0 bytes 23 files changed, 129 insertions(+), 1 deletion(-) delete mode 100755 cor_custom/__pycache__/__init__.cpython-36.pyc delete mode 100755 cor_custom/controllers/__pycache__/__init__.cpython-36.pyc delete mode 100755 cor_custom/controllers/__pycache__/controllers.cpython-36.pyc delete mode 100644 cor_custom/models/__pycache__/__init__.cpython-36.pyc delete mode 100644 cor_custom/models/__pycache__/analytic.cpython-36.pyc delete mode 100755 cor_custom/models/__pycache__/crm_lead.cpython-36.pyc delete mode 100755 cor_custom/models/__pycache__/models.cpython-36.pyc delete mode 100644 cor_custom/models/__pycache__/product.cpython-36.pyc delete mode 100644 cor_custom/models/__pycache__/project.cpython-36.pyc delete mode 100755 cor_custom/models/__pycache__/project_overview.cpython-36.pyc delete mode 100755 cor_custom/report/__pycache__/__init__.cpython-36.pyc delete mode 100755 cor_custom/report/__pycache__/project_profitability_report_analysis.cpython-36.pyc create mode 100644 cor_custom/wizard/__init__.py create mode 100644 cor_custom/wizard/project_create_sale_order.py create mode 100644 cor_custom/wizard/project_create_sale_order_views.xml delete mode 100644 odoo-debrand/__pycache__/__init__.cpython-36.pyc delete mode 100644 odoo-debrand/controllers/__pycache__/__init__.cpython-36.pyc delete mode 100644 odoo-debrand/controllers/__pycache__/controllers.cpython-36.pyc delete mode 100644 odoo-debrand/models/__pycache__/__init__.cpython-36.pyc delete mode 100644 odoo-debrand/models/__pycache__/models.cpython-36.pyc diff --git a/cor_custom/__init__.py b/cor_custom/__init__.py index 8628669..1099cf8 100755 --- a/cor_custom/__init__.py +++ b/cor_custom/__init__.py @@ -2,4 +2,5 @@ from . import controllers from . import models +from . import wizard from . import report \ No newline at end of file diff --git a/cor_custom/__manifest__.py b/cor_custom/__manifest__.py index f071be5..8b17674 100755 --- a/cor_custom/__manifest__.py +++ b/cor_custom/__manifest__.py @@ -33,6 +33,7 @@ 'report/project_profitability_report_analysis_views.xml', 'views/views.xml', 'views/templates.xml', + 'wizard/project_create_sale_order_views.xml', ], # only loaded in demonstration mode 'demo': [ diff --git a/cor_custom/__pycache__/__init__.cpython-36.pyc b/cor_custom/__pycache__/__init__.cpython-36.pyc deleted file mode 100755 index 638c9eeee6ca180eae2d5b074c1412ce15d39de7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 239 zcmX}lK?=e!5CzbrsYSHChh5Ylx|HGx+_)=3kS2>l+9^r8@G9QGOL&mFbmbLXIa9&F z{Jbz>W}9V;$L*=kjIkHi|3s(*mS16LrnzM;uQ(@1=%|V&3$&;NIzF*{_U8CK=i{=5 zE;z8(IFHYy1#RpkXL@kqn8zb?w8ROD7~{@dLZlIZ>O#B`0|UcjAcg}bAj<)Wiv@s03PTEG4nr1ps*(6 zE$-y}ypp2)oSf96Vn0o$TMR`YjVl?7Sb!9m_~oUaUr?f-pOT+%Xac5mlS_+B@^f_) zQ&RHtiuIH8i*!MlIZ>O%Z$CI*Jb3`l?x$aVnYViq8g!Vt`$$>_I|p$H_5Ab$Dk=NFXd=cnZ7 z8=8PA-Q?2ZlKfoV#FUi$ykh<2{32bDEQk>gkpeRFN{aGxa#D*x@^H3ZLFFwDo80`A O(wtN~kTu0X%m4uV7%UI~ diff --git a/cor_custom/models/__pycache__/__init__.cpython-36.pyc b/cor_custom/models/__pycache__/__init__.cpython-36.pyc deleted file mode 100644 index b5c4e70da103d82d264c494b2987f9fe428001ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 344 zcmX}myG{fl6b4|JyBjz0HKrJe(bAZ0?2L^a4VeJN7-r4{m^J$>_9nj4#LmiBu<{&s zT?jv4INWZx+s*F%OMNiLzHyvehT7o>PZ)+7?%2pB=j05X$t*cX=Q2+&(1k3LOLQsA zV5qWi@g1z#5$v}ornGBU* z^f!JokkR*S)cF^EvQc3Dbe`L2nyXT38&!=|rM6s*eB1p&D|iIZfbBobGNpApIruRx zbD5gFshwfOZBJdz0XLv2Bfq;w8Bo(7qfjj2k|mzxiLZhpe8#3+deVOyZ+H^986l06 z&NCLUBu12xeH$Y;i`qP_({gF@?AyFnt9R4ZI8L|Laf#;4bFmnUaKu_NAG`h&#hMpb zy$wct;=w(`4MyGI{5S4af(?h~P79sJ3SUM?tO#UB#yk7eKgSc--r9rbS6{EaBK(T| z^5EKE`$bfAc7D+R8CqiO-9vUAI6IzO2TuYxbCJ7kelN zr?$VSb0gA<5R_vnx1;rP`GSA8I(glt^E9j)P(w4rSYIyWxiU(+IC`{aeVjs!kbr7zeN|uD zNUIdGnZ2XaQVF^Y@d^|T1KPe%+Xs)g{=|h@+I^E(O3#!sg3_>|Ud$Chk9I~GsMILr zK%iAQwZUbI%O zv}vm2RLZ8-ldOSbS|vraOOy65n7m}yd^Sl|JB`0V77{m*7r`kIfd9dVQ3$v2#LZ>F9h}HdQmZi`SF5%W7wJQWigpjrcRf1K;a={lXioM-bNu1hViRKDd zuDk=UWR9G8g`Svkwk;BgGWmJNGl~CWzlh`LbnuHdf#dvk{<&c6yn#nO1H&BVmQLjo zxAKTr`NVgfcMkKI|IJ}O_b!94KIySw?xejxFyBdi(_a+4WXkj_!FZ{RpEX5}vD@qJ z3qQca9pW;Fc+4d}4=#IH`@2i}mIKQJ%RS4X<-X+&;D|kDyB8kY0FOt8HX7OJ$nwx~ zYm(_8JG{A9kc9OcLue2=ci*`8A zMZ=TB+1Wg8ch03)aHR@SXJs;9HI0zE-TlZHTuSSys!U!dN@scns(j|kcr!u5si?Kg za@~%g!X?jjGRrF7?tNPFMA;9BMWSKQbm2ChmIbeM@>Z0L%Ql+pOzPw$)4YwQrBK|m ziJGOTIbGGo)lH0c#Sg73z1csaH17bSNIa0H_W_Tqopb+(9X-K#_^NBjYn-i6`yKx; D-eEc4 diff --git a/cor_custom/models/__pycache__/models.cpython-36.pyc b/cor_custom/models/__pycache__/models.cpython-36.pyc deleted file mode 100755 index 18206e2f506784bae4310bafab77e46a0f53af8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 150 zcmXr!<>lIZ>O%YjMh1q*3`hXTXK(=GViq8g!Vt`$$>_I|p$H_5AbvUP=NFXd=cnZ7 z8=8PA-Q?2ZlKfoV#FUi$ykh<2{32bDEQk>gkj1i#t3kIjAjUc0avWz8Lzy| ztNhHbf-K9KAcP3U*BrKCi0MW@<1B<7Of_-i3*A6h z*h^WpDz|bmX_t;eyY_77MbUJ%J+%2(x4Q}p{E$Xysa!-ZQGyH6hx6jusl3WNWs`nS z(isWKmzk^+Bb6%a>%`7vvQD!Yo~TmRHn}81H?%jcByxer?)Y05m|V#M74HYlWG85b zYX8ROY|iH%7Q@d|-}$os?4qKn+PuDT4_8+gMAEaCkaFad>gqSsyGU?%I&E4zZJ=ph zyzZxiqBFLs4sw8|Hq)Zf2Nb1+Scay{UQE|Dv^Oq(qw?w_4l5FFD8#2OSF1=Y z%6cYsX|<1s+=DX|;blci#Cs|Z)+FI*}-~NdHZaL1M z&eBr@{25+N3wOAiIzu;fhhFFn{m>uQ!kX)R>2QzxKRVnO{-A#1hYetAybesg!Zdkf z*XcC>f)uAyGk!dhrqPok<=QlcITxumZj{jR>}de_46lBGML40$ozUZM=!@E*&ad)o z2Oe+WnkEl^s)Y@UeVM-k>>6L;>lWLz*z5dN{@Q`hU*ebe<)8d8;8&o`>!x{M02`aahg^_z!@_wvx8JrjMLR^D}e1yMk4;jb(}|ik+FT5rXZ`>WX9#8kJ(W^PB}~E zV_28l%a$zCLLI_x{aia)Tr822Lv)w5*jc6ff*tj9*jTyZf9YI+tD#dkZtY3M>BKBmbkaiCkrhQE}J8{8iG_7l@+ezp*XAJqGm`~ zm)(Yb6zDih;OoISljQG=gUf;o^>mf6=gPnF$-hgxrDC}e3jr86GTyl zFh`MTMG+eMI3>6pMNiPGs*?bIL~+SN`Cu|DyCOv+f}v)G@;EBc_e^_K=D*#A*x43s zcfUG{(Ur8EezApKu$A*XfA<6XxmkAIn=$7|<}HNdCY=%xl}B6UpxLTqc1IIMLxx^W zG6T2f)m+c5;TJpu5!O;CAe=w*8MO!0zh;zo;#PCXr*X&|m_0O+0-9NvQG}_5D|SY; z_$qJnHBhuLyDt3bgsXf5Q|bl7?vzfeB8m?mC&jI*4ei9E>1#8CG=@PJ!$NdtO{P1< z`NsC5x~aQ}Y5Vh8-aaWN)9b{C?94 ziuR!lBJXeG)ftwj{bT0~=iBeTcMJSYImU0`p7^eF>bZ;qTT$yjfk66bA2C&tD$=y$DfY>ZsYQ zFrMVbj}m2?;;BdwRrL-C)eS5r=!qif=b13;XG4t%TGJx!8UHX&jjx1W6uEkX_}|9z z7G8Z3i{rN3b+_SN#<%6R-L^OV=)Vf2drp?!?X=Z3h*U4r@(L~2X|dg@eml+MB3z$) zfclaM+p~^OwPAvtIGel&tCsMn2en0FNbeTrO3@z8AX4?RUM0|@6exR+lego^DZ#K$7Kiplq}K2eAT~r`5%S&qKW_j diff --git a/cor_custom/models/__pycache__/project_overview.cpython-36.pyc b/cor_custom/models/__pycache__/project_overview.cpython-36.pyc deleted file mode 100755 index 430c331b63e12c426713b177acb1263dee7e9b78..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5983 zcmb7I%WoUU8Q%vV%a=&KMOl_*S+Pw&Xy@G~vST~8KlCQhBOO&2T9N?vBkrDvD2 zBrJ;{3L2+?0S85k9)hB$00oL3dg@=$Q%^-vv~%sr*B*W9@0;BvDcML<2|GLU%{Sj` zzWL_IeX&%^v%mby{N+hS`L{CimqPy%9{*D`Okt|4G*rAbS8MAHU5#j|MoP}58)>|C zH`C5GvTdVbv~!J|)V7gXk6a8Y-wXKe6H3P6d)}f?Hnvy>aolAK9IW)G6 zK|^C|LuVS(KU3g;3f84X_7?YAb~D&5ccV@{em7Mtq`&9zkPuSg|1+Z~q0&-XYD?>@ zvZph3Pwi_lHPzQcJ*I1W>c?6?6>6hZ21Y9vW>{fUomE(IPdhkf#rVJURf>&$rT2}YT=oO@_NLy?1$nZFO;?px zA5pxHP2-P#+b@S@R<0`j3al%)#>v*$#_=%qNaeqYtsLKH<#;$A*%np~SUDb98IED? zKd?5DId({4OH&H@*wI+AKM_tq!cq7YNkET9eojOZ9;x?!dPjkTC>jOKV{I~8Re};* z3iDG6G-=&aZ26E9*&Ruh(M$HB!j8$9P0;?cTkMCMI$POPH>Tle(~$9=+WvVsg~7tSyI0t8XgiN+#+DYorsSjG8Y4i8~wVMOC?_C6}b;lb)kco--7N9@j~j=HnT%4`N1iZ?79XO|zQ z`iuK`Kalll6r-Mb4=q)qraebrzKlc6Fc{Y2{@{X#=7Ysls6l*_2r zAO1>oo%tee$la*e0l39n0MboMxT)M4{Jl0@G^K6rj!o5K+@1NE9IIaC1_y{MyhsU2nvx%zrQ4x3sNU^GXsof)Nq;f(&zgKFS z(CX(!idlih&wwPGCpXV|-Qb+ZJn#9J4Oe6H#7vouQ`GnzUVp}cd+ z?s{7`-*W8x_3qA-{Hp8tLDOq@FTP1;k&PK;_x!CGm6=`OKIE0%wYY6=S#Hnv>#MHU zv|RrpI?3Y4j4WJ4^Oyjf$j1?;RLVpVeWG2wz-f}tQ*(%#1>!9Nd)ghul(t(ONk-8s z6MJDHIg_Mdy9==&bY6y8SBHrn4@C9AvXOL}Juo%Mxv^muNfXAr;I7S0Zg1Hg`1{lb zPQvPa8;HwHO*U}2S2c~FCI3=RV7IZaN62Hjljo>+9t}k;j=30%{4u*WZ`z$evWpzE z{JZO(#o2B#@jI~mk43iU!$gNYWt_||0?snKDoJ*+fq^jV4bm^Sg3O8SjHrW5;{zji zheqz^@FSs4s(n-lhOKLNU2n(6d03=2qWin&L0#O(dH;m)ZlK#*Veg*x3^W+Pq zuGCmWC&W)MTp?N&q?*1axko%!g}Qw}fiPBGtG&*wi=SYk*yO)=wR)Rd{IP$P9x^%aJh6!l!vGxzyIWo;7A|8Xj) zv!|2U0V}ObSYM+4 z%hXV!W9>NgNf@!q)10UwFZnYEOQSR2tnYxWs!WAi_FJS%?Uc~%&X&l=CqWbv+(0*h z&g~5`JB%3c1U^7WT!2|aes91nD|A#7F&*7K^zC5;N#H_snt?DjxYz#J-tmR*_u3-k z+ZJ!$#RmS)xpN^h&;C~W^Q7>D|9FjlL-*OhYg7g z$l8>YpS!l*w7ZloBIWm(Ckl}+Tn`p_=mr!yRCpeEp6iQr^DaT664_@GS;Dl8y&c#c z1OWDNe9KUTetGSx$VE|dfM_P;6E;XmvLLh0z5Bi`${UUgQMd&o#KkX>h!h=X{u*`j zz8x@o!|J(#NYizLxFAKvOq7eJ{D1?96W`#q=irO&Zg4^&!bkuoHY=`Qpl~{0qC`M+ z0DndhBf%`-um}-|%HW!cHHhg13P~vIC-q}WLO*l=q!>Fe9uXHq%(0;Y0z_hZIF2Ne zoj$Kin+LF#jO289M2c`Df1SEB`*4HFt@|d4Y?R{rH$n-Ga&rC0fRJCH#YTMX`us8t zE0*Ps?wBviNl8gO&Lsq2OpKP2*s;n!8o4$T1;fQ|13?ZBi!c&FQB}{;j4YsHLOM^t zVPK0mJXmP%uS?j>`%$e$>5!0w>KK2U8oEWq)Uz<(EN1+_p;6SlTEtUPGwPVGsTxK_ z^o?vqt!Oj`B|V|egPPK2&`#+y7|mdfp-!loh^8%LW?r4wmo<{7p*N?V0nc3gzo?F> zi;!<%ya0|0v>CdQISKlbHm|LybNX>en9$CkKcT0vR#Q{*Ke8ffr$~PBwz{ZIsLRlv z$NCpw$AW64^JKTWyYNl7{2D%1;`*bbW||^zngG*1m-gtyOG8biIZ+SecQbG&f4u8=DU~I-nu5zH|a~Vbm&>W16)OMyGZs+ Ulwe>}4b{-5@W#JZ)KdC?0V2{g3jhEB diff --git a/cor_custom/models/project.py b/cor_custom/models/project.py index 5d7236c..f9ebade 100755 --- a/cor_custom/models/project.py +++ b/cor_custom/models/project.py @@ -29,7 +29,7 @@ class InheritProjectProductEmployeeMap(models.Model): _inherit = 'project.sale.line.employee.map' employee_price = fields.Float("Consultant Price") - budgeted_qty = fields.Float(string='Budgeted qty', related='sale_line_id.product_uom_qty', readonly=True) + budgeted_qty = fields.Float(string='Budgeted Qty', related='sale_line_id.product_uom_qty', readonly=True) budgeted_uom = fields.Many2one('uom.uom', string='Budgeted UOM', related='sale_line_id.product_uom', readonly=True) timesheet_hour = fields.Float("Timesheet Hour", compute='_compute_timesheet_hour', default=0.0) diff --git a/cor_custom/report/__pycache__/__init__.cpython-36.pyc b/cor_custom/report/__pycache__/__init__.cpython-36.pyc deleted file mode 100755 index af86dae655f1942ea5a481ca8c66075f356bd9d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 214 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 SOL + for wizard_line in self.line_ids: + map_key = (wizard_line.product_id.id, wizard_line.price_unit) + if map_key not in map_product_price_sol: + print("wwwwwwwwww", wizard_line) + print("wwwwwwwwww", wizard_line.budgeted_qty) + + values = { + 'order_id': sale_order.id, + 'product_id': wizard_line.product_id.id, + 'price_unit': wizard_line.price_unit, + 'product_uom_qty': wizard_line.budgeted_qty, + } + if wizard_line.product_id.service_tracking in ['task_in_project', 'task_global_project']: + values['task_id'] = task_id + if wizard_line.product_id.service_tracking in ['task_in_project', 'project_only']: + values['project_id'] = project_id + print("wwwwwwwwww", values) + sale_order_line = self.env['sale.order.line'].create(values) + map_product_price_sol[map_key] = sale_order_line + + if wizard_line.employee_id.id not in lines_already_present: + map_entries |= EmployeeMap.create({ + 'project_id': self.project_id.id, + 'sale_line_id': map_product_price_sol[map_key].id, + 'employee_id': wizard_line.employee_id.id, + }) + else: + map_entries |= lines_already_present[wizard_line.employee_id.id] + lines_already_present[wizard_line.employee_id.id].write({ + 'sale_line_id': map_product_price_sol[map_key].id + }) + + # link the project to the SO + self.project_id.write({ + 'sale_order_id': sale_order.id, + 'sale_line_id': sale_order.order_line[0].id, + 'partner_id': self.partner_id.id, + }) + non_billable_tasks.write({ + 'partner_id': sale_order.partner_id.id, + 'email_from': sale_order.partner_id.email, + }) + non_allow_billable_tasks.sale_line_id = False + + tasks = self.project_id.tasks.filtered(lambda t: not t.non_allow_billable) + # assign SOL to timesheets + for map_entry in map_entries: + search_domain = [('employee_id', '=', map_entry.employee_id.id), ('so_line', '=', False)] + ticket_timesheet_ids = self.env.context.get('ticket_timesheet_ids', []) + if ticket_timesheet_ids: + search_domain.append(('id', 'in', ticket_timesheet_ids)) + else: + search_domain.append(('task_id', 'in', tasks.ids)) + self.env['account.analytic.line'].search(search_domain).write({ + 'so_line': map_entry.sale_line_id.id + }) + #map_entry.sale_line_id.with_context({'no_update_planned_hours': True}).write({ + # 'product_uom_qty': map_entry.sale_line_id.qty_delivered + #}) + + return map_entries + + +class ProjectCreateSalesOrderLine(models.TransientModel): + _inherit= 'project.create.sale.order.line' + + + employee_id = fields.Many2one('hr.employee', string="Consultant", help="Consultant that has timesheets on the project.") + budgeted_qty = fields.Float(string='Budgeted Qty', digits='Product Unit of Measure', default=1.0) + budgeted_uom = fields.Many2one('uom.uom', string='Budgeted UOM', related='product_id.uom_id', readonly=True) + employee_price = fields.Float("Consultant Price") + + + + + diff --git a/cor_custom/wizard/project_create_sale_order_views.xml b/cor_custom/wizard/project_create_sale_order_views.xml new file mode 100644 index 0000000..8681d35 --- /dev/null +++ b/cor_custom/wizard/project_create_sale_order_views.xml @@ -0,0 +1,16 @@ + + + + + project.create.sale.order.wizard.form.budgeted + project.create.sale.order + + + + + + + + + + diff --git a/odoo-debrand/__pycache__/__init__.cpython-36.pyc b/odoo-debrand/__pycache__/__init__.cpython-36.pyc deleted file mode 100644 index 3678e9e59359a2817304f6df64c0a0a99efdb587..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 216 zcmYj~F$%&!5JhJb6;V^$SlOk}MQlYZtR-NVX3^|GlucG<*CMCLIlO}>No(a5temxS zU_S2;!~g3f8MWQ>~>^m-^zBTHcy&xZ$R|!R?eYU1*w!FWQ7Qz5oCK diff --git a/odoo-debrand/controllers/__pycache__/__init__.cpython-36.pyc b/odoo-debrand/controllers/__pycache__/__init__.cpython-36.pyc deleted file mode 100644 index 1f25061ac191ec8377d6e6172980f64e3fe6df7d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 199 zcmXr!<>l({SBhWG%)s!N0SPbx*$zNlEC3`@7*ZH>7;+h-7#SH-n1UHJnO`yjg*6#( zaVO{Jl@#UYT**+x0;IsiuK@jw{M=Oi(&E%2{ea5kjKrecfTH}Y z)Z~(4{rr^td_!aXjMSWh_>$D(60m@7N@`M3VqS_qlG*z4@tJvtqzE;3 diff --git a/odoo-debrand/controllers/__pycache__/controllers.cpython-36.pyc b/odoo-debrand/controllers/__pycache__/controllers.cpython-36.pyc deleted file mode 100644 index c38df28c99267915e9f1f2678be6468ae4bc82f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3859 zcmbVP&2k&Z5#B%SE*1+A1pg&jhGi)gmMu`RRVq8hr1V2DRw7djNtK*UIh*Cq5Zu-N zz%v7qKrJqTt}3bW06wKs&I{y}$^-ZTa+qsQ&LjAgo>_omoT^9_Z0$^U&&*DDPxse@ zkLz{k<;!dS{Ia6_Q@QY~0DTu;+Ex_>DM(Eeuk2M%mAvL@ve!KwdMz>1idRv^96d2p z%d;eHBz9W$s*+X{$8+SGnpcy(>$$S8dv)k5NiA)74LR3L=F+Cul(d!1r!B7~X&dMT zZ$VY?BCezAL?ho~H(rXDWxFEVRlGJ)k%MXzeWH3x*oiOUC7>>6F3?wy3nQ9$88>4m zeg|Jhb<}vFc~`L>zl*QNZ8W#3;70tO_a16`*M6a(dDMEYpcZaTbnkuO7tkW`i+BO} z>qy;K)|b8$uG?8xxkd0-156o^^F7Rbf@wY=A@=(LI|gB+2cy(aqZG4YAA`g=W~?vz zG>9_j&HGUnkRed^R=|S8fMRYQk$i-+k=E((%1MMz>1Z`adEN;S$}`##^i6~hNsys~ zb&Z=z9w1D(6AW06X&Ce|H)5J+qbtArZE$mR@1}R_=BHo2CjHLMFF&{*3M*#6^9cA5 zBv=ur?rGp71F1+udQV3Nsvz@)4xYAA^|=Zjt{@A%QR8lD!-D~3c{*C%IK_t>htjN# zFi-nIHuRIcmyaqNva8Cj)6aTD?8=QS&oG!_2p4e!j5yv2wW(rr&@aIID|qQ2M0BcS z9cg2ODY42xvr?}~Wn4kZ*kqt_Tp^#7{aBT~IX1IK0Tw;8$u_el%2+K-y36diIyMWH z#>|OpMWxUSV?~*OWn=4=nk^3h1vA{Z9>ZFY*@Yd?O_Z14j;n=6zAm)5iL8lAzGm}< zhO9MMnQ6!#JB363T2$i}sus?XI?+@Gb{D);m?aO~0%%byYWY8k8mg@+uT=6=wiqv! z9PH+@<#?rVfvU6B!i6ZVztF}F)F>M98k&QMZ>}jT%Gf9jH2+M4^;b~~ydo^AmzER_ z_!`VY3oneZl{HE$(PC-gQ^?(4D|^Zp%2Or#v7xX_&m8zlp(^6}Z;$*&$+Rz&LY(;0 z4madU8sZSS4(H8H$^sUJT&Dz@DD81;diL9+KkauPbsrqG#Tp+bf7m`H5yL(T7mSK`Btl*e%9UVwjTVyjfBE>~&P5a3;TzXY9rt*r9d@LdgU&49BJ@_POBW5w)o0zOhk)hG>mcmvKJ zV9P@IC>SJ+tDW!Fjql_HyF*WUADpGh$Pm=J&h4Wp!C8=EZqLAwS5gMJIC8RFcw2m$sKF1A; zlOt}TL+J+X*(tXmO(bIifzKGP^^+jP$9V#1PTm(E0ySwLFdvh3!D=BPD}vBTe#%{W z4*pajr{o~10`d;b`HMpCLHGUs#&MqF4H1kRyTkA}An7j2V;nNNAw2ezk2j8S()U4q zCIz$70^pr7k|zm7@kP4RA98mVXyWKTg>C2_G>U1chU%y`v^G3~GBrcK%bKP&q+}UJ z4c*m@iWqOe=8 z6m{~s0=FX_5Ypha$KcwnvPOp@Da232Mh#wB%x;6UP-7@)NE1bZsj(J|f(zFeC|1Vi zRDvpNFb`EEUy02a3K;O_Id4ne0=^1z8+s@LsJf=a?nH^}Jt$0L4NBG-lqmIrR{o67J1?$$>RO z*G0jJ(g^+hrYJSHpwy`13Mb3WwQ0FofpVx9x+r6X-V?Loi)G1SwRjb^CThGU$}l*0 zVTYS(kO2f8@JfKvDC2enDFWFG37$Y!`+x?OB*=P{SHpY&Q5-?a1D-I5fQ(yEgD4ar ziDq2k?v$62^g6UKqB6(&BU zIe<~;n5D`3CGJqnrua#2Kw$7n34JE)cog;c(g`Nf(a@Jx!ljbZ)0`jyg9Nm~5Z-XJNG{C`n&fI4!V0gC79|sI{{Q0pd6|<4oG+mS1|$6&dk&Z zd9|ti!ea6SwkxyA0@xK>^2MpY{fi#p4xRxY_7nE%@W;zkgmK5cWtri{4*n1OU30?(Ok6!;2|DcT~wFVRd`Lc zsoRjzF34IS6)@9OM^`SSY3GNZ+yRxg;De+qnr+c!q7krqp^@+aiKY$>uL{(K2w?s499+py3zIB%-l7!ASm?~^B`r&f8An+hd{l;umQ%QK z4XHd7@3LGq{gVJL1h_m0aAJzB+y7%mNBkopmQd3cbFJfmLc$Pkh(9x;5(SB*j5vps zvrt52v;YE&(h8{C+=hOCNa183$$un7fE};z2H`Wv)>6i6-RvYHd6r^O?)PFs1r5?Z zl({SBhW6%)s!N0SPbx*$zNlEC3`@7*ZH>7;+h-7#SH-n1UHJnO`yjg*6#( zvE}Bcq~;X+X)@hnC<5tO$xy@sq`<^4Z~ct?+*JM2;?yGjfXd{I#G>4QqWrAXK0xr2&X~w&oRkB{}Y@w@i zYOkoz!Q*iCl@qVPiLp0SD=f{}p7}gK-z57xJN=7`2jXW)$S<<7IGzts%n%h2pfzb| zPMaVP8kVz$=bVx^1Oi~^1em0=@QmdV@DC&nf8!gHavL=YWNmCTu4E0yvSLx$uvMxy zrGxxim&p#$B1ukxC84+BiUZ3pi` zsaNty7jsxW>nCo#_9Y~(N{X_S#w25{nxvh|1d6seDvV5;VqQ$79{LBi_eCC=s+A?} z%5-~x@)E`Dq5^tKX51{K)d z&McfwEOnhy%Z;qZKZqV+R0%ZOk*mJtKUidx&4%-Jqr8)lo7oj;m75wWBr-EtB(OTmzi)ST% OzApX69-{r=_t;+m=>2s7 From 7e7b45c85d5e57e78d2adaeae7637376453445dd Mon Sep 17 00:00:00 2001 From: projectsodoo Date: Sun, 20 Dec 2020 00:15:53 +0530 Subject: [PATCH 2/8] Project Report updated --- project_report/__init__.py | 8 ++ project_report/__manifest__.py | 24 ++++++ project_report/models/__init__.py | 5 ++ project_report/models/project.py | 12 +++ project_report/report/__init__.py | 5 ++ .../report/project_budget_amt_analysis.py | 39 +++++++++ .../project_budget_amt_analysis_views.xml | 63 ++++++++++++++ .../report/project_budget_hrs_analysis.py | 39 +++++++++ .../project_budget_hrs_analysis_views.xml | 64 ++++++++++++++ project_report/security/ir.model.access.csv | 6 ++ project_report/views/project_view.xml | 24 ++++++ project_report/wizard/__init__.py | 6 ++ .../wizard/project_create_expenses.py | 86 +++++++++++++++++++ .../wizard/project_create_expenses_views.xml | 42 +++++++++ .../wizard/project_create_invoice.py | 58 +++++++++++++ .../wizard/project_create_invoice_views.xml | 30 +++++++ 16 files changed, 511 insertions(+) create mode 100755 project_report/__init__.py create mode 100755 project_report/__manifest__.py create mode 100755 project_report/models/__init__.py create mode 100755 project_report/models/project.py create mode 100755 project_report/report/__init__.py create mode 100755 project_report/report/project_budget_amt_analysis.py create mode 100755 project_report/report/project_budget_amt_analysis_views.xml create mode 100755 project_report/report/project_budget_hrs_analysis.py create mode 100755 project_report/report/project_budget_hrs_analysis_views.xml create mode 100755 project_report/security/ir.model.access.csv create mode 100755 project_report/views/project_view.xml create mode 100755 project_report/wizard/__init__.py create mode 100644 project_report/wizard/project_create_expenses.py create mode 100644 project_report/wizard/project_create_expenses_views.xml create mode 100644 project_report/wizard/project_create_invoice.py create mode 100644 project_report/wizard/project_create_invoice_views.xml diff --git a/project_report/__init__.py b/project_report/__init__.py new file mode 100755 index 0000000..4d39843 --- /dev/null +++ b/project_report/__init__.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- + +from . import models +from . import wizard +from . import report + + + diff --git a/project_report/__manifest__.py b/project_report/__manifest__.py new file mode 100755 index 0000000..45c3274 --- /dev/null +++ b/project_report/__manifest__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- + +{ + 'name': 'Project Report', + 'summary': 'Projects Report', + 'description': "", + 'version': '1.0', + 'license': 'LGPL-3', + 'category': 'Services/Project', + 'author': "SunArc Technologies", + 'website': "http://www.sunarctechnologies.com", + 'depends': [ + 'cor_custom' + ], + 'data': [ + 'security/ir.model.access.csv', + 'views/project_view.xml', + 'wizard/project_create_expenses_views.xml', + 'report/project_budget_hrs_analysis_views.xml', + 'report/project_budget_amt_analysis_views.xml', + ], + 'auto_install': False, + 'installable': True, +} \ No newline at end of file diff --git a/project_report/models/__init__.py b/project_report/models/__init__.py new file mode 100755 index 0000000..3134359 --- /dev/null +++ b/project_report/models/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import project + diff --git a/project_report/models/project.py b/project_report/models/project.py new file mode 100755 index 0000000..f8fba07 --- /dev/null +++ b/project_report/models/project.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- + +from odoo import api, fields, models, _ + + +class Project(models.Model): + _inherit = 'project.project' + + budgeted_hours = fields.Float(string='Budgeted Hours') + budgeted_revenue = fields.Float(string='Budgeted Revenue') + + diff --git a/project_report/report/__init__.py b/project_report/report/__init__.py new file mode 100755 index 0000000..bda40bb --- /dev/null +++ b/project_report/report/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import project_budget_hrs_analysis +from . import project_budget_amt_analysis diff --git a/project_report/report/project_budget_amt_analysis.py b/project_report/report/project_budget_amt_analysis.py new file mode 100755 index 0000000..a60b852 --- /dev/null +++ b/project_report/report/project_budget_amt_analysis.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import fields, models, tools + + +class BudgetAmtAnalysis(models.Model): + + _name = "project.budget.amt.report" + _description = "Project budget amount analysis report" + _order = 'project_id' + _auto = False + + #analytic_account_id = fields.Many2one('account.analytic.account', string='Analytic Account', readonly=True) + project_id = fields.Many2one('project.project', string='Project', readonly=True) + partner_id = fields.Many2one('res.partner', string='Client', readonly=True) + employee_id = fields.Many2one('hr.employee', string='Employee', readonly=True) + budgeted_revenue = fields.Float("Budgeted Revenue", digits=(16, 2), readonly=True, group_operator="sum") + actual_revenue = fields.Float("Actual Revenue", digits=(16, 2), readonly=True, group_operator="sum") + + def init(self): + '''Create the view''' + tools.drop_view_if_exists(self._cr, self._table) + self._cr.execute(""" + CREATE OR REPLACE VIEW %s AS ( + SELECT min(AAL.id) as id, + PRO.id AS project_id, + PRO.partner_id AS partner_id, + AAL.employee_id AS employee_id, + PRO.budgeted_hours AS budgeted_revenue, + sum(AAL.amount) AS actual_revenue + FROM project_project PRO + LEFT JOIN account_analytic_account AA ON PRO.analytic_account_id = AA.id + LEFT JOIN account_analytic_line AAL ON AAL.account_id = AA.id + WHERE AAL.amount < 0.0 AND AAL.project_id IS NOT NULL AND PRO.active = 't' AND PRO.allow_timesheets = 't' + group by Pro.id, PRO.partner_id, AAL.employee_id, Pro.budgeted_hours, AAL.unit_amount + )""" % (self._table,)) + + diff --git a/project_report/report/project_budget_amt_analysis_views.xml b/project_report/report/project_budget_amt_analysis_views.xml new file mode 100755 index 0000000..44c17c0 --- /dev/null +++ b/project_report/report/project_budget_amt_analysis_views.xml @@ -0,0 +1,63 @@ + + + + + project.budget.amt.report.pivot + project.budget.amt.report + + + + + + + + + + + project.budget.amt.report.graph + project.budget.amt.report + + + + + + + + + + + + project.budget.amt.report.search + project.budget.amt.report + + + + + + + + + + + + + + + + Projects Revenue Acutal Vs Budget + project.budget.amt.report + pivot,graph + + { + 'group_by_no_leaf':1, + 'group_by':[], + } + + + + + diff --git a/project_report/report/project_budget_hrs_analysis.py b/project_report/report/project_budget_hrs_analysis.py new file mode 100755 index 0000000..df7e2d5 --- /dev/null +++ b/project_report/report/project_budget_hrs_analysis.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import fields, models, tools + + +class BudgetHrsAnalysis(models.Model): + + _name = "project.budget.hrs.report" + _description = "Project budget hours analysis report" + _order = 'project_id' + _auto = False + + #analytic_account_id = fields.Many2one('account.analytic.account', string='Analytic Account', readonly=True) + project_id = fields.Many2one('project.project', string='Project', readonly=True) + partner_id = fields.Many2one('res.partner', string='Client', readonly=True) + employee_id = fields.Many2one('hr.employee', string='Employee', readonly=True) + budgeted_hours = fields.Float("Budgeted Hours", digits=(16, 2), readonly=True, group_operator="sum") + actual_hours = fields.Float("Actual Hours", digits=(16, 2), readonly=True, group_operator="sum") + + def init(self): + '''Create the view''' + tools.drop_view_if_exists(self._cr, self._table) + self._cr.execute(""" + CREATE OR REPLACE VIEW %s AS ( + SELECT min(AAL.id) as id, + PRO.id AS project_id, + PRO.partner_id AS partner_id, + AAL.employee_id AS employee_id, + PRO.budgeted_hours AS budgeted_hours, + sum(AAL.unit_amount) AS actual_hours + FROM project_project PRO + LEFT JOIN account_analytic_account AA ON PRO.analytic_account_id = AA.id + LEFT JOIN account_analytic_line AAL ON AAL.account_id = AA.id + WHERE AAL.amount < 0.0 AND AAL.project_id IS NOT NULL AND PRO.active = 't' AND PRO.allow_timesheets = 't' + group by Pro.id, PRO.partner_id, AAL.employee_id, Pro.budgeted_hours, AAL.unit_amount + )""" % (self._table,)) + + diff --git a/project_report/report/project_budget_hrs_analysis_views.xml b/project_report/report/project_budget_hrs_analysis_views.xml new file mode 100755 index 0000000..ae29b1e --- /dev/null +++ b/project_report/report/project_budget_hrs_analysis_views.xml @@ -0,0 +1,64 @@ + + + + + project.budget.hrs.report.pivot + project.budget.hrs.report + + + + + + + + + + + project.budget.hrs.report.graph + project.budget.hrs.report + + + + + + + + + + + + project.budget.hrs.report.search + project.budget.hrs.report + + + + + + + + + + + + + + + + Projects Hours Acutal Vs Budget + + project.budget.hrs.report + pivot,graph + + { + 'group_by_no_leaf':1, + 'group_by':[], + } + + + + + diff --git a/project_report/security/ir.model.access.csv b/project_report/security/ir.model.access.csv new file mode 100755 index 0000000..aa845cf --- /dev/null +++ b/project_report/security/ir.model.access.csv @@ -0,0 +1,6 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_project_budget_hrs_report_manager,project.budget.hrs.report,model_project_budget_hrs_report,project.group_project_manager,1,1,1,1 +access_project_budget_amt_report_manager,project.budget.amt.report,model_project_budget_amt_report,project.group_project_manager,1,1,1,1 +access_project_create_expense_manager,access_project_create_expense_project_manager,model_project_create_expense,project.group_project_manager,1,1,1,1 + + diff --git a/project_report/views/project_view.xml b/project_report/views/project_view.xml new file mode 100755 index 0000000..1ac1b86 --- /dev/null +++ b/project_report/views/project_view.xml @@ -0,0 +1,24 @@ + + + + + + Project Budget + project.project + + +
+ +
+ + + + +
+
+ + + +
diff --git a/project_report/wizard/__init__.py b/project_report/wizard/__init__.py new file mode 100755 index 0000000..f44b1f1 --- /dev/null +++ b/project_report/wizard/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- + +from . import project_create_expenses + + + diff --git a/project_report/wizard/project_create_expenses.py b/project_report/wizard/project_create_expenses.py new file mode 100644 index 0000000..1add259 --- /dev/null +++ b/project_report/wizard/project_create_expenses.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models, _ +from odoo.exceptions import UserError +from odoo.exceptions import ValidationError + + +class ProjectCreateExpense(models.TransientModel): + _name = 'project.create.expense' + _description = "Create Expense from project" + + @api.model + def default_get(self, fields): + result = super(ProjectCreateExpense, self).default_get(fields) + active_model = self._context.get('active_model') + if active_model != 'project.project': + raise UserError(_('You can only apply this action from a project.')) + active_id = self._context.get('active_id') + if 'project_id' in fields and active_id: + result['project_id'] = active_id + if 'analytic_id' in fields and active_id: + project = self.env['project.project'].browse(active_id) + if not project.analytic_account_id: + raise UserError(_("Please define Analytic Account.")) + result['analytic_id'] = project.analytic_account_id.id + return result + + project_id = fields.Many2one('project.project', "Project", required=True) + analytic_id = fields.Many2one('account.analytic.account', "Analytic Account", required=True) + description = fields.Char(string="Description", required=True) + ispercentage = fields.Boolean(string="Is Percentage", default=False) + #sale_order_id = fields.Many2one('sale.order', string="Sales Order", domain="['|', '|', ('partner_id', '=', partner_id), ('partner_id', 'child_of', commercial_partner_id), ('partner_id', 'parent_of', partner_id)]") + expenses_from = fields.Selection([ + ('invoiced', 'Invoiced'), + ('to_invoice', 'To Invoice') + ], "Expenses from", default='to_invoice') + per_from_amt = fields.Float(string="Of", digits=(6, 2)) + percentage_rate = fields.Float(string="Percentage (%)") + expenses_amt = fields.Float(string="Amount", digits=(6, 2), required=True) + + @api.onchange('ispercentage', 'expenses_from', 'percentage_rate', 'per_from_amt') + def onchange_ispercentage(self): + expense_amount = 0 + active_id = self._context.get('active_id') + if self.ispercentage and self.expenses_from: + profit = dict.fromkeys(['invoiced', 'to_invoice'], 0.0) + profitability_raw_data = self.env['project.profitability.report'].read_group([('project_id', '=', active_id)], + ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced'], ['project_id']) + print("profitability_raw_dataprofitability_raw_data", profitability_raw_data) + for data in profitability_raw_data: + profit['invoiced'] += data.get('amount_untaxed_invoiced', 0.0) + profit['to_invoice'] += data.get('amount_untaxed_to_invoice', 0.0) + if self.expenses_from == 'invoiced': + self.per_from_amt = profit['invoiced'] + if self.expenses_from == 'to_invoice': + self.per_from_amt = profit['to_invoice'] + if self.percentage_rate > 0.0 and self.per_from_amt > 0.0: + expense_amount = self.per_from_amt * (self.percentage_rate / 100) + self.expenses_amt = expense_amount + + + def action_create_project_expense(self): + """ Private implementation of generating the sales order """ + expenses_amt = self.expenses_amt + if self.expenses_amt < 0: + expenses_amt = self.expense_amount * -1 + if self.expenses_amt == 0: + raise ValidationError(_("Amount shoud not be zero")) + analytic = self.env['account.analytic.line'].create({ + 'project_id': False, + 'partner_id': False, + 'account_id': self.project_id.analytic_account_id.id, + 'name': self.description, + 'date': fields.Date.context_today(self), + 'user_id': self.env.uid, + 'product_uom_id': False, + #'amount': self.expenses_amt * -1, + 'amount': expenses_amt + }) + action = self.env["ir.actions.actions"]._for_xml_id("analytic.account_analytic_line_action") + action['context'] = {'default_account_id': self.analytic_id.id} + action['domain'] = [('account_id', '=', self.analytic_id.id)] + return action + + diff --git a/project_report/wizard/project_create_expenses_views.xml b/project_report/wizard/project_create_expenses_views.xml new file mode 100644 index 0000000..c437702 --- /dev/null +++ b/project_report/wizard/project_create_expenses_views.xml @@ -0,0 +1,42 @@ + + + + + project.create.expense.view.form + project.create.expense + +
+ + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + Create Expense + project.create.expense + form + + new + + +
diff --git a/project_report/wizard/project_create_invoice.py b/project_report/wizard/project_create_invoice.py new file mode 100644 index 0000000..0584981 --- /dev/null +++ b/project_report/wizard/project_create_invoice.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models, _ +from odoo.exceptions import UserError + + +class ProjectCreateExpenses(models.TransientModel): + _name = 'project.create.expenses' + _description = "Create Expenses from project" + + @api.model + def default_get(self, fields): + result = super(ProjectCreateInvoice, self).default_get(fields) + + active_model = self._context.get('active_model') + if active_model != 'project.project': + raise UserError(_('You can only apply this action from a project.')) + + active_id = self._context.get('active_id') + if 'project_id' in fields and active_id: + result['project_id'] = active_id + return result + + project_id = fields.Many2one('project.project', "Project", help="Project to make billable", required=True) + _candidate_orders = fields.Many2many('sale.order', compute='_compute_candidate_orders') + sale_order_id = fields.Many2one( + 'sale.order', string="Choose the Sales Order to invoice", required=True, + domain="[('id', 'in', _candidate_orders)]" + ) + amount_to_invoice = fields.Monetary("Amount to invoice", compute='_compute_amount_to_invoice', currency_field='currency_id', help="Total amount to invoice on the sales order, including all items (services, storables, expenses, ...)") + currency_id = fields.Many2one(related='sale_order_id.currency_id', readonly=True) + + @api.depends('project_id.tasks.sale_line_id.order_id.invoice_status') + def _compute_candidate_orders(self): + for p in self: + p._candidate_orders = p.project_id\ + .mapped('tasks.sale_line_id.order_id')\ + .filtered(lambda so: so.invoice_status == 'to invoice') + + @api.depends('sale_order_id') + def _compute_amount_to_invoice(self): + for wizard in self: + amount_untaxed = 0.0 + amount_tax = 0.0 + for line in wizard.sale_order_id.order_line.filtered(lambda sol: sol.invoice_status == 'to invoice'): + amount_untaxed += line.price_reduce * line.qty_to_invoice + amount_tax += line.price_tax + wizard.amount_to_invoice = amount_untaxed + amount_tax + + def action_create_invoice(self): + if not self.sale_order_id and self.sale_order_id.invoice_status != 'to invoice': + raise UserError(_("The selected Sales Order should contain something to invoice.")) + action = self.env["ir.actions.actions"]._for_xml_id("sale.action_view_sale_advance_payment_inv") + action['context'] = { + 'active_ids': self.sale_order_id.ids + } + return action diff --git a/project_report/wizard/project_create_invoice_views.xml b/project_report/wizard/project_create_invoice_views.xml new file mode 100644 index 0000000..867fb06 --- /dev/null +++ b/project_report/wizard/project_create_invoice_views.xml @@ -0,0 +1,30 @@ + + + + + project.create.expense.view.form + project.create.expense + +
+ + + + + +
+
+
+
+
+ + + Create Expense + project.create.expense + form + + new + + +
From 4adbd6bca36baebbdee827729ef98e704165bd18 Mon Sep 17 00:00:00 2001 From: projectsodoo Date: Sun, 20 Dec 2020 00:23:37 +0530 Subject: [PATCH 3/8] updated report init file --- project_report/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/project_report/__init__.py b/project_report/__init__.py index 4d39843..5c92962 100755 --- a/project_report/__init__.py +++ b/project_report/__init__.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- - -from . import models from . import wizard +from . import models from . import report From d7ecb60c7e3f11c469f64c2d1f8ae60b9ed83476 Mon Sep 17 00:00:00 2001 From: projectsodoo Date: Sun, 20 Dec 2020 00:27:37 +0530 Subject: [PATCH 4/8] updated report manifest file --- project_report/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project_report/__manifest__.py b/project_report/__manifest__.py index 45c3274..544e76a 100755 --- a/project_report/__manifest__.py +++ b/project_report/__manifest__.py @@ -14,8 +14,8 @@ ], 'data': [ 'security/ir.model.access.csv', - 'views/project_view.xml', 'wizard/project_create_expenses_views.xml', + 'views/project_view.xml', 'report/project_budget_hrs_analysis_views.xml', 'report/project_budget_amt_analysis_views.xml', ], From d459a19b094f79913816c95d8c64891d39a95213 Mon Sep 17 00:00:00 2001 From: projectsodoo Date: Sun, 20 Dec 2020 09:02:55 +0530 Subject: [PATCH 5/8] updated condition --- project_report/wizard/project_create_expenses.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/project_report/wizard/project_create_expenses.py b/project_report/wizard/project_create_expenses.py index 1add259..db60c65 100644 --- a/project_report/wizard/project_create_expenses.py +++ b/project_report/wizard/project_create_expenses.py @@ -61,9 +61,8 @@ class ProjectCreateExpense(models.TransientModel): def action_create_project_expense(self): - """ Private implementation of generating the sales order """ expenses_amt = self.expenses_amt - if self.expenses_amt < 0: + if self.expenses_amt > 0: expenses_amt = self.expense_amount * -1 if self.expenses_amt == 0: raise ValidationError(_("Amount shoud not be zero")) From df1bb030dcc8dedee8673eb6c1bbc0603e707df7 Mon Sep 17 00:00:00 2001 From: projectsodoo Date: Sun, 20 Dec 2020 09:05:31 +0530 Subject: [PATCH 6/8] updated condition --- project_report/wizard/project_create_expenses.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project_report/wizard/project_create_expenses.py b/project_report/wizard/project_create_expenses.py index db60c65..c4c894c 100644 --- a/project_report/wizard/project_create_expenses.py +++ b/project_report/wizard/project_create_expenses.py @@ -63,8 +63,8 @@ class ProjectCreateExpense(models.TransientModel): def action_create_project_expense(self): expenses_amt = self.expenses_amt if self.expenses_amt > 0: - expenses_amt = self.expense_amount * -1 - if self.expenses_amt == 0: + expenses_amt = expenses_amount * -1 + if expenses_amt == 0: raise ValidationError(_("Amount shoud not be zero")) analytic = self.env['account.analytic.line'].create({ 'project_id': False, From 3bad728a415aeae9920babc186c8db12c1fa9850 Mon Sep 17 00:00:00 2001 From: projectsodoo Date: Sun, 20 Dec 2020 09:08:13 +0530 Subject: [PATCH 7/8] updated expense condition --- project_report/wizard/project_create_expenses.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project_report/wizard/project_create_expenses.py b/project_report/wizard/project_create_expenses.py index c4c894c..57c352d 100644 --- a/project_report/wizard/project_create_expenses.py +++ b/project_report/wizard/project_create_expenses.py @@ -62,10 +62,10 @@ class ProjectCreateExpense(models.TransientModel): def action_create_project_expense(self): expenses_amt = self.expenses_amt - if self.expenses_amt > 0: - expenses_amt = expenses_amount * -1 if expenses_amt == 0: raise ValidationError(_("Amount shoud not be zero")) + if expenses_amt > 0: + expenses_amt = expenses_amt * -1 analytic = self.env['account.analytic.line'].create({ 'project_id': False, 'partner_id': False, From 452913d6ddc3e7d58d5a24b4b2c6b80b48023726 Mon Sep 17 00:00:00 2001 From: projectsodoo Date: Sun, 20 Dec 2020 14:27:45 +0530 Subject: [PATCH 8/8] Updated report and expenses --- .../report/project_budget_amt_analysis.py | 9 ++- .../wizard/project_create_expenses.py | 14 +++-- .../wizard/project_create_expenses_views.xml | 2 +- .../wizard/project_create_invoice.py | 58 ------------------- .../wizard/project_create_invoice_views.xml | 30 ---------- 5 files changed, 16 insertions(+), 97 deletions(-) delete mode 100644 project_report/wizard/project_create_invoice.py delete mode 100644 project_report/wizard/project_create_invoice_views.xml diff --git a/project_report/report/project_budget_amt_analysis.py b/project_report/report/project_budget_amt_analysis.py index a60b852..85bf419 100755 --- a/project_report/report/project_budget_amt_analysis.py +++ b/project_report/report/project_budget_amt_analysis.py @@ -27,13 +27,16 @@ class BudgetAmtAnalysis(models.Model): PRO.id AS project_id, PRO.partner_id AS partner_id, AAL.employee_id AS employee_id, - PRO.budgeted_hours AS budgeted_revenue, - sum(AAL.amount) AS actual_revenue + --PRO.budgeted_hours AS budgeted_revenue, + --sum(AAL.amount) AS budgeted_revenue + SO.amount_total AS budgeted_revenue, + SO.amount_total - sum(AAL.amount) AS actual_revenue FROM project_project PRO + LEFT JOIN sale_order SO ON PRO.sale_order_id = SO.id LEFT JOIN account_analytic_account AA ON PRO.analytic_account_id = AA.id LEFT JOIN account_analytic_line AAL ON AAL.account_id = AA.id WHERE AAL.amount < 0.0 AND AAL.project_id IS NOT NULL AND PRO.active = 't' AND PRO.allow_timesheets = 't' - group by Pro.id, PRO.partner_id, AAL.employee_id, Pro.budgeted_hours, AAL.unit_amount + group by Pro.id, PRO.partner_id, AAL.employee_id, Pro.budgeted_hours, AAL.unit_amount, so.amount_total )""" % (self._table,)) diff --git a/project_report/wizard/project_create_expenses.py b/project_report/wizard/project_create_expenses.py index 57c352d..57086d5 100644 --- a/project_report/wizard/project_create_expenses.py +++ b/project_report/wizard/project_create_expenses.py @@ -39,15 +39,13 @@ class ProjectCreateExpense(models.TransientModel): percentage_rate = fields.Float(string="Percentage (%)") expenses_amt = fields.Float(string="Amount", digits=(6, 2), required=True) - @api.onchange('ispercentage', 'expenses_from', 'percentage_rate', 'per_from_amt') + @api.onchange('ispercentage', 'expenses_from') def onchange_ispercentage(self): - expense_amount = 0 active_id = self._context.get('active_id') if self.ispercentage and self.expenses_from: profit = dict.fromkeys(['invoiced', 'to_invoice'], 0.0) profitability_raw_data = self.env['project.profitability.report'].read_group([('project_id', '=', active_id)], ['project_id', 'amount_untaxed_to_invoice', 'amount_untaxed_invoiced'], ['project_id']) - print("profitability_raw_dataprofitability_raw_data", profitability_raw_data) for data in profitability_raw_data: profit['invoiced'] += data.get('amount_untaxed_invoiced', 0.0) profit['to_invoice'] += data.get('amount_untaxed_to_invoice', 0.0) @@ -55,8 +53,14 @@ class ProjectCreateExpense(models.TransientModel): self.per_from_amt = profit['invoiced'] if self.expenses_from == 'to_invoice': self.per_from_amt = profit['to_invoice'] - if self.percentage_rate > 0.0 and self.per_from_amt > 0.0: - expense_amount = self.per_from_amt * (self.percentage_rate / 100) + #if self.percentage_rate > 0.0 and self.per_from_amt > 0.0: + #expense_amount = self.per_from_amt * (self.percentage_rate / 100) + #self.expenses_amt = expense_amount + + @api.onchange('ispercentage', 'per_from_amt', 'percentage_rate') + def onchange_percentage_rate(self): + if self.percentage_rate > 0.0 and self.per_from_amt > 0.0: + expense_amount = self.per_from_amt * (self.percentage_rate / 100) self.expenses_amt = expense_amount diff --git a/project_report/wizard/project_create_expenses_views.xml b/project_report/wizard/project_create_expenses_views.xml index c437702..e794baa 100644 --- a/project_report/wizard/project_create_expenses_views.xml +++ b/project_report/wizard/project_create_expenses_views.xml @@ -14,7 +14,7 @@ - + diff --git a/project_report/wizard/project_create_invoice.py b/project_report/wizard/project_create_invoice.py deleted file mode 100644 index 0584981..0000000 --- a/project_report/wizard/project_create_invoice.py +++ /dev/null @@ -1,58 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from odoo import api, fields, models, _ -from odoo.exceptions import UserError - - -class ProjectCreateExpenses(models.TransientModel): - _name = 'project.create.expenses' - _description = "Create Expenses from project" - - @api.model - def default_get(self, fields): - result = super(ProjectCreateInvoice, self).default_get(fields) - - active_model = self._context.get('active_model') - if active_model != 'project.project': - raise UserError(_('You can only apply this action from a project.')) - - active_id = self._context.get('active_id') - if 'project_id' in fields and active_id: - result['project_id'] = active_id - return result - - project_id = fields.Many2one('project.project', "Project", help="Project to make billable", required=True) - _candidate_orders = fields.Many2many('sale.order', compute='_compute_candidate_orders') - sale_order_id = fields.Many2one( - 'sale.order', string="Choose the Sales Order to invoice", required=True, - domain="[('id', 'in', _candidate_orders)]" - ) - amount_to_invoice = fields.Monetary("Amount to invoice", compute='_compute_amount_to_invoice', currency_field='currency_id', help="Total amount to invoice on the sales order, including all items (services, storables, expenses, ...)") - currency_id = fields.Many2one(related='sale_order_id.currency_id', readonly=True) - - @api.depends('project_id.tasks.sale_line_id.order_id.invoice_status') - def _compute_candidate_orders(self): - for p in self: - p._candidate_orders = p.project_id\ - .mapped('tasks.sale_line_id.order_id')\ - .filtered(lambda so: so.invoice_status == 'to invoice') - - @api.depends('sale_order_id') - def _compute_amount_to_invoice(self): - for wizard in self: - amount_untaxed = 0.0 - amount_tax = 0.0 - for line in wizard.sale_order_id.order_line.filtered(lambda sol: sol.invoice_status == 'to invoice'): - amount_untaxed += line.price_reduce * line.qty_to_invoice - amount_tax += line.price_tax - wizard.amount_to_invoice = amount_untaxed + amount_tax - - def action_create_invoice(self): - if not self.sale_order_id and self.sale_order_id.invoice_status != 'to invoice': - raise UserError(_("The selected Sales Order should contain something to invoice.")) - action = self.env["ir.actions.actions"]._for_xml_id("sale.action_view_sale_advance_payment_inv") - action['context'] = { - 'active_ids': self.sale_order_id.ids - } - return action diff --git a/project_report/wizard/project_create_invoice_views.xml b/project_report/wizard/project_create_invoice_views.xml deleted file mode 100644 index 867fb06..0000000 --- a/project_report/wizard/project_create_invoice_views.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - project.create.expense.view.form - project.create.expense - -
- - - - - -
-
-
-
-
- - - Create Expense - project.create.expense - form - - new - - -