commit c0296ab2a89954786fa907eaf2b4b00bc4c914b5 Author: Leszek Manicki Date: Mon May 6 11:40:59 2019 +0200 Initial commit diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..be3f7b2 --- /dev/null +++ b/COPYING @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/itis_hr_attendance_extend/__init__.py b/itis_hr_attendance_extend/__init__.py new file mode 100644 index 0000000..7433469 --- /dev/null +++ b/itis_hr_attendance_extend/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + +from . import wizard +from . import models diff --git a/itis_hr_attendance_extend/__openerp__.py b/itis_hr_attendance_extend/__openerp__.py new file mode 100644 index 0000000..d8e9a70 --- /dev/null +++ b/itis_hr_attendance_extend/__openerp__.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + +{ + 'name': "ITIS HR Attendance Extend", + 'summary': """ Module will extend HR Attendance""", + 'description': """ + Module to extend HR Attendance + """, + 'author': "IT IS AG", + 'website': "http://www.itis-odoo.de", + 'category': 'base', + 'version': '1.0.55.0', + 'depends': ['hr_attendance', 'hr_timesheet', 'hr_timesheet_sheet'], + 'data': [ + 'security/groups.xml', + 'views/hr_timesheet_sheet_view.xml', + 'views/itis_holiday_view.xml', + 'views/templates.xml', + 'views/hr_holiday_view.xml', + 'wizard/sign_in_task_view.xml', + 'wizard/hr_timesheet_overview_export.xml', + 'security/ir.model.access.csv', + 'data/cron.xml', + 'data/data.xml', + ], + 'qweb': ['static/src/xml/templates.xml'], + 'css': [], + 'demo': [], diff --git a/itis_hr_attendance_extend/data/cron.xml b/itis_hr_attendance_extend/data/cron.xml new file mode 100644 index 0000000..62f55f5 --- /dev/null +++ b/itis_hr_attendance_extend/data/cron.xml @@ -0,0 +1,80 @@ + + + + ITIS Timesheets Monat abschließen + close_timesheet + months + 1 + + + -1 + hr_timesheet_sheet.sheet + + + + + ITIS Setting Cost Center for Existing Records + set_cost_center_existing_rec + days + 1 + + + -1 + hr.analytic.timesheet + + + + + ITIS Get Monthly Timesheet Overview + get_monthly_timesheet_overview + months + 1 + + + -1 + hr.analytic.timesheet + + + + + + ITIS Create Daily Timesheet + create_daily_timesheet + days + 1 + + + -1 + hr_timesheet_sheet.sheet + + + + + + ITIS Create Missing Date Timesheet + create_missingdate_timesheet + months + 1 + + + -1 + hr_timesheet_sheet.sheet + + + + + + ITIS Employee Sign Out + automatic_sign_out + days + 1 + + + -1 + hr_timesheet_sheet.sheet + + + + + + \ No newline at end of file diff --git a/itis_hr_attendance_extend/data/data.xml b/itis_hr_attendance_extend/data/data.xml new file mode 100644 index 0000000..dc38994 --- /dev/null +++ b/itis_hr_attendance_extend/data/data.xml @@ -0,0 +1,28 @@ + + + + Holiday + True + True + + + + Monthly Timesheet Overview + + + ${(user.email or '') | safe} + ${(user.email or '') | safe} + Monthly Timesheet Overview Report + Sehr geehrte Kollegen,

+
+

anbei erhalten Sie den aktuellen Report zur Kostenstellenübersicht nach Mitarbeiter. +


+

Mit freundlichen Grüßen

+

Ihr HR-Team

+ ]]> +
+
+
+ +
\ No newline at end of file diff --git a/itis_hr_attendance_extend/i18n/de.po b/itis_hr_attendance_extend/i18n/de.po new file mode 100644 index 0000000..d9f2b4f --- /dev/null +++ b/itis_hr_attendance_extend/i18n/de.po @@ -0,0 +1,624 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * itis_hr_attendance_extend +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-09-19 13:19+0000\n" +"PO-Revision-Date: 2017-09-19 15:22+0100\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: \n" +"X-Generator: Poedit 1.5.4\n" + +#. module: itis_hr_attendance_extend +#: model:email.template,body_html:itis_hr_attendance_extend.email_template_monthly_timesheet_overview +msgid "" +"\n" +"\t\t\t

Sehr geehrte Kollegen,

\n" +"\t\t\t
\n" +"\t\t\t

anbei erhalten Sie den aktuellen Report zur Kostenstellenübersicht " +"nach Mitarbeiter.\n" +"\t\t\t


\n" +"\t\t\t

Mit freundlichen Grüßen

\n" +"\t\t\t

Ihr HR-Team

\n" +"\t\t\t\n" +"\t\t\t" +msgstr "" +"\n" +"\t\t\t

Sehr geehrte Kollegen,

\n" +"\t\t\t
\n" +"\t\t\t

anbei erhalten Sie den aktuellen Report zur Kostenstellenübersicht " +"nach Mitarbeiter.\n" +"\t\t\t


\n" +"\t\t\t

Mit freundlichen Grüßen

\n" +"\t\t\t

Ihr HR-Team

\n" +"\t\t\t\n" +"\t\t\t" + +#. module: itis_hr_attendance_extend +#: field:account.analytic.account,account_code:0 +msgid "Account Code" +msgstr "Kürzel Kostenstelle" + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/models/hr_timesheet_sheet.py:453 +#, python-format +msgid "Actual Overttime Count" +msgstr "Über-/Unterstunden" + +#. module: itis_hr_attendance_extend +#. openerp-web +#: code:addons/itis_hr_attendance_extend/static/src/xml/templates.xml:58 +#, python-format +msgid "Add" +msgstr "Hinzufügen" + +#. module: itis_hr_attendance_extend +#. openerp-web +#: code:addons/itis_hr_attendance_extend/static/src/xml/templates.xml:64 +#, python-format +msgid "Add a Line" +msgstr "Zeile hinzufügen" + +#. module: itis_hr_attendance_extend +#. openerp-web +#: code:addons/itis_hr_attendance_extend/static/src/js/hr_extend.js:125 +#, python-format +msgid "Add comment" +msgstr "Add comment" + +#. module: itis_hr_attendance_extend +#: model:ir.model,name:itis_hr_attendance_extend.model_account_analytic_account +#: field:sign.in.task,analytic_account_id:0 +msgid "Analytic Account" +msgstr "Kostenstelle" + +#. module: itis_hr_attendance_extend +#: view:hr.analytic.timesheet:itis_hr_attendance_extend.hr_timesheet_overview_search +msgid "Analytic account" +msgstr "Kostenstelle" + +#. module: itis_hr_attendance_extend +#: field:hr.attendance,timesheet_id:0 +msgid "Anlytic Timesheet" +msgstr "Zeiterfassung" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_form_editable_itis_new +msgid "Approve" +msgstr "Genehmige" + +#. module: itis_hr_attendance_extend +#: model:ir.model,name:itis_hr_attendance_extend.model_hr_attendance +msgid "Attendance" +msgstr "Anwesenheit" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_form_editable_itis_new +msgid "Attendances" +msgstr "Anwesenheitszeiten" + +#. module: itis_hr_attendance_extend +#: view:sign.in.task:itis_hr_attendance_extend.sign_in_task_form_view +#: view:timesheet.overview.export:itis_hr_attendance_extend.timesheet_overview_export_form_view +msgid "Cancel" +msgstr "Abbrechen" + +#. module: itis_hr_attendance_extend +#: view:timesheet.overview.export:itis_hr_attendance_extend.timesheet_overview_export_form_view +msgid "Click 'Export' button to export timesheet overview csv" +msgstr "" +"Auf 'Export' klicken um die Übersicht der Zeiterfassungen als CSV zu " +"exportieren" + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,emp_comment:0 field:sign.in.task,emp_comment:0 +msgid "Comment" +msgstr "Kommentar" + +#. module: itis_hr_attendance_extend +#: model:ir.actions.act_window,name:itis_hr_attendance_extend.act_hr_timesheet_sheet +#: model:ir.ui.menu,name:itis_hr_attendance_extend.menu_act_hr_timesheet_sheet_form_my_current_editable +msgid "Create Timesheet" +msgstr "Timesheet anlegen" + +#. module: itis_hr_attendance_extend +#: field:itis.holiday,create_uid:0 field:planned.hours,create_uid:0 +#: field:service.description,create_uid:0 field:sign.in.task,create_uid:0 +#: field:timesheet.overview.export,create_uid:0 +msgid "Created by" +msgstr "Erstellt von" + +#. module: itis_hr_attendance_extend +#: field:itis.holiday,create_date:0 field:planned.hours,create_date:0 +#: field:service.description,create_date:0 field:sign.in.task,create_date:0 +#: field:timesheet.overview.export,create_date:0 +msgid "Created on" +msgstr "Erstellt am" + +#. module: itis_hr_attendance_extend +#: field:itis.holiday,date:0 field:planned.hours,sheet_date:0 +msgid "Date" +msgstr "Datum" + +#. module: itis_hr_attendance_extend +#: view:hr.analytic.timesheet:itis_hr_attendance_extend.hr_timesheet_overview_search +msgid "Date From" +msgstr "Von" + +#. module: itis_hr_attendance_extend +#: view:hr.analytic.timesheet:itis_hr_attendance_extend.hr_timesheet_overview_search +msgid "Date To" +msgstr "Bis" + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/models/hr_timesheet_sheet.py:86 +#, python-format +msgid "Date should be between timesheet date." +msgstr "Das Datum muss innerhalb des Datumsbereichs liegen." + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,dept_account_id:0 +msgid "Dept. Analytic Account" +msgstr "Kostenstelle Bereich" + +#. module: itis_hr_attendance_extend +#: view:hr.analytic.timesheet:itis_hr_attendance_extend.hr_timesheet_overview_search +msgid "Dept. Analytic account" +msgstr "Kostenstelle Bereich" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_form_editable_itis_new +msgid "Details" +msgstr "Details" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_form_editable_itis_new +msgid "Differences" +msgstr "Differenzen" + +#. module: itis_hr_attendance_extend +#: model:ir.model,name:itis_hr_attendance_extend.model_hr_employee +msgid "Employee" +msgstr "Mitarbeiter/-in" + +#. module: itis_hr_attendance_extend +#: model:ir.actions.act_window,name:itis_hr_attendance_extend.emp_service_description_action +msgid "Employee Service Description" +msgstr "Leistung" + +#. module: itis_hr_attendance_extend +#: view:timesheet.overview.export:itis_hr_attendance_extend.timesheet_overview_export_form_view +msgid "Export" +msgstr "Export" + +#. module: itis_hr_attendance_extend +#: view:timesheet.overview.export:itis_hr_attendance_extend.timesheet_overview_export_form_view +msgid "Export file:" +msgstr "Export Datei:" + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/wizard/hr_timesheet_overview_export.py:97 +#, python-format +msgid "Exported Timsheet Overview" +msgstr "exportierter Zeiterfassungsbericht" + +#. module: itis_hr_attendance_extend +#: field:timesheet.overview.export,file_name:0 +msgid "File" +msgstr "File" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_tree_simplified_inherit_itis +msgid "Geplante Stunden" +msgstr "Geplante Stunden" + +#. module: itis_hr_attendance_extend +#: view:hr.analytic.timesheet:itis_hr_attendance_extend.hr_timesheet_overview_search +msgid "Group By" +msgstr "Gruppierung" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.view_hr_timesheet_sheet_filter_inherit +msgid "Group by month of date" +msgstr "nach Monat gruppieren" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.view_hr_timesheet_sheet_filter_inherit +msgid "Group by week of date" +msgstr "nach Woche gruppieren" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.view_hr_timesheet_sheet_filter_inherit +msgid "Group by year of date" +msgstr "nach Jahr gruppieren" + +#. module: itis_hr_attendance_extend +#: model:hr.holidays.status,name:itis_hr_attendance_extend.itis_holiday_leave_type_new +#: view:itis.holiday:itis_hr_attendance_extend.view_calendar_itis_holiday +msgid "Holiday" +msgstr "Urlaub" + +#. module: itis_hr_attendance_extend +#: field:hr.holidays,holiday_name:0 field:itis.holiday,name:0 +msgid "Holiday Name" +msgstr "Feiertag" + +#. module: itis_hr_attendance_extend +#: model:ir.actions.act_window,name:itis_hr_attendance_extend.act_itis_holiday +#: model:ir.ui.menu,name:itis_hr_attendance_extend.menu_itis_holiday +msgid "Holidays" +msgstr "Feiertage" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_form_editable_itis_new +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_sheet_form_inherited +#: field:planned.hours,duration:0 +msgid "Hours" +msgstr "Stunden" + +#. module: itis_hr_attendance_extend +#: field:itis.holiday,id:0 field:planned.hours,id:0 +#: field:service.description,id:0 field:sign.in.task,id:0 +#: field:timesheet.overview.export,id:0 +msgid "ID" +msgstr "ID" + +#. module: itis_hr_attendance_extend +#: field:itis.holiday,write_uid:0 field:planned.hours,write_uid:0 +#: field:service.description,write_uid:0 field:sign.in.task,write_uid:0 +#: field:timesheet.overview.export,write_uid:0 +msgid "Last Updated by" +msgstr "Aktualisiert von" + +#. module: itis_hr_attendance_extend +#: field:itis.holiday,write_date:0 field:planned.hours,write_date:0 +#: field:service.description,write_date:0 field:sign.in.task,write_date:0 +#: field:timesheet.overview.export,write_date:0 +msgid "Last Updated on" +msgstr "Aktualisiert am" + +#. module: itis_hr_attendance_extend +#: model:ir.model,name:itis_hr_attendance_extend.model_hr_holidays +msgid "Leave" +msgstr "Urlaub" + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/models/hr_holiday.py:90 +#, python-format +msgid "Leave Request" +msgstr "Leave Request" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.view_hr_timesheet_sheet_filter_inherit +msgid "Month" +msgstr "Monat" + +#. module: itis_hr_attendance_extend +#: model:email.template,subject:itis_hr_attendance_extend.email_template_monthly_timesheet_overview +msgid "Monthly Timesheet Overview Report" +msgstr "Monatlicher Bericht der Zeiterfassungen" + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/models/hr_payroll.py:58 +#, python-format +msgid "Normal Working Days paid at 100%" +msgstr "Normaler Arbeitstag bezahlt zu 100%" + +#. module: itis_hr_attendance_extend +#. openerp-web +#: code:addons/itis_hr_attendance_extend/models/hr_timesheet_sheet.py:458 +#: code:addons/itis_hr_attendance_extend/static/src/xml/templates.xml:101 +#, python-format +msgid "Overtime Hours" +msgstr "Überstunden" + +#. module: itis_hr_attendance_extend +#: model:ir.model,name:itis_hr_attendance_extend.model_hr_payslip +msgid "Pay Slip" +msgstr "Mitarbeitervergütung" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_form_editable_itis_new +msgid "Period" +msgstr "Periode" + +#. module: itis_hr_attendance_extend +#. openerp-web +#: code:addons/itis_hr_attendance_extend/models/hr_timesheet_sheet.py:452 +#: code:addons/itis_hr_attendance_extend/models/hr_timesheet_sheet.py:456 +#: code:addons/itis_hr_attendance_extend/static/src/xml/templates.xml:88 +#: field:hr_timesheet_sheet.sheet,planned_ids:0 +#, python-format +msgid "Planned Hours" +msgstr "Geplante Stunden" + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/wizard/sign_in_task.py:55 +#, python-format +msgid "Please define cost unit for this employee." +msgstr "Bitte tragen Sie die Kostenstelle für den Mitarbeiter ein." + +#. module: itis_hr_attendance_extend +#: view:hr.analytic.timesheet:itis_hr_attendance_extend.hr_timesheet_overview_search +msgid "Product" +msgstr "Produkt" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_form_editable_itis_new +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_sheet_form_inherited +msgid "Refresh" +msgstr "Aktualisieren" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_form_editable_itis_new +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_sheet_form_inherited +msgid "Refuse" +msgstr "Zurücksetzen" + +#. module: itis_hr_attendance_extend +#. openerp-web +#: code:addons/itis_hr_attendance_extend/static/src/js/hr_extend.js:117 +#, python-format +msgid "Select Service Description" +msgstr "Leistung auswählen" + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,service_desc_id:0 +#: field:sign.in.task,service_desc_id:0 +msgid "Service Desc" +msgstr "Leistung" + +#. module: itis_hr_attendance_extend +#: model:ir.ui.menu,name:itis_hr_attendance_extend.menu_emp_service_description +#: view:service.description:itis_hr_attendance_extend.itis_service_description_form +#: view:service.description:itis_hr_attendance_extend.itis_service_description_tree +#: field:service.description,name:0 +msgid "Service Description" +msgstr "Leistung" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_form_editable_itis_new +msgid "Set to Draft" +msgstr "Setze auf Entwurf" + +#. module: itis_hr_attendance_extend +#: field:planned.hours,sheet_id:0 +msgid "Sheet" +msgstr "Tabelle" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_form_editable_itis_new +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_sheet_form_inherited +msgid "Sign In" +msgstr "Anmelden" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_form_editable_itis_new +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_sheet_form_inherited +msgid "Sign Out" +msgstr "Abmelden" + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/models/hr_timesheet_sheet.py:297 +#, python-format +msgid "Start date and end date have to be the same day." +msgstr "Start und Enddatum müssen derselbe Tag sein." + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_form_editable_itis_new +msgid "Submit to Manager" +msgstr "Dem Manager vorlegen" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_form_editable_itis_new +msgid "Summary" +msgstr "Zusammenfassung" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_tree_simplified_inherit_itis +msgid "Summe Stunden" +msgstr "Summe Stunden" + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/models/hr_holiday.py:38 +#, python-format +msgid "The start date must be anterior to the end date." +msgstr "Das startdatum muss vor dem Enddatum liegen." + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/models/hr_timesheet_sheet.py:451 +#, python-format +msgid "Time Diffrence" +msgstr "Zeit Differenz" + +#. module: itis_hr_attendance_extend +#: view:hr.analytic.timesheet:itis_hr_attendance_extend.hr_timesheet_overview_search +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_form_editable_itis_new +#: field:hr_timesheet_sheet.sheet,timesheet_ids2:0 +#: model:ir.model,name:itis_hr_attendance_extend.model_hr_timesheet_sheet_sheet +msgid "Timesheet" +msgstr "Stundenzettel" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_form_editable_itis_new +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_sheet_form_inherited +msgid "Timesheet Activities" +msgstr "Zeiterfassungsaktivitäten" + +#. module: itis_hr_attendance_extend +#: model:ir.actions.server,name:itis_hr_attendance_extend.ir_actions_server_hr_timesheet_overview_manager +#: model:ir.ui.menu,name:itis_hr_attendance_extend.menu_hr_timesheet_overview_manager +msgid "Timesheet Activities Manager" +msgstr "Zeiterfassung Übersicht" + +#. module: itis_hr_attendance_extend +#: model:ir.actions.act_window,name:itis_hr_attendance_extend.act_hr_timesheet_overview +#: model:ir.ui.menu,name:itis_hr_attendance_extend.menu_hr_timesheet_overview +msgid "Timesheet Activities Overview" +msgstr "Bericht Zeiterfassung" + +#. module: itis_hr_attendance_extend +#: field:timesheet.overview.export,name:0 +msgid "Timesheet CSV" +msgstr "Timesheet CSV" + +#. module: itis_hr_attendance_extend +#: model:ir.model,name:itis_hr_attendance_extend.model_hr_analytic_timesheet +msgid "Timesheet Line" +msgstr "Zeiterfassung Positionen" + +#. module: itis_hr_attendance_extend +#: view:hr.analytic.timesheet:itis_hr_attendance_extend.hr_timesheet_overview_search +msgid "Timesheet Month" +msgstr "monatliche Zeiterfassung" + +#. module: itis_hr_attendance_extend +#: view:hr.analytic.timesheet:itis_hr_attendance_extend.view_timehseet_activity_overview_tree +#: view:hr.analytic.timesheet:itis_hr_attendance_extend.view_timehseet_activity_overview_tree_manager +msgid "Timesheet Overview" +msgstr "Zeiterfassung Übersicht" + +#. module: itis_hr_attendance_extend +#: model:ir.actions.act_window,name:itis_hr_attendance_extend.launch_timesheet_overview_export_wizard +#: model:ir.actions.act_window,name:itis_hr_attendance_extend.timehseet_overview_export_action +msgid "Timesheet Overview Export" +msgstr "Zeiterfassung Übersicht Export" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_form_editable_itis_new +msgid "Timesheet Period" +msgstr "Zeiterfassungsperiode" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_form_editable_itis_new +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_sheet_form_inherited +msgid "Timesheet Summary" +msgstr "Zusammenfassung" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_sheet_form_inherited +msgid "Timesheet abschließen" +msgstr "Timesheet abschließen" + +#. module: itis_hr_attendance_extend +#: view:hr.analytic.timesheet:itis_hr_attendance_extend.hr_timesheet_overview_search +msgid "Timesheet by Month" +msgstr "Zeiterfassung nach Monat" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_form_editable_itis_new +msgid "Timesheets" +msgstr "Zeiterfassung" + +#. module: itis_hr_attendance_extend +#. openerp-web +#: code:addons/itis_hr_attendance_extend/static/src/xml/templates.xml:31 +#: code:addons/itis_hr_attendance_extend/static/src/xml/templates.xml:65 +#, python-format +msgid "Total" +msgstr "Total" + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/models/hr_timesheet_sheet.py:457 +#, python-format +msgid "Total Hours" +msgstr "Summe Stunden" + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/models/hr_timesheet_sheet.py:450 +#, python-format +msgid "Total Planned Hours" +msgstr "Arbeitszeit-Soll" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_tree_simplified_inherit_itis +msgid "Total time" +msgstr "Total time" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_sheet_form_inherited +msgid "True" +msgstr "True" + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/wizard/sign_in_task.py:55 +#, python-format +msgid "User Error!" +msgstr "Benutzerfehler!" + +#. module: itis_hr_attendance_extend +#: view:hr.analytic.timesheet:itis_hr_attendance_extend.hr_timesheet_overview_search +msgid "Users" +msgstr "Benutzer" + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/models/hr_holiday.py:38 +#, python-format +msgid "Warning!" +msgstr "Warning!" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.view_hr_timesheet_sheet_filter_inherit +msgid "Week" +msgstr "Woche" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.view_hr_timesheet_sheet_filter_inherit +msgid "Year" +msgstr "Jahr" + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/models/hr_timesheet_sheet.py:299 +#, python-format +msgid "You can only create one timesheet each day." +msgstr "Es darf pro Tag nur eine Zeiterfassung existieren." + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/models/hr_timesheet_sheet.py:305 +#, python-format +msgid "You do not have pemission to create timesheets!" +msgstr "Sie haben keine Berechtigung Timesheets anzulegen!" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.view_hr_timesheet_sheet_filter_inherit +msgid "[('date_from', '>=',self)]" +msgstr "[('date_from', '>=',self)]" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_sheet_form_inherited +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_tree_simplified_inherit_itis +msgid "false" +msgstr "false" + +#. module: itis_hr_attendance_extend +#: view:sign.in.task:itis_hr_attendance_extend.sign_in_task_form_view +#: view:timesheet.overview.export:itis_hr_attendance_extend.timesheet_overview_export_form_view +msgid "or" +msgstr "oder" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_form_editable_itis_new +msgid "to" +msgstr "to" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_tree_simplified_inherit_itis +msgid "total_contract_time" +msgstr "total_contract_time" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_tree_simplified_inherit_itis +msgid "total_overtime_time" +msgstr "total_overtime_time" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_tree_simplified_inherit_itis +msgid "Überstunden" +msgstr "Überstunden" diff --git a/itis_hr_attendance_extend/i18n/en_US.po b/itis_hr_attendance_extend/i18n/en_US.po new file mode 100644 index 0000000..b10b294 --- /dev/null +++ b/itis_hr_attendance_extend/i18n/en_US.po @@ -0,0 +1,530 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * itis_hr_attendance_extend +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-06-23 07:26+0000\n" +"PO-Revision-Date: 2017-06-23 09:29+0100\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: \n" +"X-Generator: Poedit 1.5.4\n" + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,currency_id:0 +msgid "Account Currency" +msgstr "Account Currency" + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/models/hr_timesheet_sheet.py:320 +#: field:hr_timesheet_sheet.sheet,actual_ot:0 +#, python-format +msgid "Actual Overttime Count" +msgstr "Actual Overttime Count" + +#. module: itis_hr_attendance_extend +#. openerp-web +#: code:addons/itis_hr_attendance_extend/static/src/xml/templates.xml:58 +#, python-format +msgid "Add" +msgstr "Add" + +#. module: itis_hr_attendance_extend +#. openerp-web +#: code:addons/itis_hr_attendance_extend/static/src/xml/templates.xml:64 +#, python-format +msgid "Add a Line" +msgstr "Add a Line" + +#. module: itis_hr_attendance_extend +#. openerp-web +#: code:addons/itis_hr_attendance_extend/static/src/js/hr_extend.js:125 +#, python-format +msgid "Add comment" +msgstr "Add comment" + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,amount:0 +msgid "Amount" +msgstr "Amount" + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,amount_currency:0 +msgid "Amount Currency" +msgstr "Amount Currency" + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,account_id:0 +#: field:sign.in.task,analytic_account_id:0 +msgid "Analytic Account" +msgstr "Analytic Account" + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,journal_id:0 +msgid "Analytic Journal" +msgstr "Analytic Journal" + +#. module: itis_hr_attendance_extend +#: field:hr.attendance,timesheet_id:0 +msgid "Anlytic Timesheet" +msgstr "Anlytic Timesheet" + +#. module: itis_hr_attendance_extend +#: model:ir.model,name:itis_hr_attendance_extend.model_hr_attendance +msgid "Attendance" +msgstr "Attendance" + +#. module: itis_hr_attendance_extend +#: help:hr.analytic.timesheet,amount:0 +msgid "" +"Calculated by multiplying the quantity and the price given in the Product's " +"cost price. Always expressed in the company main currency." +msgstr "" +"Calculated by multiplying the quantity and the price given in the Product's " +"cost price. Always expressed in the company main currency." + +#. module: itis_hr_attendance_extend +#: view:sign.in.task:itis_hr_attendance_extend.sign_in_task_form_view +msgid "Cancel" +msgstr "Cancel" + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,code:0 +msgid "Code" +msgstr "Code" + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,emp_comment:0 field:sign.in.task,emp_comment:0 +msgid "Comment" +msgstr "Comment" + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,company_id:0 +msgid "Company" +msgstr "Company" + +#. module: itis_hr_attendance_extend +#: field:itis.holiday,create_uid:0 field:planned.hours,create_uid:0 +#: field:service.description,create_uid:0 field:sign.in.task,create_uid:0 +msgid "Created by" +msgstr "Created by" + +#. module: itis_hr_attendance_extend +#: field:itis.holiday,create_date:0 field:planned.hours,create_date:0 +#: field:service.description,create_date:0 field:sign.in.task,create_date:0 +msgid "Created on" +msgstr "Created on" + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,date:0 field:itis.holiday,date:0 +#: field:planned.hours,sheet_date:0 +msgid "Date" +msgstr "Date" + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/models/hr_timesheet_sheet.py:51 +#, python-format +msgid "Date should be between timesheet date." +msgstr "Date should be between timesheet date." + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,name:0 +msgid "Description" +msgstr "Description" + +#. module: itis_hr_attendance_extend +#: field:calendar.event,display_name:0 +#: field:hr.analytic.timesheet,display_name:0 +#: field:hr.attendance,display_name:0 field:itis.holiday,display_name:0 +#: field:planned.hours,display_name:0 field:service.description,display_name:0 +#: field:sign.in.task,display_name:0 +msgid "Display Name" +msgstr "Display Name" + +#. module: itis_hr_attendance_extend +#: model:ir.model,name:itis_hr_attendance_extend.model_hr_employee +msgid "Employee" +msgstr "Employee" + +#. module: itis_hr_attendance_extend +#: model:ir.actions.act_window,name:itis_hr_attendance_extend.emp_service_description_action +msgid "Employee Service Description" +msgstr "Employee Service Description" + +#. module: itis_hr_attendance_extend +#: model:ir.model,name:itis_hr_attendance_extend.model_calendar_event +msgid "Event" +msgstr "Event" + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,general_account_id:0 +msgid "General Account" +msgstr "General Account" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_tree_simplified_inherit_itis +msgid "Geplante Stunden" +msgstr "Planned Hour" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.view_hr_timesheet_sheet_filter_inherit +msgid "Group by month of date" +msgstr "Group by month of date" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.view_hr_timesheet_sheet_filter_inherit +msgid "Group by week of date" +msgstr "Group by week of date" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.view_hr_timesheet_sheet_filter_inherit +msgid "Group by year of date" +msgstr "Group by year of date" + +#. module: itis_hr_attendance_extend +#: model:hr.holidays.status,name:itis_hr_attendance_extend.itis_holiday_leave_type_new +#: view:itis.holiday:itis_hr_attendance_extend.view_calendar_itis_holiday +msgid "Holiday" +msgstr "Holiday" + +#. module: itis_hr_attendance_extend +#: field:hr.holidays,holiday_name:0 field:itis.holiday,name:0 +msgid "Holiday Name" +msgstr "Holiday Name" + +#. module: itis_hr_attendance_extend +#: model:ir.actions.act_window,name:itis_hr_attendance_extend.act_itis_holiday +#: model:ir.ui.menu,name:itis_hr_attendance_extend.menu_itis_holiday +msgid "Holidays" +msgstr "Holidays" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_sheet_form_inherited +#: field:planned.hours,duration:0 +msgid "Hours" +msgstr "Hours" + +#. module: itis_hr_attendance_extend +#: field:itis.holiday,id:0 field:planned.hours,id:0 +#: field:service.description,id:0 field:sign.in.task,id:0 +msgid "ID" +msgstr "ID" + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,invoice_id:0 +msgid "Invoice" +msgstr "Invoice" + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,to_invoice:0 +msgid "Invoiceable" +msgstr "Invoiceable" + +#. module: itis_hr_attendance_extend +#: help:hr.analytic.timesheet,to_invoice:0 +msgid "" +"It allows to set the discount while making invoice, keep empty if the " +"activities should not be invoiced." +msgstr "" +"It allows to set the discount while making invoice, keep empty if the " +"activities should not be invoiced." + +#. module: itis_hr_attendance_extend +#: field:calendar.event,__last_update:0 +#: field:hr.analytic.timesheet,__last_update:0 +#: field:hr.attendance,__last_update:0 field:itis.holiday,__last_update:0 +#: field:planned.hours,__last_update:0 +#: field:service.description,__last_update:0 +#: field:sign.in.task,__last_update:0 +msgid "Last Modified on" +msgstr "Last Modified on" + +#. module: itis_hr_attendance_extend +#: field:itis.holiday,write_uid:0 field:planned.hours,write_uid:0 +#: field:service.description,write_uid:0 field:sign.in.task,write_uid:0 +msgid "Last Updated by" +msgstr "Last Updated by" + +#. module: itis_hr_attendance_extend +#: field:itis.holiday,write_date:0 field:planned.hours,write_date:0 +#: field:service.description,write_date:0 field:sign.in.task,write_date:0 +msgid "Last Updated on" +msgstr "Last Updated on" + +#. module: itis_hr_attendance_extend +#: model:ir.model,name:itis_hr_attendance_extend.model_hr_holidays +msgid "Leave" +msgstr "Leave" + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/models/hr_holiday.py:86 +#, python-format +msgid "Leave Request" +msgstr "Leave Request" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.view_hr_timesheet_sheet_filter_inherit +msgid "Month" +msgstr "Month" + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,move_id:0 +msgid "Move Line" +msgstr "Move Line" + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/models/hr_payroll.py:57 +#, python-format +msgid "Normal Working Days paid at 100%" +msgstr "Normal Working Days paid at 100%" + +#. module: itis_hr_attendance_extend +#. openerp-web +#: code:addons/itis_hr_attendance_extend/models/hr_timesheet_sheet.py:325 +#: code:addons/itis_hr_attendance_extend/static/src/xml/templates.xml:101 +#: field:hr_timesheet_sheet.sheet,overtime_hours:0 +#, python-format +msgid "Overtime Hours" +msgstr "Overtime Hours" + +#. module: itis_hr_attendance_extend +#: model:ir.model,name:itis_hr_attendance_extend.model_hr_payslip +msgid "Pay Slip" +msgstr "Pay Slip" + +#. module: itis_hr_attendance_extend +#. openerp-web +#: code:addons/itis_hr_attendance_extend/models/hr_timesheet_sheet.py:319 +#: code:addons/itis_hr_attendance_extend/models/hr_timesheet_sheet.py:323 +#: code:addons/itis_hr_attendance_extend/static/src/xml/templates.xml:88 +#: field:hr_timesheet_sheet.sheet,planned_ids:0 +#: field:hr_timesheet_sheet.sheet,total_planned_hours:0 +#, python-format +msgid "Planned Hours" +msgstr "Planned Hours" + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/wizard/sign_in_task.py:55 +#, python-format +msgid "Please define cost unit for this employee." +msgstr "Please define cost unit for this employee." + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,product_id:0 +msgid "Product" +msgstr "Product" + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,unit_amount:0 +msgid "Quantity" +msgstr "Quantity" + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,ref:0 +msgid "Ref." +msgstr "Ref." + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_sheet_form_inherited +msgid "Refresh" +msgstr "Refresh" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_sheet_form_inherited +msgid "Refuse" +msgstr "Refuse" + +#. module: itis_hr_attendance_extend +#. openerp-web +#: code:addons/itis_hr_attendance_extend/static/src/js/hr_extend.js:117 +#, python-format +msgid "Select Service Description" +msgstr "Select Service Description" + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,service_desc_id:0 +#: field:sign.in.task,service_desc_id:0 +msgid "Service Desc" +msgstr "Service Desc" + +#. module: itis_hr_attendance_extend +#: model:ir.ui.menu,name:itis_hr_attendance_extend.menu_emp_service_description +#: view:service.description:itis_hr_attendance_extend.itis_service_description_form +#: view:service.description:itis_hr_attendance_extend.itis_service_description_tree +#: field:service.description,name:0 +msgid "Service Description" +msgstr "Service Description" + +#. module: itis_hr_attendance_extend +#: field:planned.hours,sheet_id:0 +msgid "Sheet" +msgstr "Sheet" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_sheet_form_inherited +msgid "Sign In" +msgstr "Sign In" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_sheet_form_inherited +msgid "Sign Out" +msgstr "Sign Out" + +#. module: itis_hr_attendance_extend +#: help:hr.analytic.timesheet,unit_amount:0 +msgid "Specifies the amount of quantity to count." +msgstr "Specifies the amount of quantity to count." + +#. module: itis_hr_attendance_extend +#: field:hr.holidays,state_value:0 +msgid "State value" +msgstr "State value" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_tree_simplified_inherit_itis +msgid "Summe Stunden" +msgstr "Total Hour" + +#. module: itis_hr_attendance_extend +#: help:hr.analytic.timesheet,amount_currency:0 +msgid "" +"The amount expressed in the related account currency if not equal to the " +"company one." +msgstr "" +"The amount expressed in the related account currency if not equal to the " +"company one." + +#. module: itis_hr_attendance_extend +#: help:hr.analytic.timesheet,currency_id:0 +msgid "The related account currency if not equal to the company one." +msgstr "The related account currency if not equal to the company one." + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/models/hr_holiday.py:34 +#, python-format +msgid "The start date must be anterior to the end date." +msgstr "The start date must be anterior to the end date." + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/models/hr_timesheet_sheet.py:318 +#: field:hr_timesheet_sheet.sheet,time_diff:0 +#, python-format +msgid "Time Diffrence" +msgstr "Time Diffrence" + +#. module: itis_hr_attendance_extend +#: field:hr_timesheet_sheet.sheet,timesheet_ids2:0 +#: model:ir.model,name:itis_hr_attendance_extend.model_hr_timesheet_sheet_sheet +msgid "Timesheet" +msgstr "Timesheet" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_sheet_form_inherited +msgid "Timesheet Activities" +msgstr "Timesheet Activities" + +#. module: itis_hr_attendance_extend +#: model:ir.model,name:itis_hr_attendance_extend.model_hr_analytic_timesheet +msgid "Timesheet Line" +msgstr "Timesheet Line" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_sheet_form_inherited +msgid "Timesheet Summary" +msgstr "Timesheet Summary" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_sheet_form_inherited +msgid "Timesheet abschließen" +msgstr "Timesheet abschließen" + +#. module: itis_hr_attendance_extend +#. openerp-web +#: code:addons/itis_hr_attendance_extend/static/src/xml/templates.xml:31 +#: code:addons/itis_hr_attendance_extend/static/src/xml/templates.xml:65 +#, python-format +msgid "Total" +msgstr "Total" + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/models/hr_timesheet_sheet.py:324 +#: field:hr_timesheet_sheet.sheet,total_timesheet_hours:0 +#, python-format +msgid "Total Hours" +msgstr "Total Hours" + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/models/hr_timesheet_sheet.py:317 +#: field:hr_timesheet_sheet.sheet,total_contract_time:0 +#, python-format +msgid "Total Planned Hours" +msgstr "Total Planned Hours" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_tree_simplified_inherit_itis +msgid "Total time" +msgstr "Total time" + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,product_uom_id:0 +msgid "Unit of Measure" +msgstr "Unit of Measure" + +#. module: itis_hr_attendance_extend +#: field:hr.analytic.timesheet,user_id:0 +msgid "User" +msgstr "User" + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/wizard/sign_in_task.py:55 +#, python-format +msgid "User Error!" +msgstr "User Error!" + +#. module: itis_hr_attendance_extend +#: code:addons/itis_hr_attendance_extend/models/hr_holiday.py:34 +#, python-format +msgid "Warning!" +msgstr "Warning!" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.view_hr_timesheet_sheet_filter_inherit +msgid "Week" +msgstr "Week" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.view_hr_timesheet_sheet_filter_inherit +msgid "Year" +msgstr "Year" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_sheet_form_inherited +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_tree_simplified_inherit_itis +msgid "false" +msgstr "false" + +#. module: itis_hr_attendance_extend +#: view:sign.in.task:itis_hr_attendance_extend.sign_in_task_form_view +msgid "or" +msgstr "or" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_tree_simplified_inherit_itis +msgid "total_contract_time" +msgstr "total_contract_time" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_tree_simplified_inherit_itis +msgid "total_overtime_time" +msgstr "total_overtime_time" + +#. module: itis_hr_attendance_extend +#: view:hr_timesheet_sheet.sheet:itis_hr_attendance_extend.hr_timesheet_sheet_tree_simplified_inherit_itis +msgid "Überstunden" +msgstr "Overtime" diff --git a/itis_hr_attendance_extend/models/__init__.py b/itis_hr_attendance_extend/models/__init__.py new file mode 100644 index 0000000..fa2470e --- /dev/null +++ b/itis_hr_attendance_extend/models/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + +from . import hr_attendance +from . import hr_timesheet_sheet +from . import itis_holiday +from . import hr_payroll +from . import hr_holiday diff --git a/itis_hr_attendance_extend/models/hr_attendance.py b/itis_hr_attendance_extend/models/hr_attendance.py new file mode 100644 index 0000000..7cb7070 --- /dev/null +++ b/itis_hr_attendance_extend/models/hr_attendance.py @@ -0,0 +1,200 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + +from openerp import models, api, fields +from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT +from datetime import datetime +from dateutil.relativedelta import relativedelta +import csv +import os +import logging +logger = logging.getLogger(__name__) + + +class AnalyticAccount(models.Model): + + _inherit = "account.analytic.account" + + account_code = fields.Char("Account Code") + + +class HRAttendance(models.Model): + + _inherit = "hr.attendance" + + timesheet_id = fields.Many2one("hr.analytic.timesheet", "Anlytic Timesheet") + + @api.model + def create(self, values): + t_id = self.env.context.get('timesheet_id', False) + if t_id: + values.update({ + 'timesheet_id': t_id, + }) + res = super(HRAttendance, self).create(values) + if 'action' in values and values['action'] == 'sign_out': + timesheet_obj = self.env['hr.analytic.timesheet'] + sign_in = self.search([('employee_id', '=', values['employee_id']), ('name', '<', res.name), ('action', '=', ('sign_in'))], limit=1, order='name DESC') + if sign_in and sign_in.timesheet_id: + timesheet_obj.browse(sign_in.timesheet_id.id).unit_amount = res.worked_hours + return res + + +class HRAnalyticTimesheet(models.Model): + + _inherit = "hr.analytic.timesheet" + + + service_desc_id = fields.Many2one('service.description',string="Service Desc") + emp_comment = fields.Char("Comment") + dept_account_id = fields.Many2one('account.analytic.account',string="Dept. Analytic Account") + analytic_account_code = fields.Char(related='account_id.account_code',string="Analytic Account") + dept_account_code = fields.Char(related='dept_account_id.account_code',string='Dept. Analytic Account') + + identification_id = fields.Char(string="Personal-Nr", compute="get_employee_data") + + @api.model + def open_analytic_timesheet_tree(self): + """This function is called from IR.ACTION.SERVER, use to open the analytic timesheet tree view wih required filter""" + filter_user_ids = [] + hr_employee_recs = self.env['hr.employee'].search([('user_id','!=',False),('parent_id','!=',False)]) + if hr_employee_recs: # to check the condition, current user employee is manager of the record present in the hr.analytic.timesheet + for hr_employee_rec in hr_employee_recs: + if hr_employee_rec.parent_id.user_id and hr_employee_rec.parent_id.user_id.id == self._uid: + filter_user_ids.append(hr_employee_rec.user_id.id) + + domain = "[('user_id', 'in', " + str(filter_user_ids) + ")]" + tree_view_id = self.env.ref('itis_hr_attendance_extend.view_timehseet_activity_overview_tree_manager').id + value = { + 'domain': domain, + 'name': 'Timesheet', + 'view_type': 'form', + 'view_mode': 'tree', + 'res_model': 'hr.analytic.timesheet', + 'view_id': tree_view_id, + 'type': 'ir.actions.act_window' + } + return value + + @api.one + def get_employee_data(self): + """Computed function to get the required data from the hr.employee""" + hr_employee_rec = self.env['hr.employee'].search([('user_id','=',self.user_id.id)],limit=1) + if hr_employee_rec: + self.identification_id = hr_employee_rec.identification_id + + @api.model + def set_cost_center_existing_rec(self): + """Call from Scheduler, Use to update dept_account_is for old records""" + # print"---In set_cost_center_existing_rec-----" + analytic_timesheet_records = self.search([('dept_account_id','=',False),('sheet_id','!=',False)]) + for analytic_timesheet_brw in analytic_timesheet_records: + employee_id = analytic_timesheet_brw.sheet_id.employee_id + if employee_id.bereich and employee_id.bereich.account_id:dept_account_id=employee_id.bereich.account_id.id + elif employee_id.department_id and employee_id.department_id.account_id:dept_account_id=employee_id.department_id.account_id.id + else:dept_account_id = False + + if dept_account_id: + self._cr.execute('update hr_analytic_timesheet set dept_account_id=%s where id =%s',(dept_account_id,analytic_timesheet_brw.id)) + + @api.model + # @api.multi + def get_monthly_timesheet_overview(self): + """Call from Scheduler, Use to generate monthly timesheet overview report and send it via email""" + + logger.info("---In the get_monthly_timesheet_overview cron--") + timesheet_overview_export = self.env['timesheet.overview.export'] + today_date = datetime.today().date() + last_month_date = today_date - relativedelta(months= 1) + # print"today_date----last_month_date--",today_date,last_month_date + + analytic_timesheet_records = self.search([('date','<',today_date),('date','>=',last_month_date)],order='account_id') + if analytic_timesheet_records: + logger.info("---Records to get %s" %analytic_timesheet_records) + # call the subfunction to generate the .csv report + context = timesheet_overview_export.export_csv_subfunction(analytic_timesheet_records,False) + if context: + # create attachement record of the related csv file + ir_attachment = self.env['ir.attachment'] + file_name ='timesheet_overview_'+str(last_month_date)+'_'+str(today_date)+'.csv' + attachment_data = { + 'name': file_name, + 'datas_fname':file_name, + 'datas':context.get('default_name'), + 'res_model': 'email.template', + } + ir_attachment_brw = ir_attachment.create(attachment_data) + + #template = self.env.ref('itis_hr_attendance_extend.email_template_monthly_timesheet_overview', False) + template = False #Added by IT IS to disable email sending. + if ir_attachment_brw and template: + logger.info("---Template found and send a mail") + template.write({'attachment_ids': [(6, 0, [ir_attachment_brw.id])]}) # link a attachment to email template + template.send_mail(analytic_timesheet_records[0].id)# send a mail with attachment + template.write({'attachment_ids': [(3, ir_attachment_brw.id)]})# to unlink the attachment from template after sending a email + + + @api.model + def create(self, values): + if values.get('sheet_id'): + dept_account_id = False + timesheet_brw = self.env['hr_timesheet_sheet.sheet'].browse(values['sheet_id']) + if timesheet_brw and timesheet_brw.employee_id: + employee_id = timesheet_brw.employee_id + if employee_id.bereich and employee_id.bereich.account_id:dept_account_id=employee_id.bereich.account_id.id + elif employee_id.department_id and employee_id.department_id.account_id:dept_account_id=employee_id.department_id.account_id.id + + if dept_account_id: + values.update({'dept_account_id':dept_account_id}) + + if not values.get('name'): + values.update({'name':'/'}) + return super(HRAnalyticTimesheet, self).create(values) + + @api.one + def update_hours(self, last_sign_in): + + return True + lst_dt = datetime.strptime(last_sign_in, DEFAULT_SERVER_DATETIME_FORMAT) + nw_dt = datetime.today() + scn = (nw_dt - lst_dt).total_seconds() + for tm in self: + unit_amount = scn/360 + tm.write({'unit_amount': unit_amount}) + return True + +class hr_employee(models.Model): + + _inherit = 'hr.employee' + + @api.model + def create(self, values): + res = super(hr_employee, self).create(values) + # to create holiday for the related employee + today_date = datetime.today() + itis_holiday = self.env['itis.holiday'].search([('date','>',today_date)]) + if itis_holiday: + hr_holidays_status_brw = self.env['hr.holidays.status'].search([('is_holiday','=',True)],limit=1) + if hr_holidays_status_brw: + for hr_employee_brw in res: + for itis_holiday_brw in itis_holiday: + holiday_created = self.env['hr.holidays'].create({'employee_id':hr_employee_brw.id, 'date_from':itis_holiday_brw.date,'date_to':itis_holiday_brw.date,'holiday_name':itis_holiday_brw.name,'holiday_status_id':hr_holidays_status_brw.id}) + self._cr.execute("update hr_holidays set state = 'validate' where id = %s",(holiday_created.id,)) + return res diff --git a/itis_hr_attendance_extend/models/hr_holiday.py b/itis_hr_attendance_extend/models/hr_holiday.py new file mode 100644 index 0000000..576d5e9 --- /dev/null +++ b/itis_hr_attendance_extend/models/hr_holiday.py @@ -0,0 +1,177 @@ +from openerp import models, api, fields, _ +from openerp.osv import osv +from datetime import datetime + +class HRHoliday(models.Model): + _inherit = "hr.holidays" + + holiday_name = fields.Char(string ='Holiday Name') + state_value = fields.Char(compute='_compute_state_value') + + @api.one + def _compute_state_value(self): + self.state_value = dict(self.fields_get(allfields=['state'])['state']['selection'])[self.state] + return + + def create(self, cr, uid, values, context=None): + """ + To create holiday list entry calender of leave request + + """ + # following condition is use to give a warning and to calculate no of day leave + if values.get('date_from') and values.get('date_to'): + date_from,date_to= values['date_from'],values['date_to'] + # print"Date from----Date to------",len(date_from),len(date_to) + # print"Date from----Date to------",date_from,date_to + + if len(date_from) == 10: + date_from = date_from+' 09:00:00' + values.update({'date_from':date_from}) + if len(date_to) == 10: + date_to = date_to+' 18:00:00' + values.update({'date_to':date_to}) + elif len(date_to) == 19: + date_to = date_to[0:11] + '18:00:00' + values.update({'date_to':date_to}) + # print"Values-----",values + if date_from > date_to: + raise osv.except_osv(_('Warning!'),_('The start date must be anterior to the end date.')) + + # start_date = date_from + # # stop_date = date_to + # office_leave_time = self.pool.get('leave.time') + # office_leave_time_record = office_leave_time.search(cr,uid,[('active','=',True)],limit=1) + # if office_leave_time_record: + # office_leave_time_brw = office_leave_time.browse(cr,uid,office_leave_time_record[0]) + # if values.get('leave_selection') == 'full_day': + # start_time = str(office_leave_time_brw.fullday_start_time)+':00:00' + # start_date = datetime.strptime(date_from, "%Y-%m-%d %H:%M:%S").strftime('%Y-%m-%d ')+start_time + # # end_time = str(office_leave_time_brw.fullday_end_time)+':00:00' + # #stop_date = datetime.strptime(date_to, "%Y-%m-%d %H:%M:%S").strftime('%Y-%m-%d ')+end_time + # elif values.get('leave_selection') == 'half_day': + # if values.get('half_day_type') == 'morning': + # start_time = str(office_leave_time_brw.halfday_morning_start_time)+':00:00' + # start_date = datetime.strptime(date_from, "%Y-%m-%d %H:%M:%S").strftime('%Y-%m-%d ')+start_time + # # end_time = str(office_leave_time_brw.halfday_morning_end_time)+':00:00' + # # stop_date = datetime.strptime(date_to, "%Y-%m-%d %H:%M:%S").strftime('%Y-%m-%d ')+end_time + # + # else: + # start_time = str(office_leave_time_brw.halfday_afternoon_start_time)+':00:00' + # start_date = datetime.strptime(date_from, "%Y-%m-%d %H:%M:%S").strftime('%Y-%m-%d ')+start_time + # # end_time = str(office_leave_time_brw.halfday_afternoon_end_time)+':00:00' + # # stop_date = datetime.strptime(date_to, "%Y-%m-%d %H:%M:%S").strftime('%Y-%m-%d ')+end_time + # + # values.update({'date_from':start_date}) + # print"START date----end date-----",start_date,stop_date + + # if values.get('leave_selection') and values.get('leave_selection') == 'half_day': + # if date_from == date_to: + # values.update({'number_of_days_temp':0.5}) + # else: + # print"DATE---From-----",date_from + # print"DATE---T-----",date_to + # date_from = datetime.datetime.strptime(date_from,'%Y-%m-%d %H:%M:%S').strftime('%Y-%m-%d')+' 00:00:00' + # date_to = datetime.datetime.strptime(date_to,'%Y-%m-%d %H:%M:%S').strftime('%Y-%m-%d')+' 00:00:00' + # diff_day = self._get_number_of_days(date_from, date_to) + # diff_day = round(math.floor(diff_day)) + # values.update({'number_of_days_temp':diff_day}) + + res = super(HRHoliday, self).create(cr, uid, values, context) + + for hr_holidays_brw in self.browse(cr,uid,res): + if hr_holidays_brw.state == 'confirm' and hr_holidays_brw.holiday_type == 'employee' and hr_holidays_brw.type == 'remove': + notes = '' + if notes: + notes = hr_holidays_brw.notes + meeting_obj = self.pool.get('calendar.event') + if hr_holidays_brw.holiday_name: + name = hr_holidays_brw.holiday_name + else: + name = (hr_holidays_brw.name or _('Leave Request')) +' -To Approve' + + start_date = hr_holidays_brw.date_from + stop_date = hr_holidays_brw.date_to + meeting_vals = { + 'name': name, + 'categ_ids': hr_holidays_brw.holiday_status_id.categ_id and [(6,0,[hr_holidays_brw.holiday_status_id.categ_id.id])] or [], + 'duration': hr_holidays_brw.number_of_days_temp * 8, + 'description': notes, + 'user_id': hr_holidays_brw.user_id.id, + 'start':start_date, + 'stop': stop_date, + 'allday': False, + 'state': 'open', # to block that meeting date in the calendar + 'class': 'confidential', + # 'leave_status':'To Be Approve' + } + #Add the partner_id (if exist) as an attendee + if hr_holidays_brw.user_id and hr_holidays_brw.user_id.partner_id: + meeting_vals['partner_ids'] = [(4,hr_holidays_brw.user_id.partner_id.id)] + + ctx_no_email = dict(context or {}, no_email=True) + meeting_id = meeting_obj.create(cr, uid, meeting_vals, context=ctx_no_email) + self.write(cr, uid, hr_holidays_brw.id, {'meeting_id': meeting_id}) + return res + + # def holidays_validate(self, cr, uid, ids, context=None): + # obj_emp = self.pool.get('hr.employee') + # ids2 = obj_emp.search(cr, uid, [('user_id', '=', uid)]) + # manager = ids2 and ids2[0] or False + # self.write(cr, uid, ids, {'state':'validate'}) + # data_holiday = self.browse(cr, uid, ids) + # for record in data_holiday: + # if record.double_validation: + # self.write(cr, uid, [record.id], {'manager_id2': manager}) + # else: + # self.write(cr, uid, [record.id], {'manager_id': manager}) + # if record.holiday_type == 'employee' and record.type == 'remove': + # meeting_obj = self.pool.get('calendar.event') + # + # # to check for the existing calender events for this type + # if record.meeting_id: + # self._create_resource_leave(cr, uid, [record], context=context) + # meeting_obj.write(cr, uid, record.meeting_id, {'name': record.name or _('Leave Request'),}) + # else: + # meeting_vals = { + # 'name': record.name or _('Leave Request'), + # 'categ_ids': record.holiday_status_id.categ_id and [(6,0,[record.holiday_status_id.categ_id.id])] or [], + # 'duration': record.number_of_days_temp * 8, + # 'description': record.notes, + # 'user_id': record.user_id.id, + # 'start': record.date_from, + # 'stop': record.date_to, + # 'allday': False, + # 'state': 'open', # to block that meeting date in the calendar + # 'class': 'confidential' + # } + # #Add the partner_id (if exist) as an attendee + # if record.user_id and record.user_id.partner_id: + # meeting_vals['partner_ids'] = [(4,record.user_id.partner_id.id)] + # + # ctx_no_email = dict(context or {}, no_email=True) + # meeting_id = meeting_obj.create(cr, uid, meeting_vals, context=ctx_no_email) + # self._create_resource_leave(cr, uid, [record], context=context) + # self.write(cr, uid, ids, {'meeting_id': meeting_id}) + # elif record.holiday_type == 'category': + # emp_ids = obj_emp.search(cr, uid, [('category_ids', 'child_of', [record.category_id.id])]) + # leave_ids = [] + # batch_context = dict(context, mail_notify_force_send=False) + # for emp in obj_emp.browse(cr, uid, emp_ids, context=context): + # vals = { + # 'name': record.name, + # 'type': record.type, + # 'holiday_type': 'employee', + # 'holiday_status_id': record.holiday_status_id.id, + # 'date_from': record.date_from, + # 'date_to': record.date_to, + # 'notes': record.notes, + # 'number_of_days_temp': record.number_of_days_temp, + # 'parent_id': record.id, + # 'employee_id': emp.id + # } + # leave_ids.append(self.create(cr, uid, vals, context=batch_context)) + # for leave_id in leave_ids: + # # TODO is it necessary to interleave the calls? + # for sig in ('confirm', 'validate', 'second_validate'): + # self.signal_workflow(cr, uid, [leave_id], sig) + # return True \ No newline at end of file diff --git a/itis_hr_attendance_extend/models/hr_payroll.py b/itis_hr_attendance_extend/models/hr_payroll.py new file mode 100644 index 0000000..bce254b --- /dev/null +++ b/itis_hr_attendance_extend/models/hr_payroll.py @@ -0,0 +1,104 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + +from openerp import models, api, fields, _ +from openerp.tools import DEFAULT_SERVER_DATE_FORMAT +from datetime import datetime, timedelta + + +class HRPayslip(models.Model): + + _inherit = 'hr.payslip' + + def get_worked_day_lines(self, cr, uid, contract_ids, date_from, date_to, context=None): + """ + @param contract_ids: list of contract id + @return: returns a list of dict containing the input that should be applied for the given contract between date_from and date_to + """ + + def was_on_leave(employee_id, datetime_day, context=None): + res = False + day = datetime_day.strftime("%Y-%m-%d") + holiday_ids = self.pool.get('hr.holidays').search(cr, uid, [('state','=','validate'),('employee_id','=',employee_id),('type','=','remove'),('date_from','<=',day),('date_to','>=',day)]) + if holiday_ids: + res = self.pool.get('hr.holidays').browse(cr, uid, holiday_ids, context=context)[0].holiday_status_id.name + return res + + res = [] + for contract in self.pool.get('hr.contract').browse(cr, uid, contract_ids, context=context): + if not contract.working_hours: + #fill only if the contract as a working schedule linked + continue + attendances = { + 'name': _("Normal Working Days paid at 100%"), + 'sequence': 1, + 'code': 'WORK100', + 'number_of_days': 0.0, + 'number_of_hours': 0.0, + 'contract_id': contract.id, + } + leaves = {} + day_from = datetime.strptime(date_from,"%Y-%m-%d") + day_to = datetime.strptime(date_to,"%Y-%m-%d") + contract_day_start = datetime.strptime(contract.date_start,"%Y-%m-%d") + + if day_from < contract_day_start: + day_from = contract_day_start + if contract.date_end: + contract_day_end = datetime.strptime(contract.date_end,"%Y-%m-%d") + if day_to > contract_day_end: + day_to = contract_day_end + nb_of_days = (day_to - day_from).days + 1 + for day in range(0, nb_of_days): + working_hours_on_day = self.pool.get('resource.calendar').working_hours_on_day(cr, uid, contract.working_hours, day_from + timedelta(days=day), context) + is_holiday = self.is_holiday(cr,uid,day_from + timedelta(days=day), context) + if is_holiday: + continue + if working_hours_on_day: + #the employee had to work + leave_type = was_on_leave(contract.employee_id.id, day_from + timedelta(days=day), context=context) + if leave_type: + #if he was on leave, fill the leaves dict + if leave_type in leaves: + leaves[leave_type]['number_of_days'] += 1.0 + leaves[leave_type]['number_of_hours'] += working_hours_on_day + else: + leaves[leave_type] = { + 'name': leave_type, + 'sequence': 5, + 'code': leave_type, + 'number_of_days': 1.0, + 'number_of_hours': working_hours_on_day, + 'contract_id': contract.id, + } + else: + #add the input vals to tmp (increment if existing) + attendances['number_of_days'] += 1.0 + attendances['number_of_hours'] += working_hours_on_day + leaves = [value for key,value in leaves.items()] + res += [attendances] + leaves + return res + + def is_holiday(self,cr,uid,day,context): + search_id = self.pool.get('itis.holiday').search(cr,uid,[('date','=',day)]) + if search_id: + return True + else: + return False diff --git a/itis_hr_attendance_extend/models/hr_timesheet_sheet.py b/itis_hr_attendance_extend/models/hr_timesheet_sheet.py new file mode 100644 index 0000000..28aae22 --- /dev/null +++ b/itis_hr_attendance_extend/models/hr_timesheet_sheet.py @@ -0,0 +1,466 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + +from openerp import models, api, fields, _ +from openerp.osv import osv +from openerp.tools import DEFAULT_SERVER_DATE_FORMAT +from datetime import datetime, timedelta +from dateutil.relativedelta import relativedelta +from openerp import SUPERUSER_ID +from openerp.exceptions import Warning +from openerp.http import request +import logging +logger = logging.getLogger(__name__) + + +class HRTimesheetSheet(models.Model): + + _inherit = "hr_timesheet_sheet.sheet" + + @api.model + def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True): + """To display the functional field value in the group by""" + res = super(HRTimesheetSheet, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy) + if 'total_timesheet' in fields: + for line in res: + if '__domain' in line: + lines = self.search(line['__domain']) + inv_value = 0.0 + for line2 in lines: + inv_value += line2.total_timesheet + line['total_timesheet'] = inv_value + if 'total_contract_time' in fields: + for line in res: + if '__domain' in line: + lines = self.search(line['__domain']) + inv_value = 0.0 + for line2 in lines: + inv_value += line2.total_contract_time + line['total_contract_time'] = inv_value + if 'time_diff' in fields: + for line in res: + if '__domain' in line: + lines = self.search(line['__domain']) + inv_value = 0.0 + for line2 in lines: + inv_value += line2.time_diff + line['time_diff'] = inv_value + return res + + @api.multi + def write(self, vals): + res = super(HRTimesheetSheet, self).write(vals) + + if 'timesheet_ids2' in vals: + for timesheet_value in vals['timesheet_ids2']: + if timesheet_value[2]: + date = timesheet_value[2].get('date') + if not date or (date>=self.date_from and date<=self.date_to): + pass + else: + raise Warning(_("Date should be between timesheet date.")) + + return res + + def name_get(self, cr, uid, ids, context=None): + if not ids: + return [] + if isinstance(ids, (long, int)): + ids = [ids] + return [(r['id'], datetime.strptime(r['date_from'], '%Y-%m-%d').strftime('%d-%m-%Y')) \ + for r in self.read(cr, uid, ids, ['date_from'], + context=context, load='_classic_write')] + + @api.multi + def get_analytic_timesheet_data(self): + """ + This function is call from the Javascript + """ + data_dict = {} + data_list_new =[] + if self and self.timesheet_ids: + for timesheet_record in self.timesheet_ids: + data_list =[] + data_list_new.append(timesheet_record) + data_list.append(timesheet_record.service_desc_id and timesheet_record.service_desc_id.name or False) + data_list.append(timesheet_record.emp_comment) + data_dict[timesheet_record.account_id.id] =data_list + return data_dict + + + @api.model + def create_daily_timesheet(self): + """ + Scheduler, use to create daily timesheet for the all employee + """ + # print"In daily timesheet create scheduler---" + today_date = datetime.now() + for employee_brw in self.env['hr.employee'].search([('user_id','!=',False)]): + emp_contract_record =self.env['hr.contract'].search([("employee_id", '=', employee_brw.id),("date_start", '<=', today_date),'|',("date_end", '>=', today_date),("date_end", '=', False)]) + if emp_contract_record: + timesheets = self.search([("employee_id", '=', employee_brw.id),("date_from", '<=', today_date),("date_to", '>=', today_date)]) + if not timesheets: + values = {'employee_id':employee_brw.id, + 'date_from':today_date, + 'date_to':today_date + } + try: + self.create(values) + except: + #Todo Error handling + pass + + @api.model + def create_missingdate_timesheet(self): + """ + Scheduler, use to create missing date timesheet for the all employee + DATE NEED TO PROVIDED HERE. + """ + print"In create_missingdate_timesheet---" + # today_date = datetime.now() + provided_dates = [datetime.strptime("2017-09-09 00:00:00",'%Y-%m-%d %H:%M:%S'),datetime.strptime("2017-09-10 00:00:00",'%Y-%m-%d %H:%M:%S')] + for date in provided_dates: + for employee_brw in self.env['hr.employee'].search([('user_id','!=',False)]): + emp_contract_record =self.env['hr.contract'].search([("employee_id", '=', employee_brw.id),("date_start", '<=', date),'|',("date_end", '>=', date),("date_end", '=', False)]) + if emp_contract_record: + timesheets = self.search([("employee_id", '=', employee_brw.id),("date_from", '<=', date),("date_to", '>=', date)]) + if not timesheets: + values = {'employee_id':employee_brw.id, + 'date_from':date, + 'date_to':date + } + try: + print"timesheet create----",employee_brw + self.create(values) + except: + #Todo Error handling + pass + + def check_employee_attendance_state(self, cr, uid, sheet_id, context=None): + ids_signin = self.pool.get('hr.attendance').search(cr,uid,[('sheet_id', '=', sheet_id),('action','=','sign_in')]) + ids_signout = self.pool.get('hr.attendance').search(cr,uid,[('sheet_id', '=', sheet_id),('action','=','sign_out')]) + + if len(ids_signin) != len(ids_signout): + logger.info("--Sign in, Sign out not equal timesheet ids--%s" %sheet_id) + # raise osv.except_osv(('Warning!'),_('The timesheet cannot be validated as it does not contain an equal number of sign ins and sign outs.')) + return True + + @api.model + def automatic_sign_out(self): + """ + Scheduler, Use to sign out the employee which are not sign out + """ + logger.info("--In automatic_sign_out scheduler--") + today_date = datetime.now().strftime('%Y-%m-%d %H:%M:%S') + cron_record = self.env['ir.cron'].search([('function','=','automatic_sign_out')],limit=1) + if cron_record: + cron_date = datetime.strptime(cron_record.nextcall,'%Y-%m-%d %H:%M:%S').date() + else: + cron_date = datetime.now().date() + logger.info("--Date of the scheduler--%s"%(cron_date)) + hr_attendance = self.env['hr.attendance'] + for employee_brw in self.env['hr.employee'].search([('user_id','!=',False)]): + # timesheets = self.search([("employee_id", '=', employee_brw.id),("date_from", '<=', today_date),("date_to", '>=', today_date)],limit=1) + timesheets = self.search([("employee_id", '=', employee_brw.id),("date_from", '=', cron_date)],limit=1) + today_hr_attendance_ids = [] + if timesheets: + today_hr_attendance_ids = [x.id for x in timesheets.attendances_ids] + # today_date = datetime.now().date().strftime('%Y-%m-%d') + # hr_attendance_records = hr_attendance.search([("employee_id", '=', employee_brw.id),('sheet_id','=',timesheets[0].id)]) + # for hr_attendance_record in hr_attendance_records: + # date_new = datetime.strptime(hr_attendance_record.name,'%Y-%m-%d %H:%M:%S').strftime('%Y-%m-%d') + # if date_new == today_date: + # today_hr_attendance_ids.append(hr_attendance_record.id) + if today_hr_attendance_ids: + today_hr_attendance_ids.sort(reverse=True) + if hr_attendance.browse(today_hr_attendance_ids[0]).action=='sign_in': + logger.info("--Automatically sign out employee %s" %employee_brw) + hr_attendance.create({'employee_id':employee_brw.id,'sheet_id':timesheets[0].id,'action':'sign_out','name':today_date}) + self.send_sign_out_email(employee_brw) + + def send_sign_out_email(self,employee_brw): + """ + This function is use to send a email to the user for automatic sign out + """ + + if employee_brw and employee_brw.user_id: + email_to = False + if employee_brw.work_email: + email_to = employee_brw.work_email + elif employee_brw.user_id.partner_id and employee_brw.user_id.partner_id.email: + email_to = employee_brw.user_id.partner_id.email + + if email_to: + ir_mail_env = self.env['ir.mail_server'] + active_outgoing_mail_server = ir_mail_env.search([('id','!=',False)], limit=1) + email_vals = { } + + body_html= """ +

+ Hallo """+str(employee_brw.name) +""", +

+

+ Sie wurden automatisch von TicTac abgemeldet. Bitte passen Sie ihr Timesheet an. +

+

+ Vielen Dank ihr HR Team. +

+ """ + + email_vals['email_from'] = employee_brw.company_id and employee_brw.company_id.email or 'info@yourcompany.example.com' + email_vals['email_to'] = email_to + email_vals['subject'] = 'Automatic Sign Out' + email_vals['body_html'] = body_html + # if active_outgoing_mail_server: + # email_vals['mail_server_id'] = active_outgoing_mail_server.id + mail = self.env['mail.mail'].create(email_vals) + mail.send() + logger.info("--Sign out email send.") + + + @api.multi + def action_set_to_draft(self): + res = super(HRTimesheetSheet, self).action_set_to_draft() + #newovertime + overtime_count = self.employee_id.employee_overtime_id.emp_overtime_count - self.time_diff + self.employee_id.employee_overtime_id.write({'emp_overtime_count': overtime_count}) + # overtime_count = self.employee_id.overtime_count - self.time_diff + # self.employee_id.write({'overtime_count': overtime_count}) + return res + + @api.one + def action_cancel(self): + #newovertime + overtime_count = self.employee_id.employee_overtime_id.emp_overtime_count - self.time_diff + self.employee_id.employee_overtime_id.write({'emp_overtime_count': overtime_count}) + # overtime_count = self.employee_id.overtime_count - self.time_diff + # self.employee_id.write({'overtime_count': overtime_count}) + self.write({'state': 'draft'}) + return True + + @api.multi + def button_confirm(self): + + res = super(HRTimesheetSheet, self).button_confirm() + #newovertime + new_overtime = self.employee_id.employee_overtime_id.emp_overtime_count + self.time_diff + self.employee_id.employee_overtime_id.write({'emp_overtime_count': new_overtime}) + # new_overtime = self.employee_id.overtime_count + self.time_diff + # self.pool.get('hr.employee').write(self._cr,SUPERUSER_ID,self.employee_id.id,{'overtime_count': new_overtime}) + #self.employee_id.write({'overtime_count': new_overtime}) + self.write({'state': 'confirm'}) + return res + + @api.model + def create(self, values): + #cr, uid, context = self.env.cr, self.env.uid, self.env.context + res_users_obj = self.env["res.users"] + ir_model_obj = self.env["ir.model.data"] + res_user_data = res_users_obj.browse([self.env.uid]) + xml_list = [] + group_ids = [] + for group in res_user_data.groups_id: + group_ids.append(group.id) + model_data = ir_model_obj.search([['model','=','res.groups'],['res_id','in',group_ids]]) + #model_data = ir_model_obj.browse(cr,uid,model_ids,context) + for value in model_data: + xml_list.append(value.name) + if "group_hr_manager" in xml_list or "group_hr_payroll_manager" in xml_list or "group_hr_user" in xml_list or self.env.uid == 1: + if 'date_from' in values and 'date_to' in values and values['date_from'] != values['date_to']: + raise Warning(_("Start date and end date have to be the same day.")) + if 'date_from' in values and 'date_to' in values and 'employee_id' in values and self.search([('employee_id','=',values['employee_id']),('date_from','<=',values['date_from']),('date_to','>=',values['date_from'])]): + raise Warning(_("You can only create one timesheet each day.")) + res = super(HRTimesheetSheet, self).create(values) + res.calc_planned_hours() + res.calc_leave_hours() + return res + else: + raise Warning(_("You do not have pemission to create timesheets!")) + + @api.one + def cal_tot_cont_time(self): + total_duration = 0.0 + for pln_hrs in self.planned_ids: + total_duration += pln_hrs.duration + self.total_contract_time = total_duration + self.time_diff = self.total_timesheet - self.total_contract_time + return True + + @api.one + def cal_total_hours(self): + total_duration = 0.0 + for pln_hrs in self.planned_ids: + total_duration += pln_hrs.duration + self.total_timesheet_hours = self.total_timesheet + self.total_planned_hours = total_duration + self.overtime_hours = self.total_timesheet_hours - self.total_planned_hours + + + @api.multi + def fetch_holiday_list(self): + res = [] + for hld in self.env["itis.holiday"].search([]): + res.append(hld.date) + return res + + @api.model + def close_timesheet(self): + for timesheet in self.search([('date_to','<',datetime.today().date().replace(day=1)),('state','=','draft')]): + timesheet.button_confirm() + return + + @api.one + def calc_planned_hours(self): + res = {} + hld_list = self.fetch_holiday_list() + date_from = datetime.strptime(self.date_from, DEFAULT_SERVER_DATE_FORMAT) + date_to = datetime.strptime(self.date_to, DEFAULT_SERVER_DATE_FORMAT) + temp_date = date_from + while temp_date <= date_to: + weekday = temp_date.weekday() + day_hours = 0.0 + if datetime.strftime(temp_date, DEFAULT_SERVER_DATE_FORMAT) in hld_list: + res.update({temp_date:day_hours}) + temp_date += timedelta(days=1) + continue + # contract_ids = self.pool.get('hr.contract').search(self._cr, SUPERUSER_ID, [('employee_id','=',self.id)]) + # contract_ids = self.pool.get('hr.contract').browse(self._cr, SUPERUSER_ID,contract_ids) + # for contract in contract_ids: + for contract in self.employee_id.contract_ids: + cont_start_date = datetime.strptime(contract.date_start, DEFAULT_SERVER_DATE_FORMAT) + cont_end_date = False + if not contract.date_end: + if cont_start_date <= temp_date: + day_hours += self.get_hours(weekday, contract.working_hours.attendance_ids) + else: + cont_end_date = datetime.strptime(contract.date_end, DEFAULT_SERVER_DATE_FORMAT) + if cont_start_date <= temp_date and cont_end_date >= temp_date: + day_hours += self.get_hours(weekday, contract.working_hours.attendance_ids) + res.update({temp_date:day_hours}) + temp_date += timedelta(days=1) + plan_hr_obj = self.env['planned.hours'] + dts = res.keys() + for plan_hrs in self.planned_ids: + sheet_date = datetime.strptime(plan_hrs.sheet_date, DEFAULT_SERVER_DATE_FORMAT) + if sheet_date not in dts: + sheet_date.unlink() + + for dt, hrs in res.iteritems(): + dt_exist = False + for plan_hrs in self.planned_ids: + sheet_date = datetime.strptime(plan_hrs.sheet_date, DEFAULT_SERVER_DATE_FORMAT) + if sheet_date == dt: + dt_exist = True + if plan_hrs.duration != hrs: + plan_hrs.write({'duration': hrs}) + if not dt_exist: + vals = { + 'sheet_date': datetime.strftime(dt, DEFAULT_SERVER_DATE_FORMAT), + 'duration': hrs, + 'sheet_id': self.id, + } + plan_hr_obj.create(vals) + + def get_hours(self, weekday, atten_ids): + res = 0.0 + for atten in atten_ids: + if int(atten.dayofweek) == weekday: + res += atten.hour_to - atten.hour_from + return res + + @api.depends("timesheet_ids.unit_amount") + @api.one + def calc_actual_ot(self): + if self.state not in ['new', 'draft']: + # self.actual_ot = self.employee_id.overtime_count + # newovertime + self.actual_ot = self.employee_id.employee_overtime_id.emp_overtime_count + return True + act_wk_dict = {} + act_working = 0.0 + for timesheet in self.timesheet_ids: + tm = act_wk_dict.get(timesheet.date, 0.0) + timesheet.unit_amount + act_wk_dict.update({timesheet.date: tm}) + act_working += timesheet.unit_amount + wk_dts = act_wk_dict.keys() + pln_wk_dict = {} + pl_working = 0.0 + for pln_hr in self.planned_ids: + pln_wk_dict.update({pln_hr.sheet_date: pln_hr.duration}) + is_cur_sheet = False + cur_date = datetime.today() + date_from = datetime.strptime(self.date_from, DEFAULT_SERVER_DATE_FORMAT) + date_to = datetime.strptime(self.date_to, DEFAULT_SERVER_DATE_FORMAT) + if date_from <= cur_date and date_to >= cur_date: + is_cur_sheet = True + tot_time = 0.0 + while date_from <= date_to: + if is_cur_sheet and date_from > cur_date: + date_from += timedelta(days=1) + continue + dt_str = datetime.strftime(date_from, DEFAULT_SERVER_DATE_FORMAT) + tot_time += act_wk_dict.get(dt_str, 0.0) - pln_wk_dict.get(dt_str, 0.0) + date_from += timedelta(days=1) + # print"emp overtime----",self.employee_id.overtime_count + # print"tot_time--------",tot_time + + # add a logic to add all the overtime hr for the current month + date_from = datetime.strptime(self.date_from, DEFAULT_SERVER_DATE_FORMAT) + first_date = (date_from + relativedelta(months=-1)).replace(day=1) + monthly_overtime = 0.0 + while first_date <= date_from: + timesheet_record = self.search([('date_from','=',first_date),('employee_id','=',self.employee_id.id),('state','in',['new','draft'])],limit=1) + if timesheet_record: + # print"timesheet_record.time_diff----",timesheet_record.time_diff + monthly_overtime += timesheet_record.time_diff + first_date += timedelta(days=1) + # print"monthly_overtime-----",monthly_overtime + # self.actual_ot = self.employee_id.overtime_count + monthly_overtime + # newovertime + self.actual_ot = self.employee_id.employee_overtime_id.emp_overtime_count + monthly_overtime + return True + + total_contract_time = fields.Float(_("Total Planned Hours"), compute="cal_tot_cont_time", multi="cal_tot_cont_time") + time_diff = fields.Float(_("Time Diffrence"), compute="cal_tot_cont_time", multi="cal_tot_cont_time") + planned_ids = fields.One2many("planned.hours", "sheet_id", _("Planned Hours")) + actual_ot = fields.Float(_("Actual Overttime Count"), compute="calc_actual_ot") + timesheet_ids2 = fields.One2many("hr.analytic.timesheet","sheet_id",string="Timesheet") + + total_planned_hours = fields.Float(_("Planned Hours"), compute="cal_total_hours", multi="total_hours") + total_timesheet_hours =fields.Float(_("Total Hours"), compute="cal_total_hours", multi="total_hours") + overtime_hours =fields.Float(_("Overtime Hours"), compute="cal_total_hours", multi="total_hours") + + + +class PlannedHours(models.Model): + + _name = 'planned.hours' + + sheet_date = fields.Date("Date") + duration = fields.Float("Hours") + sheet_id = fields.Many2one("hr_timesheet_sheet.sheet", 'Sheet') + +class ServiceDescription(models.Model): + + _name = 'service.description' + + name = fields.Char("Service Description") + # sheet_id = fields.Many2one("hr_timesheet_sheet.sheet", 'Sheet') + diff --git a/itis_hr_attendance_extend/models/itis_holiday.py b/itis_hr_attendance_extend/models/itis_holiday.py new file mode 100644 index 0000000..23478f4 --- /dev/null +++ b/itis_hr_attendance_extend/models/itis_holiday.py @@ -0,0 +1,115 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + +from openerp import models, api, fields, _ +from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT +from datetime import datetime + + +class ITISHoliday(models.Model): + + _name = "itis.holiday" + + name = fields.Char("Holiday Name") + date = fields.Date("Date") + + @api.model + def get_holiday_date(self): + """ + function call from the js, use to return the holiday dates + """ + holiday_dates = [] + for holiday_brw in self.search([]): + holiday_dates.append(holiday_brw.date) + + return holiday_dates + + @api.model + def create(self, values): + """ + To create holiday list entry calender of leave request + + """ + res = super(ITISHoliday, self).create(values) + if values: + holiday_date = values.get('date') + holiday_name = values.get('name') + + if holiday_date and holiday_name: + hr_holidays_status_brw = self.env['hr.holidays.status'].search([('is_holiday','=',True)],limit=1) + hr_holidays_env = self.env['hr.holidays'] + if hr_holidays_status_brw: + hr_emp_records = self.env['hr.employee'].search([('user_id','!=',None)]) + for hr_emp_brw in hr_emp_records: + try: + hr_holiday_brw = hr_holidays_env.with_context(mail_notify_force_send=False,holiday_create=True,mail_create_nosubscribe=False,mail_create_nolog=False).\ + create({'employee_id':hr_emp_brw.id, 'date_from':holiday_date,'date_to':holiday_date, + 'holiday_name':holiday_name,'holiday_status_id':hr_holidays_status_brw.id, + 'holiday_type':'employee','leave_selection':'full_day','leave_selection_date_to':'full_day',}) + # msg = _("Holiday %s created.") %(holiday_name) + # hr_holiday_brw.message_post(body=msg) + self._cr.execute("update hr_holidays set state = 'validate' where id = %s",(hr_holiday_brw.id,)) + except: + #Todo Error handling + pass + return res + + @api.multi + def unlink(self): + """ + To delete the related holiday from the leave request + """ + for itis_holiday_brw in self: + hr_holidays_env = self.env['hr.holidays'] + hr_holidays_records = hr_holidays_env.search([('date_from','=',itis_holiday_brw.date),('holiday_name','=',itis_holiday_brw.name)]) + for hr_holiday_brw in hr_holidays_records: + self._cr.execute("delete from hr_holidays where id = %s",(hr_holiday_brw.id,)) + + return super(ITISHoliday, self).unlink() + + @api.multi + def write(self, vals): + """ + To write on the leave request holiday base upon the conditions + """ + hr_holidays_status_brw = self.env['hr.holidays.status'].search([('is_holiday','=',True)],limit=1) + hr_holidays_env = self.env['hr.holidays'] + if vals.get('date'): + + hr_holidays_records = hr_holidays_env.search([('date_from','=',self.date),('holiday_name','=',self.name)]) + for hr_holiday_brw in hr_holidays_records: + self._cr.execute("delete from hr_holidays where id = %s",(hr_holiday_brw.id,)) + if vals.get('name'): + name = vals.get('name') + else: + name = self.name + if hr_holidays_status_brw: + hr_emp_records = self.env['hr.employee'].search([('user_id','!=',None)]) + for hr_emp_brw in hr_emp_records: + hr_holiday_brw = hr_holidays_env.create({'employee_id':hr_emp_brw.id,'date_from':vals.get('date'),'date_to':vals.get('date'),'holiday_name':name,'holiday_status_id':hr_holidays_status_brw.id}) + # msg = _("Holiday %s created.") %(name) + # hr_holiday_brw.message_post(body=msg) + self._cr.execute("update hr_holidays set state = 'validate' where id = %s",(hr_holiday_brw.id,)) + elif vals.get('name') and not vals.get('date'): + hr_holidays_records = hr_holidays_env.search([('date_from','=',self.date),('holiday_name','=',self.name)]) + for hr_holidays_brw in hr_holidays_records: + self._cr.execute("update hr_holidays set holiday_name = %s where id = %s" , (vals.get('name'),hr_holidays_brw.id)) + res = super(ITISHoliday, self).write(vals) + return res diff --git a/itis_hr_attendance_extend/security/groups.xml b/itis_hr_attendance_extend/security/groups.xml new file mode 100644 index 0000000..221fe15 --- /dev/null +++ b/itis_hr_attendance_extend/security/groups.xml @@ -0,0 +1,10 @@ + + + + + Vorgesetzter + the user will have the additional right to see timesheet overview manager view. + + + + \ No newline at end of file diff --git a/itis_hr_attendance_extend/security/ir.model.access.csv b/itis_hr_attendance_extend/security/ir.model.access.csv new file mode 100644 index 0000000..82968e9 --- /dev/null +++ b/itis_hr_attendance_extend/security/ir.model.access.csv @@ -0,0 +1,7 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_planned_hours,access_planned_hours,model_planned_hours,,1,1,1,1 +access_itis_holiday,access_itis_holiday,model_itis_holiday,base.group_user,1,0,0,0 +access_itis_holiday_officer,access_itis_holiday_officer,model_itis_holiday,base.group_hr_user,1,1,1,1 +access_service_des_read,access_service_desc_read,model_service_description,base.group_user,1,0,0,0 +access_service_des_officer,access_service_des_officer,model_service_description,base.group_hr_user,1,1,1,1 +access_service_des_manager,access_service_des_manager,model_service_description,base.group_hr_manager,1,1,1,1 \ No newline at end of file diff --git a/itis_hr_attendance_extend/static/src/css/traffic_light.css b/itis_hr_attendance_extend/static/src/css/traffic_light.css new file mode 100644 index 0000000..dfd0f81 --- /dev/null +++ b/itis_hr_attendance_extend/static/src/css/traffic_light.css @@ -0,0 +1,59 @@ +.led-green { + float: left; + margin: 0 auto; + width: 24px; + height: 24px; + background-color: #ABFF00; + border-radius: 50%; + box-shadow: rgba(0,0,0,0.2) 0 -1px 7px 1px, inset #304701 0 -1px 9px, #89FF00 0 2px 12px; +} +.led-green-off { + float: left; + margin: 0 auto; + width: 24px; + height: 24px; + background-color: #304701; + border-radius: 50%; +} +.led-yellow { + float: left; + margin: 0 auto; + width: 24px; + height: 24px; + background-color: #FF0; + border-radius: 50%; + box-shadow: rgba(0,0,0,0.2) 0 -1px 7px 1px, inset #808002 0 -1px 9px, #FF0 0 2px 12px; +} +.led-yellow-off { + float: left; + margin: 0 auto; + width: 24px; + height: 24px; + background-color: #808002; + border-radius: 50%; +} +.led-red { + float: left; + margin: 0 auto; + width: 24px; + height: 24px; + background-color: #F00; + border-radius: 50%; + box-shadow: rgba(0,0,0,0.2) 0 -1px 7px 1px, inset #441313 0 -1px 9px, rgba(255, 0, 0, 0.5) 0 2px 12px; +} +.led-red-off { + float: left; + margin: 0 auto; + width: 24px; + height: 24px; + background-color: #441313; + border-radius: 50%; +} +.itis_traffic_light{ + position: absolute; + margin-left: 10px; +} + +.openerp .oe_timesheet_weekly .oe_timesheet_weekend { + background: #ffff00; +} \ No newline at end of file diff --git a/itis_hr_attendance_extend/static/src/js/hr_extend.js b/itis_hr_attendance_extend/static/src/js/hr_extend.js new file mode 100644 index 0000000..2b5db88 --- /dev/null +++ b/itis_hr_attendance_extend/static/src/js/hr_extend.js @@ -0,0 +1,261 @@ +openerp.itis_hr_attendance_extend = function (instance) { + + var QWeb = instance.web.qweb; + var _t = instance.web._t; + var _lt = instance.web._lt; + var actionManager = instance.web.ActionManager; + + instance.hr_attendance.AttendanceSlider.include({ + do_update_attendance: function() { + var self = this; + this.$el.hide(); + var employee = new instance.web.DataSetSearch(self, 'hr.employee', self.session.user_context, [ + ['user_id', '=', self.session.uid] + ]); + employee.read_slice(['id', 'name', 'state', 'last_sign', 'attendance_access']).then(function (res) { + if (_.isEmpty(res) ) + return; + if (res[0].attendance_access === false){ + return; + } + self.$el.show(); + self.employee = res[0]; + self.last_sign = instance.web.str_to_datetime(self.employee.last_sign); + self.set({"signed_in": self.employee.state !== "absent"}); + if(self.employee.state !== "absent"){ + self.do_sign_out(); + }else{ + self.do_sign_in(); + } + }); + }, + do_sign_in: function () { + var self = this; + var sign_in_obj = new instance.web.DataSet(self, 'sign.in.task'); + sign_in_obj.call('create', [{ + 'analytic_account_id': false + }]).done(function(result){ + console.log("idddd',",result); + self.temp_wizard_id = result; + var action = { + type: 'ir.actions.act_window', + res_model: 'sign.in.task', + view_mode: 'form', + view_type: 'form', + res_id: result, + views: [[false, 'form']], + target: 'new', + } + var act_ = new actionManager().do_action(action, { + on_close: function() { + self.read_values(); + }, + }); + }); + }, + read_values: function (){ + var self = this; + console.log('thssiss',this.temp_wizard_id); + var sign_in_obj = new instance.web.DataSet(self, 'sign.in.task'); + sign_in_obj.call("do_entry_timesheet", [[this.temp_wizard_id]]).done(function(result){ + console.log('reeeeee',result); + if(result){ + self.super_do_update_attendance(result); + } + }); + }, + super_do_update_attendance: function (timesheet_id) { + var self = this; + var context = new instance.web.CompoundContext(); + context.add({'timesheet_id': timesheet_id}) + var hr_employee = new instance.web.DataSet(self, 'hr.employee'); + hr_employee.call('attendance_action_change', [ + [self.employee.id], + context + ]).done(function (result) { + self.last_sign = new Date(); + self.set({"timesheet_id": timesheet_id}) + self.set({"signed_in": ! self.get("signed_in")}); + }); + }, + do_sign_out: function(){ + var self = this; + var ts_obj = new instance.web.DataSet(self, "hr.analytic.timesheet"); + var timesheet_id = self.get("timesheet_id"); + console.log("self.last_sign",self.last_sign); + ts_obj.call("update_hours", [[timesheet_id], self.last_sign]).done(function (result){ + console.log("rrrrr",result); + if(result){ + self.super_do_update_attendance(timesheet_id); + } + }); + }, + }); + instance.hr_timesheet_sheet.WeeklyTimesheet.include({ + + init_add_account: function() { + var self = this; + if (self.dfm) + return; + console.log("In my customize-------") + self.$(".oe_timesheet_weekly_add_row").show(); + self.dfm = new instance.web.form.DefaultFieldManager(self); + self.dfm.extend_field_desc({ + account: { + relation: "account.analytic.account", + }, + service_desc:{ + relation: "service.description", + }, + }); + +// Add a logic to add comment and service description fields + self.service_desc_m2o = new instance.web.form.FieldMany2One(self.dfm, { + attrs: { + name: "service_desc", + type: "many2one", + placeholder: _t("Select Service Description"), + }, + }); + self.service_desc_m2o.prependTo(self.$(".oe_timesheet_weekly_add_row_service")); + self.comment_char = new instance.web.form.FieldText(self.dfm, { + attrs: { + name: "emp_comment", + type: "char", + placeholder: _t("Add comment"), + }, + }); + self.comment_char.prependTo(self.$(".oe_timesheet_weekly_add_row_comment")); +// END + + self.account_m2o = new instance.web.form.FieldMany2One(self.dfm, { + attrs: { + name: "account", + type: "many2one", + domain: [ + ['type','in',['normal', 'contract']], + ['state', '<>', 'close'], + ['use_timesheets','=',1], + ['id', 'not in', _.pluck(self.accounts, "account")], + ], + context: { + default_use_timesheets: 1, + default_type: "contract", + }, + modifiers: '{"required": true}', + }, + }); + self.account_m2o.prependTo(self.$(".oe_timesheet_weekly_add_row_account")); + + self.$(".oe_timesheet_weekly_add_row button").click(function() { + var id = self.account_m2o.get_value(); + var service_desc_id = self.service_desc_m2o.get_value(); + var comment = self.comment_char.get_value(); + + if (id === false) { + self.dfm.set({display_invalid_fields: true}); + return; + } + var ops = self.generate_o2m_value(); + new instance.web.Model("hr.analytic.timesheet").call("multi_on_change_account_id", [[], [id], + new instance.web.CompoundContext({'user_id': self.get('user_id')})]).then(function(res) { + res = res[id]; + var def = _.extend({}, self.default_get, res.value, { + name: self.description_line, + unit_amount: 0, + date: instance.web.date_to_str(self.dates[0]), + account_id: id, + emp_comment: comment, + service_desc_id : service_desc_id, + }); + ops.push(def); + self.set({"sheets": ops}); + }); + }); + }, + + initialize_content: function(){ + var self = this; + var sheet_id = this.field_manager.datarecord.id; +// Add a logic to get the holiday dates from the python function + new instance.web.Model("itis.holiday").call("get_holiday_date").then(function(results){ + self.holiday = results; + }); + + if(sheet_id){ + new instance.web.Model("planned.hours").call("search_read", [[['sheet_id', '=', sheet_id]], ['sheet_date', 'duration']]).then(function(results){ + results.sort(self.dynamicSort("sheet_date")); + self.planned_hours = results; + }); + }else{ + self.planned_hours = []; + } + + this._super(); +// new instance.web.Model("hr_timesheet_sheet.sheet").call("get_analytic_timesheet_data",[[sheet_id]]).then(function(results){ +// console.log("RESULT-------",results) +// self.analytic_timesheet_data = results; +// }); + }, + dynamicSort: function(property){ + var sortOrder = 1; + if(property[0] === "-"){ + sortOrder = -1; + property = property.substr(1); + } + return function(a,b){ + var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0; + return result * sortOrder; + } + }, + display_data: function(){ + var self = this; + this._super(); + var tot = 0.0; + var self = this; + var day_tots = _.map(_.range(self.dates.length), function() { return 0 }); + var super_tot = 0; + _.each(self.accounts, function(account) { + var acc_tot = 0; + _.each(_.range(self.dates.length), function(day_count) { + var sum = self.sum_box(account, day_count); + acc_tot += sum; + day_tots[day_count] += sum; + super_tot += sum; + }); + }); + var count = 0; + _.each(this.planned_hours, function(pln_hrs){ + var overtime = day_tots[count]-pln_hrs.duration; + tot += pln_hrs.duration; + self.$('[data-pln-dt="' + pln_hrs.sheet_date + '"]').html(self.format_client(pln_hrs.duration)); + self.$('[data-ovr-tm="' + pln_hrs.sheet_date + '"]').html(self.format_client(overtime)); + count += 1; + }); + var tot_ovr_tm = super_tot - tot; + self.$('.oe_ph_hrs_total').html(self.format_client(tot)); + self.$('.oe_ovr_tm_total').html(self.format_client(tot_ovr_tm)); + } + }); + instance.web.form.FieldFloat.include({ + render_value: function(){ + if(this.options.from_itis){ + cur_val = this.get_value(); + var trf_lgt = this.$el.find(".itis_traffic_light"); + if(trf_lgt.length === 0){ + this.$el.append("") + } + if(cur_val <= 20.0 && cur_val >= -20.0){ + this.$el.find(".itis_traffic_light").html("
    
    
    
"); + } + if((cur_val > 20.0 && cur_val < 39.99) || (cur_val >= -39.99 && cur_val < -20.0)){ + this.$el.find(".itis_traffic_light").html("
    
    
    
"); + } + if(cur_val > 39.99 || cur_val < -39.99){ + this.$el.find(".itis_traffic_light").html("
    
    
    
"); + } + } + this._super(); + } + }); +}; \ No newline at end of file diff --git a/itis_hr_attendance_extend/static/src/xml/templates.xml b/itis_hr_attendance_extend/static/src/xml/templates.xml new file mode 100644 index 0000000..34c1802 --- /dev/null +++ b/itis_hr_attendance_extend/static/src/xml/templates.xml @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
Total
+ + + +
+
+
+
Total
+
+
+ + + +
+ +
+
+ + + + + +
+
Planned Hours
+
+ + + + + + + + + + +
+
Overtime Hours
+
+ + + + + + + + +
+
+ + + +
\ No newline at end of file diff --git a/itis_hr_attendance_extend/tests/__init__.py b/itis_hr_attendance_extend/tests/__init__.py new file mode 100644 index 0000000..6fa1bc9 --- /dev/null +++ b/itis_hr_attendance_extend/tests/__init__.py @@ -0,0 +1 @@ +from . import test_hr_attendance_extend \ No newline at end of file diff --git a/itis_hr_attendance_extend/tests/test_hr_attendance_extend.py b/itis_hr_attendance_extend/tests/test_hr_attendance_extend.py new file mode 100644 index 0000000..e7a365f --- /dev/null +++ b/itis_hr_attendance_extend/tests/test_hr_attendance_extend.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +from openerp.tests.common import TransactionCase +from datetime import datetime +import logging +_logger = logging.getLogger(__name__) + +class TestHrAttendanceExtend(TransactionCase): + + + def test_itis_holiday_create(self): + """test case to test creation of the hr holidays""" + + itis_holiday = self.env['itis.holiday'] + today_date = datetime.now().date().strftime('%Y-%m-%d') + itis_holiday_rec = itis_holiday.create({'name':'Holiday','date':today_date}) + if itis_holiday_rec: + _logger.info('-----Holiday is successfully created.') + else: + self.assertEqual(0,1,'Odoo-Alfresco:- Holiday test case is failed.') + + diff --git a/itis_hr_attendance_extend/views/hr_holiday_view.xml b/itis_hr_attendance_extend/views/hr_holiday_view.xml new file mode 100644 index 0000000..299fd71 --- /dev/null +++ b/itis_hr_attendance_extend/views/hr_holiday_view.xml @@ -0,0 +1,21 @@ + + + + + + + + Leave Request Inherit + hr.holidays + + + + + + + + + + + + diff --git a/itis_hr_attendance_extend/views/hr_timesheet_sheet_view.xml b/itis_hr_attendance_extend/views/hr_timesheet_sheet_view.xml new file mode 100644 index 0000000..285ad7d --- /dev/null +++ b/itis_hr_attendance_extend/views/hr_timesheet_sheet_view.xml @@ -0,0 +1,519 @@ + + + + + + hr_timesheet_sheet_sheet_form_inherited + hr_timesheet_sheet.sheet + + + + false + + + + True + + + + + 1 + + +
+
+ + + + + + + 1 + + + + + + + + + + + + + + 1 + + + 1 + + + 1 + + + + + + + + +
+ + + + hr.employee.form.itis.inherit + hr.employee + + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + hr.payroll.structure.form.inherit.itis + hr.payroll.structure + + + + + + + + + + + hr.contract.view.tree.inherit + hr.contract + + + + + + + + + + + hr_contract_view_form_itis + hr.contract + + + + + + + + + + + + + True + + + + + + itis_employee_childrenform + itis_employee_children + +
+ + + + + + + + +
+
+
+ + + + hr_payroll_view_hr_payslip_form_itis + hr.payslip + + + + + + + + + + itis.hr.contact.tree + itis.hr.contact + + + + + + + + + + + + itis.hr.contact.form + itis.hr.contact + +
+ +
+

+ +

+
+ + + + + + + + + + +
+
+
+
+ + + + + Contacts + ir.actions.act_window + itis.hr.contact + form + tree,form + + + + + + + + hr.emp.data.tree + hr.employee + 100 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + code + ir.actions.server + + action = model.open_emp_data_tree() + True + Personalübersicht + + + + + + + + + + + + + + + + hr.health.insurance.form + hr.health.insurance + +
+ +
+
+
+
+
+
+ + + hr.health.insurance.tree + hr.health.insurance + + + + + + + + + Health Insurance + ir.actions.act_window + hr.health.insurance + form + tree,form + + + + + + planned_jobs_tree + planned.job + + + + + + + + + Planned Jobs + ir.actions.act_window + planned.job + form + tree,form + + + + + + hr.family.status.form + hr.family.status + +
+ +
+
+
+
+
+
+ + + hr.family.status.tree + hr.family.status + + + + + + + + + Family Status + ir.actions.act_window + hr.family.status + form + tree,form + + + + + + leave.days.calc.error.tree + itis.leave.days.calc.error + + + + + + + + + + + Fehler Urlaubsberechnung + ir.actions.act_window + itis.leave.days.calc.error + form + tree,form + + + + + + leave.time.tree + leave.time + +
+ + + + + + + + + + + +
+
+
+ + + + payroll.hr.employee.view.form.inherit + hr.employee + + + + + 1 + + + + + + + Office Leave Timing + ir.actions.act_window + leave.time + form + tree,form + + + + + + + emp.overtime.count.tree + employee.overtime.count + + + + + + + + + + emp.overtime.count.form + employee.overtime.count + +
+ + + + + + +
+
+
+ + + Employee Overtime Count + ir.actions.act_window + employee.overtime.count + form + tree,form + + +
+
diff --git a/itis_hr_extend/views/hr_holiday_view.xml b/itis_hr_extend/views/hr_holiday_view.xml new file mode 100644 index 0000000..c0e290e --- /dev/null +++ b/itis_hr_extend/views/hr_holiday_view.xml @@ -0,0 +1,96 @@ + + + + hr_holidays_view_tree_itis + hr.holidays + + + + date + + + date + + + + + + + hr_holidays_view_form_itis + hr.holidays + + + + True + base.group_user + + + + + + + + + + + [('is_holiday', '!=',True)] + + + + + hr.holidays.status.form.inherit.itis + hr.holidays.status + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/itis_hr_extend/wizard/__init__.py b/itis_hr_extend/wizard/__init__.py new file mode 100644 index 0000000..30dfcb1 --- /dev/null +++ b/itis_hr_extend/wizard/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + +from . import ot_change +from . import fte_wizard +from . import emp_payroll_wizard +from . import emp_data_wizard + + diff --git a/itis_hr_extend/wizard/emp_data_wizard.py b/itis_hr_extend/wizard/emp_data_wizard.py new file mode 100755 index 0000000..c2bb27a --- /dev/null +++ b/itis_hr_extend/wizard/emp_data_wizard.py @@ -0,0 +1,167 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + + +from openerp import models, fields, api, _ +from openerp.exceptions import Warning +import csv +from datetime import datetime +import base64 +import os + +class employee_data_export(models.TransientModel): + + _name = 'employee.data.export' + + name = fields.Binary('Timesheet CSV') + file_name = fields.Char('File') + report_selection = fields.Selection([('export_employee','Personalübersicht'), + ('export_workcouncil','BR Übersicht')], + string='Report',default='export_employee', required=True) + + @api.multi + def export_emp_data_csv(self): + """ + This function is use to export the employee data records which are preselected. + """ + + if self._context and 'active_model' in self._context and self._context['active_model'] == 'hr.employee': + context = self._context.copy() + hr_employee = self.env['hr.employee'] + if self.report_selection =='export_workcouncil': + hr_employee_records = hr_employee.search([('executive_employee','=',False),('id','in',context['active_ids'])]) + else: + hr_employee_records = hr_employee.browse(context['active_ids']) + # print"analytic_timesheet_records----",analytic_timesheet_records + context = self.export_csv_subfunction(hr_employee_records) + + return { + 'name': _('Exported Employee Data'), + 'view_type': 'form', + "view_mode": 'form', + 'res_model': 'employee.data.export', + 'type': 'ir.actions.act_window', + 'context': context, + 'target':'new', + } + + def get_date_format(self,date): + if date: + return datetime.strptime(date,'%Y-%m-%d').strftime('%d.%m.%Y') + else: + return '' + + + def export_csv_subfunction(self,emp_data_records): + """ + It is a subfunction for the export csv. + """ + + data_list = [] + if self._context.get('for_work_council') or self.report_selection =='export_workcouncil': + csv_header = ['Personalnummer','Vorname','Nachname','Bereich','Team','Stellenbezeichnung','Vertragstyp', + 'Ersteintrittsdatum','Enddatum befristeter Vertrag','Befristungsgrund','Probezeit Enddatum', + 'letztes MA Gespraech',] + csv_name = "Betriebsratsübersicht" + + else: + csv_header = ['Personalnummer','Vorname','Nachname','Geburtstag','Company','Bereich','Team','Planstellenbezeichnung', + 'Stellenbezeichnung','Vertragstyp','Ersteintrittsdatum','Enddatum befristeter Vertrag','Befristungsgrund', + 'Probezeit Enddatum','letztes MA Gespraech','5-Jahresjubilaeum','Arbeitszeit','Urlaub','Schwerbehinderung', + 'letzte Vertragsaenderung_L&G','Startdatum der letzten Vertragversänderung','Verguetung','Verguetung bei VZ','Verguetung inkl. AG Kosten (25%)','BR Mitglied', + 'Bemerkungen','Manager'] + csv_name = "Personalübersicht" + time_csv = datetime.now().strftime('%Y-%m-%d_%H%M%S') + '.csv' + csv_path = "/tmp/" + time_csv + for emp_record in emp_data_records: + + if self._context.get('for_work_council') or self.report_selection =='export_workcouncil': + vals = { + 'Personalnummer': (emp_record.identification_id or '').encode('utf-8'), + 'Nachname': (emp_record.second_name or '').encode('utf-8'), + 'Vorname': (emp_record.surname or '').encode('utf-8'), + 'Bereich': (emp_record.bereich and emp_record.bereich.name or '').encode('utf-8'), + 'Team': (emp_record.department_id and emp_record.department_id.name or '').encode('utf-8'), + 'Stellenbezeichnung': (emp_record.job_id and emp_record.job_id.name or '').encode('utf-8'), + 'Vertragstyp': (emp_record.sudo().contract_type and emp_record.sudo().contract_type.name or '').encode('utf-8'), + 'Ersteintrittsdatum': self.get_date_format(emp_record.initial_date), + 'Enddatum befristeter Vertrag': self.get_date_format(emp_record.temp_contract_end_date), + 'Befristungsgrund': (emp_record.contract_limitation_reason and emp_record.contract_limitation_reason.name or '').encode('utf-8'), + 'Probezeit Enddatum': self.get_date_format(emp_record.contract_trial_end_date), + 'letztes MA Gespraech': self.get_date_format(emp_record.last_ma_conversation_date), + + } + + else: + notes = '' + if emp_record.contract_notes: + notes= emp_record.contract_notes.replace("\n"," / ") + vals = { + 'Personalnummer': (emp_record.identification_id or '').encode('utf-8'), + 'Nachname': (emp_record.second_name or '').encode('utf-8'), + 'Vorname': (emp_record.surname or '').encode('utf-8'), + 'Geburtstag': self.get_date_format(emp_record.birthday), + 'Company': (emp_record.address_id and emp_record.address_id.sudo().name or '').encode('utf-8'), + 'Bereich': (emp_record.bereich and emp_record.bereich.name or '').encode('utf-8'), + 'Team': (emp_record.department_id and emp_record.department_id.name or '').encode('utf-8'), + 'Planstellenbezeichnung': (emp_record.planned_job_id and emp_record.planned_job_id.name or '').encode('utf-8'), + 'Stellenbezeichnung': (emp_record.job_id and emp_record.job_id.name or '').encode('utf-8'), + 'Vertragstyp': (emp_record.sudo().contract_type and emp_record.sudo().contract_type.name or '').encode('utf-8'), + 'Ersteintrittsdatum': self.get_date_format(emp_record.initial_date), + 'Enddatum befristeter Vertrag': self.get_date_format(emp_record.temp_contract_end_date), + 'Befristungsgrund': (emp_record.contract_limitation_reason and emp_record.contract_limitation_reason.name or '').encode('utf-8'), + 'Probezeit Enddatum': self.get_date_format(emp_record.contract_trial_end_date), + 'letztes MA Gespraech': self.get_date_format(emp_record.last_ma_conversation_date), + '5-Jahresjubilaeum': self.get_date_format(emp_record.five_years), + 'Arbeitszeit': (emp_record.contract_working_hours and emp_record.contract_working_hours.name or '').encode('utf-8'), + 'Urlaub': emp_record.contract_leaves or '', + 'Schwerbehinderung': ('ja' if emp_record.disability=='yes' else 'nein' or ''), + # 'letzte Vertragsaenderung_L&G': emp_record.last_contract_changed_wage or '', + 'letzte Vertragsaenderung_L&G': ("%.2f" % emp_record.last_contract_changed_wage).replace('.',',') or '', + 'Startdatum der letzten Vertragversänderung':self.get_date_format(emp_record.last_contract_changed_date), + 'Verguetung': ("%.2f" % emp_record.emp_wage_cal).replace('.',',') or '', + # 'Verguetung bei VZ': emp_record.compensation_at_vz or '', + 'Verguetung bei VZ': ("%.2f" % emp_record.compensation_at_vz).replace('.',',') or '', + # 'Verguetung inkl. AG Kosten (25%)': emp_record.remuneration_incl_ag_costs or '', + 'Verguetung inkl. AG Kosten (25%)': ("%.2f" % emp_record.remuneration_incl_ag_costs).replace('.',',') or '', + 'BR Mitglied': ('ja' if emp_record.br_member=='yes' else 'nein' or '').encode('utf-8'), + 'Bemerkungen': (notes).encode('utf-8'), + 'Manager': (emp_record.parent_id and emp_record.parent_id.name or '').encode('utf-8'), + + } + data_list.append(vals) + + with open(csv_path, 'wb') as csvfile: + + w = csv.DictWriter(csvfile, fieldnames=csv_header, delimiter=';',quoting=csv.QUOTE_ALL) + w.writeheader() + w.writerows(data_list) + csvfile.close() + + data = '' + with open(csv_path, 'rb') as csvfile: + data = csvfile.read() + data = data.encode('base64') + csvfile.close() + context = self._context.copy() + file_name = datetime.now().strftime('%Y%m%d_%H_%M')+'_'+csv_name+ '.csv' + context.update({'default_name': data, 'default_file_name':file_name}) + os.remove(csv_path) + return context diff --git a/itis_hr_extend/wizard/emp_data_wizard_view.xml b/itis_hr_extend/wizard/emp_data_wizard_view.xml new file mode 100755 index 0000000..9341b1e --- /dev/null +++ b/itis_hr_extend/wizard/emp_data_wizard_view.xml @@ -0,0 +1,49 @@ + + + + + + emloyee.data.export.form.view + employee.data.export + +
+
+ + + Personalübersicht Export + ir.actions.act_window + employee.data.export + form + form + new + + + + + + +
+
\ No newline at end of file diff --git a/itis_hr_extend/wizard/emp_payroll_wizard.py b/itis_hr_extend/wizard/emp_payroll_wizard.py new file mode 100644 index 0000000..dbaffdc --- /dev/null +++ b/itis_hr_extend/wizard/emp_payroll_wizard.py @@ -0,0 +1,327 @@ +# -*- coding: utf-8 -*- + +from openerp import models, api, fields, _ +from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT +from datetime import datetime +from dateutil.relativedelta import relativedelta +from calendar import monthrange +import csv +import os +import base64 + +def get_years(): + year = [] + for i in range(2016,2040): + year.append((i,str(i))) + return year + +class create_emp_payroll(models.TransientModel): + + _name = 'create.emp.payroll' + + @api.model + def _default_date_from(self): + date = datetime.today().date() + last_month_date = (date - relativedelta(months= 1)).replace(day=20) + return last_month_date + + @api.model + def _default_date_to(self): + date = datetime.today().date().replace(day=20) + return date + + @api.model + def _default_month(self): + date = datetime.today().date() + return date.month + + @api.model + def _default_year(self): + date = datetime.today().date() + return date.year + + month = fields.Selection([(1,'January'),(2,'February'),(3,'March'),(4,'April'),(5,'May'),(6,'June') + ,(7,'July'),(8,'Augast'),(9,'September'),(10,'October'),(11,'November'),(12,'December')],default =_default_month,string='Month') + year = fields.Selection(get_years(),default =_default_year,string='Year') + date_from = fields.Date('Date From',default =_default_date_from) + date_to = fields.Date('Date To',default =_default_date_to) + + + + @api.multi + def generate_employee_report(self): + emp_payroll_report = self.env['employee.payroll.report'] + record_ids = [] + + + hr_contract_records = self.env['hr.contract'].search([('employee_id','!=',False)],order='employee_id') + # hr_contract_records = self.env['hr.contract'].search([('id','=',169)],order='employee_id') + for hr_contract_brw in hr_contract_records: + if hr_contract_brw.date_start: + # print"hr_contract_brw----",hr_contract_brw + # ----------------to calculate the selected year month combination for the contract + selected_year_month = str(self.year)+'-'+str(self.month) + # print"selected_year_month------",selected_year_month + + contract_date_start = datetime.strptime(hr_contract_brw.date_start,'%Y-%m-%d').date() + if hr_contract_brw.date_end: + contract_date_end = datetime.strptime(hr_contract_brw.date_end,'%Y-%m-%d').date() + else: + contract_date_end = datetime.today().date() + #Added newly + selected_month_range = monthrange(self.year,self.month) + selected_month_enddate = datetime.strptime(selected_year_month+'-'+str(selected_month_range[1]),'%Y-%m-%d').date() + if contract_date_end < selected_month_enddate: + contract_date_end = selected_month_enddate + + + contract_date_start_new = contract_date_start.replace(day=1) + contract_date_end_new = contract_date_end.replace(day=1) + # print"contract_date_start_new----",contract_date_start_new + # print"contract_date_end_new----",contract_date_end_new + contracted_year_months = [] + while contract_date_start_new <=contract_date_end_new: + data = str(contract_date_start_new.year)+'-'+str(contract_date_start_new.month) + contracted_year_months.append(data) + contract_date_start_new = contract_date_start_new + relativedelta(months= 1) + # print"contracted_year_months----",contracted_year_months + + # Selected year and month criteria + # if contract_date_start.year <= self.year and contract_date_start.month <= self.month and contract_date_end.year >= self.year and contract_date_end.month >= self.month: + if selected_year_month in contracted_year_months: + # print"Active Contract------",hr_contract_brw.name + # print"Employee Name ------",hr_contract_brw.employee_id.name + + # --------------to calculate gross salary + gross_salary = 0.0 + hr_payslip = self.env['hr.payslip'] + selected_month_range = monthrange(self.year,self.month) + + period_start_date = datetime.strptime(selected_year_month+'-01','%Y-%m-%d').date() + period_end_date = datetime.strptime(selected_year_month+'-'+str(selected_month_range[1]),'%Y-%m-%d').date() + + if contract_date_start <= period_start_date: + period_contract_start_date =str(period_start_date) + else: + period_contract_start_date =str(contract_date_start) + if contract_date_end >= period_end_date: + period_contract_end_date =str(period_end_date) + else: + period_contract_end_date =str(contract_date_end) + + #To check for the date and values + if period_contract_start_date > period_contract_end_date: + period_contract_end_date = period_contract_start_date + #period_contract_end_date = period_contract_start_date + + # print"period_contract_start_date------",period_contract_start_date + # print"period_contract_end_date------",period_contract_end_date + # print"contract_date_end------",contract_date_end + payslip_values = {'employee_id':hr_contract_brw.employee_id.id,'date_from':period_contract_start_date,'date_to':period_contract_end_date, + 'contract_id':hr_contract_brw.id,'struct_id':hr_contract_brw.struct_id.id,'journal_id':1 } + + hr_payslip_brw=hr_payslip.sudo().create(payslip_values) + + res = self.pool.get('hr.payslip').onchange_employee_id(self._cr, self._uid, [], period_contract_start_date, period_contract_end_date, + hr_contract_brw.employee_id.id, hr_contract_brw.id, None) + if res and res.get('value'): + value = res.get('value') + worked_days_line_ids = value.get('worked_days_line_ids') + for line_rec in worked_days_line_ids: + line_rec.update({'payslip_id':hr_payslip_brw.id}) + self.env['hr.payslip.worked_days'].create(line_rec) + hr_payslip_brw.compute_sheet() + for data in hr_payslip_brw.details_by_salary_rule_category: + if data.code == "NET": + gross_salary = data.total + hr_payslip_brw.unlink() + + + # ---------------to calculate sick days + sick_days = 0.0 + selected_date_from = datetime.strptime(self.date_from,'%Y-%m-%d').date() + selected_date_to = datetime.strptime(self.date_to,'%Y-%m-%d').date() + + + if contract_date_start<= selected_date_from: + sick_leave_start_date = selected_date_from + else: + sick_leave_start_date = contract_date_start + if contract_date_end >= selected_date_to: + sick_leave_end_date = selected_date_to + else: + sick_leave_end_date = contract_date_end + + while sick_leave_start_date <=sick_leave_end_date: + # print"sick_leave_start_date----",sick_leave_start_date + + hr_analytic_env = self.env['hr.analytic.timesheet'] + search_domain = [ + + ('date', '=', str(sick_leave_start_date)), + ('user_id', '=',hr_contract_brw.employee_id.user_id.id), + ('account_id', '=', hr_contract_brw.employee_id.company_id.sick_account_id.id) + ] + + timesheet_line_ids = hr_analytic_env.search(search_domain) + # print"timesheet_line_ids--------",timesheet_line_ids + if len(timesheet_line_ids): + for line in timesheet_line_ids: + for plan in line.sheet_id.planned_ids: + if plan.sheet_date == line.date and plan.duration: + sick_days +=line.unit_amount/plan.duration + + sick_days = float("{0:.2f}".format(sick_days)) + + # print"sick_days--------",sick_days + + # sick_day_status = self.env['hr.holidays.status'].search([('is_sick_leave_type','=',True)],limit=1) + # if sick_day_status: + # sick_day_leave_records = self.env['hr.holidays'].search([('holiday_status_id','=',sick_day_status.id),('state','=','validate'), + # ('employee_id','=',hr_contract_brw.employee_id.id),('date_from','<=',str(sick_leave_start_date)),('date_to','>=',str(sick_leave_start_date))],limit=1) + # + # if sick_day_leave_records: + # leave_date_from = datetime.strptime(sick_day_leave_records.date_from,DEFAULT_SERVER_DATETIME_FORMAT).date() + # leave_date_to = datetime.strptime(sick_day_leave_records.date_to,DEFAULT_SERVER_DATETIME_FORMAT).date() + # if leave_date_from == sick_leave_start_date and leave_date_to == sick_leave_start_date: + # sick_days += sick_day_leave_records.number_of_days_temp + # else: + # if leave_date_from == sick_leave_start_date and sick_day_leave_records.leave_selection =='half_day': + # sick_days +=0.5 + # elif leave_date_to == sick_leave_start_date and sick_day_leave_records.leave_selection_date_to =='half_day': + # sick_days +=0.5 + # else: + # sick_days +=1 + + sick_leave_start_date = sick_leave_start_date+relativedelta(days=1) + # print"sick_days------",sick_days + + + # ----------------For coloring base on the last modification date + change_record,employee_brw='N',hr_contract_brw.employee_id + if self.date_from and self.date_to: + if hr_contract_brw.write_date >= self.date_from and hr_contract_brw.write_date <= self.date_to and \ + employee_brw.write_date >= self.date_from and employee_brw.write_date <= self.date_to: + change_record = 'SV' + elif self.date_from <= hr_contract_brw.write_date and self.date_to >= hr_contract_brw.write_date: + change_record = 'V' + elif self.date_from <= employee_brw.write_date and self.date_to >= employee_brw.write_date: + change_record = 'ST' + + # ----------------To get a wage base on the hourly basis time + wage =0.0 + if hr_contract_brw: + wage = hr_contract_brw.wage + + + vals = {'contract_id':hr_contract_brw.id,'employee_id':hr_contract_brw.employee_id.id, + 'record_change':change_record,'sick_days':sick_days,'gross_salary':gross_salary,'wage':wage} + record_ids.append(emp_payroll_report.create(vals).id) + + emp_payroll_report_tree_view = self.env.ref('itis_hr_extend.itis_emp_payroll_report_tree', False) + return { + 'name': ("Employee Report"), + 'view_mode': 'tree', + 'view_id': False, + 'view_type': 'form', + 'res_model': 'employee.payroll.report', + 'type': 'ir.actions.act_window', + 'target': 'current', + 'domain': "[('id', 'in', %s)]" % record_ids, + 'views': [(emp_payroll_report_tree_view and emp_payroll_report_tree_view.id or False, 'tree')], + 'context': {} + } + + + +class export_emp_payroll(models.TransientModel): + + _name = 'export.emp.payroll' + + name = fields.Binary('Employee Report CSV') + file_name = fields.Char('File') + + @api.multi + def export_csv(self): + """ + This function is use to export the employee payroll report + """ + emp_payroll_report = self.env['employee.payroll.report'] + if self._context and 'active_model' in self._context and self._context['active_model'] == 'employee.payroll.report': + + emp_payroll_report_records = emp_payroll_report.browse(self._context['active_ids']) + + data_list = [] + csv_header = ['record_change','Personal-Nr', 'Name', 'Vorname', "Geburtsdatum", "Privatanschrift",'Bankverbindung','Krankenkasse', + 'Schwerbehinderung','Schwerbehinderung Gültigkeit','Familienstand','Anzahl Kinder', 'Vertragsreferenz','Vertragsbeginn','Vertragsende', + 'Arbeitszeit','Vergütungsmodell','Bruttogehalt','Wage','Krankheitstage','Bemerkung Vertragsinformationen'] + time_csv = datetime.now().strftime('%Y-%m-%d_%H_%M_%S') + '.csv' + csv_path = "/tmp/" + time_csv + + for emp_report_brw in emp_payroll_report_records: + + bank_info ='' + if emp_report_brw.bank_account_id: + bank_account_id = emp_report_brw.bank_account_id + if bank_account_id.state =='iban': + bank_info = (bank_account_id.bank_name or ' ') +' '+'IBAN '+(bank_account_id.acc_number or' ') + else: + bank_info = (bank_account_id.bank_name or' ')+' '+(bank_account_id.acc_number or' ') + if bank_account_id.bank_bic: + bank_info = bank_info+' BIC- '+bank_account_id.bank_bic + # + record_change = emp_report_brw.record_change + if record_change =='V': + record_change = 'VÄ' + + vals = { + 'record_change': record_change, + 'Personal-Nr':(emp_report_brw.identification_id or '').encode('utf-8'), + "Name": (emp_report_brw.name or '').encode('utf-8'), + 'Vorname': (emp_report_brw.surname or '').encode('utf-8'), + 'Geburtsdatum': emp_report_brw.birthday or '', + 'Privatanschrift': (emp_report_brw.address_home_id or '').encode('utf-8') , + 'Bankverbindung': bank_info.encode('utf-8'), + 'Krankenkasse': (emp_report_brw.health_insurance and emp_report_brw.health_insurance.name or '').encode('utf-8'), + 'Schwerbehinderung': emp_report_brw.disability or '', + 'Schwerbehinderung Gültigkeit':emp_report_brw.disability_limited_until or '', + 'Familienstand': emp_report_brw.family_status and emp_report_brw.family_status.name or '', + 'Anzahl Kinder': emp_report_brw.children, + + 'Vertragsreferenz':(emp_report_brw.contract_name or '').encode('utf-8'), + 'Vertragsbeginn':emp_report_brw.contract_start_date, + 'Vertragsende':emp_report_brw.contract_end_date or '', + 'Arbeitszeit':(emp_report_brw.working_hours and emp_report_brw.working_hours.name or '').encode('utf-8'), + 'Vergütungsmodell':(emp_report_brw.struct_id and emp_report_brw.struct_id.name or '').encode('utf-8'), + 'Bruttogehalt':emp_report_brw.gross_salary, + 'Wage':emp_report_brw.wage, + 'Krankheitstage':emp_report_brw.sick_days, + 'Bemerkung Vertragsinformationen':(emp_report_brw.notes or '').replace('\n',' ').encode('utf-8'), + } + data_list.append(vals) + + with open(csv_path, 'wb') as csvfile: + + w = csv.DictWriter(csvfile, fieldnames=csv_header, delimiter=',', quoting=csv.QUOTE_ALL) + w.writeheader() + w.writerows(data_list) + csvfile.close() + + data = '' + with open(csv_path, 'rb') as csvfile: + data = csvfile.read() + data = data.encode('base64') + csvfile.close() + context = self._context.copy() + context.update({'default_name': data, 'default_file_name': 'employee_report_export_' + time_csv}) + os.remove(csv_path) + + return { + 'name': _('Exported Employee Report'), + 'view_type': 'form', + "view_mode": 'form', + 'res_model': 'export.emp.payroll', + 'type': 'ir.actions.act_window', + 'context': context, + 'target':'new', + } \ No newline at end of file diff --git a/itis_hr_extend/wizard/emp_payroll_wizard_view.xml b/itis_hr_extend/wizard/emp_payroll_wizard_view.xml new file mode 100644 index 0000000..b898fb5 --- /dev/null +++ b/itis_hr_extend/wizard/emp_payroll_wizard_view.xml @@ -0,0 +1,83 @@ + + + + + + emp.payroll.wiz.form.view + create.emp.payroll + +
+
+
+ + + Employee Payroll Report + ir.actions.act_window + create.emp.payroll + form + form + new + + + + + + + + emp.payroll.export.form.view + export.emp.payroll + +
+
+ + + Employee Report Export + ir.actions.act_window + export.emp.payroll + form + form + new + + + + + + + +
+
\ No newline at end of file diff --git a/itis_hr_extend/wizard/fte_wizard.py b/itis_hr_extend/wizard/fte_wizard.py new file mode 100644 index 0000000..ffe686e --- /dev/null +++ b/itis_hr_extend/wizard/fte_wizard.py @@ -0,0 +1,108 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + +from openerp import models, api, fields, _ + + +class create_fte(models.TransientModel): + + _name = 'create.fte' + + @api.model + def check_parent(self, dep_dict, parent, pass_list): + dep_env = self.env['hr.department'] + for dep in dep_env.browse(dep_dict.keys()): + if dep.id not in pass_list: + if dep.parent_id.id == parent: + return False + return True + + @api.model + def compute_child(self, dep, dep_dict, parent_list, pass_list): +# print "dep_dict", dep_dict + if dep.parent_id: + # print parent_list,">>" , dep.name, ">>", dep.parent_id.name, '=', dep_dict.get(dep.id) + if dep.parent_id.id not in parent_list: + if not dep_dict.get(dep.parent_id.id): + dep_dict[dep.parent_id.id] = dep_dict.get(dep.id) + else: + dep_dict[dep.parent_id.id] += dep_dict.get(dep.id) + if dep_dict.get(dep.id) and self.check_parent(dep_dict, dep.parent_id.id, pass_list): + parent_list.append(dep.parent_id.id) + else: + dep_dict[dep.parent_id.id] = dep_dict.get(dep.id) + self.compute_child(dep.parent_id, dep_dict, parent_list, pass_list) + else: + if not dep_dict.get(dep.parent_id.id): + dep_dict[dep.id] = dep_dict.get(dep.id) + else: + dep_dict[dep.id] += dep_dict.get(dep.id) + return dep_dict, parent_list + + + + + @api.model + def calc_fte(self, dep_dict): + dep_env = self.env['hr.department'] + parent_list = [] + pass_list = [] + for dep in dep_env.browse(dep_dict.keys()): + pass_list.append(dep.id) + dep_dict, parent_list = self.compute_child(dep, dep_dict, parent_list, pass_list) + # print "dep_dict", dep_dict + return dep_dict + + @api.multi + def generate_fte_report(self): + department_env = self.env['hr.department'] + employee_env = self.env['hr.employee'] + dep_dict = {} + for emp in employee_env.search([]): +# print emp.fte, emp.name + for fte in emp.fte_ids: + if not dep_dict.get(fte.department_id.id): + dep_dict[fte.department_id.id] = (fte.fte/100) * emp.fte + else: + dep_dict[fte.department_id.id] += (fte.fte/100) * emp.fte + fte_list = [] + dep_dict = self.calc_fte(dep_dict) + for dep in department_env.search([]): + + vals = { + 'department_id': dep.id, + 'planned_fte': dep.planned_fte, + 'fte': dep_dict.get(dep.id, 0.0), + 'diff_fte': dep.planned_fte - dep_dict.get(dep.id, 0.0) + } + fte_list.append((0,0,vals)) + fte = self.env['fte.report'].create({'fte_ids': fte_list}) + + fte_view = self.env.ref('itis_hr_extend.itis_fte_report_form', False) + return { + 'name': _('FTE Report'), + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'fte.report', + 'views': [(fte_view.id,'form')], + 'type': 'ir.actions.act_window', + 'target': 'current', + 'res_id':fte.id + } diff --git a/itis_hr_extend/wizard/fte_wizard_view.xml b/itis_hr_extend/wizard/fte_wizard_view.xml new file mode 100644 index 0000000..19b45f9 --- /dev/null +++ b/itis_hr_extend/wizard/fte_wizard_view.xml @@ -0,0 +1,35 @@ + + + + + + fte.wiz.form.view + create.fte + +
+
+
+ + + FTE Report + ir.actions.act_window + create.fte + form + form + new + + + + + +
+
\ No newline at end of file diff --git a/itis_hr_extend/wizard/ot_change.py b/itis_hr_extend/wizard/ot_change.py new file mode 100644 index 0000000..708caac --- /dev/null +++ b/itis_hr_extend/wizard/ot_change.py @@ -0,0 +1,101 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + +from openerp import models, api, fields, _ +from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT +from datetime import datetime, timedelta + + +class OTChange(models.TransientModel): + + _name = "ot.change" + + reason = fields.Char("Reason") + ot_time = fields.Float("Overtime Count") + leave_day = fields.Float("Leave Day") + + @api.model + def default_get(self, fields): + + res = super(OTChange, self).default_get(fields) + emp_id = self.env.context.get("active_id") + emp_rec = self.env['hr.employee'].browse(emp_id) + if self.env.context.get("from_ot_change", False): + # res.update({'ot_time': emp_rec.overtime_count}) + res.update({'ot_time': emp_rec.employee_overtime_id.emp_overtime_count}) + else: + res.update({'leave_day': emp_rec.additional_leave_days}) + return res + + @api.multi + def set_ot_time(self): + emp_id = self.env.context.get("active_id") + emp_rec = self.env['hr.employee'].browse(emp_id) + if self.env.context.get("from_ot_change", False): + emp_rec.update_overtime_count(self.ot_time, self.reason) + else: + emp_rec.update_leave_day(self.leave_day, self.reason) + return True + +class LDChange(models.TransientModel): + + _name = "ld.change" + + reason = fields.Char("Reason") + type = fields.Selection([('add', 'Hinzufügen'),('sub', 'Abziehen')], "Type") + leave_day = fields.Float("Leave Day") + + @api.multi + def set_ld_time(self): + leave_journal_obj = self.env['hr.leave.journal'] + leave_days = self.leave_day + if self.type == 'sub': + leave_days = leave_days * -1 + values = { + 'employee_id': self.env.context.get("active_id"), + 'year': datetime.today().year, + 'year_type': 'actual', + 'type': 'manual', + 'leave_type':'days', + 'leave_days': leave_days, + 'name': self.reason + ' ' + self.env['res.users'].browse(self._uid).name + ' ' + datetime.now().strftime('%d%m%Y %H:%M:%S'), + } + leave_journal_obj.create(values) + + #for SOW17 + @api.multi + def set_nextyear_ld_time(self): + """Add a logic to give ability to change leave day for the next year. + User can only change it after May month + """ + leave_journal_obj = self.env['hr.leave.journal'] + leave_days = self.leave_day + if self.type == 'sub': + leave_days = leave_days * -1 + values = { + 'employee_id': self.env.context.get("active_id"), + 'year': datetime.today().year+1, + 'year_type': 'next', + 'type': 'manual', + 'leave_type':'days', + 'leave_days': leave_days, + 'name': self.reason + ' ' + self.env['res.users'].browse(self._uid).name + ' ' + datetime.now().strftime('%d%m%Y %H:%M:%S'), + } + leave_journal_obj.create(values) diff --git a/itis_hr_extend/wizard/ot_change_view.xml b/itis_hr_extend/wizard/ot_change_view.xml new file mode 100644 index 0000000..04d040b --- /dev/null +++ b/itis_hr_extend/wizard/ot_change_view.xml @@ -0,0 +1,45 @@ + + + + + + ot_change_form_view + ot.change + +
+ + + + + +
+
+
+
+
+ + + ld_change_form_view + ld.change + +
+ + + + + +
+
+
+
+
+
+
\ No newline at end of file diff --git a/itis_hr_leave_extend/__init__.py b/itis_hr_leave_extend/__init__.py new file mode 100644 index 0000000..7433469 --- /dev/null +++ b/itis_hr_leave_extend/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + +from . import wizard +from . import models diff --git a/itis_hr_leave_extend/__openerp__.py b/itis_hr_leave_extend/__openerp__.py new file mode 100644 index 0000000..5646bee --- /dev/null +++ b/itis_hr_leave_extend/__openerp__.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + +{ + 'name': "ITIS HR Leave Extend", + 'summary': """ Module will extend Human Ressources leave""", + 'description': """ + Module to extend the functionalities of the HR module. + """, + 'author': "IT IS AG", + 'website': "http://www.itis-odoo.de", + 'category': 'base', + 'version': '1.0.55.0', + 'depends': ['itis_hr_extend','itis_hr_attendance_extend'], + 'data': [ + 'views/hr_setting_view.xml', + 'security/ir.model.access.csv', + 'wizard/hr_sick_leave.xml' + ], + 'css': [], + 'demo': [], diff --git a/itis_hr_leave_extend/i18n/de.po b/itis_hr_leave_extend/i18n/de.po new file mode 100644 index 0000000..130f0c4 --- /dev/null +++ b/itis_hr_leave_extend/i18n/de.po @@ -0,0 +1,208 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * itis_hr_leave_extend +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-06-07 13:17+0000\n" +"PO-Revision-Date: 2017-06-07 15:19+0100\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: \n" +"X-Generator: Poedit 1.5.4\n" + +#. module: itis_hr_leave_extend +#: field:hr.config.settings,leave_account_id:0 +#: field:res.company,leave_account_id:0 +msgid "Analytic Account for Leave" +msgstr "Kosenstelle für Urlaub" + +#. module: itis_hr_leave_extend +#: field:hr.config.settings,ot_leave_account_id:0 +#: field:res.company,ot_leave_account_id:0 +msgid "Analytic Account for Overtime Leave" +msgstr "Kostenstelle für Überstundenabbau" + +#. module: itis_hr_leave_extend +#: view:hr.config.settings:itis_hr_leave_extend.view_human_resources_configuration +msgid "Analytic account" +msgstr "Kostenstelle" + +#. module: itis_hr_leave_extend +#: view:hr.sick.leave:itis_hr_leave_extend.sick_leave_form_view +msgid "Cancel" +msgstr "Cancel" + +#. module: itis_hr_leave_extend +#: model:ir.model,name:itis_hr_leave_extend.model_res_company +msgid "Companies" +msgstr "Unternehmen" + +#. module: itis_hr_leave_extend +#: field:hr.holidays.timesheet,create_uid:0 field:hr.sick.leave,create_uid:0 +msgid "Created by" +msgstr "Erstellt von" + +#. module: itis_hr_leave_extend +#: field:hr.holidays.timesheet,create_date:0 field:hr.sick.leave,create_date:0 +msgid "Created on" +msgstr "Erstellt am" + +#. module: itis_hr_leave_extend +#: field:hr.holidays.timesheet,date:0 +msgid "Date" +msgstr "Datum" + +#. module: itis_hr_leave_extend +#: field:hr.sick.leave,end_date:0 +msgid "End Date" +msgstr "End Date" + +#. module: itis_hr_leave_extend +#: model:ir.actions.act_window,name:itis_hr_leave_extend.launch_sick_leave_wizard +msgid "Fill Employee Sick Leave" +msgstr "Krankheitstage erfassen" + +#. module: itis_hr_leave_extend +#: model:ir.actions.act_window,name:itis_hr_leave_extend.sick_leave_action +msgid "Fill Sick Leave" +msgstr "Krankheitstage erfassen" + +#. module: itis_hr_leave_extend +#: view:hr.sick.leave:itis_hr_leave_extend.sick_leave_form_view +msgid "Fill Sick Time" +msgstr "Krankentage buchen." + +#. module: itis_hr_leave_extend +#: field:hr.holidays.timesheet,holiday_id:0 +msgid "Holiday" +msgstr "Urlaub" + +#. module: itis_hr_leave_extend +#: field:hr.holidays.timesheet,duration:0 +msgid "Hours" +msgstr "Stunden" + +#. module: itis_hr_leave_extend +#: field:hr.holidays.timesheet,id:0 field:hr.sick.leave,id:0 +msgid "ID" +msgstr "ID" + +#. module: itis_hr_leave_extend +#: field:hr.holidays.timesheet,write_uid:0 field:hr.sick.leave,write_uid:0 +msgid "Last Updated by" +msgstr "Aktualisiert von" + +#. module: itis_hr_leave_extend +#: field:hr.holidays.timesheet,write_date:0 field:hr.sick.leave,write_date:0 +msgid "Last Updated on" +msgstr "Aktualisiert am" + +#. module: itis_hr_leave_extend +#: model:ir.model,name:itis_hr_leave_extend.model_hr_holidays +msgid "Leave" +msgstr "Urlaub" + +#. module: itis_hr_leave_extend +#: model:ir.model,name:itis_hr_leave_extend.model_hr_holidays_status +msgid "Leave Type" +msgstr "Abwesenheitstyp" + +#. module: itis_hr_leave_extend +#: code:addons/itis_hr_leave_extend/models/hr_holiday.py:148 +#, python-format +msgid "Please define cost unit for this employee." +msgstr "Bitte definieren Sie ein Konstenjournal für diesen Mitarbeiter." + +#. module: itis_hr_leave_extend +#: code:addons/itis_hr_leave_extend/models/hr_holiday.py:121 +#, python-format +msgid "" +"Please set the analytic account for Leaves.\n" +"Please contact your administrator for the same." +msgstr "" +"Bitte hinterlegen Sie die Kostenstelle für Urlaub.Bitte kontaktieren Sie " +"dafür Ihren Administrator." + +#. module: itis_hr_leave_extend +#: code:addons/itis_hr_leave_extend/wizard/hr_sick_leave.py:55 +#, python-format +msgid "" +"Please set the analytic account for Sick Leaves.\n" +"Please contact your administrator for the same." +msgstr "" +"Bitte hinterlegen Sie die Kostenstelle für Krankheit\n" +"Bitte kontaktieren Sie dafür ihren Administrator." + +#. module: itis_hr_leave_extend +#: field:hr.holidays.timesheet,sheet_id:0 +msgid "Sheet" +msgstr "Sheet" + +#. module: itis_hr_leave_extend +#: field:hr.sick.leave,start_date:0 +msgid "Start Date" +msgstr "Start Date" + +#. module: itis_hr_leave_extend +#: code:addons/itis_hr_leave_extend/models/hr_holiday.py:133 +#, python-format +msgid "" +"The Time period is allready closed. \n" +" Please contact the Human Resource Team if the leave request should be " +"confirmed nevertheless" +msgstr "" +"Die Zeiterfassung für den entsprechenden Zeitraum ist bereits " +"abgeschlossen. \n" +"Bitte wenden Sie sich an die Peronalabteilung, wenn der Antrag trotzdem " +"genehmigt werden soll." + +#. module: itis_hr_leave_extend +#: view:hr.sick.leave:itis_hr_leave_extend.sick_leave_form_view +msgid "This wizard is use to fill up the time sheet when employee is sick." +msgstr "" +"Mit dieser Maske kann die Krankheitszeit eines Mitarbeiters in dessen " +"Abwesenheit erfasst und gebucht werden." + +#. module: itis_hr_leave_extend +#: field:hr.holidays,holidays_timesheet_ids:0 +#: field:hr.holidays.timesheet,timesheet_id:0 +#: model:ir.model,name:itis_hr_leave_extend.model_hr_timesheet_sheet_sheet +msgid "Timesheet" +msgstr "Zeiterfassung" + +#. module: itis_hr_leave_extend +#: code:addons/itis_hr_leave_extend/models/hr_holiday.py:148 +#, python-format +msgid "User Error!" +msgstr "Benutzerfehler!" + +#. module: itis_hr_leave_extend +#: code:addons/itis_hr_leave_extend/wizard/hr_sick_leave.py:145 +#, python-format +msgid "" +"User Error! \n" +"Please define cost unit for this employee." +msgstr "" +"Fehler! \n" +"Bitte legen Sie eine Kostenstelle für den Mitarbeiter fest." + +#. module: itis_hr_leave_extend +#: view:hr.config.settings:itis_hr_leave_extend.view_human_resources_configuration +msgid "for Leave" +msgstr "für Urlaub" + +#. module: itis_hr_leave_extend +#: view:hr.config.settings:itis_hr_leave_extend.view_human_resources_configuration +msgid "for Overtime Leave" +msgstr "für Überstundenabbau" + +#. module: itis_hr_leave_extend +#: view:hr.sick.leave:itis_hr_leave_extend.sick_leave_form_view +msgid "or" +msgstr "or" diff --git a/itis_hr_leave_extend/i18n/en_US.po b/itis_hr_leave_extend/i18n/en_US.po new file mode 100644 index 0000000..abcfca2 --- /dev/null +++ b/itis_hr_leave_extend/i18n/en_US.po @@ -0,0 +1,835 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * itis_hr_extend +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-04-19 15:57+0000\n" +"PO-Revision-Date: 2017-04-19 17:59+0100\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: \n" +"X-Generator: Poedit 1.5.4\n" + +#. module: itis_hr_extend +#: field:hr.employee,five_years:0 +msgid "5-Jahres-Jubiläum" +msgstr "5 year anniversary" + +#. module: itis_hr_extend +#: selection:ld.change,type:0 +msgid "Abziehen" +msgstr "Substract" + +#. module: itis_hr_extend +#: view:itis.hr.contact:itis_hr_extend.itis_hr_contact_form +msgid "Address" +msgstr "Address" + +#. module: itis_hr_extend +#: field:hr.employee,active_employee:0 +msgid "Aktiv" +msgstr "active" + +#. module: itis_hr_extend +#: field:hr.holidays,approved_at:0 +msgid "Approved/Refuse At" +msgstr "Approved/Refuse At" + +#. module: itis_hr_extend +#: field:hr.holidays,approved_by:0 +msgid "Approved/Refuse By" +msgstr "Approved/Refuse By" + +#. module: itis_hr_extend +#: selection:hr.leave.journal,type:0 +msgid "Ausgleich" +msgstr "Compensation" + +#. module: itis_hr_extend +#: field:hr.employee,disability_limited_until:0 +msgid "Befristet bis" +msgstr "Limited until" + +#. module: itis_hr_extend +#: field:hr.contract,limitation_reason:0 +msgid "Befristungsgrund" +msgstr "reason of Limitation" + +#. module: itis_hr_extend +#: field:hr.leave.journal,description:0 field:hr.leave.journal,name:0 +msgid "Begründung" +msgstr "reason" + +#. module: itis_hr_extend +#: code:addons/itis_hr_extend/models/hr_employee.py:280 +#: code:addons/itis_hr_extend/models/hr_employee.py:326 +#, python-format +msgid "Berechnung Urlaub zu Jahresbeginn" +msgstr "calculation year leaves" + +#. module: itis_hr_extend +#: field:hr.employee,bereich:0 +msgid "Bereich" +msgstr "Section" + +#. module: itis_hr_extend +#: field:itis_confession,name:0 field:itis_limitation_reason,name:0 +msgid "Bezeichnung" +msgstr "Name" + +#. module: itis_hr_extend +#: view:create.fte:itis_hr_extend.fte_wiz_form_view +#: view:ld.change:itis_hr_extend.ld_change_form_view +#: view:ot.change:itis_hr_extend.ot_change_form_view +msgid "Cancel" +msgstr "Cancel" + +#. module: itis_hr_extend +#: view:itis.hr.contact:itis_hr_extend.itis_hr_contact_form +#: field:itis.hr.contact,city:0 +msgid "City" +msgstr "City" + +#. module: itis_hr_extend +#: view:create.fte:itis_hr_extend.fte_wiz_form_view +msgid "Click 'Generate' button to Generate FTE report" +msgstr "Click 'Generate' button to Generate FTE report" + +#. module: itis_hr_extend +#: field:employee.report.data,color:0 +msgid "Color" +msgstr "Color" + +#. module: itis_hr_extend +#: model:ir.actions.act_window,name:itis_hr_extend.action_itis_hr_contact +#: view:itis.hr.contact:itis_hr_extend.itis_hr_contact_tree +msgid "Contacts" +msgstr "Contacts" + +#. module: itis_hr_extend +#: model:ir.model,name:itis_hr_extend.model_hr_contract +msgid "Contract" +msgstr "Contract" + +#. module: itis_hr_extend +#: field:hr.leave.journal,contract_id:0 +msgid "Contract id" +msgstr "Contract id" + +#. module: itis_hr_extend +#: view:itis.hr.contact:itis_hr_extend.itis_hr_contact_form +#: field:itis.hr.contact,country_id:0 +msgid "Country" +msgstr "Country" + +#. module: itis_hr_extend +#: field:create.fte,create_uid:0 field:employee.report,create_uid:0 +#: field:employee.report.data,create_uid:0 field:fte.records,create_uid:0 +#: field:fte.report,create_uid:0 field:hr.employee.fte,create_uid:0 +#: field:hr.family.status,create_uid:0 field:hr.health.insurance,create_uid:0 +#: field:hr.leave.journal,create_uid:0 field:itis.hr.contact,create_uid:0 +#: field:itis.leave.days.calc.error,create_uid:0 +#: field:itis_confession,create_uid:0 +#: field:itis_employee_children,create_uid:0 +#: field:itis_limitation_reason,create_uid:0 field:ld.change,create_uid:0 +#: field:ot.change,create_uid:0 +msgid "Created by" +msgstr "Created by" + +#. module: itis_hr_extend +#: field:create.fte,create_date:0 field:employee.report,create_date:0 +#: field:employee.report.data,create_date:0 field:fte.records,create_date:0 +#: field:fte.report,create_date:0 field:hr.employee.fte,create_date:0 +#: field:hr.family.status,create_date:0 +#: field:hr.health.insurance,create_date:0 +#: field:hr.leave.journal,create_date:0 field:itis.hr.contact,create_date:0 +#: field:itis.leave.days.calc.error,create_date:0 +#: field:itis_confession,create_date:0 +#: field:itis_employee_children,create_date:0 +#: field:itis_limitation_reason,create_date:0 field:ld.change,create_date:0 +#: field:ot.change,create_date:0 +msgid "Created on" +msgstr "Created on" + +#. module: itis_hr_extend +#: field:employee.report,name:0 field:fte.report,name:0 +msgid "Date" +msgstr "Date" + +#. module: itis_hr_extend +#: field:fte.records,department_id:0 field:hr.employee.fte,department_id:0 +msgid "Department" +msgstr "Department" + +#. module: itis_hr_extend +#: field:fte.records,diff_fte:0 +msgid "Difference FTE" +msgstr "Difference FTE" + +#. module: itis_hr_extend +#: field:itis.hr.contact,email:0 +msgid "Email" +msgstr "Email" + +#. module: itis_hr_extend +#: field:employee.report.data,employee_id:0 field:hr.employee.fte,emp_id:0 +#: model:ir.model,name:itis_hr_extend.model_hr_employee +msgid "Employee" +msgstr "Employee" + +#. module: itis_hr_extend +#: field:employee.report.data,employee_report_id:0 +#: model:ir.actions.act_window,name:itis_hr_extend.employee_report_action +#: model:ir.ui.menu,name:itis_hr_extend.menu_employee_report +msgid "Employee Report" +msgstr "Employee Report" + +#. module: itis_hr_extend +#: field:hr.leave.journal,employee_id:0 +msgid "Employee id" +msgstr "Employee id" + +#. module: itis_hr_extend +#: view:employee.report:itis_hr_extend.itis_employee_report_tree +#: field:employee.report,employee_ids:0 +msgid "Employees" +msgstr "Employees" + +#. module: itis_hr_extend +#: field:fte.records,fte:0 field:hr.employee.fte,fte:0 +msgid "FTE" +msgstr "FTE" + +#. module: itis_hr_extend +#: view:fte.records:itis_hr_extend.itis_fte_records_form +#: view:fte.report:itis_hr_extend.itis_fte_report_form +#: field:fte.report,fte_ids:0 +msgid "FTE Records" +msgstr "FTE Records" + +#. module: itis_hr_extend +#: code:addons/itis_hr_extend/wizard/fte_wizard.py:108 +#: field:fte.records,fte_id:0 +#: view:fte.report:itis_hr_extend.itis_fte_report_tree +#: model:ir.actions.act_window,name:itis_hr_extend.fte_report_action +#: model:ir.actions.act_window,name:itis_hr_extend.fte_window_action +#, python-format +msgid "FTE Report" +msgstr "FTE Report" + +#. module: itis_hr_extend +#: model:ir.ui.menu,name:itis_hr_extend.menu_fte_report +msgid "FTE Reports" +msgstr "FTE Reports" + +#. module: itis_hr_extend +#: view:hr.employee:itis_hr_extend.hr_hr_employee_view_form_itis +msgid "FTE(%)" +msgstr "FTE(%)" + +#. module: itis_hr_extend +#: view:hr.employee:itis_hr_extend.hr_hr_employee_view_form_itis +#: field:hr.employee,fte_ids:0 +msgid "FTEs" +msgstr "FTEs" + +#. module: itis_hr_extend +#: view:hr.family.status:itis_hr_extend.itis_family_status_form +#: view:hr.family.status:itis_hr_extend.itis_family_status_tree +#: model:ir.actions.act_window,name:itis_hr_extend.hr_family_status_action +#: model:ir.ui.menu,name:itis_hr_extend.menu_family_status +#: view:itis.leave.days.calc.error:itis_hr_extend.itis_leave_days_calc_error_tree +msgid "Family Status" +msgstr "Family Status" + +#. module: itis_hr_extend +#: field:itis.hr.contact,fax:0 +msgid "Fax" +msgstr "Fax" + +#. module: itis_hr_extend +#: model:ir.actions.act_window,name:itis_hr_extend.leave_days_calc_error_action +#: model:ir.ui.menu,name:itis_hr_extend.menu_days_calc_error +msgid "Fehler Urlaubsberechnung" +msgstr "leave Calculation Errors" + +#. module: itis_hr_extend +#: code:addons/itis_hr_extend/models/hr_employee.py:384 +#, python-format +msgid "" +"Fehler automatische Kalkulation durch keine durchgängigen Arbeitsverträge" +msgstr "error automatic calculation due to gaps between contracts" + +#. module: itis_hr_extend +#: code:addons/itis_hr_extend/models/hr_employee.py:387 +#, python-format +msgid "Fehler automatische Kalkulation durch Änderung Urlaubsanspruch" +msgstr "error automatic calculation due to change of base leave" + +#. module: itis_hr_extend +#: code:addons/itis_hr_extend/models/hr_employee.py:390 +#, python-format +msgid "Fehler automatische Kalkulation durch Änderung Wochenarbeitstage" +msgstr "error automatic calculation due to change of work days a week" + +#. module: itis_hr_extend +#: code:addons/itis_hr_extend/models/hr_employee.py:317 +#, python-format +msgid "Fehler in Berechnung" +msgstr "error in calculation" + +#. module: itis_hr_extend +#: field:itis.leave.days.calc.error,error:0 +msgid "Fehlermeldung" +msgstr "error meassage" + +#. module: itis_hr_extend +#: field:itis_employee_children,birth_date:0 +msgid "Geburtsdatum" +msgstr "birthdate" + +#. module: itis_hr_extend +#: field:hr.employee,birth_name:0 +msgid "Geburtsname" +msgstr "birth name" + +#. module: itis_hr_extend +#: view:create.fte:itis_hr_extend.fte_wiz_form_view +msgid "Generate" +msgstr "Generate" + +#. module: itis_hr_extend +#: model:ir.ui.menu,name:itis_hr_extend.menu_fte_report_generate +msgid "Generate FTE Report" +msgstr "Generate FTE Report" + +#. module: itis_hr_extend +#: field:employee.report.data,sum_leaves:0 +msgid "Gesamtanspruch" +msgstr "Sum Leaves" + +#. module: itis_hr_extend +#: model:ir.ui.menu,name:itis_hr_extend.itis_hr_contact_menu +msgid "HR Contacts" +msgstr "HR Contacts" + +#. module: itis_hr_extend +#: view:hr.employee:itis_hr_extend.hr_hr_employee_view_form_itis +#: view:hr.employee:itis_hr_extend.view_employee_form_inherit_itis +msgid "HR Settings" +msgstr "HR Settings" + +#. module: itis_hr_extend +#: view:hr.health.insurance:itis_hr_extend.itis_health_insurance_form +#: view:hr.health.insurance:itis_hr_extend.itis_health_insurance_tree +#: model:ir.actions.act_window,name:itis_hr_extend.hr_health_action +#: model:ir.ui.menu,name:itis_hr_extend.menu_health_insurance +msgid "Health Insurance" +msgstr "Health Insurance" + +#. module: itis_hr_extend +#: selection:ld.change,type:0 +msgid "Hinzufügen" +msgstr "Add" + +#. module: itis_hr_extend +#: field:create.fte,id:0 field:employee.report,id:0 +#: field:employee.report.data,id:0 field:fte.records,id:0 +#: field:fte.report,id:0 field:hr.employee.fte,id:0 +#: field:hr.family.status,id:0 field:hr.health.insurance,id:0 +#: field:hr.leave.journal,id:0 field:itis.hr.contact,id:0 +#: field:itis.leave.days.calc.error,id:0 field:itis_confession,id:0 +#: field:itis_employee_children,id:0 field:itis_limitation_reason,id:0 +#: field:ld.change,id:0 field:ot.change,id:0 +msgid "ID" +msgstr "ID" + +#. module: itis_hr_extend +#: field:hr.holidays,is_ot_leave:0 +msgid "Is OT Leave" +msgstr "Is Overtime Leave" + +#. module: itis_hr_extend +#: selection:hr.employee,disability:0 +msgid "Ja" +msgstr "Yes" + +#. module: itis_hr_extend +#: field:hr.leave.journal,year:0 field:itis.leave.days.calc.error,year:0 +msgid "Jahr" +msgstr "Year" + +#. module: itis_hr_extend +#: code:addons/itis_hr_extend/models/hr_employee.py:304 +#, python-format +msgid "Kein Vertrag am 01.Januar vorhanden" +msgstr "No contract on January 01." + +#. module: itis_hr_extend +#: view:hr.employee:itis_hr_extend.hr_hr_employee_view_form_itis +#: field:hr.employee,children_ids:0 +msgid "Kinder" +msgstr "Children" + +#. module: itis_hr_extend +#: field:hr.employee,confession:0 +msgid "Konfession" +msgstr "Confession" + +#. module: itis_hr_extend +#: field:hr.employee,health_insurance:0 +msgid "Krankenkasse" +msgstr "health Insurance company" + +#. module: itis_hr_extend +#: field:create.fte,write_uid:0 field:employee.report,write_uid:0 +#: field:employee.report.data,write_uid:0 field:fte.records,write_uid:0 +#: field:fte.report,write_uid:0 field:hr.employee.fte,write_uid:0 +#: field:hr.family.status,write_uid:0 field:hr.health.insurance,write_uid:0 +#: field:hr.leave.journal,write_uid:0 field:itis.hr.contact,write_uid:0 +#: field:itis.leave.days.calc.error,write_uid:0 +#: field:itis_confession,write_uid:0 field:itis_employee_children,write_uid:0 +#: field:itis_limitation_reason,write_uid:0 field:ld.change,write_uid:0 +#: field:ot.change,write_uid:0 +msgid "Last Updated by" +msgstr "Last Updated by" + +#. module: itis_hr_extend +#: field:create.fte,write_date:0 field:employee.report,write_date:0 +#: field:employee.report.data,write_date:0 field:fte.records,write_date:0 +#: field:fte.report,write_date:0 field:hr.employee.fte,write_date:0 +#: field:hr.family.status,write_date:0 field:hr.health.insurance,write_date:0 +#: field:hr.leave.journal,write_date:0 field:itis.hr.contact,write_date:0 +#: field:itis.leave.days.calc.error,write_date:0 +#: field:itis_confession,write_date:0 +#: field:itis_employee_children,write_date:0 +#: field:itis_limitation_reason,write_date:0 field:ld.change,write_date:0 +#: field:ot.change,write_date:0 +msgid "Last Updated on" +msgstr "Last Updated on" + +#. module: itis_hr_extend +#: model:ir.model,name:itis_hr_extend.model_hr_holidays +msgid "Leave" +msgstr "Leave" + +#. module: itis_hr_extend +#: field:ld.change,leave_day:0 field:ot.change,leave_day:0 +msgid "Leave Day" +msgstr "Leave Day" + +#. module: itis_hr_extend +#: field:hr.leave.journal,leave_id:0 +msgid "Leave id" +msgstr "Leave id" + +#. module: itis_hr_extend +#: field:hr.employee,leave_journal_ids:0 +msgid "Leave journal ids" +msgstr "Leave journal ids" + +#. module: itis_hr_extend +#: field:hr.leave.journal,leave_type:0 +msgid "Leave type" +msgstr "Leave type" + +#. module: itis_hr_extend +#: model:ir.actions.act_window,name:itis_hr_extend.act_hr_leaves_overview +msgid "Leaves" +msgstr "Leaves" + +#. module: itis_hr_extend +#: field:hr.holidays,ljournal_ids:0 +msgid "Ljournal ids" +msgstr "Ljournal ids" + +#. module: itis_hr_extend +#: selection:hr.leave.journal,type:0 +msgid "Manuell" +msgstr "Manual" + +#. module: itis_hr_extend +#: code:addons/itis_hr_extend/models/hr_employee.py:295 +#: code:addons/itis_hr_extend/models/hr_employee.py:302 +#, python-format +msgid "Mehr als ein Vertrag zum 01.Januar" +msgstr "More than one contract on January 01." + +#. module: itis_hr_extend +#: model:ir.model,name:itis_hr_extend.model_mail_message +msgid "Message" +msgstr "Message" + +#. module: itis_hr_extend +#: field:itis.leave.days.calc.error,name:0 +#: field:itis_employee_children,parent_id:0 +msgid "Mitarbeiter" +msgstr "Employee" + +#. module: itis_hr_extend +#: view:hr.employee:itis_hr_extend.hr_hr_employee_view_form_itis +msgid "Mitarbeiter/in" +msgstr "Employee" + +#. module: itis_hr_extend +#: field:itis.hr.contact,mobile:0 +msgid "Mobile" +msgstr "Mobile" + +#. module: itis_hr_extend +#: view:hr.employee:itis_hr_extend.view_employee_form_inherit_itis +msgid "Monatlich Lohnrelevante Informationen" +msgstr "salary export information" + +#. module: itis_hr_extend +#: field:hr.employee,second_name:0 +msgid "Nachname" +msgstr "Surname" + +#. module: itis_hr_extend +#: field:hr.health.insurance,name:0 +#: view:itis.hr.contact:itis_hr_extend.itis_hr_contact_form +#: view:itis.hr.contact:itis_hr_extend.itis_hr_contact_tree +#: field:itis.hr.contact,name:0 field:itis_employee_children,name:0 +msgid "Name" +msgstr "Name" + +#. module: itis_hr_extend +#: code:addons/itis_hr_extend/models/employee_report.py:42 +#, python-format +msgid "No associated employee found with user" +msgstr "No associated employee found with user" + +#. module: itis_hr_extend +#: field:hr.employee,emergency_contact:0 +msgid "Notfallkontakt" +msgstr "emergency contact" + +#. module: itis_hr_extend +#: code:addons/itis_hr_extend/models/hr_holiday.py:106 +#: code:addons/itis_hr_extend/models/hr_holiday.py:119 +#, python-format +msgid "Only the Manager of this employee can approve this leave request." +msgstr "Only the Manager of this employee can approve this leave request." + +#. module: itis_hr_extend +#: field:employee.report.data,overtime_count:0 +#: field:hr.employee,overtime_count:0 field:ot.change,ot_time:0 +msgid "Overtime Count" +msgstr "Overtime Count" + +#. module: itis_hr_extend +#: model:hr.holidays.status,name:itis_hr_extend.itis_leave_overtime +msgid "Overtime Leave" +msgstr "Overtime Leave" + +#. module: itis_hr_extend +#: code:addons/itis_hr_extend/models/hr_employee.py:180 +#: code:addons/itis_hr_extend/models/hr_employee.py:202 +#, python-format +msgid "Overtime has been chagned from %s to %s.
Reason : %s" +msgstr "Overtime has been chagned from %s to %s.
Reason : %s" + +#. module: itis_hr_extend +#: field:itis.hr.contact,phone:0 +msgid "Phone" +msgstr "Phone" + +#. module: itis_hr_extend +#: field:fte.records,planned_fte:0 field:hr.department,planned_fte:0 +msgid "Planned FTE" +msgstr "Planned FTE" + +#. module: itis_hr_extend +#: code:addons/itis_hr_extend/models/hr_holiday.py:295 +#: code:addons/itis_hr_extend/models/hr_holiday.py:315 +#, python-format +msgid "Please create a leave request for every year." +msgstr "Please create a leave request for every year." + +#. module: itis_hr_extend +#: field:ld.change,reason:0 field:ot.change,reason:0 +msgid "Reason" +msgstr "reason" + +#. module: itis_hr_extend +#: model:ir.ui.menu,name:itis_hr_extend.menu_hr_reports +msgid "Reports" +msgstr "Reports" + +#. module: itis_hr_extend +#: selection:hr.leave.journal,year_type:0 +msgid "Restanspruch" +msgstr "Remainig last year leaves" + +#. module: itis_hr_extend +#: field:hr.employee,disability:0 +msgid "Schwerbehinderung" +msgstr "Disability" + +#. module: itis_hr_extend +#: view:hr.leave.journal:itis_hr_extend.itis_hr_leave_journal_form +msgid "Search Leave" +msgstr "Search Leave" + +#. module: itis_hr_extend +#: view:hr.employee:itis_hr_extend.hr_hr_employee_view_form_itis +msgid "Sozialversicherungsnummer" +msgstr "social security number" + +#. module: itis_hr_extend +#: view:itis.hr.contact:itis_hr_extend.itis_hr_contact_form +#: field:itis.hr.contact,state_id:0 +msgid "State" +msgstr "State" + +#. module: itis_hr_extend +#: field:hr.family.status,name:0 +msgid "Status" +msgstr "Status" + +#. module: itis_hr_extend +#: view:hr.employee:itis_hr_extend.hr_hr_employee_view_form_itis +msgid "Steuer-ID" +msgstr "tax-ID" + +#. module: itis_hr_extend +#: field:hr.employee,taxclass:0 +msgid "Steuerklasse" +msgstr "tax category" + +#. module: itis_hr_extend +#: selection:hr.employee,taxclass:0 +msgid "Steuerklasse 1" +msgstr "Steuerklasse 1" + +#. module: itis_hr_extend +#: selection:hr.employee,taxclass:0 +msgid "Steuerklasse 2" +msgstr "Steuerklasse 2" + +#. module: itis_hr_extend +#: selection:hr.employee,taxclass:0 +msgid "Steuerklasse 3" +msgstr "Steuerklasse 3" + +#. module: itis_hr_extend +#: selection:hr.employee,taxclass:0 +msgid "Steuerklasse 4" +msgstr "Steuerklasse 4" + +#. module: itis_hr_extend +#: selection:hr.employee,taxclass:0 +msgid "Steuerklasse 5" +msgstr "Steuerklasse 5" + +#. module: itis_hr_extend +#: selection:hr.employee,taxclass:0 +msgid "Steuerklasse 6" +msgstr "Steuerklasse 6" + +#. module: itis_hr_extend +#: field:itis.hr.contact,street:0 +msgid "Street" +msgstr "Street" + +#. module: itis_hr_extend +#: view:itis.hr.contact:itis_hr_extend.itis_hr_contact_form +msgid "Street 2..." +msgstr "Street 2..." + +#. module: itis_hr_extend +#: view:itis.hr.contact:itis_hr_extend.itis_hr_contact_form +msgid "Street..." +msgstr "Street..." + +#. module: itis_hr_extend +#: field:itis.hr.contact,street2:0 +msgid "Street2" +msgstr "Street2" + +#. module: itis_hr_extend +#: field:hr.leave.journal,leave_hours:0 +#: selection:hr.leave.journal,leave_type:0 +msgid "Stunden" +msgstr "Hours" + +#. module: itis_hr_extend +#: field:hr.leave.journal,leave_days:0 selection:hr.leave.journal,leave_type:0 +msgid "Tage" +msgstr "Days" + +#. module: itis_hr_extend +#: view:hr.employee:itis_hr_extend.hr_hr_employee_view_form_itis +msgid "Telefon (interne Durchwahl)" +msgstr "Telefone number (internal)" + +#. module: itis_hr_extend +#: code:addons/itis_hr_extend/models/hr_holiday.py:71 +#, python-format +msgid "" +"The number of remaining leaves is not sufficient for this leave type.\n" +"Please verify also the leaves waiting for validation." +msgstr "" +"The number of remaining leaves is not sufficient for this leave type.Please " +"verify also the leaves waiting for validation." + +#. module: itis_hr_extend +#: code:addons/itis_hr_extend/models/hr_employee.py:223 +#, python-format +msgid "There are 2 contracts assigned to this employee." +msgstr "There are 2 contracts assigned to this employee." + +#. module: itis_hr_extend +#: view:hr.contract:itis_hr_extend.hr_contract_view_form_itis +#: view:hr.employee:itis_hr_extend.hr_hr_employee_view_form_itis +msgid "True" +msgstr "True" + +#. module: itis_hr_extend +#: field:hr.leave.journal,type:0 field:ld.change,type:0 +msgid "Type" +msgstr "Type" + +#. module: itis_hr_extend +#: code:addons/itis_hr_extend/models/hr_employee.py:258 +#: code:addons/itis_hr_extend/models/hr_employee.py:269 +#, python-format +msgid "Umwandlung Resturlaub" +msgstr "transfer remaining leaves" + +#. module: itis_hr_extend +#: view:hr.employee:itis_hr_extend.hr_hr_employee_view_form_itis +msgid "Update" +msgstr "Update" + +#. module: itis_hr_extend +#: field:hr.contract,base_leaves:0 +msgid "Urlaubsanspruch" +msgstr "leave entitlement" + +#. module: itis_hr_extend +#: view:hr.employee:itis_hr_extend.hr_hr_employee_view_form_itis +msgid "Urlaubsjournal" +msgstr "Leave Journal" + +#. module: itis_hr_extend +#: code:addons/itis_hr_extend/models/employee_report.py:44 +#, python-format +msgid "User is associated with multiple employee" +msgstr "User is associated with multiple employee" + +#. module: itis_hr_extend +#: code:addons/itis_hr_extend/models/hr_employee.py:420 +#, python-format +msgid "Verfall Resturlaub" +msgstr "deletion remaining last year leaves" + +#. module: itis_hr_extend +#: selection:hr.leave.journal,type:0 +msgid "Vertraglich" +msgstr "based on contract" + +#. module: itis_hr_extend +#: view:hr.employee:itis_hr_extend.hr_hr_employee_view_form_itis +msgid "Vertragsinformationen" +msgstr "contract informationen" + +#. module: itis_hr_extend +#: field:hr.employee,surname:0 +msgid "Vorname" +msgstr "First name" + +#. module: itis_hr_extend +#: field:hr.employee,wage_info:0 +msgid "Wage Information" +msgstr "Wage Information" + +#. module: itis_hr_extend +#: field:hr.leave.journal,year_type:0 +msgid "Year type" +msgstr "Year type" + +#. module: itis_hr_extend +#: view:itis.hr.contact:itis_hr_extend.itis_hr_contact_form +msgid "ZIP" +msgstr "ZIP" + +#. module: itis_hr_extend +#: field:hr.employee,sign_permission:0 +msgid "Zeichnungsbefugnis" +msgstr "signing rights" + +#. module: itis_hr_extend +#: field:itis.hr.contact,zip:0 +msgid "Zip" +msgstr "Zip" + +#. module: itis_hr_extend +#: selection:hr.leave.journal,type:0 +msgid "Zusatzurlaub" +msgstr "additional leaves" + +#. module: itis_hr_extend +#: selection:hr.leave.journal,year_type:0 +msgid "aktuell" +msgstr "actual" + +#. module: itis_hr_extend +#: view:hr.payslip:itis_hr_extend.hr_payroll_view_hr_payslip_form_itis +msgid "base.group_hr_payroll_manager" +msgstr "base.group_hr_payroll_manager" + +#. module: itis_hr_extend +#: view:hr.holidays:itis_hr_extend.hr_holidays_view_form_itis +msgid "base.group_user" +msgstr "base.group_user" + +#. module: itis_hr_extend +#: field:hr.leave.journal,leave_end:0 +msgid "bis" +msgstr "to" + +#. module: itis_hr_extend +#: view:hr.employee:itis_hr_extend.hr_hr_employee_view_form_itis +msgid "e.g. Part Time" +msgstr "e.g. Part Time" + +#. module: itis_hr_extend +#: view:hr.holidays:itis_hr_extend.hr_holidays_view_form_itis +msgid "hours" +msgstr "hours" + +#. module: itis_hr_extend +#: selection:hr.employee,disability:0 +msgid "nein" +msgstr "no" + +#. module: itis_hr_extend +#: view:create.fte:itis_hr_extend.fte_wiz_form_view +#: view:ld.change:itis_hr_extend.ld_change_form_view +#: view:ot.change:itis_hr_extend.ot_change_form_view +msgid "or" +msgstr "or" + +#. module: itis_hr_extend +#: field:hr.leave.journal,leave_start:0 +msgid "von" +msgstr "of" + +#. module: itis_hr_extend +#: field:hr.employee,emergency_contact2:0 +msgid "zweiter Notfallkontakt" +msgstr "second emergency contact" + +#. module: itis_hr_extend +#: code:addons/itis_hr_extend/models/hr_employee.py:307 +#, python-format +msgid "Überschneidende Verträge" +msgstr "two contracts on the same date" diff --git a/itis_hr_leave_extend/models/__init__.py b/itis_hr_leave_extend/models/__init__.py new file mode 100644 index 0000000..10c6dda --- /dev/null +++ b/itis_hr_leave_extend/models/__init__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + +from . import hr_holiday diff --git a/itis_hr_leave_extend/models/hr_holiday.py b/itis_hr_leave_extend/models/hr_holiday.py new file mode 100644 index 0000000..3d7ad1e --- /dev/null +++ b/itis_hr_leave_extend/models/hr_holiday.py @@ -0,0 +1,333 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + +from openerp import models, api, fields, _ +from openerp.osv import osv +from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT +from datetime import datetime, timedelta +from openerp.exceptions import Warning +import math +from openerp import SUPERUSER_ID + + +class HRHolidayTimesheet(models.Model): + + _name = "hr.holidays.timesheet" + + date = fields.Date('Date') + holiday_id = fields.Many2one("hr.holidays", "Holiday") + sheet_id = fields.Many2one('hr_timesheet_sheet.sheet', 'Sheet') + timesheet_id = fields.Many2one("hr.analytic.timesheet", "Timesheet") + duration = fields.Float("Hours") + +class HRTimesheetSheet(models.Model): + + _inherit = "hr_timesheet_sheet.sheet" + + @api.model + def create(self, values): + res = super(HRTimesheetSheet, self).create(values) + res.calc_leave_hours() + return res + + @api.multi + def calc_leave_hours(self): + leave_obj = self.env['hr.holidays'] + leave_recs = leave_obj.search([('employee_id', '=', self.employee_id.id), ('state', '=', 'validate'), ('state', '!=', 'refuse')]) + for leave in leave_recs: + leave_processed = True + for hl_ts_rec in leave.holidays_timesheet_ids: + if not hl_ts_rec.timesheet_id: + #print"Calc leave hours - No Timesheet_id", hl_ts_rec + leave_processed = False + if not leave_processed: + leave.make_timesheet_entry() + +class HRHoliday(models.Model): + + _inherit = "hr.holidays" + + holidays_timesheet_ids = fields.One2many("hr.holidays.timesheet", "holiday_id", "Timesheet") + + @api.multi + def holidays_refuse(self): + res = super(HRHoliday, self).holidays_refuse() + for hl_ts_rec in self.sudo().holidays_timesheet_ids: + hl_ts_rec.timesheet_id.unlink() + hl_ts_rec.write({'sheet_id': False}) + return res + + @api.multi + def holidays_validate(self): + res = super(HRHoliday, self).holidays_validate() + self.make_timesheet_entry() + return res + + @api.multi + def make_holidays_timesheet(self, res): + result = [] + holi_ts_obj = self.env['hr.holidays.timesheet'] + cur_recs = holi_ts_obj.search([('holiday_id', '=', self.id)]) + res_days = res.keys() + for rec in cur_recs: + if rec.date not in res_days: + rec.unlink() + for day, duration in res.iteritems(): + holiday = None + holiday = self.env['itis.holiday'].search([('date', '=', day)]) + if holiday: + continue + cur_rec = holi_ts_obj.search([('holiday_id', '=', self.id), ('date', '=', day)]) + if not cur_rec.id: + cur_rec = holi_ts_obj.create({'date': day, 'duration': duration, "holiday_id": self.id}) + if cur_rec.duration != duration: + cur_rec.update({'duration': duration}) + result.append(cur_rec) + return result + + @api.multi + def make_timesheet_entry(self): + res = self.count_day_hours_leave() + res = self.make_holidays_timesheet(res) + account_id = False + if self.is_ot_leave: + account_id = self.env.user.company_id.ot_leave_account_id + else: + account_id = self.env.user.company_id.leave_account_id + if not account_id: + raise Warning(_('Please set the analytic account for Leaves.\nPlease contact your administrator for the same.')) + sheet_obj = self.env['hr_timesheet_sheet.sheet'] + timesheets = sheet_obj.search([("employee_id", '=', self.employee_id.id)]) + for hl_ts_rec in res: + if hl_ts_rec.timesheet_id: + continue + cur_day = datetime.strptime(hl_ts_rec.date, DEFAULT_SERVER_DATE_FORMAT) + for timesheet in timesheets: + ts_date_from = datetime.strptime(timesheet.date_from, DEFAULT_SERVER_DATE_FORMAT) + ts_date_to = datetime.strptime(timesheet.date_to, DEFAULT_SERVER_DATE_FORMAT) + if cur_day >= ts_date_from and cur_day <= ts_date_to: + if timesheet.state != 'draft': + continue + #raise Warning(_('The Time period is allready closed. \n Please contact the Human Resource Team if the leave request should be confirmed nevertheless')) + #print"cur_day ", cur_day + ana_ts_id = self.create_timesheet(account_id, timesheet, hl_ts_rec.duration, hl_ts_rec.date) + hl_ts_rec.write({'timesheet_id': ana_ts_id[0], 'sheet_id': timesheet.id}) + return True + + @api.one + def create_timesheet(self, account_id, sheet, duration, day): + timesheet_obj = self.pool.get('hr.analytic.timesheet') + cr = self.env.cr + uid = self.env.uid + emp_obj = self.env['hr.employee'] + hour = duration + res = timesheet_obj.default_get(cr, uid, ['product_id','product_uom_id']) + # res.update({ + # 'general_account_id': False, + # }) + if not res['product_id']: + res['product_id'] = 1 + if not res['product_uom_id']: + res['product_uom_id'] = 5 + if not res['product_uom_id']: + raise osv.except_osv(_('User Error!'), _('Please define cost unit for this employee.')) + up = timesheet_obj.on_change_unit_amount(cr, uid, False, res['product_id'], hour,False, res['product_uom_id'])['value'] + print"UP ", up + res['name'] = "Leave on " + day + res['account_id'] = account_id.id + res['unit_amount'] = hour + emp_journal = emp_obj.search([('user_id', '=', self.employee_id.user_id.id)]).journal_id + res['journal_id'] = emp_journal and emp_journal.id or False + res.update(up) + up = timesheet_obj.on_change_account_id(cr, uid, [], res['account_id']).get('value', {}) + res.update(up) + print"RES ", res + # if not res['general_account_id']: + # res['general_account_id'] = 698 + res.update({ + 'date': day, + 'user_id': self.employee_id.user_id.id, + 'sheet_id': sheet.id, + }) + return timesheet_obj.create(cr, SUPERUSER_ID, res) + + @api.multi + def count_day_hours_leave(self): + res = {} + date_from = datetime.strptime(self.date_from, DEFAULT_SERVER_DATETIME_FORMAT) + date_to = datetime.strptime(self.date_to, DEFAULT_SERVER_DATETIME_FORMAT) + same_day = self.check_same_day(date_from, date_to) + temp_date = date_from + day_hours = 0.0 + weekday = temp_date.weekday() + for contract in self.employee_id.contract_ids: + cont_start_date = datetime.strptime(contract.date_start, DEFAULT_SERVER_DATE_FORMAT) + cont_end_date = False + if not contract.date_end: + if cont_start_date <= temp_date: + if same_day: + cur_hour = self.get_day_hours(date_from, contract.working_hours.attendance_ids) + day_hours = cur_hour + day_str = datetime.strftime(temp_date, DEFAULT_SERVER_DATETIME_FORMAT).split(" ")[0] + new_hour = res.get(day_str, 0.0) + cur_hour + if self.leave_selection =='half_day': + new_hour =new_hour/2 + res.update({day_str: new_hour}) + else: + fday_cur_hour = self.get_day_hours(date_from, contract.working_hours.attendance_ids) + day_hours += fday_cur_hour + lday_cur_hour = self.get_day_hours(date_to, contract.working_hours.attendance_ids) + day_hours = lday_cur_hour + fday_str = datetime.strftime(date_from, DEFAULT_SERVER_DATETIME_FORMAT).split(" ")[0] + fday_new_hour = res.get(fday_str, 0.0) + fday_cur_hour + if self.leave_selection =='half_day': + fday_new_hour =fday_new_hour/2 + res.update({fday_str: fday_new_hour}) + lday_str = datetime.strftime(date_to, DEFAULT_SERVER_DATETIME_FORMAT).split(" ")[0] + lday_new_hour = res.get(lday_str, 0.0) + lday_cur_hour + if self.leave_selection_date_to =='half_day': + lday_new_hour =lday_new_hour/2 + #if temp_date == self.start_date and self.start_date_leave_selection == 'half_day': + # lday_new_hour =lday_new_hour/2 + #elif temp_date == self.end_date and self.end_date_leave_selection == 'half_day': + # lday_new_hour =lday_new_hour/2 + res.update({lday_str: lday_new_hour}) + else: + cont_end_date = datetime.strptime(contract.date_end, DEFAULT_SERVER_DATE_FORMAT) + cont_end_date += timedelta(days=1) + if cont_start_date <= temp_date and cont_end_date >= temp_date: + if same_day: + cur_hour = self.get_day_hours(date_from, contract.working_hours.attendance_ids) + day_hours += cur_hour + day_str = datetime.strftime(temp_date, DEFAULT_SERVER_DATETIME_FORMAT).split(" ")[0] + new_hour = res.get(day_str, 0.0) + cur_hour + if self.leave_selection =='half_day': + new_hour =new_hour/2 + res.update({day_str: new_hour}) + else: + fday_cur_hour = self.get_day_hours(date_from, contract.working_hours.attendance_ids) + day_hours += fday_cur_hour + lday_cur_hour = self.get_day_hours(date_to, contract.working_hours.attendance_ids) + day_hours = lday_cur_hour + fday_str = datetime.strftime(date_from, DEFAULT_SERVER_DATETIME_FORMAT).split(" ")[0] + fday_new_hour = res.get(fday_str, 0.0) + fday_cur_hour + if self.leave_selection =='half_day': + fday_new_hour =fday_new_hour/2 + res.update({fday_str: fday_new_hour}) + lday_str = datetime.strftime(date_to, DEFAULT_SERVER_DATETIME_FORMAT).split(" ")[0] + lday_new_hour = res.get(lday_str, 0.0) + lday_cur_hour + if self.leave_selection_date_to =='half_day': + lday_new_hour =lday_new_hour/2 + res.update({lday_str: lday_new_hour}) + date_from = datetime.strptime(self.date_from.split(" ")[0], DEFAULT_SERVER_DATE_FORMAT) + date_to = datetime.strptime(self.date_to.split(" ")[0], DEFAULT_SERVER_DATE_FORMAT) + temp_date = date_from + temp_date += timedelta(days=1) + while temp_date < date_to: + weekday = temp_date.weekday() + for contract in self.employee_id.contract_ids: + cont_start_date = datetime.strptime(contract.date_start, DEFAULT_SERVER_DATE_FORMAT) + cont_end_date = False + if not contract.date_end: + if cont_start_date <= temp_date: + cur_hour = self.get_hours(weekday, contract.working_hours.attendance_ids) + day_hours += cur_hour + day_str = datetime.strftime(temp_date, DEFAULT_SERVER_DATE_FORMAT).split(" ")[0] + new_hour = res.get(day_str, 0.0) + cur_hour + res.update({day_str: new_hour}) + else: + cont_end_date = datetime.strptime(contract.date_end, DEFAULT_SERVER_DATE_FORMAT) +# cont_end_date += timedelta(days=1) + if cont_start_date <= temp_date and cont_end_date >= temp_date: + cur_hour = self.get_hours(weekday, contract.working_hours.attendance_ids) + day_hours = cur_hour + day_str = datetime.strftime(temp_date, DEFAULT_SERVER_DATE_FORMAT).split(" ")[0] + new_hour = res.get(day_str, 0.0) + cur_hour + res.update({day_str: new_hour}) + + temp_date += timedelta(days=1) + return res + + @api.onchange("number_of_days_temp","leave_selection","leave_selection_date_to") + def calc_days(self): + res = 0 + if not self.date_from or not self.date_to: + return {} + date_from = datetime.strptime(self.date_from.split(" ")[0], DEFAULT_SERVER_DATE_FORMAT) + date_to = datetime.strptime(self.date_to.split(" ")[0], DEFAULT_SERVER_DATE_FORMAT) + # if date_from == date_to: + # if self.leave_selection =='half_day' or self.leave_selection_date_to =='half_day': + # self.number_of_days_temp = 0.5 + # return {} + temp_date = date_from + while temp_date <= date_to: + holiday = None + holiday = self.env['itis.holiday'].search([('date', '=', temp_date)]) + if holiday: + temp_date += timedelta(days=1) + continue + weekday = temp_date.weekday() + for contract in self.employee_id.contract_ids: + cont_start_date = datetime.strptime(contract.date_start, DEFAULT_SERVER_DATE_FORMAT) + cont_end_date = False + if not contract.date_end: + if cont_start_date <= temp_date: + if self.get_hours(weekday, contract.working_hours.attendance_ids) > 0.0: + if temp_date == date_from and self.leave_selection =='half_day': + res += 0.25 + break + if temp_date == date_to and self.leave_selection_date_to =='half_day': + res += 0.25 + break + res += 1 + else: + cont_end_date = datetime.strptime(contract.date_end, DEFAULT_SERVER_DATE_FORMAT) +# cont_end_date += timedelta(days=1) + if cont_start_date <= temp_date and cont_end_date >= temp_date: + if self.get_hours(weekday, contract.working_hours.attendance_ids) > 0.0: + if temp_date == date_from and self.leave_selection =='half_day': + res += 0.25 + break + if temp_date == date_to and self.leave_selection_date_to =='half_day': + res += 0.25 + break + res += 1 + temp_date += timedelta(days=1) + self.number_of_days_temp = res + return {} + +class HRHolidayStatus(models.Model): + + _inherit = "hr.holidays.status" + + def name_get(self, cr, uid, ids, context=None): + if context is None: + context = {} + if not context.get('employee_id',False): + # leave counts is based on employee_id, would be inaccurate if not based on correct employee + return super(HRHolidayStatus, self).name_get(cr, uid, ids, context=context) + + res = [] + for record in self.browse(cr, uid, ids, context=context): + name = record.name + if not record.limit: + name = name + res.append((record.id, name)) + return res diff --git a/itis_hr_leave_extend/security/ir.model.access.csv b/itis_hr_leave_extend/security/ir.model.access.csv new file mode 100644 index 0000000..80cfbae --- /dev/null +++ b/itis_hr_leave_extend/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_hr_holidays_timesheet,access_hr_holidays_timesheet,model_hr_holidays_timesheet,base.group_user,1,1,1,1 +access_hr_sick_leave,access_hr_sick_leave,model_hr_sick_leave,base.group_hr_manager,1,1,1,1 \ No newline at end of file diff --git a/itis_hr_leave_extend/tests/__init__.py b/itis_hr_leave_extend/tests/__init__.py new file mode 100644 index 0000000..1b6d2d6 --- /dev/null +++ b/itis_hr_leave_extend/tests/__init__.py @@ -0,0 +1 @@ +from . import test_hr_leave_extend \ No newline at end of file diff --git a/itis_hr_leave_extend/tests/test_hr_leave_extend.py b/itis_hr_leave_extend/tests/test_hr_leave_extend.py new file mode 100644 index 0000000..e30ecc8 --- /dev/null +++ b/itis_hr_leave_extend/tests/test_hr_leave_extend.py @@ -0,0 +1,168 @@ +# -*- coding: utf-8 -*- + +from openerp.tests.common import TransactionCase +from datetime import datetime +from dateutil.relativedelta import relativedelta +from openerp.osv.orm import except_orm +import logging +_logger = logging.getLogger(__name__) + +class TestHrLeave(TransactionCase): + + def setUp(self): + super(TestHrLeave, self).setUp() + cr, uid = self.cr, self.uid + + # Find Employee group + group_employee_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_user') + self.group_employee_id = group_employee_ref and group_employee_ref[1] or False + + # Find Hr User group + group_hr_user_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_hr_user') + self.group_hr_user_ref_id = group_hr_user_ref and group_hr_user_ref[1] or False + + # Find Hr Manager group + group_hr_manager_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_hr_manager') + self.group_hr_manager_ref_id = group_hr_manager_ref and group_hr_manager_ref[1] or False + + + + self.test_hrmanager_user = self.env['res.users'].create({ + 'name': 'Bastien HrManager', + 'login': 'bastien', + 'alias_name': 'bastien', + 'email': 'bastien.hrmanager@example.com', + 'groups_id': [(6, 0, [self.group_employee_id, self.group_hr_manager_ref_id])] + }) + + self.test_hrmanager_employee = self.env['hr.employee'].create({ + 'name': 'Hr Manager Test', + 'user_id':self.test_hrmanager_user.id, + }) + + + self.test_user = self.env['res.users'].create({ + 'name': 'Agrolait Test User', + 'login': 'user', + 'email': 'hro@example.com', + 'signature': '--\nAgr', + 'groups_id': [(6, 0, [self.group_employee_id])] + }) + + self.test_employee = self.env['hr.employee'].create({ + 'name': 'Agrolait Test Emp', + 'user_id':self.test_user.id, + 'parent_id':self.test_hrmanager_employee.id, + }) + + working_hours = self.env["resource.calendar"].search([('name','=','45 Hours/Week')]) + struct_id = self.env["hr.payroll.structure"].search([]) + today_date = datetime.now().date() + test_contract = self.env['hr.contract'].create({ + 'name':'test employee contract', + 'employee_id':self.test_employee.id, + 'struct_id':struct_id[0].id, + 'wage':100, + 'date_start':str(today_date.replace(month=01,day=01)), + 'date_end':str(today_date.replace(month=12,day=01)), + 'working_hours':working_hours.id, + }) + + def test_fillup_sick_leave(self): + """test case to test the sick leave fill up functionality""" + hr_sick_leave = self.env["hr.sick.leave"] + hr_analytic_timesheet =self.env['hr.analytic.timesheet'] + today_date = datetime.now().date() + end_date = today_date+relativedelta(days=1) + hr_sick_leave_rec = hr_sick_leave.create({ + 'start_date':today_date, + 'end_date':end_date, + }) + + hr_sick_leave_rec.with_context(active_ids = [self.test_employee.id]).confirm_sick_time() + leave_record = hr_analytic_timesheet.search([('date','>=',today_date),('date','<=',end_date),('user_id','<=',self.test_user.id)]) + print"leave_record------",leave_record + if leave_record: + _logger.info('-----Sick leave is created.') + else: + self.assertEqual(1,2,'Sick leave is not created.') + + def test_create_timesheet(self): + """test case to test creation of timesheet and planned,fillup hours,closed timesheet""" + account_journal = self.env['account.analytic.journal'].search([]) + account_analytic = self.env['account.analytic.account'].search([('use_timesheets','=',True),('type','=','contract')]) + timesheet_sheet = self.env['hr_timesheet_sheet.sheet'].create({ + 'date_from': str(datetime.today()), + 'date_to': str(datetime.today()), + 'name': 'Agrolait Test', + 'state': 'new', + 'user_id': self.test_user.id, + 'employee_id': self.test_employee.id, + 'timesheet_ids': [(0, 0, { + 'date': str(datetime.today()), + 'name': 'Develop yaml for hr module(1)', + 'user_id': self.test_user.id, + 'unit_amount': 8.00, + 'journal_id':account_journal[0].id, + 'account_id':account_analytic[0].id, + })]}) + + try: + timesheet_sheet.action_timesheet_confirm() + except Exception: + pass + print"Planned hour--------",timesheet_sheet.total_contract_time + print"total_timesheet-11-------",timesheet_sheet.total_timesheet + print"actual_ot-11-------",timesheet_sheet.actual_ot + print"time_diff-11-------",timesheet_sheet.time_diff + self.assertEqual(timesheet_sheet.actual_ot,timesheet_sheet.time_diff,'Total overtime hour need to be equal.') + try: + timesheet_sheet.button_confirm() + except Exception: + pass + self.assertEqual(timesheet_sheet.actual_ot,timesheet_sheet.time_diff,'Total overtime hour need to be equal.') + + def test_create_half_day_leave(self): + """test half day leave test cases""" + + hr_holidays = self.registry('hr.holidays') + holidays_status_1 = self.env["hr.holidays.status"].create({ + 'name': 'NotLimited', + 'limit': True, + }) + date_from = datetime.today() + relativedelta(days=2) + date_end = datetime.today() + relativedelta(days=2) + + timesheet_rec = self.env['hr_timesheet_sheet.sheet'].create({ + 'date_from': str(date_from), + 'date_to': str(date_end), + 'name': 'Agrolait Test', + 'state': 'new', + 'user_id': self.test_user.id, + 'employee_id': self.test_employee.id, + }) + + holiday_id = hr_holidays.create(self.cr, self.test_hrmanager_user.id,{ + 'name': 'Holiday1', + 'employee_id': self.test_employee.id, + 'holiday_status_id': holidays_status_1.id, + 'date_from': str(date_from), + 'date_to': str(date_end), + 'leave_selection':'half_day', + 'half_day_type':'morning', + 'number_of_days_temp':0.5 + }) + holiday_rec = hr_holidays.browse(self.cr, self.test_hrmanager_user.id, holiday_id) + self.assertEqual(holiday_rec.state, 'confirm', 'hr_holidays: newly created leave request should be in confirm state') + self.assertEqual(holiday_rec.number_of_days_temp, 0.5, 'hr_holidays: Half day leave request need to shaw day as 0.5') + + hr_holidays.signal_workflow(self.cr, self.test_hrmanager_user.id, [holiday_id], 'validate') + self.assertEqual(holiday_rec.state, 'validate', 'hr_holidays: validates leave request should be in validate state') + + leave_record = self.env['hr.analytic.timesheet'].search([('date','>=',date_from),('date','<=',date_end),('user_id','<=',self.test_user.id)]) + if leave_record: + _logger.info('-----Half Day leave is created.') + else: + self.assertEqual(1,2,'Half Day leave is not created.') + + diff --git a/itis_hr_leave_extend/views/hr_setting_view.xml b/itis_hr_leave_extend/views/hr_setting_view.xml new file mode 100644 index 0000000..ae1ec17 --- /dev/null +++ b/itis_hr_leave_extend/views/hr_setting_view.xml @@ -0,0 +1,30 @@ + + + + + + hr settings + hr.config.settings + + + + + + + + + + + + diff --git a/itis_hr_leave_extend/wizard/__init__.py b/itis_hr_leave_extend/wizard/__init__.py new file mode 100644 index 0000000..c82151b --- /dev/null +++ b/itis_hr_leave_extend/wizard/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + +from . import hr_setting +from . import hr_sick_leave diff --git a/itis_hr_leave_extend/wizard/hr_setting.py b/itis_hr_leave_extend/wizard/hr_setting.py new file mode 100644 index 0000000..44ee312 --- /dev/null +++ b/itis_hr_leave_extend/wizard/hr_setting.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api, _ + + +class HRConfig(models.TransientModel): + + _inherit = "hr.config.settings" + + leave_account_id = fields.Many2one("account.analytic.account", "Analytic Account for Leave") + ot_leave_account_id = fields.Many2one("account.analytic.account", "Analytic Account for Overtime Leave") + + @api.multi + def set_ot_leave_account_id(self): + self.env.user.company_id.write({ + "leave_account_id": self.leave_account_id.id, + "ot_leave_account_id": self.ot_leave_account_id.id, + }) + return True + + @api.model + def default_get(self, fields): + la_id = self.env.user.company_id.leave_account_id.id or False + ola_id = self.env.user.company_id.ot_leave_account_id.id or False + res = super(HRConfig, self).default_get(fields) + res.update({ + "leave_account_id": la_id, + "ot_leave_account_id": ola_id, + }) + return res + +class ResCompany(models.Model): + + _inherit = "res.company" + + leave_account_id = fields.Many2one("account.analytic.account", "Analytic Account for Leave") + ot_leave_account_id = fields.Many2one("account.analytic.account", "Analytic Account for Overtime Leave") diff --git a/itis_hr_leave_extend/wizard/hr_sick_leave.py b/itis_hr_leave_extend/wizard/hr_sick_leave.py new file mode 100644 index 0000000..3e2e123 --- /dev/null +++ b/itis_hr_leave_extend/wizard/hr_sick_leave.py @@ -0,0 +1,278 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + +from openerp import models, fields, api, _ +from openerp.exceptions import Warning +from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT +from datetime import datetime, timedelta +from openerp import SUPERUSER_ID +from dateutil.relativedelta import relativedelta + +class hr_sick_leave(models.TransientModel): + + _name = 'hr.sick.leave' + + start_date = fields.Datetime('Start Date') + end_date = fields.Datetime('End Date') + + + @api.multi + def confirm_sick_time(self): + """ This function is use to fill the timesheet when employee is sick. + """ + hr_employee_env = self.env['hr.employee'] + sheet_obj = self.env['hr_timesheet_sheet.sheet'] + timesheet_obj = self.pool.get('hr.analytic.timesheet') + active_ids = self.env.context.get('active_ids') + if active_ids: + account_id = self.env.user.company_id and self.env.user.company_id.sick_account_id or False + if not account_id: + raise Warning(_('Please set the analytic account for Sick Leaves.\nPlease contact your administrator for the same.')) + + for hr_employee_brw in hr_employee_env.browse(active_ids): + res = self.count_day_sickleave(hr_employee_brw) + timesheets = sheet_obj.search([("employee_id", '=', hr_employee_brw.id)]) + #for sick_leave_rec in res: + for key, value in res.iteritems(): + cur_day_timesheeht_found = False + cur_day = datetime.strptime(key, DEFAULT_SERVER_DATE_FORMAT) + for timesheet in timesheets: + ts_date_from = datetime.strptime(timesheet.date_from, DEFAULT_SERVER_DATE_FORMAT) + ts_date_to = datetime.strptime(timesheet.date_to, DEFAULT_SERVER_DATE_FORMAT) + if cur_day >= ts_date_from and cur_day <= ts_date_to: + cur_day_timesheeht_found = True + # print"Final Timesheet----",timesheet + # if timesheet.state != 'draft': + # raise Warning(_('The Time period is allready closed. \n Please contact the Human Resource Team if the leave request should be confirmed nevertheless')) + # timesheet_ids = timesheet_obj.search(self.env.cr,self.env.uid,[('name','like','Sick Leave on:'),('sheet_id','=',timesheet.id),('user_id','=',hr_employee_brw.user_id.id)]) + # if timesheet_ids: + # timesheet_obj.unlink(self.env.cr,self.env.uid,timesheet_ids) + ana_ts_id = self.create_sickleave_timesheet(account_id, timesheet, value, key,hr_employee_brw) + #hl_ts_rec.write({'timesheet_id': ana_ts_id[0], 'sheet_id': timesheet.id}) + if cur_day_timesheeht_found == False: + self.create_future_timesheet(cur_day,account_id, value, key,hr_employee_brw) + + return True + + def create_future_timesheet(self,cur_day,account_id, value, key,hr_employee_brw): + """ + Use to create a future timesheet base upon the user configuration + + """ + hr_timesheet =self.env['hr_timesheet_sheet.sheet'] + timesheet_start_date = self.get_timesheet_start_date(cur_day) + timesheet_end_date =self.get_timesheet_end_date(cur_day) + + timesheets = hr_timesheet.search([("employee_id", '=', hr_employee_brw.id),("date_from", '=', timesheet_start_date),("date_to", '=', timesheet_end_date)]) + # print"START----------END--------",timesheet_start_date,timesheet_end_date,timesheets + if not timesheets: + timesheets = hr_timesheet.create({'employee_id':hr_employee_brw.id,'date_from':timesheet_start_date,'date_to':timesheet_end_date}) + + self.create_sickleave_timesheet(account_id, timesheets, value, key,hr_employee_brw) + + def get_timesheet_start_date(self,cur_day): + user = self.env['res.users'].browse(self.env.uid) + r = user.company_id and user.company_id.timesheet_range or 'month' + if r == 'month': + timesheet_start_date = cur_day.strftime('%Y-%m-01') + elif r == 'week': + timesheet_start_date = (cur_day+ relativedelta(weekday=0, days=-6)).strftime('%Y-%m-%d') + elif r == 'year': + timesheet_start_date = cur_day.strftime('%Y-01-01') + else: + timesheet_start_date = cur_day + return timesheet_start_date + + def get_timesheet_end_date(self,cur_day): + user = self.env['res.users'].browse(self.env.uid) + r = user.company_id and user.company_id.timesheet_range or 'month' + if r == 'month': + timesheet_end_date = (cur_day+ relativedelta(months=+1, day=1, days=-1)).strftime('%Y-%m-%d') + elif r == 'week': + timesheet_end_date = (cur_day+ relativedelta(weekday=6)).strftime('%Y-%m-%d') + elif r == 'year': + timesheet_end_date = cur_day.strftime('%Y-12-31') + else: + timesheet_end_date = cur_day + return timesheet_end_date + + + @api.one + def create_sickleave_timesheet(self, account_id, sheet, duration, day,hr_employee_brw): + """ + This function is use to create analytic timesheet based on the sick date and other inputs + :param account_id: analytic account id + :param sheet: timesheet id + :param duration: planned time of the leave + :param day: date of the leave + :param hr_employee_brw: employee browse record + :return: created record for the analytic timesheet + """ + timesheet_obj = self.pool.get('hr.analytic.timesheet') + cr = self.env.cr + uid = self.env.uid + emp_obj = self.env['hr.employee'] + hour = duration + + res = timesheet_obj.default_get(cr, uid, ['product_id','product_uom_id']) + + if not res['product_uom_id']: + raise Warning(_('User Error! \nPlease define cost unit for this employee.')) + up = timesheet_obj.on_change_unit_amount(cr, uid, False, res['product_id'], hour,False, res['product_uom_id'])['value'] + + res['name'] = "Sick Leave on:" + day + res['account_id'] = account_id.id + res['unit_amount'] = hour + emp_journal = emp_obj.search([('user_id', '=', hr_employee_brw.user_id.id)]).journal_id + res['journal_id'] = emp_journal and emp_journal.id or False + res.update(up) + up = timesheet_obj.on_change_account_id(cr, uid, [], res['account_id']).get('value', {}) + res.update(up) + res.update({ + 'date': day, + 'user_id': hr_employee_brw.user_id.id, + 'sheet_id': sheet.id, + }) + return timesheet_obj.create(cr, SUPERUSER_ID, res) + + + + + + + def count_day_sickleave(self,hr_employee_brw): + res = {} + date_from = datetime.strptime(self.start_date, DEFAULT_SERVER_DATETIME_FORMAT) + date_to = datetime.strptime(self.end_date, DEFAULT_SERVER_DATETIME_FORMAT) + same_day = self.check_same_day(date_from, date_to) + temp_date = date_from + day_hours = 0.0 + weekday = temp_date.weekday() + for contract in hr_employee_brw.contract_ids: + cont_start_date = datetime.strptime(contract.date_start, DEFAULT_SERVER_DATE_FORMAT) + + if not contract.date_end: + if cont_start_date <= temp_date: + if same_day: + cur_hour = self.get_sameday_hours(date_from, date_to, contract.working_hours.attendance_ids) + day_hours += cur_hour + day_str = datetime.strftime(temp_date, DEFAULT_SERVER_DATETIME_FORMAT).split(" ")[0] + new_hour = res.get(day_str, 0.0) + cur_hour + res.update({day_str: new_hour}) + else: + fday_cur_hour = self.get_fday_hours(date_from, contract.working_hours.attendance_ids) + day_hours += fday_cur_hour + lday_cur_hour = self.get_lday_hours(date_to, contract.working_hours.attendance_ids) + day_hours += lday_cur_hour + fday_str = datetime.strftime(date_from, DEFAULT_SERVER_DATETIME_FORMAT).split(" ")[0] + fday_new_hour = res.get(fday_str, 0.0) + fday_cur_hour + res.update({fday_str: fday_new_hour}) + lday_str = datetime.strftime(date_to, DEFAULT_SERVER_DATETIME_FORMAT).split(" ")[0] + lday_new_hour = res.get(lday_str, 0.0) + lday_cur_hour + res.update({lday_str: lday_new_hour}) + else: + cont_end_date = datetime.strptime(contract.date_end, DEFAULT_SERVER_DATE_FORMAT) + cont_end_date += timedelta(days=1) + if cont_start_date <= temp_date and cont_end_date >= temp_date: + if same_day: + cur_hour = self.get_sameday_hours(date_from, date_to, contract.working_hours.attendance_ids) + day_hours += cur_hour + day_str = datetime.strftime(temp_date, DEFAULT_SERVER_DATETIME_FORMAT).split(" ")[0] + new_hour = res.get(day_str, 0.0) + cur_hour + res.update({day_str: new_hour}) + else: + fday_cur_hour = self.get_fday_hours(date_from, contract.working_hours.attendance_ids) + day_hours += fday_cur_hour + lday_cur_hour = self.get_lday_hours(date_to, contract.working_hours.attendance_ids) + day_hours += lday_cur_hour + fday_str = datetime.strftime(date_from, DEFAULT_SERVER_DATETIME_FORMAT).split(" ")[0] + fday_new_hour = res.get(fday_str, 0.0) + fday_cur_hour + res.update({fday_str: fday_new_hour}) + lday_str = datetime.strftime(date_to, DEFAULT_SERVER_DATETIME_FORMAT).split(" ")[0] + lday_new_hour = res.get(lday_str, 0.0) + lday_cur_hour + res.update({lday_str: lday_new_hour}) + date_from = datetime.strptime(self.start_date.split(" ")[0], DEFAULT_SERVER_DATE_FORMAT) + date_to = datetime.strptime(self.end_date.split(" ")[0], DEFAULT_SERVER_DATE_FORMAT) + temp_date = date_from + temp_date += timedelta(days=1) + while temp_date < date_to: + weekday = temp_date.weekday() + for contract in hr_employee_brw.contract_ids: + cont_start_date = datetime.strptime(contract.date_start, DEFAULT_SERVER_DATE_FORMAT) + cont_end_date = False + if not contract.date_end: + if cont_start_date <= temp_date: + cur_hour = self.get_hours(weekday, contract.working_hours.attendance_ids) + day_hours += cur_hour + day_str = datetime.strftime(temp_date, DEFAULT_SERVER_DATE_FORMAT).split(" ")[0] + new_hour = res.get(day_str, 0.0) + cur_hour + res.update({day_str: new_hour}) + else: + cont_end_date = datetime.strptime(contract.date_end, DEFAULT_SERVER_DATE_FORMAT) + if cont_start_date <= temp_date and cont_end_date >= temp_date: + cur_hour = self.get_hours(weekday, contract.working_hours.attendance_ids) + day_hours += cur_hour + day_str = datetime.strftime(temp_date, DEFAULT_SERVER_DATE_FORMAT).split(" ")[0] + new_hour = res.get(day_str, 0.0) + cur_hour + res.update({day_str: new_hour}) + + temp_date += timedelta(days=1) + + return res + + + def check_same_day(self, date_from, date_to): + return date_from.date() == date_to.date() + + def get_sameday_hours(self, date_from, date_to, atten_ids): + + weekday = date_from.weekday() + res = self.get_hours(weekday, atten_ids) + return res + + def get_lday_hours(self, date_to, atten_ids): + weekday = date_to.weekday() + return self.get_hours(weekday, atten_ids) + + + def get_fday_hours(self, date_from, atten_ids): + weekday = date_from.weekday() + return self.get_hours(weekday, atten_ids) + + + def get_hours(self, weekday, atten_ids): + res = 0.0 + for atten in atten_ids: + if int(atten.dayofweek) == weekday: + res += atten.hour_to - atten.hour_from + return res + + + + + + + + + + + + + diff --git a/itis_hr_leave_extend/wizard/hr_sick_leave.xml b/itis_hr_leave_extend/wizard/hr_sick_leave.xml new file mode 100644 index 0000000..5ce0908 --- /dev/null +++ b/itis_hr_leave_extend/wizard/hr_sick_leave.xml @@ -0,0 +1,45 @@ + + + + + + sick.leave.form.view + hr.sick.leave + +
+

This wizard is use to fill up the time sheet when employee is sick.

+ + + + + +
+
+
+
+
+ + + Fill Sick Leave + ir.actions.act_window + hr.sick.leave + form + form + new + + + + + +
+
\ No newline at end of file diff --git a/itis_hr_notifications/__init__.py b/itis_hr_notifications/__init__.py new file mode 100644 index 0000000..a5e7e1d --- /dev/null +++ b/itis_hr_notifications/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +import models \ No newline at end of file diff --git a/itis_hr_notifications/__openerp__.py b/itis_hr_notifications/__openerp__.py new file mode 100644 index 0000000..b21d5ab --- /dev/null +++ b/itis_hr_notifications/__openerp__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +{ + 'name': "ITIS HR Notifications", + + 'summary': """ + A module by ITIS to send various HR notifications""", + + 'description': """ + A module by ITIS to send various HR notifications + """, + + 'author': "ITIS AG", + 'website': "http://itis.de", + 'category': 'Human Resource', + 'version': '1.0.55.0', + + 'depends': ['hr', 'itis_hr_attendance_extend', 'itis_hr_extend'], + + 'data': [ + 'data/email_templates.xml', + 'hr_view.xml', + 'data/ir_cron.xml', + 'security/ir.model.access.csv', + ], + + 'application': False, diff --git a/itis_hr_notifications/data/email_templates.xml b/itis_hr_notifications/data/email_templates.xml new file mode 100644 index 0000000..363bc6a --- /dev/null +++ b/itis_hr_notifications/data/email_templates.xml @@ -0,0 +1,112 @@ + + + + + + Training_end Notification + + + ${(user.email or '') | safe} + ${( object.employee_id.work_email or object.user_id != False and object.user_id.email )|safe} + Training End Notification + Hello ${object.employee_id and object.employee_id.name or object.user_id and object.user_id.name},

+
+

please be informed that the probation period for ${object.for_emp.name} is ending on ${object.date}. +


+

Regards

+

Your Human-Resources Team

+ ]]>
+
+ + + work permit Notification + + + ${(user.email or '') | safe} + ${( object.employee_id.work_email or object.user_id != False and object.user_id.email )|safe} + Work Permit End Notification + Hello ${object.employee_id and object.employee_id.name or object.user_id and object.user_id.name},

+
+

please be informed that the work permit for ${object.for_emp.name} is ending on ${object.date}.

+
+

Regards

+

Your Human-Resources Team

+ ]]>
+
+ + + Term end Notification + + + ${(user.email or '') | safe} + ${( object.employee_id.work_email or object.user_id != False and object.user_id.email )|safe} + Term End Notification + Hello ${object.employee_id and object.employee_id.name or object.user_id and object.user_id.name},

+
+

please be informed that the temporary employment for ${object.for_emp.name} is ending on ${object.date}.

+
+

Regards

+

Your Human-Resources Team

+ ]]>
+
+ + + Disability Notification + + + ${(user.email or '') | safe} + ${( object.employee_id.work_email or object.user_id != False and object.user_id.email )|safe} + Disability Notification + Hello ${object.employee_id and object.employee_id.name or object.user_id and object.user_id.name},

+
+

please be informed that the severely handicapped pass for ${object.for_emp.name} is ending on ${object.date}. +
+

Regards

+

Your Human-Resources Team

+ ]]>
+
+ + + Leave end Notification + + + ${(user.email or '') | safe} + ${( object.employee_id.work_email or object.user_id != False and object.user_id.email )|safe} + Leave Balance Notification + Hello ${object.employee_id and object.employee_id.name or object.user_id and object.user_id.name},

+
+

please be informed that you have ${object.days} remaining leave.

+

The leave needs to be taken until the end of march.

+

Remaining leave from the old year will expire on 1st of April.

+
+

Regards

+

Your Human-Resources Team

+ ]]>
+
+ + + + Overtime Notification + + + ${(user.email or '') | safe} + ${( object.employee_id.work_email or object.user_id != False and object.user_id.email )|safe} + Overtime Notification + Hello ${object.employee_id and object.employee_id.name or object.user_id and object.user_id.name},

+
+

please be informed that the timesheet for ${object.for_emp.name} is showing ${object.hours}.

+
+

Regards

+

Your Human-Resources Team

+ ]]>
+
+ +
+ +
\ No newline at end of file diff --git a/itis_hr_notifications/data/ir_cron.xml b/itis_hr_notifications/data/ir_cron.xml new file mode 100644 index 0000000..db4d733 --- /dev/null +++ b/itis_hr_notifications/data/ir_cron.xml @@ -0,0 +1,55 @@ + + + + + HR Contract Notifications + 1 + days + -1 + + + + + + + + + Employee Disability + 1 + days + -1 + + + + + + + + Employee Leave Balance + 1 + days + -1 + + + + + + + + Employee Overtime + 1 + months + -1 + + + + + + + + + \ No newline at end of file diff --git a/itis_hr_notifications/hr_view.xml b/itis_hr_notifications/hr_view.xml new file mode 100644 index 0000000..55b4688 --- /dev/null +++ b/itis_hr_notifications/hr_view.xml @@ -0,0 +1,59 @@ + + + + + + + ITIS hr settings + hr.config.settings + + + + + + + + + + + + + + \ No newline at end of file diff --git a/itis_hr_notifications/i18n/de.po b/itis_hr_notifications/i18n/de.po new file mode 100644 index 0000000..0577b80 --- /dev/null +++ b/itis_hr_notifications/i18n/de.po @@ -0,0 +1,328 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * itis_hr_notifications +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-12-11 13:55+0000\n" +"PO-Revision-Date: 2016-12-11 18:53+0100\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: \n" +"X-Generator: Poedit 1.5.4\n" + +#. module: itis_hr_notifications +#: model:email.template,body_html:itis_hr_notifications.email_template_temp_empl +msgid "" +"\n" +"\t\t\t

Hello ${object.employee_id.name},

\n" +"\t\t\t\n" +"\t\t\t

please be informed that the temporary employment for ${object." +"employee_id.name} is ending on ${object.date}.

\n" +"\t\t\t
\n" +"\t\t\t

Regards

\n" +"\t\t\t

Your Human-Resources Team

\n" +"\t\t\t" +msgstr "" +"\n" +"

Hallo ${object.employee_id.name},

\n" +"\n" +"

Das befristete Arbeitsverhältnis für ${object.employee_id.name} endet am " +"${object.date}.

\n" +"
\n" +"

mit freundlichen Grüßen

\n" +"

Ihre Personalverwaltung

\n" +"\t\t\t" + +#. module: itis_hr_notifications +#: model:email.template,body_html:itis_hr_notifications.email_template_training_end +msgid "" +"\n" +"\t\t\t

Hello ${object.employee_id.name},

\n" +"\t\t\t
\n" +"\t\t\t

please be informed that the probation period for ${object." +"employee_id.name} is ending on ${object.date}.\n" +"\t\t\t


\n" +"\t\t\t

Regards

\n" +"\t\t\t

Your Human-Resources Team

\t\t\n" +"\t\t\t" +msgstr "" +"\n" +"

Hallo ${object.employee_id.name},


die Probezeit von ${object." +"employee_id.name} endet am ${object.date}.


mit freundlichen " +"Grüßen

Ihre Personalverwaltung

\n" +"\t\t\t" + +#. module: itis_hr_notifications +#: model:email.template,body_html:itis_hr_notifications.email_template_emp_disable +msgid "" +"\n" +"\t\t\t

Hello ${object.employee_id.name},

\n" +"\t\t\t
\n" +"\t\t\t

please be informed that the severely handicapped pass for ${object." +"employee_id.name} is ending on ${object.date}.\n" +"\t\t\t
\n" +"\t\t\t

Regards

\n" +"\t\t\t

Your Human-Resources Team

\t\t\n" +"\t\t\t" +msgstr "" +"\n" +"

Hallo ${object.employee_id.name},


der Schwerbehindertenausweis " +"für ${object.employee_id.name} läuft aus am ${object.date}.

mit " +"freundlichen Grüßen

Ihre Personalverwaltung

\n" +"\t\t\t" + +#. module: itis_hr_notifications +#: model:email.template,body_html:itis_hr_notifications.email_template_overtime +msgid "" +"\n" +"\t\t\t

Hello ${object.employee_id.name},

\n" +"\t\t\t
\n" +"\t\t\t

please be informed that the timesheet for ${object.employee_id." +"name} is showing ${object.hours}.

\n" +"\t\t\t
\n" +"\t\t\t

Regards

\n" +"\t\t\t

Your Human-Resources Team

\n" +"\t\t\t" +msgstr "" +"\n" +"

Hallo ${object.employee_id.name},


das Überstundenkonto von " +"${object.employee_id.name} beläuft sich auf ${object.hours} Stunden.

mit freundlichen Grüßen

Ihre Personalverwaltung

\n" +"\t\t\t" + +#. module: itis_hr_notifications +#: model:email.template,body_html:itis_hr_notifications.email_template_leave_end +msgid "" +"\n" +"\t\t\t

Hello ${object.employee_id.name},

\n" +"\t\t\t
\n" +"\t\t\t

please be informed that you have ${object.days} remaining leave.\n" +"\t\t\t

The leave needs to be taken until the end of march.

\n" +"\t\t\t

Remaining leave from the old year will expire on 1st of April.

\n" +"\t\t\t
\n" +"\t\t\t

Regards

\n" +"\t\t\t

Your Human-Resources Team

\n" +"\t\t\t" +msgstr "" +"\n" +"

Hallo ${object.employee_id.name},


Sie haben ${object.days} " +"Tage Resturlaub..

Der Resturlaub muss bis 31. März genommen worden " +"sein.

Verbleibender Resturlaub des Vorjahres, verfällt am 01. April.

mit freundlichen Grüßen

Ihre Personalverwaltung

\n" +"\t\t\t" + +#. module: itis_hr_notifications +#: model:email.template,body_html:itis_hr_notifications.email_template_work_permit_end +msgid "" +"\n" +"\t\t\t

Hello ${object.employee_id.name},

\n" +"\n" +"\t\t\t

please be informed that the work permit for ${object.employee_id." +"name} is ending on ${object.date}.

\n" +"\t\t\t
\n" +"\t\t\t

Regards

\n" +"\t\t\t

Your Human-Resources Team

\n" +"\t\t\t" +msgstr "" +"\n" +"

Hallo ${object.employee_id.name},

Die Arbeitserlaubnis von ${object." +"employee_id.name} endet am ${object.date}.


mit freundlichen " +"Grüßen

Ihre Personalverwaltung

\n" +"\t\t\t" + +#. module: itis_hr_notifications +#: model:ir.model,name:itis_hr_notifications.model_res_company +msgid "Companies" +msgstr "Unternehmen" + +#. module: itis_hr_notifications +#: model:ir.model,name:itis_hr_notifications.model_hr_contract +msgid "Contract" +msgstr "Arbeitsvertrag" + +#. module: itis_hr_notifications +#: field:hr.notifications,create_uid:0 +msgid "Created by" +msgstr "Created by" + +#. module: itis_hr_notifications +#: field:hr.notifications,create_date:0 +msgid "Created on" +msgstr "Created on" + +#. module: itis_hr_notifications +#: field:hr.notifications,date:0 +msgid "Date" +msgstr "Datum" + +#. module: itis_hr_notifications +#: field:hr.notifications,days:0 +msgid "Days" +msgstr "Tage" + +#. module: itis_hr_notifications +#: selection:hr.notifications,type:0 +msgid "Disability" +msgstr "Behinderung" + +#. module: itis_hr_notifications +#: model:email.template,subject:itis_hr_notifications.email_template_emp_disable +msgid "Disability Notification" +msgstr "Erinnerung Behindertenausweis" + +#. module: itis_hr_notifications +#: field:hr.notifications,employee_id:0 field:hr.notifications,user_id:0 +#: model:ir.model,name:itis_hr_notifications.model_hr_employee +msgid "Employee" +msgstr "Mitarbeiter/-in" + +#. module: itis_hr_notifications +#: field:hr.notifications,for_emp:0 +msgid "For Employee" +msgstr "für mitarbeiter" + +#. module: itis_hr_notifications +#: field:hr.config.settings,remaining_leaves:0 +#: field:res.company,remaining_leaves:0 +msgid "Holiday Season notification before" +msgstr "Benachrichtigung Resturlaub" + +#. module: itis_hr_notifications +#: help:hr.config.settings,remaining_leaves:0 +#: help:res.company,remaining_leaves:0 +msgid "Holiday season Expiration" +msgstr "Benachrichtigung Verfall Resturlaub" + +#. module: itis_hr_notifications +#: field:hr.notifications,hours:0 +msgid "Hours" +msgstr "Stunden" + +#. module: itis_hr_notifications +#: field:hr.notifications,id:0 +msgid "ID" +msgstr "ID" + +#. module: itis_hr_notifications +#: field:hr.notifications,write_uid:0 +msgid "Last Updated by" +msgstr "Last Updated by" + +#. module: itis_hr_notifications +#: field:hr.notifications,write_date:0 +msgid "Last Updated on" +msgstr "Last Updated on" + +#. module: itis_hr_notifications +#: selection:hr.notifications,type:0 +msgid "Leave Balance" +msgstr "Leave Balance" + +#. module: itis_hr_notifications +#: model:email.template,subject:itis_hr_notifications.email_template_leave_end +msgid "Leave Balance Notification" +msgstr "Leave Balance Notification" + +#. module: itis_hr_notifications +#: view:hr.config.settings:itis_hr_notifications.itis_view_human_resources_configuration +msgid "Notifications" +msgstr "Notifications" + +#. module: itis_hr_notifications +#: selection:hr.notifications,type:0 +msgid "Overtime" +msgstr "Überstunden" + +#. module: itis_hr_notifications +#: model:email.template,subject:itis_hr_notifications.email_template_overtime +msgid "Overtime Notification" +msgstr "Benachrichtigung Überstunden" + +#. module: itis_hr_notifications +#: selection:hr.notifications,type:0 +msgid "Permit End" +msgstr "Ende Erlaubnis" + +#. module: itis_hr_notifications +#: field:hr.config.settings,savirity:0 field:res.company,savirity:0 +msgid "Savirity notification before" +msgstr "Erinnerung Behindertenausweis" + +#. module: itis_hr_notifications +#: help:hr.config.settings,savirity:0 help:res.company,savirity:0 +msgid "Severely handicapped persons" +msgstr "Erinnerung Behindertenausweis" + +#. module: itis_hr_notifications +#: field:hr.config.settings,term_end:0 field:res.company,term_end:0 +msgid "Term End notification before" +msgstr "Benachrichtigung Vertragsende" + +#. module: itis_hr_notifications +#: selection:hr.notifications,type:0 +msgid "Term End" +msgstr "Vertragsende" + +#. module: itis_hr_notifications +#: model:email.template,subject:itis_hr_notifications.email_template_temp_empl +msgid "Term End Notification" +msgstr "Benachrichtigung Vertragsende" + +#. module: itis_hr_notifications +#: help:hr.config.settings,term_end:0 help:res.company,term_end:0 +msgid "Term End Notification before months" +msgstr "Benachrichtigung Vertragsende" + +#. module: itis_hr_notifications +#: selection:hr.notifications,type:0 +msgid "Training End" +msgstr "Ende Probezeit" + +#. module: itis_hr_notifications +#: model:email.template,subject:itis_hr_notifications.email_template_training_end +msgid "Training End Notification" +msgstr "Benachrichtigung Ende der Probezeit" + +#. module: itis_hr_notifications +#: help:hr.config.settings,training_end_day:0 +#: help:res.company,training_end_day:0 +msgid "Training End Notification before months" +msgstr "Benachrichtigung Ende der Probezeit" + +#. module: itis_hr_notifications +#: field:hr.config.settings,training_end_day:0 +#: field:res.company,training_end_day:0 +msgid "Training End notification before" +msgstr "Benachrichtigung Ende der Probezeit" + +#. module: itis_hr_notifications +#: field:hr.notifications,type:0 +msgid "Type" +msgstr "Typ" + +#. module: itis_hr_notifications +#: view:hr.config.settings:itis_hr_notifications.itis_view_human_resources_configuration +msgid "Weeks" +msgstr "Wochen" + +#. module: itis_hr_notifications +#: model:email.template,subject:itis_hr_notifications.email_template_work_permit_end +msgid "Work Permit End Notification" +msgstr "Benachrichtigung Ende der Arbeitserlaubnis" + +#. module: itis_hr_notifications +#: field:hr.config.settings,work_permit:0 field:res.company,work_permit:0 +msgid "Work Permit notification before End" +msgstr "Benachrichtigung Ende der Arbeitserlaubnis" + +#. module: itis_hr_notifications +#: help:hr.config.settings,work_permit:0 help:res.company,work_permit:0 +msgid "Work permit Notification before months" +msgstr "Benachrichtigung Ende der Arbeitserlaubnis" diff --git a/itis_hr_notifications/i18n/en_US.po b/itis_hr_notifications/i18n/en_US.po new file mode 100644 index 0000000..4b8466a --- /dev/null +++ b/itis_hr_notifications/i18n/en_US.po @@ -0,0 +1,332 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * itis_hr_notifications +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-12-11 13:56+0000\n" +"PO-Revision-Date: 2016-12-11 13:56+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: itis_hr_notifications +#: model:email.template,body_html:itis_hr_notifications.email_template_temp_empl +msgid "\n" +"

Hello ${object.employee_id.name},

\n" +" \n" +"

please be informed that the temporary employment for ${object.employee_id.name} is ending on ${object.date}.

\n" +"
\n" +"

Regards

\n" +"

Your Human-Resources Team

\n" +" " +msgstr "\n" +"

Hello ${object.employee_id.name},

\n" +" \n" +"

please be informed that the temporary employment for ${object.employee_id.name} is ending on ${object.date}.

\n" +"
\n" +"

Regards

\n" +"

Your Human-Resources Team

\n" +" " + +#. module: itis_hr_notifications +#: model:email.template,body_html:itis_hr_notifications.email_template_training_end +msgid "\n" +"

Hello ${object.employee_id.name},

\n" +"
\n" +"

please be informed that the probation period for ${object.employee_id.name} is ending on ${object.date}.\n" +"


\n" +"

Regards

\n" +"

Your Human-Resources Team

\n" +" " +msgstr "\n" +"

Hello ${object.employee_id.name},

\n" +"
\n" +"

please be informed that the probation period for ${object.employee_id.name} is ending on ${object.date}.\n" +"


\n" +"

Regards

\n" +"

Your Human-Resources Team

\n" +" " + +#. module: itis_hr_notifications +#: model:email.template,body_html:itis_hr_notifications.email_template_emp_disable +msgid "\n" +"

Hello ${object.employee_id.name},

\n" +"
\n" +"

please be informed that the severely handicapped pass for ${object.employee_id.name} is ending on ${object.date}.\n" +"
\n" +"

Regards

\n" +"

Your Human-Resources Team

\n" +" " +msgstr "\n" +"

Hello ${object.employee_id.name},

\n" +"
\n" +"

please be informed that the severely handicapped pass for ${object.employee_id.name} is ending on ${object.date}.\n" +"
\n" +"

Regards

\n" +"

Your Human-Resources Team

\n" +" " + +#. module: itis_hr_notifications +#: model:email.template,body_html:itis_hr_notifications.email_template_overtime +msgid "\n" +"

Hello ${object.employee_id.name},

\n" +"
\n" +"

please be informed that the timesheet for ${object.employee_id.name} is showing ${object.hours}.

\n" +"
\n" +"

Regards

\n" +"

Your Human-Resources Team

\n" +" " +msgstr "\n" +"

Hello ${object.employee_id.name},

\n" +"
\n" +"

please be informed that the timesheet for ${object.employee_id.name} is showing ${object.hours}.

\n" +"
\n" +"

Regards

\n" +"

Your Human-Resources Team

\n" +" " + +#. module: itis_hr_notifications +#: model:email.template,body_html:itis_hr_notifications.email_template_leave_end +msgid "\n" +"

Hello ${object.employee_id.name},

\n" +"
\n" +"

please be informed that you have ${object.days} remaining leave.

\n" +"

The leave needs to be taken until the end of march.

\n" +"

Remaining leave from the old year will expire on 1st of April.

\n" +"
\n" +"

Regards

\n" +"

Your Human-Resources Team

\n" +" " +msgstr "\n" +"

Hello ${object.employee_id.name},

\n" +"
\n" +"

please be informed that you have ${object.days} remaining leave.

\n" +"

The leave needs to be taken until the end of march.

\n" +"

Remaining leave from the old year will expire on 1st of April.

\n" +"
\n" +"

Regards

\n" +"

Your Human-Resources Team

\n" +" " + +#. module: itis_hr_notifications +#: model:email.template,body_html:itis_hr_notifications.email_template_work_permit_end +msgid "\n" +"

Hello ${object.employee_id.name},

\n" +"\n" +"

please be informed that the work permit for ${object.employee_id.name} is ending on ${object.date}.

\n" +"
\n" +"

Regards

\n" +"

Your Human-Resources Team

\n" +" " +msgstr "\n" +"

Hello ${object.employee_id.name},

\n" +"\n" +"

please be informed that the work permit for ${object.employee_id.name} is ending on ${object.date}.

\n" +"
\n" +"

Regards

\n" +"

Your Human-Resources Team

\n" +" " + +#. module: itis_hr_notifications +#: model:ir.model,name:itis_hr_notifications.model_res_company +msgid "Companies" +msgstr "Companies" + +#. module: itis_hr_notifications +#: model:ir.model,name:itis_hr_notifications.model_hr_contract +msgid "Contract" +msgstr "Contract" + +#. module: itis_hr_notifications +#: field:hr.notifications,create_uid:0 +msgid "Created by" +msgstr "Created by" + +#. module: itis_hr_notifications +#: field:hr.notifications,create_date:0 +msgid "Created on" +msgstr "Created on" + +#. module: itis_hr_notifications +#: field:hr.notifications,date:0 +msgid "Date" +msgstr "Date" + +#. module: itis_hr_notifications +#: field:hr.notifications,days:0 +msgid "Days" +msgstr "Days" + +#. module: itis_hr_notifications +#: selection:hr.notifications,type:0 +msgid "Disability" +msgstr "Disability" + +#. module: itis_hr_notifications +#: model:email.template,subject:itis_hr_notifications.email_template_emp_disable +msgid "Disability Notification" +msgstr "Disability Notification" + +#. module: itis_hr_notifications +#: field:hr.notifications,employee_id:0 +#: field:hr.notifications,user_id:0 +#: model:ir.model,name:itis_hr_notifications.model_hr_employee +msgid "Employee" +msgstr "Employee" + +#. module: itis_hr_notifications +#: field:hr.notifications,for_emp:0 +msgid "For Employee" +msgstr "For Employee" + +#. module: itis_hr_notifications +#: field:hr.config.settings,remaining_leaves:0 +#: field:res.company,remaining_leaves:0 +msgid "Holiday Season notification before" +msgstr "Holiday Season notification before" + +#. module: itis_hr_notifications +#: help:hr.config.settings,remaining_leaves:0 +#: help:res.company,remaining_leaves:0 +msgid "Holiday season Expiration" +msgstr "Holiday season Expiration" + +#. module: itis_hr_notifications +#: field:hr.notifications,hours:0 +msgid "Hours" +msgstr "Hours" + +#. module: itis_hr_notifications +#: field:hr.notifications,id:0 +msgid "ID" +msgstr "ID" + +#. module: itis_hr_notifications +#: field:hr.notifications,write_uid:0 +msgid "Last Updated by" +msgstr "Last Updated by" + +#. module: itis_hr_notifications +#: field:hr.notifications,write_date:0 +msgid "Last Updated on" +msgstr "Last Updated on" + +#. module: itis_hr_notifications +#: selection:hr.notifications,type:0 +msgid "Leave Balance" +msgstr "Leave Balance" + +#. module: itis_hr_notifications +#: model:email.template,subject:itis_hr_notifications.email_template_leave_end +msgid "Leave Balance Notification" +msgstr "Leave Balance Notification" + +#. module: itis_hr_notifications +#: view:hr.config.settings:itis_hr_notifications.itis_view_human_resources_configuration +msgid "Notifications" +msgstr "Notifications" + +#. module: itis_hr_notifications +#: selection:hr.notifications,type:0 +msgid "Overtime" +msgstr "Overtime" + +#. module: itis_hr_notifications +#: model:email.template,subject:itis_hr_notifications.email_template_overtime +msgid "Overtime Notification" +msgstr "Overtime Notification" + +#. module: itis_hr_notifications +#: selection:hr.notifications,type:0 +msgid "Permit End" +msgstr "Permit End" + +#. module: itis_hr_notifications +#: field:hr.config.settings,savirity:0 +#: field:res.company,savirity:0 +msgid "Savirity notification before" +msgstr "Savirity notification before" + +#. module: itis_hr_notifications +#: help:hr.config.settings,savirity:0 +#: help:res.company,savirity:0 +msgid "Severely handicapped persons" +msgstr "Severely handicapped persons" + +#. module: itis_hr_notifications +#: field:hr.config.settings,term_end:0 +#: field:res.company,term_end:0 +msgid "Term End notification before" +msgstr "Term End notification before" + +#. module: itis_hr_notifications +#: selection:hr.notifications,type:0 +msgid "Term End" +msgstr "Term End" + +#. module: itis_hr_notifications +#: model:email.template,subject:itis_hr_notifications.email_template_temp_empl +msgid "Term End Notification" +msgstr "Term End Notification" + +#. module: itis_hr_notifications +#: help:hr.config.settings,term_end:0 +#: help:res.company,term_end:0 +msgid "Term End Notification before months" +msgstr "Term End Notification before months" + +#. module: itis_hr_notifications +#: selection:hr.notifications,type:0 +msgid "Training End" +msgstr "Training End" + +#. module: itis_hr_notifications +#: model:email.template,subject:itis_hr_notifications.email_template_training_end +msgid "Training End Notification" +msgstr "Training End Notification" + +#. module: itis_hr_notifications +#: help:hr.config.settings,training_end_day:0 +#: help:res.company,training_end_day:0 +msgid "Training End Notification before months" +msgstr "Training End Notification before months" + +#. module: itis_hr_notifications +#: field:hr.config.settings,training_end_day:0 +#: field:res.company,training_end_day:0 +msgid "Training End notification before" +msgstr "Training End notification before" + +#. module: itis_hr_notifications +#: field:hr.notifications,type:0 +msgid "Type" +msgstr "Type" + +#. module: itis_hr_notifications +#: view:hr.config.settings:itis_hr_notifications.itis_view_human_resources_configuration +msgid "Weeks" +msgstr "Weeks" + +#. module: itis_hr_notifications +#: model:email.template,subject:itis_hr_notifications.email_template_work_permit_end +msgid "Work Permit End Notification" +msgstr "Work Permit End Notification" + +#. module: itis_hr_notifications +#: field:hr.config.settings,work_permit:0 +#: field:res.company,work_permit:0 +msgid "Work Permit notification before End" +msgstr "Work Permit notification before End" + +#. module: itis_hr_notifications +#: help:hr.config.settings,work_permit:0 +#: help:res.company,work_permit:0 +msgid "Work permit Notification before months" +msgstr "Work permit Notification before months" + diff --git a/itis_hr_notifications/models.py b/itis_hr_notifications/models.py new file mode 100644 index 0000000..4e2fbfb --- /dev/null +++ b/itis_hr_notifications/models.py @@ -0,0 +1,324 @@ +# -*- coding: utf-8 -*- + +from openerp import models, fields, api, _ +from datetime import datetime +from dateutil.relativedelta import relativedelta as delta +from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as DF +import re + + +class res_company(models.Model): + + _inherit = 'res.company' + + training_end_day = fields.Integer('Training End notification before', help="Training End Notification before months", default=2) + work_permit = fields.Integer('Work Permit notification before End', help="Work permit Notification before months", default=3) + term_end = fields.Integer('Term End notification before', help="Term End Notification before months", default=5) + savirity = fields.Integer('Savirity notification before', help="Severely handicapped persons", default=2) + remaining_leaves = fields.Integer('Holiday Season notification before', help="Holiday season Expiration", default=3) + +class hr_config_settings(models.TransientModel): + + _inherit = 'hr.config.settings' + + training_end_day = fields.Integer('Training End notification before', help="Training End Notification before months", default=2) + work_permit = fields.Integer('Work Permit notification before End', help="Work permit Notification before months", default=3) + term_end = fields.Integer('Term End notification before', help="Term End Notification before months", default=5) + savirity = fields.Integer('Savirity notification before', help="Severely handicapped persons", default=2) + remaining_leaves = fields.Integer('Holiday Season notification before', help="Holiday season Expiration", default=3) + + + def get_default_notification(self, cr, uid, fields, context=None): + user = self.pool.get('res.users').browse(cr, uid, uid, context=context) + return { + 'training_end_day': user.company_id.training_end_day, + 'work_permit': user.company_id.work_permit, + 'term_end': user.company_id.term_end, + 'savirity': user.company_id.savirity, + 'remaining_leaves': user.company_id.remaining_leaves + } + + def set_default_notification(self, cr, uid, ids, context=None): + config = self.browse(cr, uid, ids[0], context) + user = self.pool.get('res.users').browse(cr, uid, uid, context) + user.company_id.write({ + 'training_end_day': config.training_end_day, + 'work_permit': config.work_permit, + 'term_end': config.term_end, + 'savirity': config.savirity, + 'remaining_leaves': config.remaining_leaves + }) + +class hr_notifications(models.Model): + + _name='hr.notifications' + + employee_id = fields.Many2one('hr.employee', "Employee") + user_id = fields.Many2one('res.users', "Employee") + for_emp = fields.Many2one('hr.employee', "For Employee") + days = fields.Integer('Days') + hours = fields.Float("Hours", digits=(5, 2)) + date = fields.Date('Date') + type = fields.Selection([('training_end','Training End'), + ('permit_end','Permit End'), + ('term_end','Term End'), + ('disability','Disability'), + ('leave_balance','Leave Balance'), + ('disability','Disability'), + ('overtime','Overtime'), + ], "Type") + + @api.multi + def send(self): + template_env = self.env['email.template'] + template = False + #if self.type == 'training_end': + # template = self.env.ref('itis_hr_notifications.email_template_training_end', False) + #elif self.type == 'permit_end': + # template = self.env.ref('itis_hr_notifications.email_template_work_permit_end', False) + #elif self.type == 'term_end': + # template = self.env.ref('itis_hr_notifications.email_template_temp_empl', False) + #elif self.type == 'disability': + # template = self.env.ref('itis_hr_notifications.email_template_emp_disable', False) + #elif self.type == 'leave_balance': + # template = self.env.ref('itis_hr_notifications.email_template_leave_end', False) + #elif self.type == 'overtime': + # template = self.env.ref('itis_hr_notifications.email_template_overtime', False) + if template: + + template.send_mail(self.id) + + + @api.model + def create_notification(self, type, data): + if type == 'training_end': + mail_dict = self.get_usermail(data.get('emp'),employee=True, manager=True, parent=True) + for emp in mail_dict.get('employee'): + vals = { + 'employee_id': emp.id, + 'date': data.get('date'), + 'type': 'training_end', + 'for_emp': data.get('emp').id, + } + notification = self.create(vals) + notification.send() + for user in mail_dict.get('users'): + vals = { + 'user_id': user.id, + 'date': data.get('date'), + 'type': 'training_end', + 'for_emp': data.get('emp').id, + } + notification = self.create(vals) + notification.send() + if type == 'permit_end': + mail_dict = self.get_usermail(data.get('emp'), employee=False, manager=True, parent=True) + for emp in mail_dict.get('employee'): + vals = { + 'employee_id': emp.id, + 'date': data.get('date'), + 'type': 'permit_end', + 'for_emp': data.get('emp').id, + } + notification = self.create(vals) + notification.send() + for user in mail_dict.get('users'): + vals = { + 'user_id': user.id, + 'date': data.get('date'), + 'type': 'permit_end', + 'for_emp': data.get('emp').id, + } + notification = self.create(vals) + notification.send() + if type == 'term_end': + mail_dict = self.get_usermail(data.get('emp'), employee=True, manager=True, parent=True) + for emp in mail_dict.get('employee'): + vals = { + 'employee_id': emp.id, + 'date': data.get('date'), + 'type': 'term_end', + 'for_emp': data.get('emp').id, + } + notification = self.create(vals) + notification.send() + for user in mail_dict.get('users'): + vals = { + 'user_id': user.id, + 'date': data.get('date'), + 'type': 'term_end', + 'for_emp': data.get('emp').id, + } + notification = self.create(vals) + notification.send() + if type == 'disability': + mail_dict = self.get_usermail(data.get('emp'), employee=True, manager=True, parent=False) + for emp in mail_dict.get('employee'): + vals = { + 'employee_id': emp.id, + 'date': data.get('date'), + 'type': 'disability', + 'for_emp': data.get('emp').id, + } + notification = self.create(vals) + notification.send() + for user in mail_dict.get('users'): + vals = { + 'user_id': user.id, + 'date': data.get('date'), + 'type': 'disability', + 'for_emp': data.get('emp').id, + } + notification = self.create(vals) + notification.send() + if type == 'leave_balance': + mail_dict = self.get_usermail(data.get('emp'), employee=True, manager=False, parent=False) + for emp in mail_dict.get('employee'): + vals = { + 'employee_id': emp.id, + 'date': data.get('date'), + 'type': 'leave_balance', + 'for_emp': data.get('emp').id, + 'days': abs(data.get('emp').leave_days + data.get('emp').additional_leave_days - data.get('emp').approved_leaves) + } + notification = self.create(vals) + notification.send() + if type == 'overtime': + mail_dict = self.get_usermail(data.get('emp'), employee=True, manager=True, parent=True) + for emp in mail_dict.get('employee'): + vals = { + 'employee_id': emp.id, + 'date': data.get('date'), + 'type': 'overtime', + 'for_emp': data.get('emp').id, + # 'hours': data.get('emp').overtime_count + 'hours': data.get('emp').employee_overtime_id.emp_overtime_count + } + notification = self.create(vals) + notification.send() + for user in mail_dict.get('users'): + vals = { + 'user_id': user.id, + 'date': data.get('date'), + 'type': 'overtime', + 'for_emp': data.get('emp').id, + # 'hours': data.get('emp').overtime_count + 'hours': data.get('emp').employee_overtime_id.emp_overtime_count + } + notification = self.create(vals) + notification.send() + + @api.model + def get_usermail(self, emp, employee=False, manager=False, parent=False): + # print employee, manager, parent + mail_dict = {'employee': [], 'users': []} + groups_env = self.env['res.groups'] + + if employee: + mail_dict['employee'].append(emp) + + if parent: + if emp and emp.parent_id and emp.parent_id not in mail_dict['employee']: + mail_dict['employee'].append(emp.parent_id) + if manager: + groups = [self.env.ref('base.group_hr_manager').id] + for group in groups_env.browse(groups): + for user in group.users: + if user.login and re.match('[^@]+@[^@]+\.[^@]+', user.login): + flag = True + for emp in mail_dict['employee']: + if emp.user_id.id == user.id: + flag = False + if flag: + mail_dict['users'].append(user) + return mail_dict + + + +class hr_contract(models.Model): + + _inherit = 'hr.contract' + + @api.model + def send_notification(self): + notify_env = self.env['hr.notifications'] + user_rec = self.env['res.users'].search([('id', '=', self._uid)], limit=1) + contract_ids = self.search([]) + for rec in contract_ids: + today = datetime.now()#.strftime(DF) + #training_check + if rec.trial_date_end: + exp = user_rec.company_id.training_end_day or 1 + date_after_month = today + delta(weeks=exp) + if date_after_month.strftime(DF) == rec.trial_date_end: + data_dict = {"emp":rec.employee_id, 'date': rec.trial_date_end} + notify_env.create_notification('training_end', data_dict) + + #work Permit check + if rec.visa_expire: + exp = user_rec.company_id.work_permit or 1 + date_after_month = today + delta(weeks=exp) + if date_after_month.strftime(DF) == rec.visa_expire: + data_dict = {"emp":rec.employee_id, 'date': rec.visa_expire} + notify_env.create_notification('permit_end', data_dict) + + #end of term + if rec.date_end: + exp = user_rec.company_id.term_end or 1 + date_after_month = today + delta(weeks=exp) + new_contract = self.search([('employee_id', '=', rec.employee_id.id), ('date_start', '>', rec.date_end)]) + if date_after_month.strftime(DF) == rec.date_end and not new_contract: + data_dict = {"emp":rec.employee_id, 'date': rec.date_end} + notify_env.create_notification('term_end', data_dict) + +class hr_employee(models.Model): + + _inherit = 'hr.employee' + + @api.model + def check_disability(self): + notify_env = self.env['hr.notifications'] + user_rec = self.env['res.users'].search([('id', '=', self._uid)], limit=1) + emp_ids = self.search([('disability_limited_until', '!=', False)]) + exp = user_rec.company_id.savirity or 1 + date_after_month = datetime.now() + delta(weeks=exp) + for rec in emp_ids: + if date_after_month.strftime(DF) == rec.disability_limited_until: + data_dict = {"emp":rec, 'date': rec.disability_limited_until} + notify_env.create_notification('disability', data_dict) + + @api.model + def check_leave_bal(self): + notify_env = self.env['hr.notifications'] + user_rec = self.env['res.users'].search([('id', '=', self._uid)], limit=1) + exp = user_rec.company_id.remaining_leaves or 1 + year_end = datetime(datetime.today().year, 12, 31) + emp_ids = self.search([]) + if year_end.strftime(DF) == datetime.now().strftime(DF): + for rec in emp_ids: + if rec.leave_days + rec.additional_leave_days - rec.approved_leaves: + data_dict = {'emp': rec, 'date':year_end.strftime(DF)} + notify_env.create_notification('leave_balance', data_dict) + + + @api.model + def check_overtime(self): + emp_ids = self.search([]) + notify_env = self.env['hr.notifications'] + for emp in emp_ids: + # if emp.overtime_count > 40.0 or emp.overtime_count < -40.0: + if emp.employee_overtime_id.emp_overtime_count > 39.99 or emp.employee_overtime_id.emp_overtime_count < -39.99: + data_dict = {'emp': emp} + notify_env.create_notification('overtime', data_dict) + return True + +# @api.multi +# def update_overtime_count(self, ot_time, reason): +# res = super(hr_employee, self).update_overtime_count(ot_time, reason) +# if self.overtime_count > 0.0: +# notify_env = self.env['hr.notifications'] +# data_dict = {'emp': self} +# notify_env.create_notification('overtime', data_dict) +# return res + + diff --git a/itis_hr_notifications/security/ir.model.access.csv b/itis_hr_notifications/security/ir.model.access.csv new file mode 100644 index 0000000..c26ce16 --- /dev/null +++ b/itis_hr_notifications/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_notification,access_notification,model_hr_notifications,,1,1,1,1 \ No newline at end of file diff --git a/itis_ldap_config/__init__.py b/itis_ldap_config/__init__.py new file mode 100644 index 0000000..fdcb0c1 --- /dev/null +++ b/itis_ldap_config/__init__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + +from . import models diff --git a/itis_ldap_config/__openerp__.py b/itis_ldap_config/__openerp__.py new file mode 100644 index 0000000..bffe244 --- /dev/null +++ b/itis_ldap_config/__openerp__.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + +{ + 'name': "ITIS Ldap User Config", + 'summary': """ Module to configure new ldap user with old user""", + 'description': """ + Module to configure new ldap user with old user + """, + 'author': "IT IS AG", + 'website': "http://www.itis-odoo.de", + 'category': 'base', + 'version': '1.0.55.0', + 'depends': ['base','itis_hr_extend','hr_timesheet_sheet'], + 'data': [ + 'views/ldap_view.xml', + 'security/ir.model.access.csv', + 'data/cron.xml', + ], + 'css': [], + 'demo': [], +} diff --git a/itis_ldap_config/data/cron.xml b/itis_ldap_config/data/cron.xml new file mode 100644 index 0000000..f61ff57 --- /dev/null +++ b/itis_ldap_config/data/cron.xml @@ -0,0 +1,16 @@ + + + + + ITIS Update LDAP User + configure_ldap_user + days + 1 + + + -1 + ldap.record + + + + \ No newline at end of file diff --git a/itis_ldap_config/i18n/de.po b/itis_ldap_config/i18n/de.po new file mode 100644 index 0000000..49f4201 --- /dev/null +++ b/itis_ldap_config/i18n/de.po @@ -0,0 +1,80 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * itis_ldap_config +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-11-29 08:59+0000\n" +"PO-Revision-Date: 2017-11-29 10:07+0100\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: \n" +"X-Generator: Poedit 1.5.4\n" + +#. module: itis_ldap_config +#: view:ldap.record:itis_ldap_config.ldap_record_tree +msgid "Current User name" +msgstr "aktueller Benutzer" + +#. module: itis_ldap_config +#: view:ldap.record:itis_ldap_config.ldap_record_tree +msgid "Employee Name" +msgstr "Mitarbeiter" + +#. module: itis_ldap_config +#: view:ldap.record:itis_ldap_config.ldap_record_tree +msgid "Employee No" +msgstr "Personal-Nr" + +#. module: itis_ldap_config +#: code:addons/itis_ldap_config/models/hr_timesheet.py:18 +#, python-format +msgid "Error!" +msgstr "Error!" + +#. module: itis_ldap_config +#: field:hr.analytic.timesheet,for_ldap_modification:0 +msgid "For Ldap Modification" +msgstr "For Ldap Modification" + +#. module: itis_ldap_config +#: model:ir.ui.menu,name:itis_ldap_config.menu_ldap_record +msgid "LDAP Record" +msgstr "LDAP Record" + +#. module: itis_ldap_config +#: model:ir.actions.act_window,name:itis_ldap_config.hr_ldap_record_action +#: view:ldap.record:itis_ldap_config.ldap_record_tree +msgid "Ldap Record" +msgstr "Ldap Record" + +#. module: itis_ldap_config +#: view:ldap.record:itis_ldap_config.ldap_record_tree +msgid "Ldap User name" +msgstr "Ldap Benutzername" + +#. module: itis_ldap_config +#: model:ir.model,name:itis_ldap_config.model_hr_analytic_timesheet +msgid "Timesheet Line" +msgstr "Zeiterfassungsposition" + +#. module: itis_ldap_config +#: view:ldap.record:itis_ldap_config.ldap_record_tree +msgid "User Configured" +msgstr "Benutzer konfiguriert" + +#. module: itis_ldap_config +#: model:ir.model,name:itis_ldap_config.model_res_users +msgid "Users" +msgstr "Benutzer" + +#. module: itis_ldap_config +#: code:addons/itis_ldap_config/models/hr_timesheet.py:18 +#, python-format +msgid "You cannot modify an entry in a confirmed timesheet." +msgstr "Sie können keinen Eintrag in einer bestätigten Zeiterfassung ändern" diff --git a/itis_ldap_config/models/__init__.py b/itis_ldap_config/models/__init__.py new file mode 100644 index 0000000..40333f6 --- /dev/null +++ b/itis_ldap_config/models/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + +from . import hr_timesheet +from . import ldap_record +from . import res_users + diff --git a/itis_ldap_config/models/hr_timesheet.py b/itis_ldap_config/models/hr_timesheet.py new file mode 100644 index 0000000..7cbcff2 --- /dev/null +++ b/itis_ldap_config/models/hr_timesheet.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +from openerp.osv import fields, osv +from openerp.tools.translate import _ + +class hr_timesheet_line(osv.osv): + _inherit = "hr.analytic.timesheet" + + # Add a column for ldap modifications records + _columns = { + 'for_ldap_modification': fields.boolean('For Ldap Modification'), + } + + # def _check(self, cr, uid, ids): + # for att in self.browse(cr, uid, ids): + # # print"for ldap,sheet id----",att.for_ldap_modification,att.sheet_id + # if att.sheet_id and att.sheet_id.state not in ('draft', 'new') and not att.for_ldap_modification:#do not give a warning for ldap modify records + # raise osv.except_osv(_('Error!'), _('You cannot modify an entry in a confirmed timesheet.')) + # return True \ No newline at end of file diff --git a/itis_ldap_config/models/ldap_record.py b/itis_ldap_config/models/ldap_record.py new file mode 100644 index 0000000..8561fa4 --- /dev/null +++ b/itis_ldap_config/models/ldap_record.py @@ -0,0 +1,103 @@ +# -*- coding: utf-8 -*- +from openerp import models, api, fields, _ +import logging +logger = logging.getLogger(__name__) + +class ldap_record(models.Model): + _name = 'ldap.record' + + emp_name= fields.Char() + emp_no= fields.Char() + ldap_uname= fields.Char() + cur_uname=fields.Char() + user_configured=fields.Boolean(string="User Configured") + + @api.one + def configure_ldap_user_subfunction(self,context): + ldap_record = self.env['ldap.record'] + res_users = self.env['res.users'] + if context and context.get('user_id'): + res_user_rec = res_users.browse(context.get('user_id')) + ldap_records_brw = ldap_record.search([('user_configured','=',False),('ldap_uname','=',res_user_rec.login)]) + print"ldap_records_brw------",ldap_records_brw + self.ldap_data_exchange(ldap_records_brw) + + + @api.model + def configure_ldap_user(self): + #Add a logic to map and search LDAP user + logger.info("-----Ldap userconfigure cron---- ") + ldap_record = self.env['ldap.record'] + ldap_records_brw = ldap_record.search([('user_configured','=',False)]) + self.ldap_data_exchange(ldap_records_brw) + + + def ldap_data_exchange(self,ldap_records_brw): + res_users = self.env['res.users'] + hr_employee = self.env['hr.employee'] + for ldap_record_brw in ldap_records_brw: + old_user =False + new_user = res_users.search([('login','=',ldap_record_brw.ldap_uname)],limit=1) + # old_user = res_users.search([('login','=',ldap_record_brw.cur_uname)],limit=1) + related_emp =hr_employee.search([('identification_id','=',ldap_record_brw.emp_no)],limit=1) + if related_emp: + old_user = related_emp.user_id + logger.info("---Ldap In the cron------ " ) + logger.info("---Ldap new user--main---- %s" %str(new_user)) + logger.info("---Ldap old user---main--- %s" %str(old_user)) + + # print"old_user------",old_user.name + # print"related_emp------",related_emp.name + if new_user and old_user and related_emp: + # logger.info("---Ldap new user------ %s" %new_user.login) + logger.info("---Ldap old user------ %s" %old_user.login) + + related_emp.write({'user_id':new_user.id}) #new user write to emp + + #new user write to old time sheet + related_timesheet_records = self.env['hr_timesheet_sheet.sheet'].search([('employee_id','=',related_emp.id),('user_id','=',old_user.id)]) + [i.write({'user_id':new_user.id}) for i in related_timesheet_records] + + #new user write to old analytic timesheet (I use the query here as well as write function) + related_analytic_timesheet_records = self.env['hr.analytic.timesheet'].search([('user_id','=',old_user.id)]) + # related_analytic_ids = related_analytic_timesheet_records.ids + # self._cr.execute("update hr_analytic_timesheet set for_ldap_modification=true where id in %s",(tuple(related_analytic_ids),)) + # [i.with_context(for_ldap_records=True).write({'user_id':new_user.id}) for i in related_analytic_timesheet_records] + for i in related_analytic_timesheet_records: + if not i.sheet_id: + i.line_id.write({'user_id':new_user.id}) + else: + sheet_id = i.sheet_id + i.line_id.write({'user_id':new_user.id}) + self._cr.execute("update hr_analytic_timesheet set sheet_id=%s where id =%s",(sheet_id.id,i.id)) + + #new user write to the old leave requests + related_leave_requests = self.env['hr.holidays'].search([('user_id','=',old_user.id)]).ids + if related_leave_requests: + self._cr.execute('update hr_holidays set user_id=%s where id in %s',(new_user.id,tuple(related_leave_requests))) + # print"Leave requests-------",related_leave_requests + + #new user to the old calendar events + related_calendar_events = self.env['calendar.event'].search([('user_id','=',old_user.id)]).ids + # self._cr.execute('update calendar_event set user_id=%s where id in %s',(new_user.id,tuple(related_calendar_events))) + # print"Calendar Events-------",related_calendar_events + for event_id in related_calendar_events: + if event_id: + self.env['calendar.event'].browse(event_id).write({'user_id':new_user.id}) + + #assign old user partner to new user and delete or deactivate new user partner + try: + new_user_partner = new_user.partner_id + new_user.write({'partner_id':old_user.partner_id.id}) + new_user_partner.unlink() + logger.info("-- Related Partner record can not be link-----") + except: + #Todo Error handling + pass + + # old user set to inactive + old_user.write({'active':False}) + + #write configuration is done for this ldap record + ldap_record_brw.write({'user_configured':True}) + logger.info("---Ldap In the cron---successfull--- " ) diff --git a/itis_ldap_config/models/res_users.py b/itis_ldap_config/models/res_users.py new file mode 100644 index 0000000..00a63a0 --- /dev/null +++ b/itis_ldap_config/models/res_users.py @@ -0,0 +1,17 @@ +from openerp import tools +from openerp.osv import fields, osv +from openerp import SUPERUSER_ID +from openerp.modules.registry import RegistryManager + + +class users(osv.osv): + _inherit = "res.users" + def _login(self, db, login, password): + user_id = super(users, self)._login(db, login, password) + # print"user_id-------",user_id + registry = RegistryManager.get(db) + with registry.cursor() as cr: + ldap_obj = registry.get('ldap.record') + context={'user_id':user_id} + # ldap_obj.configure_ldap_user_subfunction(cr,SUPERUSER_ID,user_id,context) + return user_id diff --git a/itis_ldap_config/security/ir.model.access.csv b/itis_ldap_config/security/ir.model.access.csv new file mode 100644 index 0000000..ed3a3ae --- /dev/null +++ b/itis_ldap_config/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_itis_ldap_record,access_ldap_record,model_ldap_record,,1,1,1,1 \ No newline at end of file diff --git a/itis_ldap_config/views/ldap_view.xml b/itis_ldap_config/views/ldap_view.xml new file mode 100644 index 0000000..889bce5 --- /dev/null +++ b/itis_ldap_config/views/ldap_view.xml @@ -0,0 +1,29 @@ + + + + + ldap.record.tree + ldap.record + + + + + + + + + + + + + + Ldap Record + ir.actions.act_window + ldap.record + form + tree,form + + + + \ No newline at end of file diff --git a/itis_payroll_export/__init__.py b/itis_payroll_export/__init__.py new file mode 100644 index 0000000..73e677b --- /dev/null +++ b/itis_payroll_export/__init__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## +import hr_setting +import wizard diff --git a/itis_payroll_export/__openerp__.py b/itis_payroll_export/__openerp__.py new file mode 100644 index 0000000..a13e0e4 --- /dev/null +++ b/itis_payroll_export/__openerp__.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +{ + 'name': "ITIS Payroll Export", + + 'summary': """ + ITIS Payroll Export + """, + + 'description': """ + Module will export Payroll data to csv file + """, + + 'author': "ITIS AG", + 'website': "http://www.itis.de", + + 'category': 'HR', + 'version': '1.0.55.0', + + # any module necessary for this one to work correctly + 'depends': ['itis_hr_leave_extend', 'itis_hr_extend'], + + # always loaded + 'data': [ + 'security/ir.model.access.csv', + 'hr_setting_view.xml', + 'wizard/payroll_export.xml', + ], diff --git a/itis_payroll_export/hr_setting.py b/itis_payroll_export/hr_setting.py new file mode 100644 index 0000000..c83f947 --- /dev/null +++ b/itis_payroll_export/hr_setting.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + + +from openerp import models, fields, api, _ + + +class hr_config(models.TransientModel): + + _inherit = "hr.config.settings" + + sick_account_id = fields.Many2one("account.analytic.account", "Sick Account") + + @api.multi + def set_sick_account_id(self): + self.env.user.company_id.write({ + "sick_account_id": self.sick_account_id.id, + }) + return True + + @api.model + def default_get(self, fields): + sick_id = self.env.user.company_id.sick_account_id.id or False + res = super(hr_config, self).default_get(fields) + res.update({ + "sick_account_id": sick_id, + }) + return res + + +class res_company(models.Model): + + _inherit = "res.company" + + sick_account_id = fields.Many2one("account.analytic.account", "Sick Account") + diff --git a/itis_payroll_export/hr_setting_view.xml b/itis_payroll_export/hr_setting_view.xml new file mode 100644 index 0000000..ee8b664 --- /dev/null +++ b/itis_payroll_export/hr_setting_view.xml @@ -0,0 +1,25 @@ + + + + + + view.hr.configuration.inh + hr.config.settings + + + +
+
+
+
+
+ +
+
+ diff --git a/itis_payroll_export/i18n/de.po b/itis_payroll_export/i18n/de.po new file mode 100644 index 0000000..c14a97c --- /dev/null +++ b/itis_payroll_export/i18n/de.po @@ -0,0 +1,100 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * itis_payroll_export +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-12-11 13:57+0000\n" +"PO-Revision-Date: 2016-12-11 18:57+0100\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: \n" +"X-Generator: Poedit 1.5.4\n" + +#. module: itis_payroll_export +#: view:payroll.export:itis_payroll_export.payroll_export_form_view +msgid "Cancel" +msgstr "Abbrechen" + +#. module: itis_payroll_export +#: view:payroll.export:itis_payroll_export.payroll_export_form_view +msgid "Click 'Export' button to export payroll csv" +msgstr "Klicken Sie auf Exportieren um die Lohndaten zu exportieren." + +#. module: itis_payroll_export +#: model:ir.model,name:itis_payroll_export.model_res_company +msgid "Companies" +msgstr "Unternehmen" + +#. module: itis_payroll_export +#: field:payroll.export,create_uid:0 +msgid "Created by" +msgstr "Created by" + +#. module: itis_payroll_export +#: field:payroll.export,create_date:0 +msgid "Created on" +msgstr "Created on" + +#. module: itis_payroll_export +#: view:payroll.export:itis_payroll_export.payroll_export_form_view +msgid "Export" +msgstr "Exportieren" + +#. module: itis_payroll_export +#: view:payroll.export:itis_payroll_export.payroll_export_form_view +msgid "Export file:" +msgstr "Export Datei:" + +#. module: itis_payroll_export +#: code:addons/itis_payroll_export/wizard/payroll_export.py:101 +#, python-format +msgid "Exported Payroll" +msgstr "Exportierter Lohnstapel" + +#. module: itis_payroll_export +#: field:payroll.export,file_name:0 +msgid "File" +msgstr "Datei" + +#. module: itis_payroll_export +#: field:payroll.export,id:0 +msgid "ID" +msgstr "ID" + +#. module: itis_payroll_export +#: field:payroll.export,write_uid:0 +msgid "Last Updated by" +msgstr "Last Updated by" + +#. module: itis_payroll_export +#: field:payroll.export,write_date:0 +msgid "Last Updated on" +msgstr "Last Updated on" + +#. module: itis_payroll_export +#: field:payroll.export,name:0 +msgid "Payroll CSV" +msgstr "Lohstapel CSV" + +#. module: itis_payroll_export +#: model:ir.actions.act_window,name:itis_payroll_export.payroll_export_action +#: model:ir.ui.menu,name:itis_payroll_export.menu_payroll_export +msgid "Payroll Export" +msgstr "Lohnstapel Export" + +#. module: itis_payroll_export +#: field:hr.config.settings,sick_account_id:0 +#: field:res.company,sick_account_id:0 +msgid "Sick Account" +msgstr "Kostenstelle Krankheit" + +#. module: itis_payroll_export +#: view:payroll.export:itis_payroll_export.payroll_export_form_view +msgid "or" +msgstr "oder" diff --git a/itis_payroll_export/i18n/en_US.po b/itis_payroll_export/i18n/en_US.po new file mode 100644 index 0000000..b3870c4 --- /dev/null +++ b/itis_payroll_export/i18n/en_US.po @@ -0,0 +1,111 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * itis_payroll_export +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-04-19 15:39+0000\n" +"PO-Revision-Date: 2017-04-19 17:43+0100\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: \n" +"X-Generator: Poedit 1.5.4\n" + +#. module: itis_payroll_export +#: view:payroll.export:itis_payroll_export.payroll_export_form_view +msgid "Cancel" +msgstr "Cancel" + +#. module: itis_payroll_export +#: view:payroll.export:itis_payroll_export.payroll_export_form_view +msgid "Click 'Export' button to export payroll csv" +msgstr "Click 'Export' button to export payroll csv" + +#. module: itis_payroll_export +#: model:ir.model,name:itis_payroll_export.model_res_company +msgid "Companies" +msgstr "Companies" + +#. module: itis_payroll_export +#: field:payroll.export,create_uid:0 +msgid "Created by" +msgstr "Created by" + +#. module: itis_payroll_export +#: field:payroll.export,create_date:0 +msgid "Created on" +msgstr "Created on" + +#. module: itis_payroll_export +#: code:addons/itis_payroll_export/wizard/payroll_export.py:73 +#, python-format +msgid "" +"Die Aktion bitte immer über den Menüpunkt \"Lohnkonten Stapel\" aufrufen" +msgstr "Use this function from menu \"Salary batches\"." + +#. module: itis_payroll_export +#: view:payroll.export:itis_payroll_export.payroll_export_form_view +msgid "Export" +msgstr "Export" + +#. module: itis_payroll_export +#: view:payroll.export:itis_payroll_export.payroll_export_form_view +msgid "Export file:" +msgstr "Export file:" + +#. module: itis_payroll_export +#: code:addons/itis_payroll_export/wizard/payroll_export.py:109 +#, python-format +msgid "Exported Payroll" +msgstr "Exported Payroll" + +#. module: itis_payroll_export +#: field:payroll.export,file_name:0 +msgid "File" +msgstr "File" + +#. module: itis_payroll_export +#: field:payroll.export,id:0 +msgid "ID" +msgstr "ID" + +#. module: itis_payroll_export +#: field:payroll.export,write_uid:0 +msgid "Last Updated by" +msgstr "Last Updated by" + +#. module: itis_payroll_export +#: field:payroll.export,write_date:0 +msgid "Last Updated on" +msgstr "Last Updated on" + +#. module: itis_payroll_export +#: model:ir.actions.act_window,name:itis_payroll_export.launch_payroll_export_wizard +msgid "Lohndaten exportieren" +msgstr "Export Salary data" + +#. module: itis_payroll_export +#: field:payroll.export,name:0 +msgid "Payroll CSV" +msgstr "Payroll CSV" + +#. module: itis_payroll_export +#: model:ir.actions.act_window,name:itis_payroll_export.payroll_export_action +msgid "Payroll Export" +msgstr "Payroll Export" + +#. module: itis_payroll_export +#: field:hr.config.settings,sick_account_id:0 +#: field:res.company,sick_account_id:0 +msgid "Sick Account" +msgstr "Sick Account" + +#. module: itis_payroll_export +#: view:payroll.export:itis_payroll_export.payroll_export_form_view +msgid "or" +msgstr "or" diff --git a/itis_payroll_export/security/ir.model.access.csv b/itis_payroll_export/security/ir.model.access.csv new file mode 100644 index 0000000..df5e297 --- /dev/null +++ b/itis_payroll_export/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +payroll_export_id,payroll_export_name,model_payroll_export,,1,1,1,1 \ No newline at end of file diff --git a/itis_payroll_export/wizard/__init__.py b/itis_payroll_export/wizard/__init__.py new file mode 100644 index 0000000..8eae18d --- /dev/null +++ b/itis_payroll_export/wizard/__init__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + +from . import payroll_export diff --git a/itis_payroll_export/wizard/__init__.pyc b/itis_payroll_export/wizard/__init__.pyc new file mode 100644 index 0000000..69ab702 Binary files /dev/null and b/itis_payroll_export/wizard/__init__.pyc differ diff --git a/itis_payroll_export/wizard/payroll_export.py b/itis_payroll_export/wizard/payroll_export.py new file mode 100644 index 0000000..1c8b0d2 --- /dev/null +++ b/itis_payroll_export/wizard/payroll_export.py @@ -0,0 +1,116 @@ +# -*- coding: utf-8 -*- + +############################################################################## +# +# TicTac allows several HR functionalities. This program bases on Odoo v. 8. Copyright +# (C) 2018 ITIS www.itis.de commissioned by Wikimedia Deutschland e.V. +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# this program. If not, see . +# +############################################################################## + + +from openerp import models, fields, api, _ +from openerp.exceptions import Warning +import csv +from datetime import datetime +import base64 +import os + +class payroll_export(models.TransientModel): + + _name = 'payroll.export' + + + name = fields.Binary('Payroll CSV') + file_name = fields.Char('File') + + @api.model + def get_sick_days(self, payslip): + # print "computing days" +# timesheet_env = self.env['hr.timesheet'] + hr_analytic_env = self.env['hr.analytic.timesheet'] + search_domain = [ + ('date', '>', payslip.date_from), + ('date', '<=', payslip.date_to), + ('user_id', '=', payslip.employee_id.user_id.id), + ('account_id', '=', payslip.company_id.sick_account_id.id) + ] + days = 0.0 + timesheet_line_ids = hr_analytic_env.search(search_domain) + if len(timesheet_line_ids): + for line in timesheet_line_ids: + for plan in line.sheet_id.planned_ids: + if plan.sheet_date == line.date and plan.duration: + days +=line.unit_amount/plan.duration + + return float("{0:.2f}".format(days)) + + @api.model + def get_net(self, payslip): + amount = 0.0 + for data in payslip.details_by_salary_rule_category: + if data.code == "NET": + amount = data.total + return amount + + + @api.multi + def export_csv(self): + payslip_env = self.env['hr.payslip'] + if self._context and 'active_model' in self._context and self._context['active_model'] == 'hr.payslip.run': + slip_ids = self.env['hr.payslip.run'].browse(self._context['active_id']).slip_ids.ids + else: + raise Warning(_('Die Aktion bitte immer über den Menüpunkt "Lohnkonten Stapel" aufrufen')) + payslip_ids = payslip_env.search([('state', '=', 'done'), ('id','in', slip_ids),('credit_note', '=', False)]) + data_list = [] + csv_header = ['Identification', 'Name', 'Krankheitstage', "Gehalt/Lohn", "Remark"] + time_csv = datetime.now().strftime('%Y-%m-%d %H:%M:%S') + '.csv' + csv_path = "/tmp/" + time_csv + for payslip in payslip_ids: + emp_name = payslip.employee_id.name + if payslip.employee_id and payslip.employee_id.surname and payslip.employee_id.second_name: + emp_name = "%s %s"%(payslip.employee_id.surname or '' , payslip.employee_id.second_name or '') + vals = { + "Identification": payslip.employee_id.identification_id or '', + 'Name': emp_name, + 'Krankheitstage': self.get_sick_days(payslip), + 'Gehalt/Lohn': self.get_net(payslip), + 'Remark':payslip.employee_id.wage_info, + } + data_list.append(vals) + + # for payslip in payslip_ids:#to write the info with null value + # payslip.employee_id.write({'wage_info':''}) + + with open(csv_path, 'wb') as csvfile: + w = csv.DictWriter(csvfile, fieldnames=csv_header, delimiter=';') + w.writeheader() + w.writerows(data_list) + csvfile.close() + data = '' + with open(csv_path, 'rb') as csvfile: + data = csvfile.read() + data = data.encode('base64') + csvfile.close() + context = self._context.copy() + context.update({'default_name': data, 'default_file_name': 'payroll_export_' + time_csv}) + os.remove(csv_path) + return { + 'name': _('Exported Payroll'), + 'view_type': 'form', + "view_mode": 'form', + 'res_model': 'payroll.export', + 'type': 'ir.actions.act_window', + 'context': context, + 'target':'new', + } diff --git a/itis_payroll_export/wizard/payroll_export.pyc b/itis_payroll_export/wizard/payroll_export.pyc new file mode 100644 index 0000000..c8d94c6 Binary files /dev/null and b/itis_payroll_export/wizard/payroll_export.pyc differ diff --git a/itis_payroll_export/wizard/payroll_export.xml b/itis_payroll_export/wizard/payroll_export.xml new file mode 100644 index 0000000..66840d6 --- /dev/null +++ b/itis_payroll_export/wizard/payroll_export.xml @@ -0,0 +1,46 @@ + + + + + + payroll.export.form.view + payroll.export + +
+
+ + + Payroll Export + ir.actions.act_window + payroll.export + form + form + new + + + + + + + + +
+
\ No newline at end of file