From 871c0cad6e776deb6eabbbf4c6daf4938a48ee8a Mon Sep 17 00:00:00 2001 From: ilo Date: Wed, 27 Nov 2024 18:41:37 -0300 Subject: [PATCH] [17.0][ADD] fieldservice_agreement_repair --- fieldservice_agreement_repair/README.rst | 86 ++++ fieldservice_agreement_repair/__init__.py | 1 + fieldservice_agreement_repair/__manifest__.py | 21 + .../models/__init__.py | 2 + .../models/fsm_order.py | 17 + .../models/repair_order.py | 26 ++ fieldservice_agreement_repair/pyproject.toml | 3 + .../readme/CONTRIBUTORS.md | 3 + .../readme/DESCRIPTION.md | 2 + fieldservice_agreement_repair/readme/USAGE.md | 1 + .../static/description/icon.png | Bin 0 -> 29789 bytes .../static/description/icon.svg | 1 + .../static/description/index.html | 434 ++++++++++++++++++ .../tests/__init__.py | 1 + .../test_fieldservice_agreement_repair.py | 93 ++++ 15 files changed, 691 insertions(+) create mode 100644 fieldservice_agreement_repair/README.rst create mode 100644 fieldservice_agreement_repair/__init__.py create mode 100644 fieldservice_agreement_repair/__manifest__.py create mode 100644 fieldservice_agreement_repair/models/__init__.py create mode 100644 fieldservice_agreement_repair/models/fsm_order.py create mode 100644 fieldservice_agreement_repair/models/repair_order.py create mode 100644 fieldservice_agreement_repair/pyproject.toml create mode 100644 fieldservice_agreement_repair/readme/CONTRIBUTORS.md create mode 100644 fieldservice_agreement_repair/readme/DESCRIPTION.md create mode 100644 fieldservice_agreement_repair/readme/USAGE.md create mode 100644 fieldservice_agreement_repair/static/description/icon.png create mode 100644 fieldservice_agreement_repair/static/description/icon.svg create mode 100644 fieldservice_agreement_repair/static/description/index.html create mode 100644 fieldservice_agreement_repair/tests/__init__.py create mode 100644 fieldservice_agreement_repair/tests/test_fieldservice_agreement_repair.py diff --git a/fieldservice_agreement_repair/README.rst b/fieldservice_agreement_repair/README.rst new file mode 100644 index 0000000000..c919b3494a --- /dev/null +++ b/fieldservice_agreement_repair/README.rst @@ -0,0 +1,86 @@ +============================= +Fieldservice Agreement Repair +============================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:3bc94f2421f97aba7e13a13c18f132028ca2eaf21f12a05e01b4d28269efde95 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Ffield--service-lightgray.png?logo=github + :target: https://github.com/OCA/field-service/tree/17.0/fieldservice_agreement_repair + :alt: OCA/field-service +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/field-service-17-0/field-service-17-0-fieldservice_agreement_repair + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/field-service&target_branch=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows you to link ``repair.order`` with an ``agreement`` +trough a ``fsm.equipment``. This way you can track the repair orders +that are covered by an agreement. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +No specific usage instructions. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Camptocamp SA +* Italo Lopes + +Contributors +------------ + +- `Camptocamp `__: + + - Italo Lopes + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/field-service `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/fieldservice_agreement_repair/__init__.py b/fieldservice_agreement_repair/__init__.py new file mode 100644 index 0000000000..0650744f6b --- /dev/null +++ b/fieldservice_agreement_repair/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/fieldservice_agreement_repair/__manifest__.py b/fieldservice_agreement_repair/__manifest__.py new file mode 100644 index 0000000000..3833da15f1 --- /dev/null +++ b/fieldservice_agreement_repair/__manifest__.py @@ -0,0 +1,21 @@ +# Copyright 2024 Camptocamp SA (https://www.camptocamp.com). +# @author: Italo Lopes +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Fieldservice Agreement Repair", + "summary": "Fieldservice Agreement Repair", + "category": "Field Service", + "version": "17.0.1.0.0", + "author": "Camptocamp SA, Italo Lopes, Odoo Community Association (OCA)", + "license": "AGPL-3", + "maintainer": "Camptocamp", + "depends": [ + # OCA/agreement + "agreement_repair", + # OCA/field-service + "fieldservice_repair", + ], + "website": "https://github.com/OCA/field-service", + "installable": True, +} diff --git a/fieldservice_agreement_repair/models/__init__.py b/fieldservice_agreement_repair/models/__init__.py new file mode 100644 index 0000000000..9943a1f6ca --- /dev/null +++ b/fieldservice_agreement_repair/models/__init__.py @@ -0,0 +1,2 @@ +from . import fsm_order +from . import repair_order diff --git a/fieldservice_agreement_repair/models/fsm_order.py b/fieldservice_agreement_repair/models/fsm_order.py new file mode 100644 index 0000000000..0853750b64 --- /dev/null +++ b/fieldservice_agreement_repair/models/fsm_order.py @@ -0,0 +1,17 @@ +# Copyright 2024 Camptocamp SA (https://www.camptocamp.com). +# @author: Italo Lopes +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, models + + +class FSMOrder(models.Model): + _inherit = "fsm.order" + + @api.model_create_multi + def create(self, vals_list): + res = super().create(vals_list) + for order in res: + if order.repair_id and order.agreement_id: + order.repair_id.agreement_id = order.agreement_id.id + return res diff --git a/fieldservice_agreement_repair/models/repair_order.py b/fieldservice_agreement_repair/models/repair_order.py new file mode 100644 index 0000000000..82dd59b0ca --- /dev/null +++ b/fieldservice_agreement_repair/models/repair_order.py @@ -0,0 +1,26 @@ +# Copyright 2024 Camptocamp SA (https://www.camptocamp.com). +# @author: Italo Lopes +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class FSMEquipment(models.Model): + _inherit = "repair.order" + + agreement_id = fields.Many2one( + "agreement", compute="_compute_agreement_id", store=True, readonly=False + ) + + @api.depends("product_id", "lot_id", "lot_id.product_id") + def _compute_agreement_id(self): + for repair in self: + if repair.product_id and repair.lot_id: + equipment_id = self.env["fsm.equipment"].search( + [ + ("product_id", "=", repair.product_id.id), + ("lot_id", "=", repair.lot_id.id), + ] + ) + if equipment_id and equipment_id.agreement_id: + repair.agreement_id = equipment_id.agreement_id.id diff --git a/fieldservice_agreement_repair/pyproject.toml b/fieldservice_agreement_repair/pyproject.toml new file mode 100644 index 0000000000..4231d0cccb --- /dev/null +++ b/fieldservice_agreement_repair/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/fieldservice_agreement_repair/readme/CONTRIBUTORS.md b/fieldservice_agreement_repair/readme/CONTRIBUTORS.md new file mode 100644 index 0000000000..ef0db2bf63 --- /dev/null +++ b/fieldservice_agreement_repair/readme/CONTRIBUTORS.md @@ -0,0 +1,3 @@ +- [Camptocamp](https://camptocamp.com): + + > - Italo Lopes \<\> diff --git a/fieldservice_agreement_repair/readme/DESCRIPTION.md b/fieldservice_agreement_repair/readme/DESCRIPTION.md new file mode 100644 index 0000000000..8759358a58 --- /dev/null +++ b/fieldservice_agreement_repair/readme/DESCRIPTION.md @@ -0,0 +1,2 @@ +This module allows you to link ``repair.order`` with an ``agreement`` trough a ``fsm.equipment``. +This way you can track the repair orders that are covered by an agreement. diff --git a/fieldservice_agreement_repair/readme/USAGE.md b/fieldservice_agreement_repair/readme/USAGE.md new file mode 100644 index 0000000000..f08cd97a88 --- /dev/null +++ b/fieldservice_agreement_repair/readme/USAGE.md @@ -0,0 +1 @@ +No specific usage instructions. diff --git a/fieldservice_agreement_repair/static/description/icon.png b/fieldservice_agreement_repair/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..e3757caa15401e8ed72d8f824c645151bdf8536a GIT binary patch literal 29789 zcmeFadsxf;{|Elw*0v5?2d%7iB!`7qhjlJX*>WgL+}sh%aYdPm5@lBqop zk~AR*!q4*Yo)1CDdEn0+bqx5I-hU!uz+W01pMN7EXsRXr2N82}`eq2SfM$7nE{Mrm z@$2{R>8Jx-1PaB62*%7uGJlFDT}mdR#VkTHQd5E=V|XY6b{q76I8Gzy==gK>WAdh)C=kT2dJ^imSc+ zLuzjNkcpEm+VrZpB}4%(iPDU^2z^v1{2^4y<@X^a?9z}S z1hOQyd13c4D`_@=Hdpd8W)h3VN;3Dg9=f?Y$UaT2%03YSwCvm3jGQY0+^4NyQafZM z^pK%kB%{j)GdRqAODJ*p)(9d<7BN8`tkOS|*%qYGrN$ip-_SE6acSxvw|4zu#SF78 zB^l+$LsufASx}%ppurz1fH6NPE~_1fFx8){PXydr+P6}I&<&mJkToDpFumFmAPo4g ze*pEU3B5FQ2!+JZG!ED)Yv6a>h~Ep=4*q_2OUYK(wtivlX9xT_i=qZ*`2D+Nll!CL zztXTc9I|ir6{Minp_1lL8#gfXr&m09P^qXpV0j(1bMF=;6tfUqfZxAKVQxbiPtesO z{t=)5`|1Cv@qe=Mf7fBqfc~Fy7-A!bDu)$D_%kZ=!%^GNdV5t@cMDeV?A3KA;tqqm zjD~HnMWC4tXyZSMRp8e3>!W2UKfuxGXi%J5xP4rF&tB1?n3>&DA=xU-8DkaJEyuio zH9psAz)ry~&TU|oOMB%ODvO324~0@{s<-c|d)Yh3n|e?k!CX1}iGQkRjeja{QSx?s zYn4w^fWlxHeWqey0|bbg`Sgt29Zs`kb*A%@C!U9-8-F5F8OLCcs@o@h!nxg9Zshb#mC?7{oZjLCDC2{Jt#_>$p6rUf;Nyus&0r z4%z!&6-VMrzy6ns+4+^W?#x?{mE=kCTv8LlX4V zN9YX<92h?`&RMbh?^d44uS!;4ysT-1d7 zQV0LS-=wWOK-`=IyCu#eCo|#tX`3gZD5ns#&mJxtzO%=|{?-ZDYXPT(>FwUs=hKOx zs70oi^O|Xge$5VjWaIOpOk6z=d$GBt=aAx*L+H{8IF#ta4f%~Wc%?BTS0ZqycAqqa zs2LsG9&?tTJdSrU&frNWJvdPJ`bDBbZ(67|6WhJAL#-XYDA3?#C_cJcMR^uvKdNv_ zJ$Kwb=dZWkmF?}lH$`HpaRjY|A6&Vx(#`#c!j(zi2S2TojEI%~0i*4Rke4{7wv zjTZt|Jyl*%5gi&ybTw}7Cvs3>%QC$g8%s4Xv_m}!BxX94wwJ9}!&RKdk$64mGB2F`Bdq>3d0z)U19mAQ66#w5L)m*POZkg_;!|jX?Ct( z?ujq<3+Bx>hYzc(F=7`=ZL(>$bc_0g1JKDmGDhBKnDh5Wa9*h$A8+}4Y*1*{eQz9; z{f~!Au+hX30|f-pi@^RE$3k-inc&$~I~nPM3J6`D2Yy-IR_R!>Xe5c1+OMvc<-~6N zsW1r2`k7S{nXj6ylrUlyaHyIm^k&yaa*Z{kW&bl3)A;Hm#$f=N)_v}s_3+&0F=}R6 z<8E)HpReJnLKOsZAV3+yVq2F;phes6mJ~uF>O#lw%f|vH_`}Ej-%NzhUt>&pyCkne+*at$nal9WygjE)Qs9~%(UpS zh$I(R9Gd@Ib%z8)uI(S$!?o@H65#ejEwt^7)!|2+Esv}&cJMp=#dT^$S~`t6DvnXW zwe1i5Ru~BzRR2ap2AKz(J`?2PuwAG0opqj3a%tGEOb^uSEg_GrPMZosMupEYh*WWr zZ!*B0KI6y!AYm_6xuzIRENTF6-3(9 zzHaxi%q=R`dE$sflfFQHfORI^&DX=uEpb_8S#s4Xwqu)0LN!?|PG8VP`lDz#P-qP9 zg>|pUKTj?w2eNAUKcog-Fgwb0pI)%Lca1wtWefd*y$>vihFTWbX&VRbIk&0U*XmYd zj7tCAfks#!yzHwDdfGQLO{npy+;lU10@_HGgl9FpXK@~PnvT+2aiCFibF1na?Ldsw z69$mA3D&yA>@n1MOa9+tn7GGA3V|u-@fXv=@@R`_UUi>|{a=G1YcumR&AVuyNyP$K zf$IUv_U9c24mutRy6E~Ux0UwUsQ6bjJV<-wAnP`=j*)$Nw77f|d_W{+q@K1W&b`q} zyU|R~YgP#akfwfd8d!=7wcJ9P(w)<2PduZeqHACpK**7+xkJ{^4gb+K)?M4ayWMW_ zMBy^2EzBn_a)4aGncJfhQ5Nd{?OSVO+MBVZ4YjpK=X$$J+CH?J3w|E0$8G#tYg_QU zYtEv|Z#&Cu&TQX=e|)9Ukd?Oj-Kw-$S3?pz!vn_C;Nkfhj@ftDsMrC0xP&qFUB|?lo?yzfo^w38+A;*dF=X}X+}wu^_mMN{F`Gq-|J!a zyz~j-eLkecpuC%IQKe*L1a59E4WDb8v)t~}kB-b0|IzTIFQaQE8UH}`RfUfNcvH&H z^XRhpZNV8ozu9E8-kYcy?z5$BcS7Dz6_>mQuPv#6PNpgMC7DM*^!_GrcYT<~oL^m! z(%x)8I-xlyK7wNR_-V!JE(==E*ON5y{9_68aly!axNVQcah2e}0+7!5b0zzgPd1!AF)Hy#v8Q8a{yY$$;coLMA|DcV@Oa1u%IG>4_C183!kZ+m~xPhZeBntID zzo&l=GDd{aKTAK{hUocv{!|gyq|l-#{iK?8)^2^SVfN@G3QafmhnLbDv6K%+^x^vPiItc_`3~HQrsZqXwzutC-y=fT zi#GZ35nPf#eqX5AwG*b^nL$U_J-9D`u!pSG=EX)b#0olL zX20+|-#e}Y64@10e?F=4Ymp+?O*{?mZV?& zEbKV&Pm{HseO6NOQRAe{bxu-<>_H32S1}j?;+?SESBi^iyrw(9Q*-!ggRh?Sj0Xf z`o&&N8h(Q8^5oK!b!sTFcpfZ6x+5r{fC`CQ^5<0sqdIP#PcefC^ZJKEBZsn@EZm?- zf&wF27opm0)R0i9U;Gt{kEzeZJewU7b_48;A_jA`e{?GtqU)Z?I+1XnuZ)-eZ^qE2 zy6Ek_y~e^K@Vj!PL#t4{X=+t1^Jdy|MyxJyCurM8kV3(ISE{s^F_Bpt7!B)yEhrl4 z>?#yb-sP!g`pMYv|1ncf`82`p96G~JfQ0VqKijjx(wzv1AeugcPE1LY_&Wo&N}Vf@ zfi)j@guE&w%e?m1y*bc?yKT0eh)?&##ozvcOqm$x{9vyc0WeBtKElc?Bv7Ey?b>)@ zUG1~F$lEm>q$sAlpojE|p-tLt>F)Hu_o9&0F5ct0%$r-+dfyzkVNsSbKEqSpWBqMy zvn};ajnMr{*syV*jK|M$Wah+WrpGo5vf!p0Nw5uKf%8sw7Wme5Ye z{JI_09Q55iJ<1th;BU1DHVuq&FZdTa!a;X~*1tc~?bli_{nl{njpCGL{6s3o;a{Gd zBi4hc2R&MD2yLtGKw(bO`o6%DHbAT)hSEtDYOqjRIyqh;G%0i_WgP1K<*_KcT4jgc zWk^}Uk<}e4xa?cTDy)O!OpB3u4fO=R<7YcHzr`hOUtHh6uoer+4-vQM`bwXKPPC0U z0Cs0^h9j&%64Lxu56dU3SP)$9{OSH^p!O}?T(TK%P7Yb2$O_{f%%zdI#`9*hvJ#NP5Uo_lRGC4qkA zhq#!L_W{-b$%9s<|NaA;7Z(n$?B&%jN8W8J0IyN6U)h+gEn*CPm(z}dTS8MibvG9gOVRgX_j7UJxcb)v; z%CDc@M<#s##>;K|L^Y6F&b5f`t3Xn~vHvn#Wbo1cfHx)==~?+`%#ZpNi&ttyO%w5R zpDT|Ygr#!P2-QnQR;+jGHV#S1>!sc3GP~7HVOwGi14R! zy_4`=b{SN~{mDEFEkzL}V*wQE)bihKgrlDi`W0zD_FS!H6=5-79mB%s!ry_^BuG~L z6~_5s_{UT?71me4@$dh61qt7+(i>L&7nw|y59otGp`8WE{#@-NSz)mGT?8i6Y{?;W z_oA{`mGjau!WbkWcU`Kqo#GOaQZGSLv%W3NO+II>@|bbHgJjLVqVlVC)ds4%Ln4en z?yv$4Xve$Kb^cMRQGbd|oB&CaX&B>2AUk%iAa`Qj1&Hxs%Y@`{Ma5G2$O6jkL zmKqKUbpKofg;MU~!9Dgx0Xz8pdK1o|Mb&7sLiLLQ^_R9}tQ zXK>GbOh}L@(YN6X0QN9ua1Zd0V^AKqf0VU#Qybgpo2P1Hf@gk_msuhP37|PBZ}50e z)Z4e)AGE!f&f!>o0I5;dTKC&OlE_UOlap);HbzpC$Vqk}r@}Y>XMR3>d&oHU%b$fAVh%ePaitG8<;2jk5Gk<68vFGckR@76LY0V_dD7M1FU zkET>{R1%+zBn^tu5bN4ziY`mU^ELI_?Mw=|+ifwEv@549bDmFtduxgk<%t;;+#< zRdjt9hXz zR5DGT5c{NsiyuDEZYk3|tOQLHGtJ(OQG69+?1;sA;VM<5sRVA;5UqyX4Jps$W@rER zA>xyS2Fb|jTW6Mu+&Phb9tpUaus`3Q4hMSft3PcjWUaY8z-{d-uouW4ef@g4RoBwf zQcV5}&c4xl14s(Qg+Y;oO677tO6_suLFFA z$MN^RM~i;Ynh<|>NOTzfX%=KZo?3lw=`l1!o$6Ux&eTd?*5<0> z1DZcP^NlZfUF|cF{l4~YYS_zm+#*g?Z}{$Q zn4<8VBtS6tO>2)t4pLcbI3ICPAmr{6#Bhm;@6>yJf3)QDDKWh?WI#SdLo^~RPAqOu z0H#-S6jApd-Id_aT7`i=OJUG}U5RNcte+~>LwH=FI4+`B*eT1N@dK`6?$wF> zZ&aEaO$~E?!U9?3^dG>#wINu)nSG%c2-EwMnAAVA$Q_<)M-pgHf>xeD&I)tph`nYn zIl8J?wAT!1z#X3DDQo{ROIR+Ru>nqTA1BQdf3N5VN9Yc*DKPJyAgT*yMa8Z~={eFd zm5FEQ`u}{r(^ze>1ygZ8!EfZz0=ZW+vGNsYf0Y#cHMsqNc5Jd6NR6zEDUK=2i zmF5TE+`v)|BM>LV``Y0C*)=uld*#1wmN5e|PAnOeAox}QV3VD9>*X1s%H(|>e_RbD z^?Al?ML)Zho1WmDZS?8iInA-2Vy1jYUX=>Jw<2M<9Q~^ac zcxagFZRw`&5PMNJHJdcG3u?q!QQPqrh{wxsB~DTac=zXjqBee2xicWK;5PhY!P-S; z&&TW1?(3yRv^!YyR;K6#<+j>e-L8%9NT}`Cf^&y|Q zR%Y=lb?+2d%m!`~rEHiB$$?ym`h{nYzT_TtZB9aqE-&gJ#_j87#5(Y60v!L?)dWw> zpg4fzaoV~&v6)y2%XrfaOvmDzQ@^Gj9@i-bw1+cvAUqxJHF4TLX}08j!qhKDu0Xg~ z=YBiXwccTH?%`Q@Fth zwB}Afk>COAb#S7VEOz$Z4C=gstse>AY9SvF_EQZ_81AQV+TIz28PDTyI;(FBnPxes zu?8tTSn!M`h_E?_d`F z=zxclFlI>h0v2gYGu$2JtHEi=1Jm^Ri?p>vZsm}whRR>$rm#AS4)mX`esI6=#P(pTjlUH zCC6fJqFstvRuPqr>aMIbx8I=nBCFGV`iEyx!z-K|TB_HS)|{KpV6=xRX|q?|?#w?! zz5ik_Ep>O#OWq@e-chOg)D6xvBNyR!2E0^NS%D4ztICYT%nGYo^!d=0EVC#CKCrpt zn{;w!mGs_S5100SEMuw0U~B>3bJ$d5VoP2xOf>SieY|D-of8QwziuwC)<(PRX!&!! zU50N8i9y?KDpD)ywK{_JW#t4$C%+f_S%}zvIR&O5yis}e6NlS8%rcw!qPaD^&6njX zg?eM!6hBr9_CL~jUTr2zuThr4VLbQ{XE*#S3NyMwJcnj-A?7 z`(1t>l#m~#EL&Gbmx2`b-f^-mE1sS6Kwh#68CQoa2ofv14b!zfyZ@cdFx&Q$*s7#@ z0wOW71LD$OD<0j=PD?>zl+wLNnh!pApF(RsJGUh4l*0;C`~9cRu14|hv0esWeGtG} zvTi3Q?A4%UBV-4>MfY&lq&ban{9{km37snpUjt`ek;4NI9F*xNu2h1c!=NoRC04Q5 zc>dOhq7YqK&?eyJkSO2zB%a*vA|r1uoyetT(CpdXn+i~`Y)BvdV#N~`seq*bFg>KK zg~U;q;(1D_@E~eI0YCPkh;Hx$`TCjS@>p|8GXo%-G|pYakdjkefU2IoT_pH%w&xJ$ zg}VMJ=w-0{tBq+`2RtXJoD7}w49kL%BbY=4d^3UyH-C73Fd*v9QqOs!_ad#gPPRoJ z0J996#6J-d?0la&?)AVPH$DD2tuD(^={%?7wB z@k`y9E`^$1g8)TgZLtXCt<)qw%s^6R_&yMyo;QGxn zN0*|w^d+80#?wYG*4b%^Rcf#js}f4E1XTz!B$)v#qnnWZ-04M~W{%KV4Wpn1u5J*! zFvRyumV8sZ8bsbktFw2}1X#K$!z>JlC<^!B?5R{uCLrn4*r;|TUNu7= zhuEQ^QD2;pTzY-}CLI7GB0`y)0|RWMeR8xth>&u{3MMKviUgJ;4k#Dc`XG->mGv9d zU@*WGKO^)iE>N@lylgsR6SSVB6P2U{DzMaSkb|mE5bWI#ZK4b1P|C&`82##tyr=hk?QSg;sjY4r6z=-NzTLti}ELVW9 z02gV086%YfGT?u4_cSES6xBs-Daho1PV&G-P0%OE( zT-8-`JI>AD9^*8N z(zWUc*=JX@U8npMs3{HRbNkK1qE>c?5V;Mi@G1JyU`ODSW^X6@ZHr4?nAo*v1Auv) zw*fE@*T#}47?m;8%l}M7ph7^H%pZRh;!l}8k#9Kh8Cx8h#szng{w$IN?)H%v=dIS9 zz?PDUp@S+F_790r1+C~?kJim&JO10dL+fU`V#TX>W1cB))V)p9te%4z>tyU_!D+ca znj$na1ByRi@8sPFTH%X@4*5zgnk5m4z%dP4`5Dm%*C6vts>&mIILZepXjoqB^##k} zfB0HEoq*NM*Bkp=q0fK2)6r`zSBm$ThrZa6Kw78}yhv=~*l2}&#&|v4w?x;i(@`^D z2jnrGiZ-uFLNOag7cPtFQ2XsqSvBYxSj!m}5H)Rcd@MeE%3hb#-kK1VP78>!aLbU+ z(_SM0a0J|Rr;JnYXEU#jO|)i5Jsedn8nuek1VAlRO&`?#_pN3%L5_D2hrTEx&R)kL2e_Rr?T{XPiU6 zHs+ml@WI-3RK`jr<{%djl1>FS`qh$@H_6HMAPY_<*KCx=GNq znMlY~;B1mI0iy1sY30o%+?6(++(k}m$Sy&eQo2Ddw@tegPHU91oa|52N2jKOwD8bm z9^Min1qXK4b&J@PW2hTF^N63c-AosR7o8kaRxl}olRamA=|e=g_f8ETVTw;3!Yi&q zqk@IZ-h~Nl_7cv?^Tb=piZ_bB?iWOOJ-li~+P3^XP``ZA(BvW>1!e9-Q8PEk#k%La z>tFe0$gjdzoxLy?%{5G#=2vn2qszollq_k%?gEn-VTCdwasg!lBbz3k3=lBt<#4=x zNTB2$QvnKmKqxYZ7RUQTnFp72))|$4{Qk`7=r1$Uckhh=yQAy+yNWx_0&A_iJUt&B zPQ#-mj~*kJ86TK3*45>#qc@m6?uW)vWhjh##l;R&2sLIOm z`;(P|7d~(56GstoT4mT3JSR|xRo_7feyvx$asyfD!khZYLF1~aEHatKa0clRuhomj zDwjQwXGe=!OkmW9>{kz}8ejSSqla&*p=dOe{hQ$W`v>K;wnu za@CfZQ-SeWnz#CJK;n*6PqFXkcgOfEutwzSZ}VQets-TMU0dl=(O{mHR7{LXLovlx z9lg$if}c%-nWY+PW|P`@=RJ=(LfIA`CL})#DD$*+Y^+e){@%Z>qQwURQb(jw9xpl_ zR;z#THL}M;X|A+&yOK-SV|nY;QL_5)z;0u#hpKe^d?>KozMAA)21OyA^KHDQL4mb} zR?IDFT}NY~>w25E5p(rdK~=|f0&(uIcwQ+wF>&QAHIbEf+E0w@HEI<=GVq6$8S%D| zOSq`6+Zyv|2_tc}7)~hJiTufd{8Z#8MfRprIKd5UHaRsxZ%DEVux~8n5+SL7=`Xmx!90~Xoo~3IJfhN=y|!l3q~*o7 z83@&!--}6shivsxn60Z_2qZrWg+O9{pZC^8?Hur{A+2GjM}pGLY#8eFPCmY9S+*@v zqN6O1m>yDb?cbRV_g=HmJ?B5$U8{B0c$@8PB4OoRG@gy0NF;v3=P$uda5BxO4}v)*RD|S!4lEKC=M`{-Evrlr6-JhHfG~yujvTGh~*( z->}1I+alXolLUi(7^puqmFr1JexljyVF=MZ9cMiG)#}?~$gvCO$M^aV(fR42V#)WC z$q#ir>_VIn00Q4jTF)wQILeT!4|DM38Xza_gA!o~RyP`Hd!BgW^Y%uJLyTwTQ$?7S z??T)j!{R{fp%$^X5pXU;{RcT*M=L{#?&;d7;$k_wbk{g&9Sy$|Ma8~}TQ8CyK2~%i zMHlK`S0MCozhMjK4KPMSg-MR!ZhirBEI!!jBJr#)60<;1?&J1o*Zel4n;YxuMZh)^ zD{tT`{eb|j??r)7JZQZea8gCX>gsYLcWPKrPjKVX>e*pXD2qy^{Mhl9Ohb$4 zJuDC5uP1!zix^~!Pk?=ZvD(yQro`mlt*&LyK>?+1XnZ8s<>q>ST%H_$`6NJsGG1xR z)lAoM0=zin*bpW{w%3T?IloToP%mQT-jm#WVxzuvhAY%=u2ejes=ZDAe9aimAC?mV z^Tl?Ev8?%6k)w!)&y#ymPGNT+U22^EnY4b-U4thtu)N7^9n6vG3$@vKHRXVGf9-Thz~f^H`}hxo_$}dfJA*w|V^Q;~BKW0am~D|A zDWJC?W6(1&-Ev$n9K+DW^IWm=2jBT&6|-hQxyiw(ehHpic4Z)1>>fRK!x3AS#ckl+ou6bWVmrU$Xygne^ z+cN{33%!0*6s9@>KT=ToNSE$^ero9I_|t-O7kCOVVtNQlL=OFmbt^i# znScutJt%V~ZCxz!ab3$U$i74^;>Hnhq~YxO6;F*_0K_;`@%=yPrGN#q*K&dqZDXIx z;4Bz4Bt;tL24*&aeO)gCSRvMD!c@xh&x?$ML;wtr(Ee-IYdx6&94F^v7*ZK(`BUwq zT4%S+L<5fKDxRpXb1ODoRleD>B^*EwlLkwM@Dj>LvuwASdLMw-zXQnvi*K86r@UH6 z*52JlT3>n0?Y7HBdf^KVr$1PL6_|1#W8+HY3J?G!!D34j3n!8wPQ!=C4RSfa`=5Xz zfYOj?3Sw4^^wQ@KUz<}c*T|j9ax8vp8&ZlE1GV&*#5%Fb37`}K!!+|DS$_Gm`>og~ z`TC$6Li?ON57dgak&9$zIEU>iey>5ze^?wZhq{c{*|bGQaJRPeL%u%;r+5YBANw8u zlUgwM=2^K&)6yzix-jHz_4W|mYYE?21>FIwq8fqMG+{Ue)j1ovph=?*5oiUA#bQMM zUY)?^anr_1Sd_Bd7R;NZQqbHc=&3MepVcqR;cNKdkAHXrq!*aR!DO6Vy#njP!()VQ zaj)Xzh(9<49Ja0HVPscFL>%|4=&K%E-o-jnY6i# zHwWCGq1YC{Aa!z*x^3h2e|dQ9LZ$_*Oj$^gpeHZxs&p#SngE*MHd81WhC(}TC8~xL zwdfF2i~DO+v*exUyIgrENVLd?g*9?rut9#MhYdHc^<1ih2v!9mLHQelCWY&arjr<* zsxp83MdoVfXj}k!uw7ae5nJGtcv=CHRs5&En(ssT5(98qEdH95`_khH<8->JtB(S8 z2m*q*<)S6cJ8+nW*h828)7H6hd7j1ZrEguXk#>r{X46&56E*A_5xIsbrMay{)f`+z zEWoqaBiK8lC@5L%X!IqiJ0OB?>UGeaT-rqJy#3uFEK- z#2QHz(MRu1MaBZ}vZu2opiQ99&Mq(dl`%$7hks!dI@>9JOPck$38T3w6Nt$Z^L4IR z!K@qxc9v^Ao`?5zE;d@Qw>W5Hd1(Zn7O`_3$mf;NSv}In z(HMSibIOx9?&?buG-+SlRmOAtFiohzopdVhfE5`}mhF0aevKI_=QH3Z!Wv>{YTH-s za9fB|VYQ4ZnzLk5R(27}+6?O(jek)C+DBSHEyaJk&q94ni3NNBM;}u82T}r@3uf6O z7MFhX?HQ;0Z5wM_ZP8r|tznGJFI)GQXQCWP}(t_U?gI_jK}+SDm)mYF7Lpo%=!0E+}>77fek$&J9&8y)i3e&kMak*P~lT{qBa@>J0bPbRpAV$~1K6 zdQ+K!QR~a)$VJ<>Pscy=>Y^iBz#Uc#rSM2~BCBBFn}6AI&UtOwnT;jrsJOYPtwFrwQ*>NVr<5NA1*nmzK1(;olcc3}5*#X4$%# zmG&A<~cbJA=@+-l#BW8 zv-Ox=yxfnN<|KVo)UlZQ`g%{rJ|H)o!2oYXIGfD`T=ya3#XQ8QUpH}IuH3^-kN+L) zwB@_aZsYjrzwflQlmrNVZ~tvmu=|TG9UeXBghP0#w@1&t}&#N7potYBaL{jBL@Yetmrn(`*(O zykK#bcp{3fbI(KtaG0XjcRPR?@m45=KXCwW$1>fC6nbp@=wsWKQD#f|DqObDc^`ru z_2DM~WiNl~ftlBN93^AxE7xC;#x62F2^C(B|Mz{xn7V%&C`&N=Id2frSf$$}*#%Ah zmOI**QKJon%hcR7F^)qM<@g!0Yw^=c?_}R6dc@zq^?BDE#wfRw_a`~T#9kJ2zd?oC zpC28*uMp^;%RVf+>?_hQP5e+);9r#EMDqDH=dLGG&0795Q)Pz41p(>$7LD^pg3j%>kPls@Ko?%LGP z7lDTe0O^D1Tzo{E;>lLQz0RL)4##QuiEzT#KC}yZMJ`WuJ%7RPNgYZQa${Tcf1cad znx13@)a)B$cRT?{ON>j{ykA}~d$x9wxovfIbVwOBlSpS|)1}PeXVIh01<>J)ZfBy? z0&i)+Rx$q6F*MxHpd7_c*XU-=i9jfqPLx$mZ1nm!Q6Hib94f6%FM1%e|3w2=+K>_O zJPo4|?K zpST{{MmYhpKdMGR?a!wBo}F_;nmYri-J{@!@2XzR6VQ-8b9^uq?%m>YkMl(ynQ)Zr z+j8N7X7ahcB!HhN?f5F+dNH@L3|-oC69fhyfuVVe10`aPSPVKLsM~ zTCv|?73+|`nqxlQIG_+E+LPlsG5&XK2cn^ILoC1UnrIuj<)$$@g9Xz51f27*G>9Dx zB@^JA&hbN57|+M~2(5JSp-kb?@iWaJ(=kx!l%Dv`!)Na814uwG?q0*vtIKa2onF*B z)=GO9x-`tQo9XgBgdjr7Lh8p9TZzTMkg|cz8j%x{lR)cu zE+|73k78HhD`?2Gi;&cevcm#Cs8t1omNoB7az2+ZijrlRo|@u;_oXb>)&mt&?zo}b z7V1JS#oJ0>uVZCqQ0HHRZk(}*8RMd!nhr9U!5zPw%mL1^Hg!5~y9hsiDR$u~Wcyeo z?i*<~4nfbveaoD!Haeogb<0r_%V`SPTr>Ku5GWSXrrk&Py2oaMv|a4bw4IO!Rb7Z~ z`w=HV0qniW&5fy(4%n_gv3oBcU7eBe#gmJEXbxabPcX>s9`T8(6L@Vo^J-6B6dBw5 zt~r0IOd&d^mWyv3_rMk#)xND<5NEG3lgU3f{oz)hX=H5B^oY$b>R|Oq!+|!=V1RZs zhMyGzIb;6d;{?c@t`TF2LCh5B{`;0S z*KT%pur@v=a}(rZ4NzYKfQvy*3%kb260oK^(Y=V(2GS<=V%Do6=8q(N0t_Oki&H}Z znw!!wa|=Ij>?yoM_Kl~k1$O9dHk~Yt=n|iP{ugnnWK8AS6Ic)nP5nD4!y(vt)y22w zxB2K@Mz9l?%P*eA(Ju!`n%`h1L)LQ-Rva|;eanZq^($2Esl!o!V2g7RZ0pJ&zld!< z>2A+6r-dS9fz*a7D~0KH(dBh~Jy0J{n0L_(jl$CES~KiiKH6&vMl|LE9JDaD)U%nSlwMMqV`OqgfOX za?sSvy#?6@Ig&n$S;P@xE)wBxnC^P{nUTHL!<`0qrE76QLYtk{Os%Q^6VsbX4{&u_+N0{Lq#oo2n=h&T^(l zY|MmCsWJ*QxY+zHCZMqXDxrPT7I|s7r!)IUc*o}LACbUwP;Jb1FsIU=31~xZUuoTz z(C+3qIa95I24D1P!nbh@Q>f^MUyc6;rx?)Wgd79__BoNN*I^VYh_)_L6msRn>vhua zRp4=mT#cqY0hdv%M8wDSNDJ&&PAWaWVLGGX=v*lC+#XovqQMJe;2n`al@d6X2mZA# zo~HHi8MO&_1pQ8=S!)v=m90HqQapB*3X5zwG-OcG6SNhf-!%nBuy2We0ko`rs);Op z|GBGHPg;yppr}v$^eex7bU+^E`G^CTAvMP)*e_?ETUw1;#`If9iQR_y01=jn_k3nZ zlZH9ts+Gvdj>XJ#3#xs~(eD)CeUh+m-YA*N#P990G4)k|W%6Mdh6&AsiBzg6fz z?0h%wl$oeN|Dpcc^Cw?lz=#^O&Ws9TulUA6iSLgB1^AJzjQJRLv1proZ=?eK4s?%+ zXPw}sOoPsXlJ7MhD2ysEsEJvthJ_=lMf0`6XKo=+12e73j!!#QvGnUs7F{nzaLP15 z8~XK>4i3}8MEVU<$pKYBVeE0riWH>VoPd?Ci_vvB+?w}zFms!+~oA$eBjnkI{?N-GF@2(On!ezZ@PD!<=_I0o4 zzB(YHADA*33yQDPt_82wFfCS9k%##@Dxxd30nlC)aL2RxP#FSrqv6(HOkia$OddVA z90~WHgZdRIhP2@X=tr)p_qG;*ZfJWAgtbyh$RBg^u0}Ax(oph8PzIyMHQdVo{J=6Q zUSHo;>l*LQgo%(@(2D&hdwE%1pq-cC_?v|KnR?rD>M`z1=O?PJc8TAjt)7+(M3)yF zWW`2B0czL|Gs!T?F$At5P;eU(gfn=gIqM@5aGx$B+vF#Cm>*5c?YhFRIo6MQ_|bf-=zFhyhE5#v~E|m-`f2q!nG0Ey`J9w=3laWB{_AOc5s$Gi}S9_{DUlP3)3z>NllERy|B$5Ah*yDv}}7XpMB6o%o3sVi2m32svu>`a}_+uRMdL<<IK8@aL@5tVkod zn*|eOYC}UC)lu1SXV{C@9KE<(&so^gZpgQTPl3Z>xO|Ir%%y`Ce(sQBe7|nZ*JK4m zM85SPIp8NmQI?KQ+aIC(o{1{ZvyyeZRaU$ui@*aPf1)T~7+sc(JPk4VA)t8fwRv_5 z0SaZ6P4BWlW0;n6F^zZyKKaQxoT_aPCAyO=G{U`kaDsQ-NL^3{qQ&bA&5zogiT|Bd z_h3W2_Dz%1EGKKYkXrlBYC6dHn-}~jjiek5e#cTbNMEI{pGL}lX^b8UUFvIJ06`m$Uo+?k4DmE5(LU0shf^h~NTK&h^+&>~6mxX` zpy}wRG60gr=H6QLU9!##>_~B?XAJ-KuF+l-PHf&%W|ws_od|r2Y8L$F7-g8B4POY* zuO{BLO;=UQ7Jlcy%|3+lmT0|YAik(RP>fhi!itJbiGTuWW}q@HddtHG)~W?scxaZP z#KL?SH1L3KG~~ z5tKfi)~%MloW_U(Mqvn`xbKh&2<1`dM@JY&q?}q(n7zNoHeD9Bm1VphJc+RNpP8qH zU6va8Xj=D4g}#3|@!6S&#^JP(ZtQ4lelnGohI)4b<~VDC;t_xlrM~ zkPaW@N0iLKTeNLKMN@SWoIW zku?-nK+Jw(;IB0CJFLHnlD&jq6Crw}REOvtyiMXGP!<_IY(7UVYj6+1y(OS|ePs+BxowT{q7v?!eGe9-e{ZoW46l)#~ zx$a{{t*w#pLEV`j-N?&*!jO(^hXsy#vpu^8&7KJA1t#2O41l4UMd^ab<_Wn^JWT3MhnP!&-Z4^L^XSnHcK{W=U zEQ4fnL?L7m3ECC-#@zNMHY)V5-UvXyxezpqkYT>?*#`x7g0pn#^wbbZC~Ju3hkJZ2k>564;aSGp=g>uk-CG(hX4>A5AY7Z zqxO{SzYS`ya!U;X0J4bad2IrVzuB_`k*`1-NW?59a<;bI#Qjl-k}sz+y>tgXlfId~ z5lW{7`Q17%b8ZU3qDj{`EjH~Ih?Nm!^Hj5ylpTMQR1Kk&6gM&s(Z%5z(0m>F4r&(t zSp><0)!}h-%y4u%AdQ-5opRIUQf=L>N$=;eyZ zX87Y~4{p5AXsSapBZ_#>9mWK>pKmS&yo@)jJOb;cGVL@E_w{lJ5O|WcYcfjwbl}L*xim|J;hm{iH-Iqyk=ZNncz+>i1Yv+kw zTQH`7Z?R08vq(G<2YaORrLFQ`)4Tq@VP(>1_r(*F`$jxtv>G+eRHHX+rwl85sffk9 zl{Kz3^^LgM6sF55#r^C`(43zj{xW??QNNG5NjzvYHs)1)R1Ls0qAhi}?Zvps_t}qi z90ujGUkrGlIY+64J0mQ0w>f`}0SQjZh!`G-)W^?{Uf&n1UPV_&)t-05MgvrW#jwJf ziYPq3U~DN!91?E@8M#wb5{9I8n?}vu1=_{gS^r}Pi2Sz3rbbrRwokq61@Ig*Ao6Yg z=GR7Lvr_2YtPxA7!GPhumnF*}kwBk(`=>F$A>fDHxxTZh(Qe%^c(pg@TaB6fM))wc$)2*YtGaGlj`w1BMH!sv6w$iMSL#W{VDCqgY2IY95?xhSi*6Qg!c2r&s3$Dn6 zGRNTS8QwJT8q2F=qLo_l)m!XHVX$vv*Vg%IW!HsqojgCW+!c6bs9{f&0zK2HaV4y~ z^vXIhb}ifq28y;@DA=k`J5Mt zM|+Tg<~CJaI6zY(nZ4*uJBXryuVU9vBOen~lNSAAx3zhoI>yz@F|Z@*1?0{8(S%I;z&>+ zp*Ob9s;i!ZQEu@A*xsRiYJFmdll-b+rDF)!M9Vn4>na;`fD{0hK`5CJD!Z>op&9#q z4d64xYsiE5Y%l?|*Gv~)2+O<{HM#Ue(0%5%l67axBIBcfcVuc#1?Hv8zuX_ zz;7IIjr+~RV@XMA6LH`BGc&&s{v+z}nIbdzah&j@;LJ*dMdGVvUWap60uzMS`TJ9x z^xmaP;;6OfS9f)p+W1QDJVl!AtamtQDumyDWvkOHeMMV8ra6XlpKe5gw{DC63nvby zWBb>iE8WR>X0&h3`PJ9Dl+L@cuUDgu)Na}{7{`Fl64^pw&$|j*Tw=;Gwor{aHJOCM&u!8NcfJe(()MW2G+L}MqWEOfd!sxn6SMn+IZ#e6vXBq+e6!cugL*gVR+uU zL;_bMNtLa4i93;qsiw2qj0#0{2hX@HBUSM798gDES3f^+SO&mT6 zh${%1_QIxgvKdC14xdVmEJQosfktlSXK=BWBG})nEA3J*OjTRUb;tx6f^E^wa;u`f z0K78fkp#dbP4M8F`+|laam2M=V^A_ZtlPbdxGa}_3Og}u-X20xe&ydMKQp?O6_>oR z5waz^UkZVt2t#T*@GJ$$6(oP0%*tKY%v1;fO!!~1zYuQLiR(gB5H8QviuM4!gMDm= zgba<$wSe&0QZuS-!Y!&l&PVKTa{9P<9avn17NHdd82wxR0AY9Cp9|gs{gY1UyWpB2 z9;f;%=oRP0PSH)^&7&|vUWyucq62`ZH8CV^?z{Nvc>FR*J5W6Zw5vROfpy}~!(Zo|@?m{)!v4K$@RT(67!M#!J9UArqi5n74 zTx5s#?{LVlXXL%3BRWTjw-U+1pAt5m)4MD)F|u&XU3@o&k=HG-fqaXlxeA}KDK@mx z@vdyL&;jH~T1I}ZO$*p6qRz*LS7XcXOmSdXV#!hg z&GJ6HzL?)d_mdm@g3rL2*h1i$af^eC7B|>o#5$WygWDp$nEl5$e7sXSY1#J)j8)BC zSAfPXl(J#C<^i0}b>LMMn0@1`7jRQy-ATDy5k?ax%X~`&rZ3dTBDTff@6X!4u1LmxO`Fh!H2-%B<}^l z@GChP7o1sA0-VtX?sY>q)U?5L8Sr>3zC53ayW+US8P+aNdiXdcLGW>6!lMMn^(&bg zFIxZNV1B}O3Am0=;@_TMhdw;NTt4Z#I&hokL{)ZQ)q=yBTQ&ll{h}CVx5)rIvUH@Jy$7!++-;KQk8zGDL8TB-O2$Ii*? z@XCDo>bk(~!hiYt1yvcBH4Xt6uX+N{xq84hsd3Mf7oi%!>33kgjF^50)hJwTx(udE zizi6;daG$8xaj`gMfCYLSY*mW9j=ew3(BXQ7p@QkIHtPn{ zo*z3c9w@slIC`7MqX^g@=mG9+L>rxVW0YjLvfDVT=L_X5O;0>+ zIi^T4-1ZRoWTiY|PLqa9UC9;DT3jWJfCRQy7_)pu`}FnzPpoR_LnPn2>Rjli@D7F> zvlaqF26%=fVoEYes&_qD3|Q5H90xKQwe?G0pKVkZussZK1CNHrXlOt(7)b*kqseA8 z*^DNep-_r4na-2zVY>mXL_zHjH%3A9Axdo788nPw&%A|E)n2LqRR4mtf(B75fJ0r7 z#c)k)D|Z=4fsaK%$R2bCo}&-iKnAR2noQ^M^|XQSFM^rC7*_za9eR}_P~HqfegjY% zCcm~asbSl)H|~dXkQ}g>fw?9nAptZ#lK`>D$?kdP!3>lO3`G)Hg%2!(kFf#o_Dhnu zTMD_&fED7O21bX)eq2B$@`&9KPWFj5i6(nM-A1S?aPRU8=beHigmv;jXX&+llIPuw z(n4wL1{%ip0pTv-ZHPh*^M0FH)goIwk;mb3DWAskMBvSW5ceM{Gc?GE&|+AXi0n<^ zf!jH_np?_gf0`395qPL9gwfD}G0XGN zi-~N=&PaNo_$9{s!WWric~*PiiBxI(#}*!u1+N#0EVx|Fv{(}~kpK(#W}b#+j~%XG l0Irr$F`ogP4u+;2W(Fe$nSdxC_J^Pl_H^}gS?83{1OPi7tAGFi literal 0 HcmV?d00001 diff --git a/fieldservice_agreement_repair/static/description/icon.svg b/fieldservice_agreement_repair/static/description/icon.svg new file mode 100644 index 0000000000..c27c090fda --- /dev/null +++ b/fieldservice_agreement_repair/static/description/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/fieldservice_agreement_repair/static/description/index.html b/fieldservice_agreement_repair/static/description/index.html new file mode 100644 index 0000000000..5734509305 --- /dev/null +++ b/fieldservice_agreement_repair/static/description/index.html @@ -0,0 +1,434 @@ + + + + + +Fieldservice Agreement Repair + + + +
+

Fieldservice Agreement Repair

+ + +

Beta License: AGPL-3 OCA/field-service Translate me on Weblate Try me on Runboat

+

This module allows you to link repair.order with an agreement +trough a fsm.equipment. This way you can track the repair orders +that are covered by an agreement.

+

Table of contents

+ +
+

Usage

+

No specific usage instructions.

+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Camptocamp SA
  • +
  • Italo Lopes
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/field-service project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/fieldservice_agreement_repair/tests/__init__.py b/fieldservice_agreement_repair/tests/__init__.py new file mode 100644 index 0000000000..9a757edeba --- /dev/null +++ b/fieldservice_agreement_repair/tests/__init__.py @@ -0,0 +1 @@ +from . import test_fieldservice_agreement_repair diff --git a/fieldservice_agreement_repair/tests/test_fieldservice_agreement_repair.py b/fieldservice_agreement_repair/tests/test_fieldservice_agreement_repair.py new file mode 100644 index 0000000000..4d93d8b756 --- /dev/null +++ b/fieldservice_agreement_repair/tests/test_fieldservice_agreement_repair.py @@ -0,0 +1,93 @@ +# Copyright 2024 Camptocamp SA (https://www.camptocamp.com). +# @author: Italo Lopes +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.tests.common import TransactionCase + + +class TestRepairPartSourceLocation(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.agreement_model = cls.env["agreement"] + cls.repair_order_model = cls.env["repair.order"] + cls.equipment_model = cls.env["fsm.equipment"] + cls.product_model = cls.env["product.product"] + cls.lot_model = cls.env["stock.production.lot"] + + cls.product = cls.product_model.create({"name": "Test Product"}) + cls.product02 = cls.product_model.create({"name": "Test Product 02"}) + cls.product03 = cls.product_model.create({"name": "Test Product 03"}) + + cls.lot = cls.lot_model.create({"product_id": cls.product.id}) + cls.lot02 = cls.lot_model.create({"product_id": cls.product02.id}) + cls.lot03 = cls.lot_model.create({"product_id": cls.product03.id}) + + cls.agreement = cls.agreement_model.create({"name": "Test Agreement"}) + cls.agreement02 = cls.agreement_model.create({"name": "Test Agreement 02"}) + + cls.equipment_with_agreement = cls.equipment_model.create( + { + "product_id": cls.product.id, + "lot_id": cls.lot.id, + "agreement_id": cls.agreement.id, + } + ) + + cls.equipment_no_agreement = cls.equipment_model.create( + { + "product_id": cls.product02.id, + "lot_id": cls.lot02.id, + } + ) + cls.repair_order = cls.repair_order_model.create( + {"product_id": cls.product.id, "lot_id": cls.lot.id} + ) + + def test_01_agreement_is_set_correctly(self): + self.repair_order._compute_agreement_id() + self.assertEqual(self.repair_order.agreement_id, self.agreement.id) + + def test_02_agreement_is_not_set_when_no_equipment(self): + repair_order = self.repair_order_model.create( + {"product_id": self.product03.id, "lot_id": self.lot03.id} + ) + repair_order._compute_agreement_id() + self.assertFalse(repair_order.agreement_id) + + def test_03_agreement_is_not_set_when_equipment_no_agreement(self): + repair_order = self.repair_order_model.create( + {"product_id": self.product02.id, "lot_id": self.lot02.id} + ) + equipment = self.equipment_model.search( + [ + ("product_id", "=", self.product02.id), + ("lot_id", "=", self.lot02.id), + ] + ) + self.assertEqual(equipment, self.equipment_no_agreement) + repair_order._compute_agreement_id() + self.assertFalse(repair_order.agreement_id) + + def test_04_agreement_is_not_set_when_no_lot(self): + product = self.env["product.product"].create({"name": "Test Product"}) + repair_order = self.env["repair.order"].create({"product_id": product.id}) + repair_order._compute_agreement_id() + self.assertFalse(repair_order.agreement_id) + + def test_05_agreement_is_set_when_lot_updated(self): + repair_order = self.repair_order_model.create( + {"product_id": self.product03.id, "lot_id": self.lot03.id} + ) + repair_order._compute_agreement_id() + self.assertFalse(repair_order.agreement_id) + repair_order.product_id = self.product.id + repair_order.lot_id = self.lot.id + repair_order._compute_agreement_id() + self.assertEqual(repair_order.agreement_id, self.agreement.id) + + def test_06_agreement_can_be_updated_manually(self): + self.repair_order._compute_agreement_id() + self.assertEqual(self.repair_order.agreement_id, self.agreement.id) + self.repair_order.agreement_id = self.agreement02.id + self.assertEqual(self.repair_order.agreement_id, self.agreement02.id)