diff --git a/copri4/License/agpl-3.0.txt b/copri4/License/agpl-3.0.txt new file mode 100644 index 0000000..be3f7b2 --- /dev/null +++ b/copri4/License/agpl-3.0.txt @@ -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/copri4/main/css/bootstrap-icons-1.5.0 b/copri4/main/css/bootstrap-icons-1.5.0 new file mode 120000 index 0000000..5dd7b38 --- /dev/null +++ b/copri4/main/css/bootstrap-icons-1.5.0 @@ -0,0 +1 @@ +/etc/shareeconf/bootstrap-icons-1.5.0 \ No newline at end of file diff --git a/copri4/main/css/favicon.ico b/copri4/main/css/favicon.ico new file mode 100644 index 0000000..5b7c354 Binary files /dev/null and b/copri4/main/css/favicon.ico differ diff --git a/copri4/main/css/local_style_2.css b/copri4/main/css/local_style_2.css new file mode 100755 index 0000000..6cab3a8 --- /dev/null +++ b/copri4/main/css/local_style_2.css @@ -0,0 +1,1052 @@ + diff --git a/copri4/main/glyphicons b/copri4/main/glyphicons new file mode 120000 index 0000000..493cef9 --- /dev/null +++ b/copri4/main/glyphicons @@ -0,0 +1 @@ +/etc/shareeconf/glyphicons \ No newline at end of file diff --git a/copri4/main/img/Open_Blue.png b/copri4/main/img/Open_Blue.png new file mode 100644 index 0000000..059f4aa Binary files /dev/null and b/copri4/main/img/Open_Blue.png differ diff --git a/copri4/main/img/Open_Green.png b/copri4/main/img/Open_Green.png new file mode 100644 index 0000000..b0ae260 Binary files /dev/null and b/copri4/main/img/Open_Green.png differ diff --git a/copri4/main/img/Open_Red.png b/copri4/main/img/Open_Red.png new file mode 100644 index 0000000..c076f9a Binary files /dev/null and b/copri4/main/img/Open_Red.png differ diff --git a/copri4/main/img/konrad-pin_blau-gruen.png b/copri4/main/img/konrad-pin_blau-gruen.png new file mode 100644 index 0000000..be73677 Binary files /dev/null and b/copri4/main/img/konrad-pin_blau-gruen.png differ diff --git a/copri4/main/img/konrad-pin_blau-rot.png b/copri4/main/img/konrad-pin_blau-rot.png new file mode 100644 index 0000000..538325f Binary files /dev/null and b/copri4/main/img/konrad-pin_blau-rot.png differ diff --git a/copri4/main/img/konrad-pin_halb-gruen-rot.png b/copri4/main/img/konrad-pin_halb-gruen-rot.png new file mode 100644 index 0000000..0f07d46 Binary files /dev/null and b/copri4/main/img/konrad-pin_halb-gruen-rot.png differ diff --git a/copri4/main/img/konrad-pin_halb-gruen.png b/copri4/main/img/konrad-pin_halb-gruen.png new file mode 100644 index 0000000..7745519 Binary files /dev/null and b/copri4/main/img/konrad-pin_halb-gruen.png differ diff --git a/copri4/main/img/konrad-pin_halb-rot-gruen.png b/copri4/main/img/konrad-pin_halb-rot-gruen.png new file mode 100644 index 0000000..f4239d0 Binary files /dev/null and b/copri4/main/img/konrad-pin_halb-rot-gruen.png differ diff --git a/copri4/main/img/konrad-pin_halb-rot.png b/copri4/main/img/konrad-pin_halb-rot.png new file mode 100644 index 0000000..740b8af Binary files /dev/null and b/copri4/main/img/konrad-pin_halb-rot.png differ diff --git a/copri4/main/img/konrad-pin_rot-gruen.png b/copri4/main/img/konrad-pin_rot-gruen.png new file mode 100644 index 0000000..9604dfe Binary files /dev/null and b/copri4/main/img/konrad-pin_rot-gruen.png differ diff --git a/copri4/main/img/konrad-pin_rot-rot.png b/copri4/main/img/konrad-pin_rot-rot.png new file mode 100644 index 0000000..3a59378 Binary files /dev/null and b/copri4/main/img/konrad-pin_rot-rot.png differ diff --git a/copri4/main/img/logout.svg b/copri4/main/img/logout.svg new file mode 100644 index 0000000..d95ac95 --- /dev/null +++ b/copri4/main/img/logout.svg @@ -0,0 +1,95 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/copri4/main/img/refresh.png b/copri4/main/img/refresh.png new file mode 100644 index 0000000..c32d51d Binary files /dev/null and b/copri4/main/img/refresh.png differ diff --git a/copri4/main/img/sharee_bike_Logo.jpg b/copri4/main/img/sharee_bike_Logo.jpg new file mode 100644 index 0000000..dd3cbb0 Binary files /dev/null and b/copri4/main/img/sharee_bike_Logo.jpg differ diff --git a/copri4/main/js/bootstrap-3.3.6-dist b/copri4/main/js/bootstrap-3.3.6-dist new file mode 120000 index 0000000..9ba5877 --- /dev/null +++ b/copri4/main/js/bootstrap-3.3.6-dist @@ -0,0 +1 @@ +/etc/shareeconf/bootstrap-3.3.6-dist \ No newline at end of file diff --git a/copri4/main/js/bootstrap-5.0.2-dist b/copri4/main/js/bootstrap-5.0.2-dist new file mode 120000 index 0000000..8d27d79 --- /dev/null +++ b/copri4/main/js/bootstrap-5.0.2-dist @@ -0,0 +1 @@ +/etc/shareeconf/bootstrap-5.0.2-dist \ No newline at end of file diff --git a/copri4/main/js/jquery-1.9.1.js b/copri4/main/js/jquery-1.9.1.js new file mode 120000 index 0000000..759613b --- /dev/null +++ b/copri4/main/js/jquery-1.9.1.js @@ -0,0 +1 @@ +/etc/shareeconf/jquery-1.9.1.js \ No newline at end of file diff --git a/copri4/main/js/jquery-3.3.1.min.js b/copri4/main/js/jquery-3.3.1.min.js new file mode 120000 index 0000000..49433bb --- /dev/null +++ b/copri4/main/js/jquery-3.3.1.min.js @@ -0,0 +1 @@ +/etc/shareeconf/jquery-3.3.1.min.js \ No newline at end of file diff --git a/copri4/main/js/jquery-ui-1.12.1 b/copri4/main/js/jquery-ui-1.12.1 new file mode 120000 index 0000000..85e8f82 --- /dev/null +++ b/copri4/main/js/jquery-ui-1.12.1 @@ -0,0 +1 @@ +/etc/shareeconf/jquery-ui-1.12.1 \ No newline at end of file diff --git a/copri4/main/js/jquery.autosize.js b/copri4/main/js/jquery.autosize.js new file mode 120000 index 0000000..3c8c919 --- /dev/null +++ b/copri4/main/js/jquery.autosize.js @@ -0,0 +1 @@ +/etc/shareeconf/jquery.autosize.js \ No newline at end of file diff --git a/copri4/main/js/mobile_script.js b/copri4/main/js/mobile_script.js new file mode 100644 index 0000000..3daed5f --- /dev/null +++ b/copri4/main/js/mobile_script.js @@ -0,0 +1,121 @@ +function show_passwd() { + var x = document.getElementById('txt04'); + if (x.type === "password") { + x.type = "text"; + } else { + x.type = "password"; + } + var y = document.getElementById('confirm_txt04'); + if (y.type === "password") { + y.type = "text"; + } else { + y.type = "password"; + } +} + +$(function() { + $( '#datepicker1' ).datepicker({ dateFormat: 'dd.mm.yy', dayNamesMin: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'], monthNames: ['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember']}); + $( '#datepicker2' ).datepicker({ dateFormat: 'dd.mm.yy', dayNamesMin: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'], monthNames: ['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember']}); + $( '#datepicker3' ).datepicker({ dateFormat: 'dd.mm.yy', dayNamesMin: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'], monthNames: ['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember']}); +}); + +function WhichButton(event,URL){ +if ('which' in event) + { + switch (event.which) + { + case 1: + if (event.ctrlKey==1) + { + var mainwindow = window.open(URL,"_self"); + mainwindow.focus(); + } + //alert ("Left mouse button was pressed"); + break; + //case 2: + // alert ("Middle mouse button was pressed"); + // break; + case 3: + var mainwindow = window.open(URL,"_self"); + mainwindow.focus(); + //alert ("Right mouse button was pressed"); + break; + } + } +} + +//align element +function align_logo() { + var w = window.outerWidth; + walign = w / 100 * 16; + w -= walign; + document.getElementById("animate_logo_2").style.left = w + 'px'; +} + +$( function() { + $( "#dialog_message" ).dialog({ + autoOpen: false + }); + $( "#dialog_opener" ).on( "click", function() { + $( "#dialog_message" ).dialog( "open" ); + }); +}); + +function toggle_box(id) { + var popup = document.getElementById(id); + popup.classList.toggle("show"); +} + + + +//check all checkboxes +function CheckAll() { + for (var i = 0; i < document.searchform.elements.length; i++) { + if(document.searchform.elements[i].type == 'checkbox' && document.searchform.elements[i].name != 'temp' && document.searchform.elements[i].name != 'csv'){ + document.searchform.elements[i].checked = !(document.searchform.elements[i].checked); + } + } +} +function CheckListAll() { + for (var i = 0; i < document.listform.elements.length; i++) { + if(document.listform.elements[i].type == 'checkbox'){ + document.listform.elements[i].checked = !(document.listform.elements[i].checked); + } + } +} +function CheckEditAll() { + for (var i = 0; i < document.editform.elements.length; i++) { + if(document.editform.elements[i].type == 'checkbox'){ + document.editform.elements[i].checked = !(document.editform.elements[i].checked); + } + } +} + +//post submit modal box position +function modal_position(xpos,ypos) { + var elx = document.getElementById('xpos'); + var ely = document.getElementById('ypos'); + var myDialogX = $("#dialog-form2").offset().left - 4; + var myDialogY = $("#dialog-form2").offset().top - 44; + //alert(myDialogX + '-----' + myDialogY); + elx.value = myDialogX; + ely.value = myDialogY; +} + + + +function go2select (select) { + var wert = select.options[select.options.selectedIndex].value; + if (select == "nothing") { + document.forms[0].reset(); + document.forms[0].elements[0].blur(); + return; + } else { + location.href = wert; + document.forms[0].reset(); + document.forms[0].elements[0].blur(); + focus(); + } +} + + diff --git a/copri4/main/robots.txt b/copri4/main/robots.txt new file mode 100755 index 0000000..1f53798 --- /dev/null +++ b/copri4/main/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / diff --git a/copri4/main/src/Lib/Config.pm b/copri4/main/src/Lib/Config.pm new file mode 100644 index 0000000..c9f9f4c --- /dev/null +++ b/copri4/main/src/Lib/Config.pm @@ -0,0 +1,25 @@ +package Config; + +#Deprecated config file +#Please use shareeconf/* + +use strict; +use warnings; +use CGI; +my $q = new CGI; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +sub envonline(){ + my $self = shift; + my %varenv = (); + return %varenv; +} + +1; + diff --git a/copri4/main/src/Lib/Mlogic.pm b/copri4/main/src/Lib/Mlogic.pm new file mode 100644 index 0000000..0eb8ce1 --- /dev/null +++ b/copri4/main/src/Lib/Mlogic.pm @@ -0,0 +1,27 @@ +package Mlogic; +use strict; +use warnings; +use CGI::Carp qw(fatalsToBrowser); +use CGI ':standard'; +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Libenzdb; +use Mod::Auth; +use POSIX; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my $self = shift; +} + +1; + + diff --git a/copri4/main/src/Lib/PDFGenerator.pm b/copri4/main/src/Lib/PDFGenerator.pm new file mode 100644 index 0000000..268c9a7 --- /dev/null +++ b/copri4/main/src/Lib/PDFGenerator.pm @@ -0,0 +1,141 @@ +package PDFGenerator; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +# +use strict; +use warnings; + +use POSIX; +use CGI::Cookie (); +use CGI; +use CGI::Carp qw(fatalsToBrowser); +use CGI ':standard'; +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Libenzdb; +use Mod::DBtank; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +sub printpre(){ + my $q = new CGI; + my $cf = new Config; + my $lb = new Libenz; + my $db = new Libenzdb; + my $dbt = new DBtank; + my $but = new Buttons; + my %varenv = $cf->envonline(); + my $path = $q->path_info(); + my $script = $q->script_name(); + my $user_agent = $q->user_agent(); + my %ib = $but->ibuttons(); + my $today = strftime("%d.%m.%Y %H:%M",localtime(time)); + my $lang="de"; + + my $printer_id=$R::printer_id; + my $mandant_main_id = $R::mandant_main_id; + my $id=$R::id; + + my $ctf = $db->get_content1("contentuser","$mandant_main_id"); + my $ctrel = $db->get_ctrel("contentadr","",$lang,"",$id); + + print $q->start_html(-title=>'PDFGenerator'); + + my $width="1799px"; +if(1==1){ + print "","\n"; +} + + print $q->div({-style=>'font-size:1.2em;font-weight:bold;padding:1em 0.1em;'},"SEPA-Lastschriftmandat"),"\n"; + print $q->div({-class=>'Oline'},""),"\n"; + + print $q->start_table({-border=>'0', -cellpadding=>'3', -cellspacing=>'0'}),"\n"; + print $q->Tr(),"\n"; + print $q->td({-class=>'tdname1'}, "Zahlungsempfänger"),"\n"; + print $q->td({-class=>'tdval1'}, "$dbt->{payone_conf}->{sepa_creditor_name}"),"\n"; + print $q->Tr(),"\n"; + print $q->td({-class=>'tdname1'}, "Gläubiger-Identifikationsnummer"),"\n"; + print $q->td({-class=>'tdval1'}, "$dbt->{payone_conf}->{sepa_creditor_id}"),"\n"; + print $q->Tr(),"\n"; + print $q->td({-class=>'tdname1'}, "Mandatsreferenz"),"\n"; + print $q->td({-class=>'tdval1'}, "$ctrel->{ct_name}"),"\n"; + print $q->end_table,"\n"; + + print $q->div({-class=>'Oline'},""),"\n"; + print $q->div({-class=>'content1'},"Ich ermächtige den Zahlungsempfänger, Zahlungen von meinem Konto mittels Lastschrift einzuziehen. Zugleich weise ich mein Kreditinstitut an, die von dem Zahlungsempfänger auf mein Konto gezogenen Lastschriften einzulösen."),"\n"; + print $q->div({-class=>'content1'},"Hinweis: Ich kann innerhalb von acht Wochen, beginnend mit dem Belastungsdatum, die Erstattung des belasteten Betrages verlangen. Es gelten dabei die mit meinem Kreditinstitut vereinbarten Bedingungen."),"\n"; + print $q->div({-class=>'Oline'},""),"\n"; + + print $q->start_table({-border=>'0',-cellpadding=>'3', -cellspacing=>'0'}),"\n"; + print $q->Tr(),"\n"; + print $q->td({-class=>'tdname1'}, "Name des Zahlungspflichtigen"),"\n"; + print $q->td({-class=>'tdval1'}, "$ctrel->{txt01}"),"\n"; + print $q->Tr(),"\n"; + print $q->td({-class=>'tdname1'}, "Straße Nr."),"\n"; + print $q->td({-class=>'tdval1'}, "$ctrel->{txt03}"),"\n"; + print $q->Tr(),"\n"; + print $q->td({-class=>'tdname1'}, "PLZ Ort"),"\n"; + print $q->td({-class=>'tdval1'}, "$ctrel->{txt06}"),"\n"; + print $q->Tr(),"\n"; + print $q->td({-class=>'tdname1'}, "Land"),"\n"; + print $q->td({-class=>'tdval1'}, "$ctrel->{txt10}"),"\n"; + print $q->Tr(),"\n"; + print $q->td({-class=>'tdname1'}, "E-Mail"),"\n"; + print $q->td({-class=>'tdval1'}, "$ctrel->{txt08}"),"\n"; + print $q->Tr(),"\n"; + print $q->td({-class=>'tdname1'}, "Swift BIC"),"\n"; + print $q->td({-class=>'tdval1'}, "$ctrel->{txt23}"),"\n"; + print $q->Tr(),"\n"; + print $q->td({-class=>'tdname1'}, "Bankkontonummer - IBAN"),"\n"; + print $q->td({-class=>'tdval1'}, "$ctrel->{txt22}"),"\n"; + + print $q->end_table,"\n"; + + print $q->div({-class=>'content1'},""),"\n"; + print $q->div({-class=>'content1'},"$ctrel->{txt06}, $today, $ctrel->{txt01}"),"\n"; + + print $q->end_html; + return Apache2::Const::OK; +} +1; + diff --git a/copri4/main/src/Lib/Printpreview.pm b/copri4/main/src/Lib/Printpreview.pm new file mode 100644 index 0000000..b677ce5 --- /dev/null +++ b/copri4/main/src/Lib/Printpreview.pm @@ -0,0 +1,825 @@ +package Printpreview; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +# +use strict; +use warnings; + +use POSIX; +use CGI::Cookie (); +use CGI; +use CGI::Carp qw(fatalsToBrowser); +use CGI ':standard'; +use DateTime; +use DateTime::Format::Pg; +use Scalar::Util qw(looks_like_number); +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Libenzdb; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +sub printpre(){ + my $q = new CGI; + my $cf = new Config; + my $lb = new Libenz; + my $db = new Libenzdb; + my $but = new Buttons; + my %varenv = $cf->envonline(); + my $path = $q->path_info(); + my $script = $q->script_name(); + my $user_agent = $q->user_agent(); + my %ib = $but->ibuttons(); + my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; + my $lang="de"; + + my $printer_id=$R::printer_id; + my $u_id=$R::u_id; + my $c_id=$R::c_id4trans; + my $mandant_main_id=$R::mandant_main_id; + my $main_id=$R::main_id; + my $ct_name2print=$R::ct_name2print; + my $wc= $1 if($R::wc =~ /(\d+\.\d+)/); + my $node = $db->get_node4multi($R::main_id,$lang); + #print "$u_id,$c_id,$mandant_main_id,$main_id,$ct_name2print,$wc"; + + + print $q->start_html(-title=>'COPRIprint', + -base=>'true', + -target=>'Printpre' + ); + + my $width="1400px"; +if(1==1){ + print ""; +} + + my $users = $db->select_users($u_id); + my $ctf = $db->get_content1("contentuser","$mandant_main_id"); + $ctf->{txt13} = $1 if($ctf->{txt13} =~ /(\d+)/); + + my $tpl = $db->get_tpl($ctf->{txt34});#Verkauf template + $tpl = $db->get_tpl($ctf->{txt36}) if($users->{kind_of_trans} =~ /Faktur/); + my $ctt = $db->get_content1("contenttrans",$c_id); + + #payone Bank + my $footer_bank = $ctf->{txt19}; + #sparkasse Bank + $footer_bank = $ctf->{txt20} if($ctt->{state} !~ /payone/i); + + + my $ctt_users = $db->get_owner($ctt->{owner}); + my $vendor = $ctt_users->{u_name};#Login-ID + $vendor = $ctt->{txt13} if($ctt->{txt13});#full Name + my $kd_nr = " Kunden Nr.: $ctt->{int10}"; + my $mandat_nr; + $mandat_nr = " Mandatsreferenz: $ctt->{txt26}" if($ctt->{txt26} =~ /PO-/); + + my $invoice_time = $ctt->{invoice_time} || $ctt->{mtime}; + my $mtime = $lb->time4de("$invoice_time",""); + + $db->updater("contenttrans","c_id",$ctt->{c_id},"invoice_time","$invoice_time",""); + # + my $scol = "c_id"; + #$scol = "$users->{cash_sort}" if($users->{cash_sort}); + my $i=0; + my $tplf = $db->get_tpl("201");#Firma tpl + my @tplf_order = split /,/,$tplf->{tpl_order}; + + my $logo = "$ctf->{img01}" || "000empty"; + if($printer_id =~ /Briefpapier/){ + #Ohne Logo da Briefpapier + $logo = "000empty"; + } + + #logging siteformat + open(PMA, ">> $varenv{logdir}/Printpreview.log"); + print PMA "$now_dt --> $ct_name2print\n"; + + my $site=1; + my $site_all=1; + my ($address_wc,$table_wc) = split(/\./,$wc); + $wc = $address_wc + $table_wc; + print PMA "wc: $wc = $address_wc + $table_wc\n"; + $wc += 3 if($ctt->{txt00} !~ /Lieferschein/);#Netto+UmSt+Summe Zeilen + print PMA "wc: $wc\n"; + my $max_site_wc = "40"; + my $max_table_wc = "14"; + print PMA "max_site_wc: $max_site_wc | max_table_wc: $max_table_wc\n"; + + my $h_top = "0"; + my $footer_top = "1820";#ende der 1.seite + print PMA "top: $h_top | $footer_top\n"; + + #1.seite + &header_small("0",$mandant_main_id,$logo) if("$ctt->{txt00}" =~ /Quittung/); + &header_big("0",$mandant_main_id,$c_id,$logo) if("$ctt->{txt00}" !~ /Quittung/); + &data_invoice("0",$vendor,$kd_nr,$mandat_nr,$ctt->{txt00},$ct_name2print,$mtime); + + #table + my ($sum_paid,$break_table_wc,$nullcount) = &data_table("0",$c_id,$scol,"",$mandant_main_id,$users->{kind_of_trans},$tpl->{tpl_order},"0",$max_table_wc,$ctt); + + #print "$site_all++ if(($wc > $max_site_wc) || ($table_wc > $max_table_wc)) --> $break_table_wc"; + #$site_all++ if(($wc > $max_site_wc) || ($table_wc > $max_table_wc)); + if($break_table_wc > $max_table_wc){ + $site_all++; + print PMA "max_site_wc: $max_site_wc | max_table_wc: $max_table_wc\n"; + print PMA "site_all: $site_all if($break_table_wc > $max_table_wc)\n"; + } + + print PMA "$site_all,$footer_top,$site,$site_all,$wc\n"; + if($site_all == 1){ + &text_description("0",$mandant_main_id,$ctt->{txt21},$ctt->{txt12},$users->{kind_of_trans},$ctt->{txt00},$nullcount); + &text_footer($mandant_main_id,$footer_top,$site,$site_all,$wc,$footer_bank,$logo); + }else{ + &text_footer($mandant_main_id,$footer_top,$site,$site_all,$wc,$footer_bank,$logo); + } + + #2.seite + if($site_all > 1){ + #Alles horizontal absolut zum obersten Punkt ausrichten + $h_top = $footer_top + 270;# second header top, depence from footer_top + &header_small($h_top,$mandant_main_id,$logo); + $h_top +=250; + &data_invoice($h_top,$vendor,$kd_nr,$mandat_nr,$ctt->{txt00},$ct_name2print,$mtime); + $h_top +=60; + #table_break + if($break_table_wc >= $max_table_wc){ + my ($sum_paid,$exit_table_wc,$nullcount) = &data_table($h_top,$c_id,$scol,"",$mandant_main_id,$users->{kind_of_trans},$tpl->{tpl_order},$break_table_wc,$max_table_wc,$ctt,$sum_paid); + $h_top += ($table_wc - $max_table_wc) * 65; + print PMA "h_top: $h_top += ($table_wc - $max_table_wc) * 65\n"; + } + + #print "$h_top | $table_wc | $break_table_wc >= $max_table_wc"; + &text_description($h_top,$mandant_main_id,$ctt->{txt21},$ctt->{txt12},$users->{kind_of_trans},$ctt->{txt00},$nullcount); + $footer_top +=130; + $site++; + print PMA "$site_all,$footer_top,$site,$site_all,$wc\n"; + &text_footer($mandant_main_id,$footer_top,$site,$site_all,$wc,$footer_bank,$logo); + } + ########## + # + close PMA; + + #Briefkopf + sub header_small(){ + my ($h_top,$mandant_main_id,$logo) = @_; + my $position; + my $h_toppx = "$h_top" . "px"; + $position = "position:absolute; top: $h_toppx;" if($h_top); + print $q->div({-style=>"$position width:$width;text-align:right;border:0px solid black;margin:0 0 200px 0;"},$q->span({-style=>'margin:0em;'},$q->img({-src=>"$varenv{metahost}/img/$logo",-height=>'120px;'})),$q->span({-style=>'font-size:1em;'},"\n")); + } + + #Briefkopf + Adresse + sub header_big(){ + my ($h_top,$mandant_main_id,$c_id,$logo) = @_; + $ctf = $db->get_content1("contentuser","$mandant_main_id"); + my $ctt = $db->get_content1("contenttrans",$c_id); + $ctt->{txt01} = $lb->newline($ctt->{txt01},$users->{tiny_mce},"0"); + + print $q->div({-style=>"width:$width; text-align:right;border:0px solid black;margin:0 0 200px 0;"},$q->span({-style=>'margin:0em;'},$q->img({-src=>"$varenv{metahost}/img/$logo",-height=>'120px;'})),$q->span({-style=>'font-size:1em;'},"")),"\n"; + + print $q->start_table({-width=>'100%',-border=>'0',-align=>'center', -cellpadding=>'3', -cellspacing=>'0'}),"\n"; + print "\n"; + + print "\n"; + print $q->start_table({-width=>'100%',-border=>'0',-align=>'left', -cellpadding=>'3', -cellspacing=>'0'}),"\n"; + print $q->Tr(); + print $q->td({-class=>'tdpdf4', -style=>'padding-bottom:0.8em;text-decoration:underline;color:black;'}, "$ctf->{txt01} | $ctf->{txt02} | $ctf->{txt03}","\n"); + #print $q->Tr(); + #print $q->td({-class=>'tdpdf1'}, "$ctt->{txt02}  ","\n"); + print $q->Tr(); + print $q->td({-class=>'tdpdf1'}, "$ctt->{txt01}  ","\n"); + print $q->Tr(); + print $q->td({-class=>'tdpdf1'}, "$ctt->{txt03}  ","\n"); + print $q->Tr(); + print $q->td({-class=>'tdpdf1'}, "$ctt->{txt06}  ","\n"); + print $q->Tr(); + print $q->td({-style=>'padding:0.8em 0;'},"\n"); + print $q->end_table; + print ""; + + + my $txid = ""; + $txid = "TXID: $ctt->{txt16}" if($ctt->{txt16} && $ctt->{state} =~ /payone/i); + my $mailaccount = ""; + $mailaccount = "Account: $ctt->{txt08}" if($ctt->{txt08}); + + print ""; + print $q->start_table({-border=>'0',-align=>'right', -cellpadding=>'0', -cellspacing=>'0'}); + print $q->Tr(); + print $q->td({-style=>'padding:2em 0;'}," "),"\n"; + print $q->Tr(); + print $q->td({-class=>'tdpdf5'}, "$txid"),"\n"; + print $q->Tr(); + print $q->td({-class=>'tdpdf5'}, "$mailaccount"),"\n"; + print $q->Tr(); + print $q->td({-class=>'tdpdf5'}, "Leistungsdatum: $ctt->{txt20}"),"\n"; + print $q->end_table; + print ""; + + print ""; + print $q->end_table; + #print $q->div({-style=>"text-align:right;width:$width;font-size:1em;"},"Login: $ctt->{txt08} "),"\n"; + #print $q->div({-style=>"text-align:right;width:$width;font-size:1em;"},"Leistungsdatum: $ctt->{txt20} "),"\n" if($ctt->{txt20}); + } + #end Adresse + + sub data_invoice(){ + my ($h_top,$vendor,$kd_nr,$mandat_nr,$node_name,$ct_name2print,$mtime) = @_; + my $position; + my $h_toppx = "$h_top" . "px"; + $position = "position:absolute; top: $h_toppx;" if($h_top); + $node_name =~ s/steuerfrei//; + + my $praefix = ""; + $praefix = "konrad-TINK" if($varenv{wwwhost} =~ /tink/); + $praefix = "$varenv{praefix}" if($varenv{syshost} =~ /sharee/); + + print $q->div({-style=>"width:$width;$position border: 0px solid black;"}, + $q->span({-style=>'font-size:1.5em;margin:0.5em 0 0.5em 0.5em;'},"$node_name"), + $q->span({-style=>'font-size:1em;margin:0.5em 0.5em 0.5em 0;'},"Nr.: $praefix-$ct_name2print"), + $q->span({-style=>'float:right;text-align:right;font-size:1em;margin:0.5em 0 0.5em 0;'},"Datum: $mtime "), + $q->span({-style=>'font-size:1em;margin:0.5em;'}," $kd_nr"), + $q->span({-style=>'font-size:1em;margin:0.5em;'}," $mandat_nr"), + #$q->span({-style=>'font-size:1.1em;margin:0.5em;'},$q->img({-src=>"$varenv{metahost}/pdf/barcode-$ctt->{ct_name}.jpeg", -height=>'60px;'})), + ); + } + + sub data_table(){ + my ($h_top,$c_id,$scol,$ctt_dummy,$mandant_main_id,$kind_of_trans,$tpl_order,$break_table_wc,$max_table_wc,$ctt,$sum_break) = @_; + #print "($h_top,$c_id,$scol,$ctt_dummy,$mandant_main_id,$kind_of_trans,$tpl_order,$break_table_wc,$max_table_wc)"; + $ctf = $db->get_content1("contentuser","$mandant_main_id"); + + my $umst1619 = $lb->umst_breaking($ctt,""); + + my $txt20 = $ctt->{txt20}; + my $max_timestamp = "210001012359"; + if($node->{node_name} !~ /journal/){ + if($txt20 =~ /(\d{2})\.(\d{2})\.(\d{4})$/){ + $max_timestamp = $3 . $2 . $1 . "2359"; + }elsif($ctf->{txt80} =~ /(\d{2})\.(\d{2})\.(\d{4})$/){ + $max_timestamp = $3 . $2 . $1 . "2359"; + } + } + + my $max_sum = $ctf->{int03} || "10000"; + my ($cttpos,$rows) = $db->collect_contentpos("contenttrans",$c_id); + my $h_toppx = "$h_top" . "px"; + my $position; + $position = "position:absolute; top: $h_toppx;" if($h_top); + + print "\n
\n"; + print $q->start_table({ -border=>'0', -width=>'100%',-align=>'center', -cellpadding=>'3', -cellspacing=>'0'}),"\n"; + my @tpl_order = split /,/,$tpl_order; + + #Tableheader + my $h=0; + print $q->Tr(),"\n"; + foreach (@tpl_order){ + my ($key,$val) = split /=/,$_; + $h++ if($val && $key !~ /int07/); + print $q->th({-class=>'tdint'},"$val"),"\n" if("$key" eq "ct_name"); + print $q->th({-class=>'tdtxt2'},"$val"),"\n" if($key =~ /txt01/); + print $q->th({-class=>'tdint'},"$val"),"\n" if($key =~ /int03/); + if($ctt->{txt00} =~ /Lieferschein/){ + print $q->th(""),"\n" if($key =~ /int02|int03/); + }else{ + print $q->th({-class=>'tdint'},"$val"),"\n" if($key =~ /int02/); + print $q->th({-class=>'tdint'},"$val"),"\n" if($key =~ /int04/); + } + } + $h--; + + #Übertrag Zwischensumme + if($break_table_wc){ + print "\n"; + print "\n"; + print "\n"; + print $q->start_table({-style=>'border:1px solid silver;', -border=>'0', -width=>'100%',-align=>'center', -cellpadding=>'3', -cellspacing=>'0'}),"\n"; + + print $q->Tr("\n"); + print $q->td({-class=>'tdsum',-colspan=>"$h"},"Übertrag:"); + print $q->td({-class=>'tdint',-nowrap=>"1"},"$sum_break €"); + print $q->end_table,"\n"; + print "\n"; + print "\n"; + + } + + #Tablecontent (ct_name(primary key)) + my $sum_parts0=0; + my $sum_parts7=0; + my $sum_parts19=0; + my $j=0; + my $k=0; + my $nullcount=0; + foreach my $id (sort { $cttpos->{$a}->{$scol} <=> $cttpos->{$b}->{$scol} } keys(%$cttpos)){ + my $cttpos_timestamp = $1 . $2 . $3 . "0000" if($cttpos->{$id}->{itime} =~ /(\d+)\-(\d+)\-(\d+)/); + #$k++; + my $menge="0";my $gesamt="0";my $kaution="0";my $gesamt_kaution="0"; + my $timeing="0";my $times;my $rent_time;my $start_time;my $end_time; + #Mietzeit wenn Verleihräder + if($kind_of_trans =~ /Faktur|Verleih/ && $cttpos->{$id}->{int12} =~ /$ctf->{txt29}/){ + $timeing="1"; + $times = $db->get_time4ct("contenttranspos",$cttpos->{$id}->{c_id}); + $start_time = $lb->time4de($times->{start_time},"1"); + $end_time = $lb->time4de($times->{end_time},"1"); + } + + my $einzel = $cttpos->{$id}->{int02}; + my $menge = $cttpos->{$id}->{int03} || 0; + my $unit = $cttpos->{$id}->{txt03}; + + #start copri pricing on 2018-03-21 + my $dt1 = DateTime->new(year => 2018, month => 3, day => 20); + my $dt0 = $dt1; + my $dt2 = $dt1; + $dt0 = DateTime::Format::Pg->parse_datetime($cttpos->{$id}->{start_time}) if($cttpos->{$id}->{start_time}); + $dt2 = DateTime::Format::Pg->parse_datetime($cttpos->{$id}->{end_time}) if($cttpos->{$id}->{end_time}); + + if(looks_like_number($einzel) && $einzel != 0 && looks_like_number($menge) && $menge != 0){ + $gesamt = $einzel * $menge; + } + + #max. Rechnungspositionen + if(($gesamt == 0) && ($cttpos_timestamp <= $max_timestamp || $ctt->{int05} == 1) && ($sum_parts19 <= $max_sum)){ + $nullcount++; + } + #print "if(($gesamt != 0) && ($cttpos_timestamp <= $max_timestamp || $ctt->{int05} == 1) && ($sum_parts19 <= $max_sum)){"; + if(($gesamt != 0) && ($cttpos_timestamp <= $max_timestamp || $ctt->{int05} == 1) && ($sum_parts19 <= $max_sum)){ + + $j++; + if($j<=$max_table_wc || $break_table_wc){ + + + my $rabatt_val = $cttpos->{$id}->{int07} || ""; + if($rabatt_val != 0 && looks_like_number($einzel) && $einzel != 0 && looks_like_number($menge) && $menge != 0){ + my $rabatt_eur = $rabatt_val; + $rabatt_eur = $einzel * $menge * $rabatt_val/100 if($cttpos->{$id}->{int08} != 1);#wenn int08 != 1 alias € + $gesamt = $einzel * $menge - $rabatt_eur; + } + $gesamt = $lb->round($gesamt); + $gesamt = $lb->cashme($gesamt); + #summieren + if("$cttpos->{$id}->{int05}" =~ /\d/){ + #print "xxx $gesamt $cttpos->{$id}->{int05} |"; + $sum_parts0 += $gesamt if("$cttpos->{$id}->{int05}" == "0"); + $sum_parts7 += $gesamt if("$cttpos->{$id}->{int05}" == "7"); + $sum_parts19 += $gesamt if("$cttpos->{$id}->{int05}" >= "16"); + }else{ + #print "yyy $gesamt $ctf->{txt13} |"; + $sum_parts0 += $gesamt if("$ctf->{txt13}" == "0"); + $sum_parts7 += $gesamt if("$ctf->{txt13}" == "7"); + $sum_parts19 += $gesamt if($ctf->{txt13} >= 16); + } + + #2. empty loop for sum + if($break_table_wc){ + #print "$j|"; + next if($j<=$max_table_wc); + } + + my ($s_date,$s_dd,$s_mo,$s_yy,$s_hh,$s_mi,$e_date,$e_yy,$e_mo,$e_dd,$e_hh,$e_mi,$times_id); + + #Make date and time + if($cttpos->{$id}->{start_time} && $cttpos->{$id}->{end_time}){ + ($s_yy,$s_mo,$s_dd,$s_hh,$s_mi) = $lb->split_date($cttpos->{$id}->{start_time}); + ($e_yy,$e_mo,$e_dd,$e_hh,$e_mi) = $lb->split_date($cttpos->{$id}->{end_time}); + } + + #Tablecontent (parameter) + print $q->Tr(),"\n"; + my $k=0; + foreach (@tpl_order){ + #$k++; + my ($key,$val) = split /=/,$_; + #if($cttpos->{$id}->{sort} =~ /^\d+$/){ + # $txtstyle = "border-bottom-width:1px;border-bottom-style:dotted;border-bottom-color:silver;"; + #} + $cttpos->{$id}->{$key} = $q->unescapeHTML("$cttpos->{$id}->{$key}"); + $cttpos->{$id}->{$key} = $lb->newline($cttpos->{$id}->{$key},""); + if("$key" eq "ct_name"){ + my $ct_pos = ""; + if($cttpos->{$id}->{int09}){#if Tarif defined + $ct_pos = "Endstation: $cttpos->{$id}->{int04}  " if($cttpos->{$id}->{int04}); + $ct_pos .= "Rad: $cttpos->{$id}->{ct_name}"; + }else{ + $ct_pos = "$cttpos->{$id}->{ct_name}"; + } + print $q->td({-class=>'tdint'},"$ct_pos "),"\n"; + } + if($key =~ /txt01/){ + print "\n"; + if($cttpos->{$id}->{$key}){ + $cttpos->{$id}->{$key} =~ s/\
/;   /g; + print "$cttpos->{$id}->{$key}
\n"; + } + #if($cttpos->{$id}->{int04}){ + # print $q->span("Station: $cttpos->{$id}->{int04}"),"\n"; + #} + #if($cttpos->{$id}->{txt06}){ + # print $q->span(" (GPS: $cttpos->{$id}->{txt06})"),"\n"; + #} + if($cttpos->{$id}->{start_time}){ + #print "
\n"; + print $q->span("Mietzeit: $s_dd.$s_mo.$s_yy $s_hh:$s_mi – $e_dd.$e_mo.$e_yy $e_hh:$e_mi"),"\n"; + } + print "\n"; + } + + if($key =~ /int03/){ + $menge =~ s/\./,/; + print $q->td({-class=>'tdint'},"$menge"),"\n"; + } + + if($ctt->{txt00} =~ /Lieferschein/){ + print $q->td(""),"\n" if($key =~ /int02|int04/); + }else{ + if($key =~ /int02/){ + if($einzel == "0"){ + $einzel=""; + }else{ + $einzel =~ s/\./,/; + } + print $q->td({-nowrap=>'1',-class=>'tdint'},"$einzel"),"\n"; + } + + if($key =~ /int04/){ + if($gesamt == "0"){ + $gesamt=""; + }else{ + $gesamt .= " €"; + $gesamt =~ s/\./,/; + } + #if($rabatt_val != 0 && $gesamt != 0){ + if($rabatt_val != 0){ + my $proz="%"; + $proz = "€" if($cttpos->{$id}->{int08} == 1); + print $q->td({-nowrap=>'1',-class=>'tdint'},"(Rabatt $rabatt_val $proz) $gesamt"),"\n"; + }else{ + print $q->td({-nowrap=>'1',-class=>'tdint'},"$gesamt"),"\n"; + } + } + } + } + } + } + }#end foreach + + #Zahlungstext Text & Vorbelegungen + my $payment_text; + foreach(@tplf_order){ + my ($key,$des,$size) = split /=/,$_; + if($key =~ /txt52|txt53|txt54|txt55|txt56|txt57|txt58|txt59|txt60/){ + $ctf->{$key} = $q->unescapeHTML("$ctf->{$key}"); + $ctf->{$key} = $lb->newline($ctf->{$key},$users->{tiny_mce},""); + $ctt->{state} =~ s/\(payone.*//; + if("$des" =~ /$ctt->{state}/ && ($j <= $max_table_wc || $break_table_wc)){ + if($sum_parts19 < 0){ + $payment_text = "$ctf->{txt58}"; + }else{ + $payment_text = "$ctf->{$key}"; + } + } + } + } + + + my $diff7 = 100 + 7; + my $diff19 = 100 + $umst1619; + my $sum_umst7 = $sum_parts7 / $diff7 * 7; + my $sum_umst19 = $sum_parts19 / $diff19 * $umst1619; + $sum_umst7 = $lb->round($sum_umst7); + $sum_umst19 = $lb->round($sum_umst19); + my $sum_netto7 = $sum_parts7 - $sum_umst7; + my $sum_netto19 = $sum_parts19 - $sum_umst19; + $sum_netto7 = $lb->cashme($sum_netto7); + $sum_netto19 = $lb->cashme($sum_netto19); + my $sum_nettoall = $sum_parts0 + $sum_netto7 + $sum_netto19; + $sum_nettoall = $lb->cashme($sum_nettoall,","); + my $sum_paid = $sum_parts0 + $sum_parts7 + $sum_parts19; + $sum_parts0 = $lb->cashme($sum_parts0,","); + $sum_parts7 = $lb->cashme($sum_parts7,","); + $sum_parts19 = $lb->cashme($sum_parts19,","); + $sum_umst7 = $lb->cashme($sum_umst7,","); + $sum_umst19 = $lb->cashme($sum_umst19,","); + $sum_paid = $lb->cashme($sum_paid,","); + + + if($ctt->{txt00} !~ /Lieferschein/){ + + print $q->Tr(),"\n"; + print $q->td({-class=>'Oline',-colspan=>5}," "),"\n"; + + print "\n"; + print "$payment_text\n"; + print "\n"; + print $q->start_table({-style=>'border:1px solid silver;', -border=>'0', -width=>'100%',-align=>'center', -cellpadding=>'3', -cellspacing=>'0'}),"\n"; + + #Summe Endrechnung + if($j <= $max_table_wc || $break_table_wc){ + + print $q->Tr(),"\n"; + print $q->td({-class=>'tdint'},"Summe:"),"\n"; + print $q->td({-class=>'tdint',-nowrap=>"1"},"$sum_paid €"),"\n"; + + + if($ctt->{txt00} !~ /steuerfrei/){#dirty hack + print $q->Tr(),"\n"; + print $q->td({-class=>'tdint'},"Betrag Netto:"),"\n"; + print $q->td({-class=>'tdint',-nowrap=>"1"},"$sum_nettoall €"),"\n"; + if($sum_parts0 != "0"){ + print $q->Tr(),"\n"; + print $q->td({-class=>'tdint',-nowrap=>"1"},"0% UmSt auf $sum_parts0 €:"),"\n"; + print $q->td({-class=>'tdint',-nowrap=>"1"},"0,00 €"),"\n"; + } + if($sum_netto7 != "0"){ + print $q->Tr(),"\n"; + print $q->td({-class=>'tdint',-nowrap=>"1"},"7% UmSt auf $sum_netto7 €:"),"\n"; + print $q->td({-class=>'tdint',-nowrap=>"1"},"$sum_umst7 €"),"\n"; + } + if($sum_parts19 != "0"){ + print $q->Tr(); + print $q->td({-class=>'tdint',-nowrap=>"1"},"$umst1619% UmSt auf $sum_netto19 €:"),"\n"; + print $q->td({-class=>'tdint',-nowrap=>"1"},"$sum_umst19 €"),"\n"; + } + } + + #Zwischensumme + }else{ + print $q->Tr(),"\n"; + print $q->td({-class=>'tdsum',-colspan=>"$h"},"Zwischensumme:"),"\n"; + print $q->td({-class=>'tdint',-nowrap=>"1"},"$sum_paid €"),"\n"; + #print $q->end_table; + } + print $q->end_table,"\n"; + print "\n"; + print "\n"; + } + + print $q->end_table,"\n"; + print "
\n"; + return ("$sum_paid","$j","$nullcount"); + } + + #Beschreibungs-Text + sub text_description(){ + my ($h_top,$mandant_main_id,$ctt_txt21,$ctt_txt12,$kind_of_trans,$node_name,$nullcount) = @_; + my $ctf = $db->get_content1("contentuser","$mandant_main_id"); + my $position; + my $h_toppx = "$h_top" . "px"; + $position = "position:absolute; top: $h_toppx;" if($h_top); + + print "\n
\n"; + print $q->start_table({-style=>"margin-top:0.5em;", -border=>'0', -width=>'100%',-align=>'center', -cellpadding=>'0', -cellspacing=>'0'}); + + #Frei-Text + my $style = "padding:0.4em;text-align:left;font-size:1em;"; + if($nullcount > 0){ + print $q->Tr(); + print $q->td({-style=>"$style",-colspan=>3},"In diesem Zeitraum gab es $nullcount kostenfreie Buchungsvorgänge."); + } + + if($ctt_txt12){ + $ctt_txt12 = $q->unescapeHTML("$ctt_txt12"); + $ctt_txt12 = $lb->newline($ctt_txt12,$users->{tiny_mce},""); + print $q->Tr(); + print $q->td({-style=>"$style",-colspan=>3},"$ctt_txt12"); + } + #Text & Vorbelegungen + print $q->Tr(); + foreach(@tplf_order){ + my ($key,$des,$size) = split /=/,$_; + + if($key =~ /txt6/){ + $ctf->{$key} = $q->unescapeHTML("$ctf->{$key}"); + $ctf->{$key} = $lb->newline($ctf->{$key},$users->{tiny_mce},""); + my @rechnungstext = split(/\
/,$ctf->{$key}); + if($ctt_txt21 =~ /$key/){ + foreach(@rechnungstext){ + if($_ =~ /signature/){ + print $q->Tr(); + print $q->td({-style=>'border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:black;'}," "); + print $q->td({-style=>'width:4em;height:2em;'}," "); + print $q->td({-style=>'border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:black;'}," "); + print $q->Tr(); + print $q->td({-class=>'tdpdf3'}, "   Unterschrift Mieterin / Mieter   ","\n"); + print $q->td(" "); + print $q->td({-class=>'tdpdf3'}, "Unterschrift ","\n"); + print $q->Tr(); + print $q->td({-colspan=>3, -style=>'border-bottom-width:2px;border-bottom-style:solid;border-bottom-color:black;'}," "); + }else{ + $style = "padding:0.4em;text-align:left;font-size:1em;"; + $style = "padding:0.4em;text-align:left;font-size:1em;" if($_ =~ s/\// && $node_name ne "Rückgabe"); + print $q->Tr(); + print $q->td({-style=>"$style",-colspan=>3},"$_"); + } + } + } + } + } + + print $q->end_table; + print "
\n"; + } + + + sub text_footer(){ + my ($mandant_main_id,$top,$site,$site_all,$wc,$footer_bank,$logo) = @_; + my $ctf = $db->get_content1("contentuser","$mandant_main_id"); + $ctf->{txt01} = $q->unescapeHTML("$ctf->{txt01}"); + my @txt11 = split (/;/,"$ctf->{txt11}");#www + my @txt19 = split (/;/,"$footer_bank");#Fußzeile + + $top *= $site; + my $top2 = $top + 120; + $top .= "px"; + $top2 .= "px"; + my $zeilen; + #$zeilen = "Top: $top , Zeilen: $wc , " if($wc); + + #if($logo =~ /empty/){ + # print $q->div({-style=>"min-width:1799px;position:absolute;top:$top;"},""); + #}else{ + + print "
"; + print $q->start_table({-width=>'100%',-border=>'0',-align=>'center', -cellpadding=>'2', -cellspacing=>'0'}); + print ""; + + print ""; + print $q->start_table({-border=>'0',-align=>'left'}); + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "KONTAKT:","\n"); + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "$ctf->{txt01}","\n"); + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "$ctf->{txt04}","\n"); + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "$ctf->{txt05}","\n"); + print $q->end_table; + print ""; + + print ""; + print $q->start_table({-border=>'0',-align=>'left'}); + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "TEL: $ctf->{txt08}","\n"); + #if($ctf->{txt09}){ + # print $q->Tr(); + # print $q->td({-class=>'tdpdf2'}, "FAX: $ctf->{txt09}","\n"); + #} + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "$ctf->{txt10}","\n"); + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "$txt11[0]","\n"); + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "$txt11[1]","\n"); + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "$txt11[2]","\n"); + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "$txt11[3]","\n"); + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "$txt11[4]","\n"); + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "$txt11[5]","\n"); + + print $q->end_table; + print ""; + print ""; + print $q->start_table({-border=>'0',-align=>'left'}); + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "$txt19[0]","\n"); + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "$txt19[1]","\n"); + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "$txt19[2]","\n"); + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "$txt19[3]","\n"); + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "$txt19[4]","\n"); + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "$txt19[5]","\n"); + print $q->end_table; + print ""; + print ""; + print $q->start_table({-width=>'100%',-border=>'0',-align=>'left'}); + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "$txt19[6]","\n"); + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "$txt19[7]","\n"); + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "$txt19[8]","\n"); + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "$txt19[9]","\n"); + print $q->Tr(); + print $q->td({-class=>'tdpdf2'}, "$txt19[10]","\n"); + print $q->end_table; + print ""; + + print ""; + print $q->end_table; + print "
"; + #end Adresse + #} + my $debug = ""; + #$debug = "(address_wc:$address_wc + table_wc:$table_wc) site_all:$site_all++ | break_table_wc:$break_table_wc if((wc:$wc > max_site_wc:$max_site_wc) || (table_wc:$table_wc > max_table_wc:$max_table_wc)) ... (sum_paid:$sum_paid,break_table_wc:$break_table_wc) = &data_table" if($ctt->{owner} eq "101"); + print $q->div({-style=>"text-align:right;width:$width;position:absolute;top:$top2;font-size:0.61em;"},"$debug $zeilen Seite: $site/$site_all"); + } + + print $q->end_html; + return Apache2::Const::OK; +} +1; + diff --git a/copri4/main/src/Mod/APIfunc.pm b/copri4/main/src/Mod/APIfunc.pm new file mode 100644 index 0000000..4aa62a5 --- /dev/null +++ b/copri4/main/src/Mod/APIfunc.pm @@ -0,0 +1,2343 @@ +package APIfunc; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +#Server methods for sharee API +# +#perl -cw +#use lib qw(/var/www/copri4/tinkdms/src); +# +use strict; +use warnings; +use POSIX; +use CGI; # only for debugging +use Digest::MD5 qw(md5 md5_hex); +use Scalar::Util qw(looks_like_number); +use DateTime; +use DateTime::Format::Pg; +use URI::Encode; +use Config::General; + +use Lib::Config; +use Mod::Libenz; +use Mod::DBtank; +use Mod::Callib; +use Mod::Basework; +use Mod::Pricing; +use Data::Dumper; +use Sys::Hostname; +my $hostname = hostname; + +my $cf = new Config; +my $lb = new Libenz; +my $dbt = new DBtank; +my $cal = new Callib; +my $bw = new Basework; +my $pri = new Pricing; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; +my $now_date = strftime "%Y-%m-%d", localtime; +my $lang="de"; +my $owner=188;#via API +my $dbh = ""; + +#helper to get template +sub get_node_meta { + my $self = shift; + my $viewsel = shift; + my $ndesc = $dbt->get_node_meta($dbh,$viewsel); + return $ndesc; +} + +#helper to get node +sub get_node { + my $self = shift; + my $main_id = shift; + my $ndesc = $dbt->get_node($dbh,$main_id); + return $ndesc; +} + +#helper to get DMS users (used by servicetool) +sub select_dmsusers { + my $self = shift; + my $u_id = shift || 0; + my $sqlcon = shift || ""; + my $users = $dbt->select_users($dbh,$u_id,$sqlcon); + return $users; +} + +#node_select +sub template_select(){ + my $self = shift; + my $node = shift; + my $return={}; + + #category means node.main_id. + #template_id from contentpos.template_id + #finally get tpl_order of contentpos + if(ref($node) eq "HASH"){ + + my $node_record = $dbt->fetch_rel4tpl4nd($dbh,$node); + my @tpl_order = split /,/,$node_record->{tpl_order}; + foreach (@tpl_order){ + my ($key,$val,$size,$interval) = split /=/,$_; + $return->{$key} = ["$val","$size","$interval"]; + } + return ($return,$node_record); + }else{ + return "Failure 4003: category OR template must be defined as integer"; + } +}#end node_select + +#Search one by key +sub service_work_search(){ + my $self = shift; + my $bike = shift || ""; + my $station = shift || ""; + my $history = shift || 0; + my $search = shift || ""; + + my $bike_id = $1 if($bike =~ /(\d+)/); + my $station_id = $1 if($station =~ /(\d+)/); + + my $dt1 = DateTime->now; + my $return={}; + + my $pref = { + table => "content", + table_pos => "contentpos", + fetch => "one", + catch => "content_contentpos", + keyfield => "c_id", + }; + if(looks_like_number($bike_id)){ + $pref->{barcode} = "=::" . $bike_id; + } + if(looks_like_number($station_id)){ + $pref->{int04} = "=::" . $station_id; + } + + $pref = { %$pref, mtime => ">=::(now() - interval '$history day')" } if($history > 0); + $pref = { %$pref, $search->{key} => "ilike::$search->{val}" } if(ref($search) eq "HASH" && $search->{key}); + + my $pos_record = $dbt->collect_post($dbh,$pref); + return $pos_record; +} + +#service pre-collect all or with bike/station ID +#obsolte and should be deleted +sub service_work_select(){ + my $self = shift; + my $bike = shift || ""; + my $station = shift || ""; + my $interval = shift || 0; + my $content_template_id = shift || 0; + my $dt1 = DateTime->now; + my $return={}; + + my $bike_id = $1 if($bike =~ /(\d+)/); + my $station_id = $1 if($station =~ /(\d+)/); + + my $pref = { + table => "content", + table_pos => "contentpos", + fetch => "all", + catch => "content_contentpos", + keyfield => "c_id", + template_id => "$content_template_id", + }; + if(looks_like_number($bike_id)){ + $pref->{barcode} = "=::" . $bike_id; + } + if(looks_like_number($station_id)){ + $pref->{int04} = "=::" . $station_id; + } + + $pref = { %$pref, mtime => ">=::(now() - interval '$interval day')" } if($interval > 0); + + + my $pos_record = $dbt->collect_post($dbh,$pref); + return $pos_record; +}#end service_work_select + + +#service_select by service_id=service-c_id +sub service_select { + my $self = shift; + my $q = shift; + my $auth = shift; + my $service_id = shift || ""; + my $interval = shift || ""; + my $pos_record = {}; + my $return = {}; + + my $bike = ""; + my $station = ""; + $bike = $1 if($q->param('bike') =~ /(\d+)/); + $station = $1 if($q->param('station') =~ /(\d+)/); + + my $cpref = {}; + my $c_table = "content"; + my $pos_table = "contentpos"; + my $template_id_pos = ""; + + #all this just get the right pos template_id + if($q->param('request') eq "service_done" || $q->param('request') eq "service_work" || $q->param('request') eq "bikes_all"){ + if(looks_like_number($bike)){ + $cpref = { + table => "$c_table", + fetch => "one", + template_id => "205", + barcode => "=::" . $q->escapeHTML($bike), + }; + } + if(looks_like_number($station)){ + $cpref = { + table => "$c_table", + fetch => "one", + template_id => "225", + int04 => "=::" . $q->escapeHTML($station), + }; + } + if($q->param('request') eq "bikes_all"){ + $cpref = { + table => "$c_table", + fetch => "one", + template_id => "205", + }; + } + if($q->param('request') eq "bikes_all" && looks_like_number($station)){ + $cpref = { + table => "$c_table", + fetch => "one", + template_id => "205", + }; + } + + } + elsif($q->param('request') eq "user_feedback"){ + $c_table = "contentadr"; + $pos_table = "contentadrpos"; + $template_id_pos = 601;#feedback template_id + $cpref = { + table => "$c_table", + fetch => "one", + template_id => "202", + c_id => "$auth->{c_id}", + }; + } + elsif($q->param('request') eq "user_minianswer"){ + $c_table = "contentadr"; + $pos_table = "contentadrpos"; + $template_id_pos = 602;#miniquery answer template_id + $cpref = { + table => "$c_table", + fetch => "one", + template_id => "202", + c_id => "$auth->{c_id}", + }; + } + + + #get real pos.template_id by parent_id=$crecord->{main_id} + my $crecord = $dbt->fetch_record($dbh,$cpref); + + #will be only done if article (bike or station) exists in DB + if(ref($crecord) eq "HASH" && $crecord->{c_id} && $crecord->{main_id}){ + + my $subrelnode = $dbt->get_subrelnode($dbh,$crecord->{main_id},$template_id_pos); + + #get service template to return template formated contentpos + my ($tpl_order,$node_template) = $self->template_select($subrelnode); + my @tpl_order = split /,/,$node_template->{tpl_order}; + + #only used by serviceapp + if($q->param('request') ne "user_feedback" && $q->param('request') ne "user_minianswer"){ + + my $pref = { + table => "$c_table", + table_pos => "$pos_table", + fetch => "all", + catch => "content_contentpos", + keyfield => "c_id", + template_id => "$node_template->{template_id}", + }; + if(looks_like_number($q->param('service_id'))){ + $pref->{c_id} = "=::" . $q->escapeHTML($q->param('service_id')); + }elsif(looks_like_number($service_id)){ + $pref->{c_id} = "=::" . $service_id; + }elsif(looks_like_number($bike)){ + $pref->{barcode} = "=::" . $q->escapeHTML($bike); + }elsif(looks_like_number($station)){ + $pref->{int04} = "=::" . $q->escapeHTML($station); + } + + if($cal->checkdate_time($q->param('timestamp'))){ + $pref->{mtime} = "<=::" . $q->escapeHTML($q->param('timestamp')); + } + + if(looks_like_number($interval) && $interval > 0){ + if($interval == 30){ + #get timestamp from 10. Aufgaben + $pref->{txt01} = "cp.txt01 like '%' and cp.txt01 != 'NaN'"; + $bw->log("service_select collect_post to get timestamp of tenth Aufgabe",$pref,""); + my $pos_record10 = $dbt->collect_post($dbh,$pref,"10"); + foreach my $id (sort { $pos_record10->{$b}->{c_id} <=> $pos_record10->{$a}->{c_id} } keys (%$pos_record10)){ + $pref->{mtime} = ">=::$pos_record10->{$id}->{mtime}"; + } + delete $pref->{txt01}; + }else{ + $pref->{mtime} = ">=::(now() - interval '$interval day')"; + } + #if service saved by servicetool fetch user saved services <= 1day + if($q->param('request') eq "service_done"){ + $pref->{owner} = $auth->{c_id}; + } + } + + $bw->log("service_select collect_post with interval $interval",$pref,""); + $pos_record = $dbt->collect_post($dbh,$pref); + + my $pos_count = 0; + foreach my $id (sort { $pos_record->{$a}->{barcode} <=> $pos_record->{$b}->{barcode} } keys (%$pos_record)){ + foreach (@tpl_order){ + my ($key,$val,$size,$interval) = split /=/,$_; + $pos_count++ if($key =~ /mtime/ && $pos_record->{$id}->{$key}); + $return->{$id}->{$key} = $pos_record->{$id}->{$key} || ""; + } + } + #only used on service init + if($pos_table eq "contentpos" && !$pos_count){ + foreach (@tpl_order){ + my ($key,$val,$size,$interval) = split /=/,$_; + if($key eq "txt01"){ + $return->{1}->{$key} = "::erledigt::"; + $pos_record->{1}->{$key} = "::erledigt::"; + }else{ + $return->{1}->{$key} = "1"; + $pos_record->{1}->{$key} = "1"; + } + } + $return->{1}->{barcode} = "$bike"; + $return->{1}->{cc_id} = "$crecord->{c_id}"; + $return->{1}->{mtime} = "$crecord->{mtime}"; + $return->{1}->{owner} = "$crecord->{owner}"; + $return->{1}->{template_id} = "$node_template->{template_id}"; + $pos_record->{1}->{barcode} = $bike; + $pos_record->{1}->{cc_id} = $crecord->{c_id}; + $pos_record->{1}->{mtime} = $crecord->{mtime}; + $pos_record->{1}->{owner} = $crecord->{owner}; + $pos_record->{1}->{template_id} = $node_template->{template_id}; + } + + #$bw->log("service_select pos_record:",$pos_record,""); + } + + return ($return,$pos_record,$node_template,$crecord); + }#end if($crecord) + else{ + return ("","","",""); + } +}#end service_select + + +#service_insert +sub service_insert(){ + my $self = shift; + my $q = shift; + my $auth = shift; + my $node_template = shift || ""; + my $crecord = shift || {}; + my $owner = shift || 0; + my $return={}; + + #insert pos with cc_id + my $c_id = 0; + if($q->param('request') eq "service_done" && ref($crecord) eq "HASH" && $crecord->{c_id} > 0){ + my $insert = { + table => "contentpos", + cc_id => $crecord->{c_id}, + barcode => $crecord->{barcode}, + int04 => $crecord->{int04}, + owner => $auth->{c_id}, + template_id => $node_template->{template_id}, + mtime => "now()", + }; + $c_id = $dbt->insert_contentoid($dbh,$insert,""); + } + + if($q->param('request') eq "user_feedback" && ref($crecord) eq "HASH" && $crecord->{c_id} > 0){ + my $bike_id = ""; + my $insert = { + table => "contentadrpos", + ca_id => $crecord->{c_id}, + txt01 => $auth->{txt01}, + txt08 => $auth->{txt08}, + owner => $owner, + template_id => $node_template->{template_id}, + mtime => "now()", + }; + + if($q->param('bike') =~ /(\d+)/){ + my $bike = $1; + $insert->{barcode} = $bike; + $c_id = $dbt->insert_contentoid($dbh,$insert,""); + + #if bike_broken then also to contentpos + if(!$q->param('bike_broken')){ + my $cpref = { + table => "content", + fetch => "one", + template_id => "205", + barcode => "$bike", + }; + my $crecord_content = $dbt->fetch_record($dbh,$cpref); + if(ref($crecord_content) eq "HASH" && $crecord_content->{c_id} && $crecord_content->{main_id}){ + my $subrelnode = $dbt->get_subrelnode($dbh,$crecord_content->{main_id},""); + my ($tpl_order,$node_template_contentpos) = $self->template_select($subrelnode); + + my $insert_contentpos = { + table => "contentpos", + cc_id => $crecord_content->{c_id}, + #int03 => $c_id, #yes, c_id from contentadrpos to make backlink + barcode => $crecord_content->{barcode}, + int04 => $crecord_content->{int04}, + owner => $owner, + template_id => $node_template_contentpos->{template_id}, + mtime => "now()", + }; + #$update->{int01} = 1 if($q->param('bike_broken'));#TODO. what should else be done if bike_broken + $insert_contentpos->{txt01} = $q->escapeHTML($q->param('message')) if($q->param('message')); + my $c_id_contentpos = $dbt->insert_contentoid($dbh,$insert_contentpos,""); + } + } + } + } + + if($q->param('request') eq "user_minianswer" && ref($crecord) eq "HASH" && $crecord->{c_id} > 0){ + my $insert = { + table => "contentadrpos", + #ca_id => $crecord->{c_id},#have to be anonym + owner => $owner, + template_id => $node_template->{template_id}, + mtime => "now()", + }; + $c_id = $dbt->insert_contentoid($dbh,$insert,""); + } + + return $c_id; +}#end service_insert + +#service_update +sub service_update(){ + my $self = shift; + my $q = shift; + my $auth = shift; + my $node_template = shift; + my $c_id = shift || ""; + my $action = shift || ""; + my $return={}; + my $update = {}; + + if($q->param('request') eq "service_done"){ + $c_id = $q->param('service_id') if($q->param('service_id')); + $update = { + table => "contentpos", + owner => $auth->{c_id}, + mtime => "now()", + }; + + }elsif($q->param('request') eq "user_feedback"){ + $update = { + table => "contentadrpos", + mtime => "now()", + int01 => 0, + }; + $update->{int01} = 1 if($q->param('bike_broken')); + $update->{txt02} = $q->escapeHTML($q->param('message')) if($q->param('message')); + + }elsif($q->param('request') eq "user_minianswer"){ + $update = { + table => "contentadrpos", + mtime => "now()", + }; + $update->{txt01} = $q->escapeHTML($q->param('q1')) if($q->param('q1')); + $update->{txt02} = $q->escapeHTML($q->param('q2')) if($q->param('q2')); + $update->{txt03} = $q->escapeHTML($q->param('q3')) if($q->param('q3')); + my $last_used_operator = $auth->{txt19}; + if($last_used_operator){ + my $dbh_operator = $dbt->dbconnect_extern("$last_used_operator"); + my $postref = { + table => "contenttrans", + table_pos => "contenttranspos", + fetch => "one", + ca_id => "$auth->{c_id}", + int26 => ">::0.1",#if cloud distance km > 0,1 + end_time => ">=::(now() - interval '10 minutes')", + }; + my $post_record = $dbt->collect_post($dbh_operator,$postref); + $update->{int02} = $post_record->{int26} if($post_record->{int26}); + $update->{txt10} = $dbt->{operator}->{$last_used_operator}->{oprefix}; + } + } + + my $record = { c_id => $c_id }; + + $node_template->{tpl_order} .= ",txt09=Wartungsarbeiten"; + my @tpl_order = split /,/,$node_template->{tpl_order}; + + if($action){ + my ($key,$val) = split /=/,$action; + $update->{$key} = $val if($key eq "txt10");#pos station log on redistribution + }elsif($q->param('work_id')){ + foreach (@tpl_order){ + my ($key,$val,$size) = split /=/,$_; + #key validation will be done by update_record + if($key eq "txt01" && $q->param('work_id') eq "$key" && $q->param('work_val') =~ /::erledigt::/){ + my $pref_pos = { + table => "contentpos", + fetch => "one", + c_id => $c_id, + }; + my $record_pos = $dbt->fetch_tablerecord($dbh,$pref_pos) if($c_id); + if($record_pos->{txt01} ne "NaN"){ + $update->{$key} = $q->escapeHTML($q->param('work_val')) . " " . $record_pos->{txt01}; + }else{ + $update->{$key} = $q->escapeHTML($q->param('work_val')); + } + } + elsif($key eq "txt01" && $q->param('work_id') eq "$key" && $q->param('work_val') !~ /\w/){ + $update->{$key} = "NaN"; + } + elsif($q->param('work_id') eq "$key"){ + $update->{$key} = $q->escapeHTML($q->param('work_val')); + } + } + }elsif(1==2){#TODO template key REST mapping + my @keywords = $q->param; + foreach (@tpl_order){ + my ($key,$val,$size,$interval) = split /=/,$_; + foreach(@keywords){ + if($_ eq $key){ + #key validation will be done by update_record + $update->{$_} = $q->escapeHTML($q->param($key)); + } + } + #unchecked checkbox doesn't deliver values. Thats the solution + #disabled delete values at all. Test with json API conflicts because we disabled checkboxes + #$update->{$key} = "null" if($key =~ /^int\d+$/ && $key !~ /^int04/ && !looks_like_number($update->{$key})); + #$update->{$key} = "NaN" if($key =~ /^txt01$/ && !$update->{$key});#sepcial on TINK Service + } + } + + my $rows = $dbt->update_record($dbh,$update,$record) if($record->{c_id} > 0); + + return $rows; +}#end service_update + +#bike_update for state update after servíce_work (cronjob) OR service_done +sub bikestate_update(){ + my $self = shift; + my $auth = shift; + my $c_id = shift || ""; + my $state = shift || ""; + my $update_hash = shift || ""; + my %varenv = $cf->envonline(); + + my $return={}; + + my $update = { + table => "content", + owner => $auth->{c_id}, + mtime => "now()", + }; + #set state only if defined + $update->{int10} = $state if($state); + #moving bike to station + if(ref($update_hash) eq "HASH" && looks_like_number($update_hash->{int04})){ + $update->{int04} = "$update_hash->{int04}"; + } + $bw->log("check state on bikestate_update 1.",$update,""); + + my $record = { c_id => $c_id }; + my $rows = $dbt->update_record($dbh,$update,$record) if($record->{c_id} > 0); + + #require "Mod/KMLout.pm"; + #my $kmlfile = KMLout::kmlGenerator($auth,""); + + return $rows; +}#bikestate_update + +#feedback response --> obsolet +sub feedback_response { + my $self = shift; + my $pos_record = shift; + my $node_template = shift; + + my %varenv = $cf->envonline(); + my @tpl_order = split /,/,$node_template->{tpl_order}; + my $return = {}; + foreach my $id (sort { $pos_record->{$a}->{mtime} cmp $pos_record->{$b}->{mtime} } keys (%$pos_record)){ + foreach (@tpl_order){ + my ($key,$val,$size) = split /=/,$_; + $return->{feedback_id} = "$pos_record->{$id}->{c_id}" if($key eq "c_id"); + $return->{bike} = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}$pos_record->{$id}->{barcode}" if($key eq "barcode"); + $return->{bike_broken} = "$pos_record->{$id}->{int01}" || "" if($key eq "int01"); + $return->{message} = "$pos_record->{$id}->{txt02}" || "" if($key eq "txt02"); + } + } + return $return; +} + +#service_work copy from service_select +sub service_work { + my $self = shift; + my $pos_record = shift; + my $article_all = shift || ""; + my $history = shift || 0; + my $node_template = shift || {}; + + my %varenv = $cf->envonline(); + my $dt1 = DateTime->now; + my $return={}; + + my $mapref = { + int09 => 1, + }; + #my $users_map = $dbt->users_map($dbh,$mapref);#get serviceAPP users + my $users_map = $dbt->users_map($dbh,"");#get all serviceAPP users (also without service key) + my $channel_map = $dbt->channel_map(); + + my @tpl_order = split /,/,$node_template->{tpl_order}; + + #because of different templates we need template grouping + #not safe, pos template_id have to be defined before any service has done! + #keep in mind, on pos tables there isn't any relation. That's because history pos.template_id will be selected + my $pref = { table => "content", + table_pos => "contentpos", + }; + my $template_group = $dbt->pos_template_group($dbh,$pref); + #$bw->log(" template_group",$template_group,""); + + my $node = {}; + my $op_return = {}; + foreach my $cid (sort { $article_all->{$a}->{barcode} <=> $article_all->{$b}->{barcode} } keys(%$article_all)){ + my $i=0; + my $article = $article_all->{$cid}->{barcode}; + my $tpl_keyseen = ""; + + #breaks JSON hash. don't do it + #$return->{$bike}->{uri_operator} = "$varenv{wwwhost}"; + + foreach my $id (sort { $pos_record->{$a}->{mtime} cmp $pos_record->{$b}->{mtime} } keys (%$pos_record)){ + $i++; + + if($article_all->{$cid}->{c_id} == $pos_record->{$id}->{cc_id}){ + $article = $article_all->{$cid}->{barcode} if($article_all->{$cid}->{template_id} && $article_all->{$cid}->{template_id} == 205);# bike template_id + $article = $article_all->{$cid}->{int04} if($article_all->{$cid}->{template_id} && $article_all->{$cid}->{template_id} == 225);# station template_id + + #breaks JSON hash. don't do it + #$return->{$article}->{template_id} = "$pos_record->{$id}->{template_id}"; + if($template_group->{$pos_record->{$id}->{template_id}}){ + @tpl_order = split /,/,$template_group->{$pos_record->{$id}->{template_id}}->{tpl_order}; + $node->{template_id} = "$pos_record->{$id}->{template_id}"; + #$bw->log("service_work ($id) template used ($node->{template_id})",$template_group->{$pos_record->{$id}->{template_id}}->{tpl_order},""); + + foreach (@tpl_order){ + my ($key,$val,$size,$interval,$service_type) = split /=/,$_; + $service_type = 0 if(!looks_like_number($service_type)); + my $erledigt = 0; + $erledigt = 1 if(!$history && $pos_record->{$id}->{$key} !~ /::erledigt::/); + $erledigt = 1 if($history && $pos_record->{$id}->{$key} =~ /::erledigt::/); + if((($key =~ /int/ && looks_like_number($pos_record->{$id}->{$key})) || ($key eq "txt01" && $pos_record->{$id}->{$key} && $pos_record->{$id}->{$key} ne "NaN" && $erledigt))){ + $tpl_keyseen .= "$key|"; + + $bw->log("if((($key =~ /int/ && looks_like_number($pos_record->{$id}->{$key})) || ($key eq \"txt01\" && $pos_record->{$id}->{$key} && $pos_record->{$id}->{$key} ne \"NaN\"))){",$tpl_keyseen,""); + my $u_name = $users_map->{$pos_record->{$id}->{owner}}->{txt01} || $channel_map->{$pos_record->{$id}->{owner}} || $pos_record->{$id}->{owner}; + my $dt2 = DateTime::Format::Pg->parse_datetime($pos_record->{$id}->{mtime}); + my $time_over = "0"; + if(looks_like_number($interval) && $interval > 0){ + my $dt2_over = $dt2->add( days => $interval ); + $bw->log("service-interval: $interval | $dt1 > $dt2_over (mtime: $pos_record->{$id}->{mtime})",$key,""); + $time_over = "1" if($dt1 > $dt2_over); + } + + my $key_change = $key; + if($history && $history > 0){ + my $dtstamp = $pos_record->{$id}->{mtime}; + $dtstamp = $dt2->epoch(); + $key_change .= "_" . $dtstamp; + } + + $return->{$article}->{$key_change}->{service_id} = "$pos_record->{$id}->{c_id}"; + $return->{$article}->{$key_change}->{work_id} = "$key"; + $return->{$article}->{$key_change}->{work_name} = "$val"; + $return->{$article}->{$key_change}->{interval} = "$interval"; + $return->{$article}->{$key_change}->{time_over} = "$time_over"; + $return->{$article}->{$key_change}->{service_type} = "$service_type"; + $return->{$article}->{$key_change}->{work_val} = "$pos_record->{$id}->{$key}"; + $return->{$article}->{$key_change}->{mtime} = "$pos_record->{$id}->{mtime}"; + $return->{$article}->{$key_change}->{user_name} = "$u_name"; + $return->{$article}->{$key_change}->{owner} = "$pos_record->{$id}->{owner}"; + } + } + } + } + } + + #set init values + #$bw->log("set service init values by @tpl_order","",""); + if(!$history && scalar(@tpl_order) > 1){ + $bw->log("tpl_keyseen",$tpl_keyseen,""); + $tpl_keyseen =~ s/\|$//; + foreach (@tpl_order){ + my ($key,$val,$size,$interval,$service_type) = split /=/,$_; + $service_type = 0 if(!looks_like_number($service_type)); + + if($key =~ /int|txt/ && (!$tpl_keyseen || $key !~ /$tpl_keyseen/)){ + $return->{$article}->{$key}->{service_id} = "1"; + $return->{$article}->{$key}->{work_id} = "$key"; + $return->{$article}->{$key}->{work_name} = "$val"; + $return->{$article}->{$key}->{interval} = "$interval"; + $return->{$article}->{$key}->{time_over} = "1";#2021-06-23 if not seen then time_over + $return->{$article}->{$key}->{service_type} = "$service_type"; + $return->{$article}->{$key}->{work_val} = "1" if($key =~ /int/); + $return->{$article}->{$key}->{work_val} = "::erledigt::" if($key =~ /txt/); + $return->{$article}->{$key}->{mtime} = "2021-09-01 00:00"; + $return->{$article}->{$key}->{user_name} = "init"; + $return->{$article}->{$key}->{owner} = "188"; + + } + } + #}else{ + #$return->{response_state} = "Failure 3099: history to short OR template fails"; + } + + } + return ($return,$node); +}#end service_work + + + + +#booking_cancel changed to booking_update +sub booking_update(){ + my $self = shift; + my $q = shift; + my $auth = shift; + my $owner = shift || 0; + my $state = $q->escapeHTML($q->param('state')) || ""; + my $lock_state = $q->escapeHTML($q->param('lock_state')) || ""; + my %varenv = $cf->envonline(); + my $rows = 0; + my $user_agent = $q->user_agent(); + my $record_pos = { c_id => 0 };#if fails + my $bike = $q->param('bike'); + my $bike_id = $1 if($q->escapeHTML($q->param('bike')) =~ /(\d+)/); + + my $state_key = 0; + my $state_text = ""; + while (my ($key, $value) = each %{ $dbt->{copri_conf}->{bike_state} }) { + if($state eq $value){ + $state_key = $key; + $state_text = "beendet" if($state eq "available"); + $state_text = "gestartet" if($state eq "occupied"); + } + } + + + my $booking_values = { + bike => "$bike", + state => "", + lock_state => "", + co2saving => "", + response_state => "OK 1017: No update", + response_text => "Es wurden keine Daten aktualisiert", + }; + + my $pref = { + table => "contenttrans", + table_pos => "contenttranspos", + fetch => "one", + template_id => "218",#Mietjournal tpl_id + barcode => $bike_id, + ca_id => "$auth->{c_id}", + "ct.close_time" => "is::null", + #txt10 => "IN::('occupied','requested')", + int10 => "IN::('3','2')", + }; + + $record_pos = $dbt->collect_post($dbh,$pref) if($q->param('bike')); + + my $pref_cc = { + table => "content", + fetch => "one", + template_id => "205", + barcode => $bike_id, + }; + + my $record_cc = $dbt->fetch_record($dbh,$pref_cc) if($q->param('bike')); + + + my $update_cc = { + table => "content", + mtime => "now()", + owner => "$owner", + }; + + + my $gps = ""; + my $latitude = ""; + my $longitude = ""; + #old + if($q->param('gps')){ + my $gps_input = $q->param('gps'); + $gps_input =~ s/\s//g; + $latitude = $q->escapeHTML($1) if($gps_input =~ /^(\d+\.\d+),\d+/); + $longitude = $q->escapeHTML($1) if($gps_input =~ /\d+,(\d+\.\d+)$/); + $gps = "$latitude,$longitude" if($latitude && $longitude); + } + #new + if($q->param('latitude') && $q->param('longitude')){ + my $latitude_in = $q->param('latitude'); + my $longitude_in = $q->param('longitude'); + $latitude = $1 if($latitude_in =~ /(\d+\.\d+)/); + $longitude = $1 if($longitude_in =~ /(\d+\.\d+)/); + $gps = "$latitude,$longitude" if($latitude && $longitude); + } + + my $Ilockit_GUID = ""; + $Ilockit_GUID = $q->escapeHTML($q->param('Ilockit_GUID')) if($q->param('Ilockit_GUID') && $q->param('Ilockit_GUID') =~ /\w+-\w+-\w+-\w+$/); + my $gps_age = 0; + my $gps_age_minutes = 60; + $gps_age = $q->escapeHTML($1) if($q->param('gps_age') =~ /^(\d+)/);#in milli-sec + $gps_age_minutes = $gps_age / 1000 / 60 if($gps_age); + + my $gps_accuracy = 0; + $gps_accuracy = $q->escapeHTML($1) if($q->param('gps_accuracy') =~ /^(\d+)/);#in meters + my $geo_distance = 1000000;#defaults to 1000000 Meter + + #my $ct_state = $state; + my $ct_state = $record_pos->{int10};#2020-07-25 changed because ct_state cannot be canceled + + #2020-09-24 requested will be all done by net_booking + #6 = "canceled"|3 = "occupied"|1 = "available" + if($state && $state =~ /$dbt->{copri_conf}->{bike_state}->{6}|$dbt->{copri_conf}->{bike_state}->{3}|$dbt->{copri_conf}->{bike_state}->{1}/ && $record_pos->{cc_id} && $record_pos->{cc_id} > 0){ + + #set rent state if lock_system 2=Ilockit + if($record_pos->{int11} eq "2"){ + my $update_pos = { + table => "contenttranspos", + #int10 => "$state_key", + mtime => "now()", + }; + + $update_pos->{txt21} = $q->escapeHTML($q->param('user_device')) if($q->param('user_device')); + $update_pos->{txt26} = $q->escapeHTML($user_agent) if($user_agent); + + #if($state =~ /canceled/ && $record_pos->{txt10} =~ /requested/) + if($state_key == 6 && $record_pos->{int10} == 2){ + $rows = $dbt->delete_content($dbh,"contenttranspos",$record_pos->{c_id}); + if($rows > 0){ + $ct_state = "1";#1 = "available" + $booking_values->{response_state} = "OK: canceled bike " . $q->param('bike'); + $booking_values->{response_text} = "Fahrrad Nr. " . $q->param('bike') . " wurde erfolgreich storniert"; + $booking_values->{state} = "available"; + }else{ + $booking_values->{response_state} = "Failure 2002: cancel bike " . $q->param('bike') . " fails, bike not requested"; + $booking_values->{response_text} = "Keine Reservierung zu Fahrrad Nr. " . $q->param('bike') . " gefunden."; + } + }else{ + + $update_pos->{txt17} = $Ilockit_GUID if($Ilockit_GUID); + + + #prevent reset occupied values OR only if genkey defined + #if(($state eq "occupied" && $record_pos->{txt10} =~ /requested/) || ($state eq "occupied" && $record_pos->{txt10} =~ /occupied/ && $q->param('genkey') eq "1")) + if(($state_key == 3 && $record_pos->{int10} == 2) || ($state_key == 3 && $record_pos->{int10} == 3 && $q->param('genkey') eq "1")){ + $update_pos->{start_time} = "now()"; + $update_pos->{end_time} = "now()"; + #$update_pos->{txt05} = "$gps";#start GPS, not exist on request + $update_pos->{txt05} = "$record_cc->{txt06}";#pos start GPS from content end GPS + $update_pos->{int06} = "$record_cc->{int04}";#pos start station from content station + $update_pos->{txt12} = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}";#pos start station prefix + $update_pos->{int21} = "$gps_age_minutes"; + $update_pos->{int22} = "$gps_accuracy"; + $update_pos->{owner} = "$owner"; + + $update_pos->{int10} = "$state_key"; + $rows = $dbt->update_record($dbh,$update_pos,$record_pos); + + if($rows > 0){ + $booking_values->{response_state} = "OK: occupied bike " . $q->param('bike'); + $booking_values->{response_text} = "Fahrrad Nr. " . $q->param('bike') . " Miete gestartet. "; + $ct_state = $state_key; + } + #Mietende request state=available and pos-state 2=requested or 3=occupied + }elsif($state_key == 1 && ($record_pos->{int10} == 2 || $record_pos->{int10} == 3)){ + + #int24 == 1 if if locked && end gps && end station && gps_age <= 3 min && in geo_fence + if($record_pos->{int24}){ + $update_pos->{owner_end} = "$owner"; + $update_pos->{end_time} = "now()"; + my $pricing = $pri->sharee_pricing($record_pos,"calc_price"); + $update_pos->{int03} = "$pricing->{computed_hours}" if(looks_like_number($pricing->{computed_hours})); + + $update_pos->{int10} = "$state_key"; + $rows = $dbt->update_record($dbh,$update_pos,$record_pos); + + $booking_values->{response_state} = "OK: available bike " . $q->param('bike') . ", still locked"; + $booking_values->{response_text} = "Danke! Die Miete Fahrrad Nr. " . $q->param('bike') . " wurde beendet. Schloß wurde bereits abgeschlossen."; + $ct_state = $state_key; + + + }elsif($gps && $gps_age_minutes <= 3){#client GPS must have + #geofencing for Ilockit + my $geo_distance_next = 100000; + my $station_next = 0; + my $geo_debug=""; + my ($stations,$stations_raw) = $self->stations_available($q,$auth); + foreach my $id (sort { $stations_raw->{$a}->{barcode} <=> $stations_raw->{$b}->{barcode} } keys (%$stations_raw)){ + my $latitude_station = $1 if($stations_raw->{$id}->{txt06} =~ /^(\d+\.\d+)/); + my $longitude_station = $1 if($stations_raw->{$id}->{txt06} =~ /(\d+\.\d+)$/); + if(!looks_like_number($latitude) || !looks_like_number($longitude)){ + $geo_debug .= "ERROR no user GPS: $stations_raw->{$id}->{barcode}|$latitude,$longitude,$latitude_station,$longitude_station --> $geo_distance Meter\n"; + }elsif(looks_like_number($latitude) && looks_like_number($longitude) && looks_like_number($latitude_station) && looks_like_number($longitude_station)){ + $update_pos->{owner_end} = "$owner"; + $update_pos->{end_time} = "now()"; + + $geo_distance = $lb->geo_fencing($latitude,$longitude,$latitude_station,$longitude_station); + #$station_next = $stations_raw->{$id}->{int04}; + if($geo_distance <= $stations_raw->{$id}->{int06}){ + $geo_distance_next = $geo_distance; + #end-Station + $update_pos->{int04} = "$stations_raw->{$id}->{int04}"; + $update_cc->{int04} = "$stations_raw->{$id}->{int04}"; + $update_pos->{int24} = "1"; + $update_pos->{int10} = "$state_key"; + $update_cc->{txt06} = "$gps";#end content coordinates + $update_pos->{txt06} = "$gps";#end pos coordinates + $update_pos->{int21} = "$gps_age_minutes"; + $update_pos->{int22} = "$gps_accuracy"; + $update_pos->{int23} = "$geo_distance"; + #end-Station prefix + $update_pos->{txt13} = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}"; + #end-Station prefix + $update_cc->{txt13} = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}"; + my $pricing = $pri->sharee_pricing($record_pos,"calc_price"); + $update_pos->{int03} = "$pricing->{computed_hours}" if(looks_like_number($pricing->{computed_hours})); + $rows = $dbt->update_record($dbh,$update_pos,$record_pos); + + if($rows > 0){ + $booking_values->{response_state} = "OK: available bike " . $q->param('bike'); + $booking_values->{response_text} = "Danke! Die Miete Fahrrad Nr. " . $q->param('bike') . " wurde beendet."; + $ct_state = $state_key; + } + + $geo_debug .= "Matching station: $stations_raw->{$id}->{barcode}|$latitude,$longitude,$latitude_station,$longitude_station --> $geo_distance Meter\n"; + last; + }else{ + if($geo_distance <= $geo_distance_next){ + $geo_distance_next = $geo_distance; + $station_next = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}$stations_raw->{$id}->{int04}"; + } + #2021-10-13 changed to save last gps @all + $update_cc->{txt06} = "$gps";#end content coordinates + $update_pos->{txt06} = "$gps";#end pos coordinates + $update_pos->{int21} = "$gps_age_minutes"; + $update_pos->{int22} = "$gps_accuracy"; + $update_pos->{int23} = "$geo_distance"; + #end-Station prefix + $update_pos->{txt13} = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}"; + #end-Station prefix + $update_cc->{txt13} = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}"; + my $pricing = $pri->sharee_pricing($record_pos,"calc_price"); + $update_pos->{int03} = "$pricing->{computed_hours}" if(looks_like_number($pricing->{computed_hours})); + $rows = $dbt->update_record($dbh,$update_pos,$record_pos); + + $geo_debug .= "Out of station distance: $stations_raw->{$id}->{barcode}|$latitude,$longitude,$latitude_station,$longitude_station --> $geo_distance_next Meter ($geo_distance_next <= $geo_distance) station_next: $station_next\n"; + + $booking_values->{response_state} = "Failure 2178: bike " . $q->param('bike') . " out of GEO fencing. $geo_distance_next meter distance to next station $station_next ."; + $booking_values->{response_text} = "Achtung! Ihr aktueller Standort liegt außerhalb einer Fahrradstation. Die Miete Fahrrad Nr. " . $q->param('bike') . " kann nicht $state_text werden. $geo_distance_next Meter Entfernung zur nächsten Station $station_next ."; + } + + }else{ + $geo_debug .= "ERROR no station GPS: $stations_raw->{$id}->{barcode}|$latitude,$longitude,$latitude_station,$longitude_station --> $geo_distance Meter\n"; + } + } + $booking_values->{geo_distance} = "$geo_distance_next"; + #print "$geo_debug\n"; + $bw->log("GEOfencing geo_debug:$geo_debug",$q,""); + + #end if gps && gps_age <= 3 + }else{ + if(!$gps){ + $booking_values->{response_state} = "Failure 2245: No GPS data, state change forbidden."; + $booking_values->{response_text} = "Fehler! Keine GPS Standortdaten, Die Miete Fahrrad Nr. " . $q->param('bike') . " kann wegen fehlendem GPS nicht $state_text werden. Bitte aktivieren Sie das GPS."; + }else{ + $booking_values->{response_state} = "Failure 2246: GPS age with $gps_age_minutes minutes too old, state change forbidden."; + $booking_values->{response_text} = "Fehler! GPS Daten sind mit $gps_age_minutes Minuten zu alt. Die Miete Fahrrad Nr. " . $q->param('bike') . " kann aufgrund nicht aktueller GPS nicht $state_text werden. Bitte aktivieren Sie das GPS."; + } + } + #end if($state eq "available" && + }elsif($state_key == 6 && $record_pos->{int10} == 3){ + $booking_values->{response_state} = "Failure 2012: occupied bike " . $q->param('bike') . " cannot be $state"; + $booking_values->{response_text} = "Fahrrad Nr. " . $q->param('bike') . " ist in Benutzung und kann somit nicht storniert werden."; + }elsif($state_key == 3 && $record_pos->{int10} == 1){ + $booking_values->{response_state} = "Failure 2016: occupied bike " . $q->param('bike') . " cannot be $state"; + $booking_values->{response_text} = "Fahrrad Nr. " . $q->param('bike') . " wurde nicht reserviert und kann somit nicht gemietet werden."; + + }else{ + $booking_values->{response_state} = "Failure 2035: bike " . $q->param('bike') . " state change to $state not possible."; + $booking_values->{response_text} = "Fehler! Die Miete Fahrrad Nr. " . $q->param('bike') . " kann nicht mit dem vorhandnen Status $state_text werden."; + } + + #contenttrans + my $update_ct = { + table => "contenttrans", + mtime => "now()", + owner => "$owner", + }; + + my $record_ct->{c_id} = $record_pos->{ct_id}; + $dbt->update_record($dbh,$update_ct,$record_ct); + if($q->param('voltage') && $q->param('voltage') =~ /(\d+)/){ + $update_cc->{int14} = $1; + $self->service_automatic($q) if($1 <= 40); + } + $update_cc->{txt15} = $q->escapeHTML($q->param('firmware')) if($q->param('firmware')); + $update_cc->{txt17} = $Ilockit_GUID if($Ilockit_GUID); + + } + #end Ilockit + }else{ + $bw->log("smartlock type not defined, int11:",$record_pos->{int11},""); + } + + #update bike content + $update_cc->{int10} = "$ct_state";#yes we believe it unsafe to get failure #if(looks_like_number($ct_state)); + $bw->log("check ct_state on update_cc 2.",$update_cc,""); + + #my $record_cc = { c_id => $record_pos->{cc_id} }; + $dbt->update_record($dbh,$update_cc,$record_cc); + + #require "Mod/KMLout.pm"; + #my $kmlfile = Mod::KMLout::kmlGenerator($auth,""); + + + }#end if $state =~ /canceled|occupied|available/ + + + if($lock_state && $lock_state =~ /locking|locked|unlocked/ && $record_pos->{cc_id} && $record_pos->{cc_id} > 0){ + #content + my $update_cc = { + table => "content", + mtime => "now()", + owner => "$owner", + }; + $update_cc->{int14} = $q->escapeHTML($q->param('voltage')) if($q->param('voltage')); + + #my $record_cc = { c_id => $record_pos->{cc_id} }; + + my $update_pos = { + table => "contenttranspos", + mtime => "now()", + int24 => 0, + }; + + $update_pos->{int14} = $q->escapeHTML($q->param('voltage')) if($q->param('voltage')); + $update_pos->{txt21} = $q->escapeHTML($q->param('user_device')) if($q->param('user_device')); + $update_pos->{txt26} = $q->escapeHTML($user_agent) if($user_agent); + + my $lock_value = 0; + if($lock_state eq "locked"){ + $lock_value = 1; + $update_cc->{int20} = "$lock_value"; + $update_pos->{int20} = "$lock_value"; + $update_pos->{end_time} = "now()";#2021-01-10 set also end_time on locked + + ####### save locked GPS if available + if($gps && $gps_age_minutes <= 3){ + #geofencing for Ilockit + my $geo_distance_next = $geo_distance; + my $geo_debug=""; + my ($stations,$stations_raw) = $self->stations_available($q,$auth); + foreach my $id (sort { $stations_raw->{$a}->{barcode} <=> $stations_raw->{$b}->{barcode} } keys (%$stations_raw)){ + my $latitude_station = $1 if($stations_raw->{$id}->{txt06} =~ /^(\d+\.\d+)/); + my $longitude_station = $1 if($stations_raw->{$id}->{txt06} =~ /(\d+\.\d+)$/); + if(!looks_like_number($latitude) || !looks_like_number($longitude)){ + $geo_debug .= "locked ERROR no user GPS: $stations_raw->{$id}->{barcode}|$latitude,$longitude,$latitude_station,$longitude_station --> $geo_distance Meter\n"; + }elsif(looks_like_number($latitude) && looks_like_number($longitude) && looks_like_number($latitude_station) && looks_like_number($longitude_station)){ + $geo_distance = $lb->geo_fencing($latitude,$longitude,$latitude_station,$longitude_station); + if($geo_distance <= $stations_raw->{$id}->{int06}){ + $geo_distance_next = $geo_distance; + #end-Station + $update_pos->{int04} = "$stations_raw->{$id}->{int04}"; + $update_cc->{int04} = "$stations_raw->{$id}->{int04}"; + $update_pos->{int24} = "1"; + + $geo_debug .= "locked Matching station: $stations_raw->{$id}->{barcode}|$latitude,$longitude,$latitude_station,$longitude_station --> $geo_distance Meter\n"; + last; + }else{ + $geo_distance_next = $geo_distance if($geo_distance <= $geo_distance_next); + $geo_debug .= "locked Out of station distance: $stations_raw->{$id}->{barcode}|$latitude,$longitude,$latitude_station,$longitude_station --> $geo_distance Meter\n"; + + } + + $update_pos->{txt06} = "$gps";#end pos coordinates + $update_pos->{int21} = "$gps_age_minutes"; + $update_pos->{int22} = "$gps_accuracy"; + $update_pos->{int23} = "$geo_distance"; + $update_cc->{txt06} = "$gps";#end content coordinates + #end-Station prefix + $update_pos->{txt13} = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}"; + #end-Station prefix + $update_cc->{txt13} = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}"; + $rows = $dbt->update_record($dbh,$update_pos,$record_pos); + + }else{ + $geo_debug .= "locked has no station GPS: $stations_raw->{$id}->{barcode}|$latitude,$longitude,$latitude_station,$longitude_station --> $geo_distance Meter\n"; + } + } + $booking_values->{geo_distance} = "$geo_distance_next"; + #print "$geo_debug\n"; + $bw->log("locked GEOfencing geo_debug:$geo_debug",$q,""); + + } + ######## end locke GPS + + if($state){ + $booking_values->{response_state} .= " OK: bike " . $q->param('bike') . " locked confirmed"; + $booking_values->{response_text} .= " Abschließen von Fahrrad Nr. " . $q->param('bike') . " bestätigt"; + }else{ + $booking_values->{response_state} = "OK: bike " . $q->param('bike') . " locked confirmed"; + $booking_values->{response_text} = "Abschließen von Fahrrad Nr. " . $q->param('bike') . " bestätigt"; + } + }elsif($lock_state eq "unlocked"){ + #int30=Station Id + #int31=Slot Id + #int27=velofactur bike Id + if($record_cc->{int30} && $record_cc->{int31} && $record_cc->{int27}){ + $bw->log("unlock velofactur station lock with: '$record_cc->{int30}' '$record_cc->{int31}' '$record_cc->{int27}' 'Freigeben' '$record_pos->{c_id}'","",""); + system(`$varenv{basedir}/src/scripts/velofaktur_client.pl $varenv{syshost} post_velo "$record_cc->{int30}" "$record_cc->{int31}" "$record_cc->{int27}" "Freigeben" "$record_pos->{c_id}"`); + } + $lock_value = 2; + $update_cc->{int20} = "$lock_value"; + $update_pos->{int20} = "$lock_value"; + $update_pos->{int23} = "$geo_distance"; + if($state){ + $booking_values->{response_state} .= " OK: bike " . $q->param('bike') . " unlocked confirmed"; + $booking_values->{response_text} .= " Aufschließen von Fahrrad Nr. " . $q->param('bike') . " bestätigt"; + }else{ + $booking_values->{response_state} = "OK: bike " . $q->param('bike') . " unlocked confirmed"; + $booking_values->{response_text} = "Aufschließen von Fahrrad Nr. " . $q->param('bike') . " bestätigt"; + } + }elsif($lock_state eq "locking"){ + $lock_value = 3; + $update_cc->{int20} = "$lock_value"; + $update_pos->{int20} = "$lock_value"; + $update_pos->{int23} = "$geo_distance"; + if($state){ + $booking_values->{response_state} .= " OK: bike " . $q->param('bike') . " locking in progress"; + $booking_values->{response_text} .= " Abschließen von Fahrrad Nr. " . $q->param('bike') . " ist im Prozess. Bitte warten bis das smartlock vollständig geschlossen wurde und das abschließen bestätigt wird."; + }else{ + $booking_values->{response_state} = "OK: bike " . $q->param('bike') . " locking in progress"; + $booking_values->{response_text} = "Abschließen von Fahrrad Nr. " . $q->param('bike') . " ist im Prozess. Bitte warten bis das smartlock vollständig geschlossen wurde und das abschließen bestätigt wird."; + } + } + + $dbt->update_record($dbh,$update_pos,$record_pos); + $dbt->update_record($dbh,$update_cc,$record_cc); + }#end locked + + #fetch final booking state after request + if($record_pos->{c_id} > 0){ + my $booking_pos = { + table => "contenttranspos", + fetch => "one", + c_id => "$record_pos->{c_id}", + }; + my $booking = $dbt->fetch_tablerecord($dbh,$booking_pos); + + if(ref($booking) eq "HASH" && $booking->{ct_name}){ + #$booking_values->{bike} = "$booking->{ct_name}"; + $booking_values->{bike} = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}$booking->{barcode}"; + $booking_values->{state} = "$dbt->{copri_conf}->{bike_state}->{$booking->{int10}}"; + $booking_values->{lock_state} = "locked" if($booking->{int20} == 1); + $booking_values->{lock_state} = "unlocked" if($booking->{int20} == 2); + $booking_values->{lock_state} = "locking" if($booking->{int20} == 3); + + #fetch tracking distance on Ilockit cloud by summary trip if(tracking && deviceId && available) + $bw->log("Ilockit_trackingcloud.pl $varenv{syshost} get_tripsum",$booking,"") if($booking->{int25}); + if($booking->{int25} == 1 && $booking->{int10} == 1){ + $bw->log("$varenv{basedir}/src/scripts/Ilockit_trackingcloud.pl $varenv{syshost} get_tripsum $booking->{c_id}",$booking->{c_id},""); + system(`$varenv{basedir}/src/scripts/Ilockit_trackingcloud.pl $varenv{syshost} get_tripsum $booking->{c_id}`) if($booking->{int13});#if ilockit clouid + sleep 2;#hopefully get distance in 2 sec. + $booking = $dbt->fetch_tablerecord($dbh,$booking_pos); + my $co2saving = ""; + $booking->{int26} = 10 if(!$booking->{int26} && ($auth->{c_id} == 1842 || $auth->{c_id} == 5781 || $auth->{c_id} == 11765 || $auth->{c_id} == 1843));#10 km test + if($booking->{int26}){ + $co2saving = "Einsparung: "; + my $co2diff = $pri->co2calc($booking); + my $sprit_price = $pri->sprit2calc($booking); + $co2saving .= "$co2diff kg CO2 und "; + $co2saving .= "$sprit_price EUR "; + $booking->{int26} =~ s/\./,/; + $co2saving .= "bei einer Strecke von $booking->{int26} KM (Demo)"; + $booking_values->{co2saving} = $co2saving; + } + } + + #to LV only if available + if($varenv{dbname} eq "sharee_lv" && $booking->{int10} == 1){ + #system(`$varenv{basedir}/src/scripts/xml2lastenvelo.pl pos2xml $booking->{c_id} "contenttranspos" ""`); + my $xml = "\n"; + $xml .= "\n"; + $xml .= "available\n"; + $xml .= "$booking_values->{bike}\n"; + $xml .= "$auth->{int01}\n"; + $xml .= "$auth->{txt08}\n"; + $xml .= "\n"; + + my $avail_file = "$varenv{xmlfile}/sharee_available.xml"; + unlink "$avail_file"; + open(FILE,">$avail_file"); + print FILE "$xml"; + close(FILE); + chmod 0666, "$avail_file"; + $bw->log("scp $avail_file",$xml,""); + system("/usr/bin/scp -P 50001 $avail_file pi\@localhost:/home/pi/lvfserver/inbox_xml_files/.") if($dbt->{copri_conf}->{stage} eq "live"); + } + + } + } + return ($rows,$booking_values); +} +#end booking_update +# +# +#dedicated service insert automatic +sub service_automatic { + my $self = shift; + my $q = shift || ""; + + my $station_id = $1 if($q->param('station') =~ /(\d+)/); + my $bike_id = $1 if($q->param('bike') =~ /(\d+)/); + my $authraw = { c_id => $owner };#default sys API + my $lock_charge = "Achtung, Fahrradschloss Ladung unter " . $q->param('voltage') . "%"; + my $response = {}; + if(looks_like_number($bike_id) || looks_like_number($station_id)){ + $q->param(-name=>'request',-value=>"service_done"); + $q->param(-name=>'work_id',-value=>"txt01"); + $q->param(-name=>'work_val',-value=>"$lock_charge"); + my $article = looks_like_number($bike_id) || looks_like_number($station_id); + + (my $xresponse->{$article}, my $responseraw, my $node_template, my $crecord) = $self->service_select($q,$authraw,"","1"); + + if(ref($xresponse->{$article}) ne "HASH" || !$xresponse->{$article}->{c_id}){ + ($response->{service_id}) = $self->service_insert($q,$authraw,$node_template,$crecord); + $bw->log("service_automatic insert ($xresponse->{$article}->{c_id}) ",$response,""); + my $rows = $self->service_update($q,$authraw,$node_template,$response->{service_id}); + } + } + +} + +#user rentals_history +sub user_rentals_history(){ + my $self = shift; + my $q = shift || ""; + my $auth = shift; + my %varenv = $cf->envonline(); + my $record_all = {}; + + my $pref = { + table => "contenttrans", + table_pos => "contenttranspos", + fetch => "all", + keyfield => "c_id", + ca_id => "$auth->{c_id}", + }; + + if(looks_like_number($q->param('month')) && $q->param('month') > 0){ + my $month = $q->param('month'); + $pref->{mtime} = ">=::(now() - interval '$month month')"; + }else{ + #2021-06-18, list only postions which are not invoiced (Form Buchungsdaten) + #$pref->{close_time} = "is::null"; + $pref->{'ct.state'} = "is::null"; + $pref->{'ct.int14'} = "is::null"; + } + + my %operator_hash = (); + if($varenv{dbname} eq "sharee_primary"){ + if($auth->{txt17}){ + if($auth->{txt17} =~ /\w\s\w/){ + %operator_hash = map { $_ => "$dbt->{operator}{$_}->{operatorApp}" } split(/\s+/,$auth->{txt17}); + }else{ + $operator_hash{$auth->{txt17}} = "$dbt->{operator}{$auth->{txt17}}->{operatorApp}"; + } + foreach my $sharee_operator (keys (%operator_hash)){ + my $dbh_operator = $dbt->dbconnect_extern("$sharee_operator"); + my $record = $dbt->collect_post($dbh_operator,$pref); + $record_all = { %$record_all, %$record }; + } + } + }else{ + $record_all = $dbt->collect_post($dbh,$pref); + } + + return ($record_all,\%operator_hash); +}#end user_rental_history + + +#user bikes occupied +sub user_bikes_occupied(){ + my $self = shift; + my $q = shift; + my $auth = shift; + + my $pref = { + table => "contenttrans", + table_pos => "contenttranspos", + fetch => "all", + template_id => "218",#Faktura tpl_id + keyfield => "c_id", + ca_id => "$auth->{c_id}", + #txt10 => "IN::('occupied','requested')", + int10 => "IN::('3','2')", + "ct.close_time" => "is::null", + }; + my $record = $dbt->collect_post($dbh,$pref); + return $record; +}#end user_bikes_occupied + + +#rentals +sub rentals(){ + my $self = shift; + my $record = shift; + my $auth = shift || ""; + my $withkey = shift || 0; + my %varenv = $cf->envonline(); + my $today4db = strftime("%Y-%m-%d %H:%M:%S",localtime(time)); + my $return = {}; + + foreach my $id (sort { $record->{$a}->{end_time} cmp $record->{$b}->{end_time} } keys (%$record)){ + $return->{$id} = $pri->sharee_pricing($record->{$id},"readonly"); + my $bike_id = $return->{$id}->{bike}; + $bike_id = $1 if($bike_id =~ /(\d+)/); + #generate always new keys. keep in mind, keys saved in contenttranspos are overwritten + if($withkey && $record->{$id}->{int11} && $record->{$id}->{int11} eq "2"){ + my @K_select = (); + @K_select = `cd /var/www/copri4/$varenv{syshost}/src/scripts && export CLASSPATH='.:/usr/share/java:/usr/share/java/postgresql.jar' && java Ilockauth $varenv{dbname} $bike_id`; + $bw->log("rentals java Ilockauth $bike_id | syshost:$varenv{syshost}",\@K_select,""); + + foreach(@K_select){ + my ($K_key,$K_val) = split(/ = /, $_); + $K_val =~ s/\n//g; + $return->{$id}->{K_seed} = "$K_val" if($K_key eq "K_seed"); + $return->{$id}->{K_a} = "$K_val" if($K_key eq "K_a" && $auth->{int19} && $auth->{int19} == 1); + $return->{$id}->{K_u} = "$K_val" if($K_key eq "K_u"); + } + } + } + + return $return; +}#end rentals + + +#bikes_available +sub bikes_available(){ + my $self = shift; + my $q = shift; + my $auth = shift; + my %varenv = $cf->envonline(); + my $authed = 0; + + #my $users_serviceapp = $dbt->select_users($dbh,$auth->{c_id},"and int09=1"); + my $return={}; + my $pref = { + table => "content", + fetch => "all", + keyfield => "barcode", + template_id => "205", + int10 => "1",#1 = "available" + }; + my $tariff_content = {}; + #have to be also used without auth!, because of public bikes and stations + #if(ref($auth) eq "HASH" && $auth->{c_id} > 0){ + $authed = 1 if(ref($auth) eq "HASH" && $auth->{c_id} > 0); + (my $bike_group,my $user_group,$tariff_content,my $user_tour) = $self->fetch_tariff($auth,$q->param('authcookie')); + my $main_ids = join(",",@{$bike_group}); + $main_ids =~ s/[a-z_-]+//ig;#should work also without Trenner + $pref = { %$pref, main_id => "IN::($main_ids)" }; + #} + #print Dumper($tariff_content); + + if($q->param('station')){ + my $station_id = $1 if($q->param('station') =~ /(\d+)/); + $pref = { %$pref, int04 => "=::" . $q->escapeHTML($station_id) } if(looks_like_number($station_id)); + } + if($q->param('bike')){ + my $bike_id = $1 if($q->param('bike') =~ /(\d+)/); + $pref = { %$pref, barcode => "=::" . $q->escapeHTML($bike_id) } if(looks_like_number($bike_id)); + } + + my $record = $dbt->fetch_record($dbh,$pref) if(ref($bike_group) eq "ARRAY" && @{$bike_group}[0]); + my $op_return = {}; + + my @adr_tariff = (); + @adr_tariff = ("$auth->{txt30}"); + @adr_tariff = split(/\s+/,$auth->{txt30}) if($auth->{txt30} =~ /\w\s+\w/); + + foreach my $id (sort { $record->{$a}->{barcode} <=> $record->{$b}->{barcode} } keys (%$record)){ + $return->{$id}->{authed} = "$authed"; + $return->{$id}->{station} = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}$record->{$id}->{int04}"; + $return->{$id}->{uri_operator} = "$varenv{wwwhost}"; + ($return->{$id}->{gps}->{latitude},$return->{$id}->{gps}->{longitude}) = split(/,/,$record->{$id}->{txt06}); + $return->{$id}->{bike} = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}$record->{$id}->{barcode}"; + #$return->{$id}->{description} = "$record->{$id}->{txt01}"; + $return->{$id}->{description} = Encode::encode('utf-8', Encode::decode('iso-8859-1', $record->{$id}->{txt01})); + $return->{$id}->{state} = "$dbt->{copri_conf}->{bike_state}->{$record->{$id}->{int10}}"; + $return->{$id}->{bike_charge} = "$record->{$id}->{int19}" if($record->{$id}->{int19}); + $return->{$id}->{system} = "Ilockit"; + if($record->{$id}->{int11} eq "2"){ + $return->{$id}->{lock_state} = "locked" if($record->{$id}->{int20} == 1); + $return->{$id}->{lock_state} = "unlocked" if($record->{$id}->{int20} == 2); + $return->{$id}->{lock_state} = "locking" if($record->{$id}->{int20} == 3); + $return->{$id}->{Ilockit_GUID} = "$record->{$id}->{txt17}"; + $return->{$id}->{Ilockit_ID} = "$record->{$id}->{txt18}"; + $return->{$id}->{bike_group} = ["$dbt->{operator}->{$varenv{dbname}}->{oprefix}$record->{$id}->{main_id}"]; + #if($users_serviceapp->{int09}){ + if($q->param('authcookie') =~ /_cleeJet3$|_34567890$/ && scalar(@{$user_tour} >= 1)){ + my @service_code = split(/\s/,$record->{$id}->{txt23}); + $return->{$id}->{service_code} = [@service_code]; + } + } + if(ref($tariff_content) eq "HASH"){ + foreach my $tid (sort { $tariff_content->{$a}->{barcode} <=> $tariff_content->{$b}->{barcode} } keys (%$tariff_content)){ + $bw->log("bikes_available tariff_content tariff_description if($record->{$id}->{main_id} == $tariff_content->{$tid}->{int12} && $auth->{txt30} =~ /$tariff_content->{$tid}->{barcode}/) BIKE:",$return->{$id}->{bike},""); + + foreach(@adr_tariff){ + if($record->{$id}->{main_id} == $tariff_content->{$tid}->{int12} && $_ == $tariff_content->{$tid}->{barcode}){ + + $return->{$id}->{tariff_description}->{name} = "$tariff_content->{$tid}->{ct_name}"; + $return->{$id}->{tariff_description}->{number} = "$tariff_content->{$tid}->{barcode}"; + $return->{$id}->{tariff_description}->{eur_per_hour} = "$tariff_content->{$tid}->{int02}" || "0"; + $return->{$id}->{tariff_description}->{max_eur_per_day} = "$tariff_content->{$tid}->{int17}" if($tariff_content->{$tid}->{int17}); + $return->{$id}->{tariff_description}->{free_hours} = "$tariff_content->{$tid}->{int16}" if($tariff_content->{$tid}->{int16}); + $return->{$id}->{tariff_description}->{abo_eur_per_month} = "$tariff_content->{$tid}->{int15}" if($tariff_content->{$tid}->{int15}); + $return->{$id}->{tariff_description}->{$id}->{operator_agb} = "Mit der Mietrad Anmietung wird folgender Betreiber AGB zugestimmt (als Demo sharee AGB)." if($auth->{c_id} == 1842 || $auth->{c_id} == 5781); + } + } + } + } + $op_return->{$dbt->{operator}->{$varenv{dbname}}->{oprefix} . $id} = $return->{$id}; + } + return $op_return; +}#end bikes_available + +#bikes_all +sub bikes_all(){ + my $self = shift; + my $q = shift; + my $auth = shift || {}; + my $stations_allraw = shift || ""; + my %varenv = $cf->envonline(); + + #my $users_serviceapp = $dbt->select_users($dbh,$auth->{c_id},"and int09=1"); + my $return={}; + my $pref = { + table => "content", + fetch => "all", + keyfield => "barcode",#2018-02-21 changed to bike id + template_id => "205",#Leihrad_liste + }; + + my ($bike_group,$user_group,$tariff_content,$user_tour) = $self->fetch_tariff($auth,$q->param('authcookie')); + my $main_ids = join(",",@{$bike_group}); + $main_ids =~ s/[a-z_]+//ig; + $pref = { %$pref, main_id => "IN::($main_ids)" }; + + my $station_id = $1 if($q->param('station') =~ /(\d+)/); + my $bike_id = $1 if($q->param('bike') =~ /(\d+)/); + $pref = { %$pref, int04 => "=::" . $q->escapeHTML($station_id) } if(looks_like_number($station_id)); + $pref = { %$pref, barcode => "=::" . $q->escapeHTML($bike_id) } if(looks_like_number($bike_id)); + + my $record = {}; + #on servicetool only stations on user_tour + $bw->log("stations_service_tour",$stations_allraw,""); + my @stations_service_tour = (); + if($q->param('authcookie') =~ /_cleeJet3$|_34567890$/){ + my $stations = ""; + if(ref($stations_allraw) eq "HASH" && scalar(@{$user_tour} >= 1)){ + foreach my $id (sort { $stations_allraw->{$a}->{int04} <=> $stations_allraw->{$b}->{int04} } keys (%$stations_allraw)){ + #push(@stations_service_tour, $stations_allraw->{$id}->{int04}) if($stations_allraw->{$id}->{int04} > 0); + push(@stations_service_tour, $stations_allraw->{$id}->{int04}) if(looks_like_number($stations_allraw->{$id}->{int04})); + } + $stations = join(",",@stations_service_tour); + $stations =~ s/[a-z_]+//ig; + $pref->{int04} = "IN::($stations)" if($stations); + $bw->log("sub bikes_all with user_tour",$pref,""); + } + $record = $dbt->fetch_record($dbh,$pref) if(ref($bike_group) eq "ARRAY" && @{$bike_group}[0]); + }else{ + $bw->log("sub bikes_all",$pref,""); + $record = $dbt->fetch_record($dbh,$pref) if(ref($bike_group) eq "ARRAY" && @{$bike_group}[0]); + } + + + + my $bikes_on_station = {}; + my $op_return = {}; + foreach my $id (sort { $record->{$a}->{barcode} <=> $record->{$b}->{barcode} } keys (%$record)){ + if(1==1){ + $bikes_on_station->{$record->{$id}->{int04}}->{bike_ist} += 1; + $return->{$id}->{uri_operator} = "$varenv{wwwhost}"; + $return->{$id}->{station} = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}$record->{$id}->{int04}"; + ($return->{$id}->{gps}->{latitude},$return->{$id}->{gps}->{longitude}) = split(/,/,$record->{$id}->{txt06}); + $return->{$id}->{bike} = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}$record->{$id}->{barcode}"; + #$return->{$id}->{description} = "$record->{$id}->{txt01}"; + $return->{$id}->{description} = Encode::encode('utf-8', Encode::decode('iso-8859-1', $record->{$id}->{txt01})); + + $return->{$id}->{state} = "$dbt->{copri_conf}->{bike_state}->{$record->{$id}->{int10}}"; + $return->{$id}->{service_state} = "0"; + $return->{$id}->{system} = "Ilockit"; + if($record->{$id}->{int11} eq "2"){ + $return->{$id}->{lock_state} = "locked" if($record->{$id}->{int20} == 1); + $return->{$id}->{lock_state} = "unlocked" if($record->{$id}->{int20} == 2); + $return->{$id}->{lock_state} = "locking" if($record->{$id}->{int20} == 3); + $return->{$id}->{Ilockit_GUID} = "$record->{$id}->{txt17}"; + $return->{$id}->{Ilockit_ID} = "$record->{$id}->{txt18}"; + $return->{$id}->{bike_group} = ["$dbt->{operator}->{$varenv{dbname}}->{oprefix}$record->{$id}->{main_id}"]; + #if($users_serviceapp->{int09}){ + if($q->param('authcookie') =~ /_cleeJet3$|_34567890$/ && scalar(@{$user_tour} >= 1)){ + my @service_code = split(/\s/,$record->{$id}->{txt23}); + $return->{$id}->{service_code} = [@service_code]; + } + } + $op_return->{$dbt->{operator}->{$varenv{dbname}}->{oprefix} . $id} = $return->{$id}; + } + } + + return ($op_return,$record,$bikes_on_station); +}#end bikes_all + +#stations_available +sub stations_available(){ + my $self = shift; + my $q = shift || ""; + my $auth = shift || ""; + my %varenv = $cf->envonline(); + + my $authed = 0; + $authed = 1 if(ref($auth) eq "HASH" && $auth->{c_id}); + my ($bike_group,$user_group,$tariff_content,$user_tour) = $self->fetch_tariff($auth,$q->param('authcookie')); + + my $return = {}; + my $pref = { + table => "content", + fetch => "all", + keyfield => "int04", + template_id => "225", + int10 => "1",#1 = "available" + }; + + my $pref_sql = ""; + $pref_sql .= " and ("; + foreach(@{$bike_group}){ + if($_ =~ /(\d+)/){ + $pref_sql .= " ct.txt24 like '%$1%' OR"; + } + } + $pref_sql =~ s/OR$//; + $pref_sql .= ")"; + $pref_sql = "" if($pref_sql !~ /\d/); + + my $record = {}; + #on servicetool only stations on user_tour + if($q->param('authcookie') =~ /_cleeJet3$|_34567890$/){ + if(scalar(@{$user_tour}) >= 1){ + $pref_sql .= " AND ("; + foreach(@{$user_tour}){ + if($_ =~ /(\d+)/){ + $pref_sql .= " ct.int07=$1 OR"; + } + } + $pref_sql =~ s/OR$//; + $pref_sql .= ")"; + $record = $dbt->fetch_record($dbh,$pref,$pref_sql) if(ref($bike_group) eq "ARRAY" && @{$bike_group}[0]); + } + }else{ + $record = $dbt->fetch_record($dbh,$pref,$pref_sql) if(ref($bike_group) eq "ARRAY" && @{$bike_group}[0]); + } + + my $op_return = {}; + foreach my $id (sort { $record->{$a}->{barcode} <=> $record->{$b}->{barcode} } keys (%$record)){ + $return->{$id}->{authed} = "$authed"; + + $return->{$id}->{station} = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}$record->{$id}->{int04}"; + if($record->{$id}->{int07}){ + $return->{$id}->{service_tour} = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}$record->{$id}->{int07}"; + }else{ + $return->{$id}->{service_tour} = ""; + } + $return->{$id}->{uri_operator} = "$varenv{wwwhost}"; + ($return->{$id}->{gps}->{latitude},$return->{$id}->{gps}->{longitude}) = split(/,/,$record->{$id}->{txt06}); + #$return->{$id}->{description} = "$record->{$id}->{txt01}"; + $return->{$id}->{description} = Encode::encode('utf-8', Encode::decode('iso-8859-1', $record->{$id}->{txt01})); + $return->{$id}->{state} = "$dbt->{copri_conf}->{bike_state}->{$record->{$id}->{int10}}"; + $return->{$id}->{station_group} = ""; + if($record->{$id}->{txt24}){#Ilockit with new station_group logic + $return->{$id}->{gps_radius} = "$record->{$id}->{int06}"; + $record->{$id}->{txt24} =~ s/(\d+)/$dbt->{operator}->{$varenv{dbname}}->{oprefix}$1/g; + my @station_group = split(/\s/,$record->{$id}->{txt24}); + $return->{$id}->{station_group} = [@station_group]; + } + + my $hotline_hash = { + table => "contentuser", + fetch => "one", + template_id => 197, + c_id => "1", + }; + my $hotline_data = $dbt->fetch_record($dbh,$hotline_hash); + + $return->{$id}->{operator_data} = { + "operator_name" => "", + "operator_hours" => "", + "operator_color" => "", + "operator_logo" => "", + "operator_phone" => "", + "operator_email" => "", + }; + $return->{$id}->{operator_data}->{operator_name} = Encode::encode('utf-8', Encode::decode('iso-8859-1',$hotline_data->{txt01})) if($hotline_data->{txt01}); + $return->{$id}->{operator_data}->{operator_hours} = Encode::encode('utf-8', Encode::decode('iso-8859-1',$hotline_data->{txt84})) if($hotline_data->{txt84}); + $return->{$id}->{operator_data}->{operator_color} = $hotline_data->{txt85} if($hotline_data->{txt85}); + $return->{$id}->{operator_data}->{operator_logo} = $hotline_data->{img01} if($hotline_data->{img01}); + $return->{$id}->{operator_data}->{operator_phone} = $hotline_data->{txt07} if($hotline_data->{txt07}); + $return->{$id}->{operator_data}->{operator_email} = $hotline_data->{txt08} if($hotline_data->{txt08}); + + $op_return->{$dbt->{operator}->{$varenv{dbname}}->{oprefix} . $id} = $return->{$id}; + } + return ($op_return, $record); +}#end stations_available + + +#stations_all +sub stations_all(){ + my $self = shift; + my $q = shift || ""; + my $bikes_on_station = shift || {}; + my $auth = shift || ""; + my %varenv = $cf->envonline(); + + my $authed = 0; + $authed = 1 if(ref($auth) eq "HASH" && $auth->{c_id}); + my ($bike_group,$user_group,$tariff_content,$user_tour) = $self->fetch_tariff($auth,$q->param('authcookie')); + + my $return={}; + my $pref = { + table => "content", + fetch => "all", + keyfield => "int04", + template_id => "225",#Station_liste + }; + + my $station_id = $1 if($q->param('station') =~ /(\d+)/); + my $work_val_id = $1 if($q->param('work_val') =~ /(\d+)/); + if(looks_like_number($station_id)){ + $pref = { %$pref, int04 => "=::" . $q->escapeHTML($station_id) }; + }elsif($q->param('work_id') eq "int04" && $work_val_id){ + $pref = { %$pref, int04 => "=::" . $q->escapeHTML("$work_val_id") }; + } + #$pref = { %$pref, int04 => ">::0" } if($q->param('authcookie') !~ /34567890|cleeJet3/);#Werkstatt + $pref = { %$pref, int10 => "1" } if($q->param('authcookie') !~ /34567890|cleeJet3/);#Werkstatt + + + my $pref_sql = ""; + $pref_sql .= " and ("; + foreach(@{$bike_group}){ + if($_ =~ /(\d+)/){ + $pref_sql .= " ct.txt24 like '%$1%' OR"; + } + } + $pref_sql =~ s/OR$//; + $pref_sql .= ")"; + $pref_sql = "" if($pref_sql !~ /\d/); + + my $record = {}; + #on servicetool only stations on user_tour + if($q->param('authcookie') =~ /_cleeJet3$|_34567890$/){ + if(scalar(@{$user_tour}) >= 1){ + $pref_sql .= " AND ("; + foreach(@{$user_tour}){ + if($_ =~ /(\d+)/){ + $pref_sql .= " ct.int07=$1 OR"; + } + } + $pref_sql =~ s/OR$//; + $pref_sql .= ")"; + $record = $dbt->fetch_record($dbh,$pref,$pref_sql) if(ref($bike_group) eq "ARRAY" && @{$bike_group}[0]); + } + }else{ + $record = $dbt->fetch_record($dbh,$pref,$pref_sql) if(ref($bike_group) eq "ARRAY" && @{$bike_group}[0]); + } + + + my $op_return = {}; + #only nececarry if amount of available bikes lower then bike_soll (like konrad) + #my $bike_ist_factor = 1; + #$bike_ist_factor = $self->bikes_soll($record,$bikes_on_station); + #$bike_ist_factor = 1 if($bike_ist_factor > 1); + + foreach my $id (sort { $record->{$a}->{barcode} <=> $record->{$b}->{barcode} } keys (%$record)){ + my $bike_soll = $record->{$id}->{int05} || 0;# * $bike_ist_factor; + #$bike_soll = $lb->round_half($bike_soll); + #$bike_soll =~ s/\.\d+//;#rounded integer + $return->{$id}->{authed} = "$authed"; + $return->{$id}->{station} = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}$record->{$id}->{int04}"; + if($record->{$id}->{int07}){ + $return->{$id}->{service_tour} = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}$record->{$id}->{int07}"; + }else{ + $return->{$id}->{service_tour} = ""; + } + $return->{$id}->{uri_operator} = "$varenv{wwwhost}"; + ($return->{$id}->{gps}->{latitude},$return->{$id}->{gps}->{longitude}) = split(/,/,$record->{$id}->{txt06}); + #$return->{$id}->{description} = "$record->{$id}->{txt01}"; + $return->{$id}->{description} = Encode::encode('utf-8', Encode::decode('iso-8859-1', $record->{$id}->{txt01})); + $return->{$id}->{state} = "$dbt->{copri_conf}->{bike_state}->{$record->{$id}->{int10}}"; + $return->{$id}->{bike_soll} = "$bike_soll"; + $return->{$id}->{bike_ist} = "$bikes_on_station->{$id}->{bike_ist}" || "0"; + $return->{$id}->{station_group} = ""; + if($record->{$id}->{txt24}){#sharee Ilockit with new station_group logic + $return->{$id}->{gps_radius} = "$record->{$id}->{int06}"; + $record->{$id}->{txt24} =~ s/(\d+)/$dbt->{operator}->{$varenv{dbname}}->{oprefix}$1/g; + my @station_group = split(/\s/,$record->{$id}->{txt24}); + $return->{$id}->{station_group} = [@station_group]; + } + $op_return->{$dbt->{operator}->{$varenv{dbname}}->{oprefix} . $id} = $return->{$id}; + } + return ($op_return,$record); +}#end stations_all + + +#collect all bike_ist +sub bikes_soll(){ + my $self = shift; + my $record = shift; + my $bikes_on_station = shift; + + my $bike_soll_all = 0; + foreach my $id (sort { $record->{$a}->{barcode} <=> $record->{$b}->{barcode} } keys (%$record)){ + $bike_soll_all += $record->{$id}->{int05}; + } + + #my $bikes_on_station_ist->{bikes_all} = '0'; + my $bikes_on_station_ist->{bikes_all_onstation} = '0'; + if(ref($bikes_on_station) eq "HASH"){ + foreach my $st (keys(%$bikes_on_station)){ + #$bikes_on_station_ist->{bikes_all} += $bikes_on_station->{$st}->{bike_ist};#incl st.0 + $bikes_on_station_ist->{bikes_all_onstation} += $bikes_on_station->{$st}->{bike_ist} if($st > 0); + } + } + my $bike_ist_factor = 1; + if(looks_like_number($bikes_on_station_ist->{bikes_all_onstation}) && $bikes_on_station_ist->{bikes_all_onstation} > 0 && looks_like_number($bike_soll_all) && $bike_soll_all > 0){ + $bike_ist_factor = sprintf('%.2f',$bikes_on_station_ist->{bikes_all_onstation} / $bike_soll_all); + } + + return $bike_ist_factor; +} + + +#Collect Tariff to get user_group---------------------- +sub fetch_tariff(){ + my $self = shift; + my $adr = shift || {}; + my $authcookie = shift || ""; + + my $tariff_content = {}; + my @user_tour = (); + my %varenv = $cf->envonline(); + my $auth_operator = {}; + + #int18 + # + # 2 = "public" + # 3 = "private" + # 4 = "hidden-lv" + # 5 = "public-bonus" + # + my $tariff = { + table => "content", + fetch => "all", + keyfield => "barcode", + template_id => "210",#Tariff tpl_id + }; + + #if no primary address then only 2=public + if((ref($adr) ne "HASH" || !$adr->{c_id}) && ($varenv{dbname} ne "sharee_lv")){ + $tariff->{int18} = 2; + $tariff_content = $dbt->fetch_record($dbh,$tariff); + }elsif(ref($adr) eq "HASH" && $adr->{c_id}){ + #select operators address to get users tarifnr array in txt30 + my $authref = { + table => "contentadr", + fetch => "one", + template_id => "202", + c_id => "=::$adr->{c_id}", + }; + $auth_operator = $dbt->fetch_record($dbh,$authref); + + if($authcookie && $authcookie =~ /_cleeJet3|_34567890/){ + my $users_serviceapp = $dbt->select_users($dbh,$auth_operator->{c_id},"and int09=1"); + if($users_serviceapp->{int09}){ + $auth_operator->{txt18} =~ s/(\d+)/$dbt->{operator}->{$varenv{dbname}}->{oprefix}$1/g; + @user_tour = ($auth_operator->{txt18}); + @user_tour = split(/\s/,$auth_operator->{txt18}) if($auth_operator->{txt18} =~ /\s/); + } + } + #$tariff->{int18} = 2;#disabled because wee need all + $tariff->{int18} = 4 if($varenv{dbname} eq "sharee_lv"); + + #FIXME user tarif select have to be fetched like in net_booking + #$tariff_content must contain tariff_description in App bikes_available listing + $tariff_content = $dbt->fetch_record($dbh,$tariff); + # + }else{ + $bw->log("NO tariff_content on",$varenv{dbname},""); + } + + my $oprefix = ""; + $oprefix = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}" if($dbt->{operator}->{$varenv{dbname}}->{oprefix}); + + my @tarifnr = (); + my @user_group = (); + my @bike_group = (); + my @adr_tariff = (); + @adr_tariff = ("$auth_operator->{txt30}"); + @adr_tariff = split(/\s+/,$auth_operator->{txt30}) if($auth_operator->{txt30} =~ /\w\s+\w/); + + foreach my $id (keys (%$tariff_content)){ + $bw->log("Tarif searching for authorized user-id $auth_operator->{c_id} by: if($auth_operator->{txt30} && $auth_operator->{txt30} =~ /$tariff_content->{$id}->{barcode}/ && $tariff_content->{$id}->{int12}) (s-type:$tariff_content->{$id}->{int18})","",""); + foreach(@adr_tariff){ + if($_ == $tariff_content->{$id}->{barcode} && $tariff_content->{$id}->{int12}){ + $bw->log("Tarif FOUND for authorized user-id $auth_operator->{c_id} if($tariff_content->{$id}->{int12}) (s-type:$tariff_content->{$id}->{int18})",$tariff_content->{$id}->{barcode},""); + push(@tarifnr, "$tariff_content->{$id}->{barcode}"); + push(@user_group, "$oprefix$tariff_content->{$id}->{int12}");#sharee bike_node.main_id + push(@bike_group, "$oprefix$tariff_content->{$id}->{int12}");#sharee bike_node.main_id + } + } + } + + #fallback to public tarif if no user tariff defined and not servicetool app request + if(!@tarifnr && $authcookie !~ /_cleeJet3|_34567890/){ + foreach my $id (keys (%$tariff_content)){ + if($tariff_content->{$id}->{int18} eq 2){ + $bw->log("Tarif FOUND FALLBACK for No Tarif users if($tariff_content->{$id}->{int12} && $varenv{dbname}) (s-type:$tariff_content->{$id}->{int18})",$id,""); + push(@tarifnr, "$tariff_content->{$id}->{barcode}"); + push(@user_group, "$oprefix$tariff_content->{$id}->{int12}");#sharee bike_node.main_id + push(@bike_group, "$oprefix$tariff_content->{$id}->{int12}");#sharee bike_node.main_id + } + } + } + #$bw->log("FETCHED_Tarif by dbname:$varenv{dbname} | user_group:@user_group | bike_group:@bike_group | user_tour:@user_tour | tarifnr: @tarifnr",$tariff_content,""); + $bw->log("FETCHED_Tarif by dbname:$varenv{dbname} | user_group:@user_group | bike_group:@bike_group | user_tour:@user_tour | tarifnr: @tarifnr",\@tarifnr,""); + return (\@bike_group,\@user_group,$tariff_content,\@user_tour); +} + +#authout +sub authout(){ + my $self = shift; + my $q = shift; + my $coo = shift || ""; + + my %varenv = $cf->envonline(); + my $dbh = ""; + my $record = { c_id => 0 };#if fails + my $return = { authcookie => "" };#if fails + + my $cgi_authcookie = $q->param('authcookie') || $coo || ""; + $bw->log("authout coo:$cgi_authcookie",$q,""); + + if($cgi_authcookie && length($cgi_authcookie) > 20){ + my $authref = { + table => "contentadr", + fetch => "one", + #keyfield => "c_id", + template_id => "202", + txt05 => "like::" . "%" . $q->escapeHTML($cgi_authcookie) . "%", + }; + $record = $dbt->fetch_record($dbh,$authref); + + my @user_group = (); + + if ($record->{c_id} > 0 && length($record->{txt05}) > 20){ + my $all_authcookie = $record->{txt05}; + my @check_cookies = split(/\|/,$record->{txt05}); + foreach(@check_cookies){ + #if(length($_) > 20 && $_ eq $cgi_authcookie){ + if(length($_) > 20 && $_ =~ /$cgi_authcookie/){ + $return = { authcookie => $_ }; + $all_authcookie =~ s/$_//g;#delete authcookie if available + $all_authcookie =~ s/\|$//; + $all_authcookie =~ s/\|\|/\|/g; + my $update = { + table => "contentadr", + txt05 => $all_authcookie, + }; + #print Dumper($update); + my $rows = 0; + $rows = $dbt->update_record($dbh,$update,$record); + if($varenv{dbname} ne "sharee_primary"){ + my $dbh_prim = $dbt->dbconnect_extern("sharee_primary"); + $rows = $dbt->update_record($dbh_prim,$update,$record); + } + if($rows == 1){ + $return = { authcookie => "1", + user_id => "$record->{txt08}", + user_group => @user_group, + }; + $return = { %$return, debuglevel => "$record->{int11}" } if($record->{int11}); + $return = { %$return, Ilockit_admin => "$record->{int19}" } if($record->{int19}); + } + } + } + } + } + + return $return; +}#end authout + +#auth_verify +sub auth_verify(){ + my $self = shift; + my $q = shift; + my $coo = shift || ""; + my $userc_id = shift || ""; + my $new_authcoo = shift || ""; + my $cgi_authcookie = $q->param('authcookie') || $q->param('sessionid') || $coo; + my $session_log = $q->param('sessionid') || ""; + my $user_agent = $q->user_agent(); + my $clientIP = $q->remote_addr(); + my %varenv = (); + $varenv{dbname} = ""; + %varenv = $cf->envonline(); + + my $record = { c_id => 0 };#if fails + my $return = { authcookie => "" }; + my $user_group = ""; + my $bike_group = ""; + my $tariff_content = ""; + my $user_tour = ""; + + #my $source = $dbt->get_dbname();#TODO, maybe substitude varenv{dbname} by $source!? + my $netloc = $q->url(-base=>1); + $bw->log("--> auth_verify on dbname $varenv{dbname},\n Starting with authcookie: $cgi_authcookie",$netloc,""); + if($cgi_authcookie && length($cgi_authcookie) > 30){ + my $authref = { + table => "contentadr", + fetch => "one", + template_id => "202", + txt05 => "like::" . "%" . $q->escapeHTML($cgi_authcookie) . "%", + }; + my $auth_operator = { c_id => 0 }; + $auth_operator = $dbt->fetch_record($dbh,$authref); + $bw->log("auth_verified on operator $varenv{dbname} anchor 1",$auth_operator->{c_id},""); + + #just part of operator-routing (sharee account management) + #primary select + if(1==1){ + if($varenv{dbname} ne "sharee_primary"){ + my $dbh_primary = $dbt->dbconnect_extern("sharee_primary"); + my $auth_primary = { c_id => 0 }; + $auth_primary = $dbt->fetch_record($dbh_primary,$authref); + + if($auth_primary->{c_id} > 0){ + $bw->log("auth_verified on primary anchor 2 by dbname $varenv{dbname}",$auth_primary->{c_id},""); + + #On booking_request, user must be authenticated and addr must exist + #At first insert/update Operator dbname array on primary + if($q->param('request') && $q->param('request') eq "booking_request"){ + + #first, save operator array which are used + my %operator_hash = ();#local DB + $bw->log("booking_request auth_verified by dbname $varenv{dbname} (dbname=$varenv{dbname})",$auth_operator->{c_id},""); + + if($auth_primary->{txt17} && $auth_primary->{txt17} =~ /\w\s\w/){#append DB's + %operator_hash = map { $_ => 1 } split(/\s+/,$auth_primary->{txt17}); + }elsif($auth_primary->{txt17}){ + $operator_hash{$auth_primary->{txt17}} = 1; + } + $operator_hash{$varenv{dbname}} = 1 if($varenv{dbname} ne "sharee_lv");#LastenVelo dbname will be only set by xml + + my @operator_array = keys %operator_hash; + $bw->log("auth_verified update operator keys by array: @operator_array",\%operator_hash,""); + my $update_primary = { + table => "contentadr", + txt17 => "@operator_array",#operator ids + txt19 => "$varenv{dbname}", + atime => "now()", + owner => "198",#update initiated by primary + }; + + #if user_device + if ($auth_primary->{c_id} > 0 && $q->param('user_device')){ + $update_primary->{txt14} = $q->escapeHTML($session_log) if($session_log); + $update_primary->{txt21} = $q->escapeHTML($q->param('user_device')) if($q->param('user_device')); + $update_primary->{txt25} = $q->escapeHTML($clientIP) if($clientIP && $clientIP =~ /\d+\.\d+\.\d+\.\d+/); + $update_primary->{txt26} = $q->escapeHTML($user_agent) if($user_agent); + } + + my $rows = $dbt->update_record($dbh_primary,$update_primary,$auth_primary); + $auth_primary = $dbt->fetch_record($dbh_primary,$authref); + } + + #if user on operator not able to authenticate because of adr authcookie does not exist + if(!$auth_operator->{c_id} || $auth_operator->{c_id} == 0 && $cgi_authcookie && length($cgi_authcookie) > 30){ + #my $uid = 0; + #($uid,my $sec,my $merchant) = split(/_/,$cgi_authcookie); + $authref = { + table => "contentadr", + fetch => "one", + template_id => "202", + c_id => "=::$auth_primary->{c_id}", + #c_id => "=::$uid", + #txt05 => "like::" . "%" . $q->escapeHTML($cgi_authcookie) . "%" + }; + my $auth_operator3 = { c_id => 0 }; + $auth_operator3 = $dbt->fetch_record($dbh,$authref);# if($uid); + $bw->log("auth_verified on operator anchor 3 by dbname $varenv{dbname}",$auth_operator3->{c_id},""); + + #if user on operator available by userid c_id, then update authcookie + if($auth_operator3->{c_id} > 0){ + my $authcookies = $auth_operator3->{txt05} . "|" . $cgi_authcookie; + my $update = { + table => "contentadr", + #txt05 => "$auth_primary->{txt05}",#authcookies + txt05 => "$authcookies",#authcookies + atime => "now()", + #mtime => "now()",#only set mtime on real user-data change + owner => "198",#update initiated by primary + }; + my $rows = $dbt->update_record($dbh,$update,$auth_operator3); + #else insert authenticated user from primary to operator + # + }elsif($auth_primary->{txt17} && $auth_primary->{txt17} =~ /$varenv{dbname}/){ + #insert + my $c_id = 0; + if($auth_primary->{c_id} > 0){ + $bw->log("INSERT adr from record_primary to operator by dbname $varenv{dbname}",$auth_primary->{c_id},""); + my $insert = { + %$auth_primary, + table => "contentadr", + mtime => 'now()', + owner => "198", + }; + $c_id = $dbt->insert_contentoid($dbh,$insert,"reset_adropkeys"); + } + }else{ + $bw->log("auth_verified on operator anchor 3 FAILS by dbname $varenv{dbname}. user seem not be activated",$auth_operator->{c_id},""); + } + } + $auth_operator = $dbt->fetch_record($dbh,$authref); + if($auth_operator->{c_id} > 0){ + $record = $auth_operator;#At first try using operator to get Tarif + $bw->log("auth_verified on operator anchor 2.2 by dbname $varenv{dbname}",$auth_operator->{c_id},""); + }else{ + $record = $auth_primary; + $bw->log("auth_verified on primary anchor 2.3 by dbname $varenv{dbname}",$auth_primary->{c_id},""); + } + }else{# if($auth_primary->{c_id}){ fails + $bw->log("auth_verified on primary anchor 4 FAILS by dbname $varenv{dbname}.",$auth_primary->{c_id},""); + $auth_operator = $dbt->fetch_record($dbh,$authref); + $record = $auth_operator; + $bw->log("auth_verified on operator anchor 9 by dbname $varenv{dbname}.",$auth_operator->{c_id},""); + } + }else{# if($varenv{dbname} eq "sharee_primary") + my $auth_operator = { c_id => 0 }; + $auth_operator = $dbt->fetch_record($dbh,$authref); + $bw->log("auth_verified on operator anchor 4 by dbname $varenv{dbname}",$auth_operator->{c_id},""); + $record = $auth_operator; + }#end if($varenv{dbname} ne "sharee_primary") + + }else{ + my $auth_operator = { c_id => 0 }; + $auth_operator = $dbt->fetch_record($dbh,$authref); + $bw->log("auth_verified on operator anchor 6 by dbname $varenv{dbname}",$auth_operator->{c_id},""); + $record = $auth_operator; + } + + if($varenv{dbname} ne "sharee_primary"){ + ($bike_group,$user_group,$tariff_content,$user_tour) = $self->fetch_tariff($record,$q->param('authcookie')); + } + + if ($record->{c_id} > 0 && length($record->{txt05}) > 30){ + my @check_cookies = split(/\|/,$record->{txt05}); + foreach(@check_cookies){ + if(length($_) > 30 && $_ =~ /$cgi_authcookie/){ + $return = { authcookie => $cgi_authcookie, + user_id => "$record->{txt08}", + user_group => $user_group, + user_tour => $user_tour, + }; + $return = { %$return, debuglevel => "$record->{int11}" } if($record->{int11}); + $return = { %$return, Ilockit_admin => "$record->{int19}" } if($record->{int19}); + } + } + } + } + elsif($userc_id && looks_like_number($userc_id) && length($userc_id) >= 4){ + my $authref = { + table => "contentadr", + fetch => "one", + template_id => "202", + c_id => "=::$userc_id", + }; + + $record = $dbt->fetch_record($dbh,$authref); + + ($bike_group,$user_group,$tariff_content,$user_tour) = $self->fetch_tariff($record,$q->param('authcookie')); + #maybe there isnt't any authcookie still available on confirm + if ($record->{c_id} > 0){ + $return = { user_id => "$record->{txt08}", + user_group => $user_group, + user_tour => $user_tour, + }; + $return = { %$return, debuglevel => "$record->{int11}" } if($record->{int11}); + $return = { %$return, Ilockit_admin => "$record->{int19}" } if($record->{int19}); + $return = { %$return, response_text => "Danke, die Anmeldebestätigung war erfolgreich." }; + } + }else{ + $bw->log("auth_verified on operator anchor FAILS by dbname $varenv{dbname}, no authcookie, dump \$q",$q,""); + } + my $agb_checked = 0; + $agb_checked = 1 if($record->{int14});#sharee AGB global + $return->{agb_checked} = "$agb_checked"; + + my $last_used_operator = $record->{txt19};#check if this is primary and/or useable + $bw->log("last_used_operator selected by txt19:",$last_used_operator,""); + if($last_used_operator){ + my $dbh_operator = $dbt->dbconnect_extern("$last_used_operator"); + my $hotline_hash = { + table => "contentuser", + fetch => "one", + template_id => 197, + c_id => "1", + }; + my $hotline_data = $dbt->fetch_record($dbh_operator,$hotline_hash); + + $return->{last_used_operator} = { + "operator_name" => "", + "operator_hours" => "", + "operator_color" => "", + "operator_logo" => "", + "operator_phone" => "", + "operator_email" => "", + }; + $return->{last_used_operator}->{operator_name} = $hotline_data->{txt01} if($hotline_data->{txt01}); + $return->{last_used_operator}->{operator_hours} = $hotline_data->{txt84} if($hotline_data->{txt84}); + $return->{last_used_operator}->{operator_color} = $hotline_data->{txt85} if($hotline_data->{txt85}); + $return->{last_used_operator}->{operator_logo} = $hotline_data->{img01} if($hotline_data->{img01}); + $return->{last_used_operator}->{operator_phone} = $hotline_data->{txt07} if($hotline_data->{txt07}); + $return->{last_used_operator}->{operator_email} = $hotline_data->{txt08} if($hotline_data->{txt08}); + } + + $bw->log("auth_verify done on txt05 authcookies by dbname $varenv{dbname}:",$record->{txt05},""); + + #Servicetool only users with users.int09=1 + if($varenv{dbname} ne "sharee_primary" && $q->param('authcookie') =~ /_34567890$|_cleeJet3$/){ + my $users_serviceapp = { u_id => 0 }; + $users_serviceapp = $dbt->select_users($dbh,$record->{c_id},"and int09=1"); + if(!$users_serviceapp->{u_id} || $users_serviceapp->{u_id} == 0){ + $record = { c_id => 0 }; + $bw->log("reset auth_verify because of only Servicetool users access:",$record,""); + } + } + + return ($return,$record); +}#end auth_verify + + +#authorization +sub authorization(){ + my $self = shift; + my $q = shift; + my $merchant_id = shift || $q->param('merchant_id') || ""; + my $hw_id = shift || $q->param('hw_id') || ""; + my $aowner = shift || 0; + $dbh = ""; + my %varenv = $cf->envonline(); + + my $user_id = $q->param('user_id') || $q->param('txt08'); + my $user_pw = $q->param('user_pw') || $q->param('txt04'); + #print "user_pw:" . $q->param('user_pw') . "|txt04:" . $q->param('txt04') . "|user_pw:" . $q->param('user_pw'); + + my $pw_length = 6;#only 6 and if < 8 user failure will be set + $user_pw = "mo2Xah6a" if(length($user_pw) < $pw_length); + + my $record = { c_id => 0 };#if fails + my $return = { authcookie => 0 };#if fails + #print "$hw_id | $merchant_id | $user_id | $user_pw\n";exit; + + + if($user_id && length($user_id) >= 4 && length($user_pw) >= $pw_length && length($hw_id) >= 10 && length($merchant_id) >= 8){ + my $authref = { + table => "contentadr", + fetch => "one", + template_id => "202", + txt08 => "ilike::" . $q->escapeHTML($user_id), + int05 => "1", + }; + + my $pass_name = $q->escapeHTML($user_pw); + $pass_name =~ s/\s//g; + my $pwmd5=md5_hex($pass_name); + $authref->{txt11} = "$pwmd5"; + + #Servicetool, only users with users.int09=1 + if($merchant_id =~ /_34567890$|_cleeJet3$/){ + my $users_serviceapp = { u_id => 0 }; + $users_serviceapp = $dbt->select_users($dbh,$record->{c_id},"and int09=1"); + $record = { c_id => 0 } if(!$users_serviceapp->{u_id}); + }else{ + #2021-10-13 because of keep DMS authcookie + #2021-12-23 user must always be registered on sharee_primary + $dbh = $dbt->dbconnect_extern("sharee_primary") if($varenv{dbname} ne "sharee_primary"); + $record = $dbt->fetch_record($dbh,$authref); + } + $return = $self->authcookie_manager($dbh,$q,$record,$merchant_id,$hw_id,$aowner); + + }else{ + $bw->log("authorization fals because of failing condition: if($user_id && length($user_id) >= 4 && length($user_pw) >= $pw_length && length($hw_id) >= 10 && length($merchant_id) >= 8)","",""); + } + return $return; +}#end authorization + +#manage authcookie +sub authcookie_manager { + my $self = shift; + $dbh = shift; + my $q = shift; + my $record = shift; + my $merchant_id = shift; + my $hw_id = shift; + my $aowner = shift || 0; + + my $user_agent = $q->user_agent(); + my $clientIP = $q->remote_addr(); + my $return = { authcookie => 0 };#if fails + my %varenv = $cf->envonline(); + + my $authcookie=md5_hex($record->{txt08}.$q->escapeHTML($hw_id)); + $authcookie = $record->{c_id} . "_" . $authcookie . "_" . $q->escapeHTML($merchant_id); + + #if user_id && user_pw matched + if ($record->{c_id} > 0 && length($authcookie) > 20){ + my $update = { + table => "contentadr", + atime => "now()", + int15 => "$aowner",#update on access + #mtime => "now()", + #owner => "198",#update initiated by primary + }; + + $update->{txt21} = $q->escapeHTML($q->param('user_device')) if($q->param('user_device')); + $update->{txt25} = $q->escapeHTML($clientIP) if($clientIP && $clientIP =~ /\d+\.\d+\.\d+\.\d+/); + $update->{txt26} = $q->escapeHTML($user_agent) if($user_agent); + + my @registered_cookies; + my $registered_cookies; + my @check_cookies = split(/\|/,$record->{txt05}); + $bw->log("check_cookies","@check_cookies",""); + @check_cookies = reverse(@check_cookies); + my $i=0; + foreach(@check_cookies){ + $i++; + #secure shortage cookies + if(length($_) > 20 && $i < 8){#max 8 clients + $bw->log("$i < 8 cookies",$_,""); + push @registered_cookies,$_; + } + } + + @registered_cookies = reverse(@registered_cookies); + foreach(@registered_cookies){ + $registered_cookies .= "$_|" if(length($_) > 20);#secure shortage cookies + } + $registered_cookies =~ s/\|$//; + + $bw->log("generated authcookie",$authcookie,""); + + #return still existing authcookie + if($registered_cookies && $registered_cookies =~ /$authcookie/){ + my $rows = $dbt->update_record($dbh,$update,$record); + + $return = { authcookie => "$authcookie", + new_authcoo => "0", + user_id => "$record->{txt08}", + }; + $return = { %$return, debuglevel => "$record->{int11}" } if($record->{int11}); + $return = { %$return, Ilockit_admin => "$record->{int19}" } if($record->{int19}); + + #return new generated authcookie + }else{ + my $all_authcookie = $authcookie; + $all_authcookie = $registered_cookies . "|" . $authcookie if($registered_cookies); + $update->{txt05} = $all_authcookie; + my $rows = $dbt->update_record($dbh,$update,$record); + + #update also operator cookies + if($varenv{dbname} eq "sharee_primary" && $record->{txt17}){ + my $auth_primary = $record; + my %operator_hash = (); + if($auth_primary->{txt17} =~ /\w\s\w/){ + %operator_hash = map { $_ => 1 } split(/\s+/,$auth_primary->{txt17}); + }else{ + $operator_hash{$auth_primary->{txt17}} = 1; + } + foreach my $sharee_operator (keys (%operator_hash)){ + my $dbh_operator = $dbt->dbconnect_extern("$sharee_operator"); + my $authref = { + table => "contentadr", + fetch => "one", + template_id => "202", + c_id => "$auth_primary->{c_id}", + }; + my $auth_operator = { c_id => 0 }; + $auth_operator = $dbt->fetch_record($dbh_operator,$authref); + + #if user on operator available by userid c_id, then update authcookie + if($auth_operator->{c_id}){ + $bw->log("update adr from record_primary to operator \"$sharee_operator\" after new new_authcoo",$update,""); + my $rows = $dbt->update_record($dbh_operator,$update,$auth_operator); + } + } + } + #end update operator cookies + + if($rows == 1){ + $return = { authcookie => "$authcookie", + new_authcoo => "1", + user_id => "$record->{txt08}", + }; + + $return = { %$return, debuglevel => "$record->{int11}" } if($record->{int11}); + $return = { %$return, Ilockit_admin => "$record->{int19}" } if($record->{int19}); + } + } + } + + return $return; +} + +1; diff --git a/copri4/main/src/Mod/APIjsonclient.pm b/copri4/main/src/Mod/APIjsonclient.pm new file mode 100644 index 0000000..c2b53b7 --- /dev/null +++ b/copri4/main/src/Mod/APIjsonclient.pm @@ -0,0 +1,141 @@ +package APIjsonclient; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +#Client for shareejson api +# +use strict; +use warnings; +use POSIX; +use CGI; # only for debugging +use JSON; +use LWP::UserAgent; +use URI::Encode; +use Config::General; +use Mod::Basework; +use Data::Dumper; + + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + + +my $q = new CGI; +my $netloc = $q->url(-base=>1); +my $ua = LWP::UserAgent->new; +my $uri_encode = URI::Encode->new( { encode_reserved => 1 } ); +$ua->agent("APIclient $netloc"); +my $bw = new Basework; + +my $json = JSON->new->allow_nonref; + +sub loop_sharees { + my $self = shift; + my $q = shift || ""; + my $auth = shift; + my $owner = shift || ""; + my @keywords = $q->param; + my $project = "all"; + + #only request keys which initated by sharee primary requests to operator + my $rest = ""; + foreach (@keywords){ + if($_ =~ /request|authcookie|system|bike|station/g){ + my $val = $q->param($_); + my $encoded_val = $uri_encode->encode($val); + $rest .= "$_=$encoded_val&"; + }elsif($_ eq "project"){ + my $val = $q->param($_); + $project = $val if($val eq "Bayern");#restricted map view only on lastenrad bayern iframe + } + } + $rest =~ s/\&$//; + + my $response_in = {}; + + my $globalconf_file = "/var/www/copri4/shareeconf/global.cfg"; + my $conf = Config::General->new($globalconf_file); + my %globalconf = $conf->getall; + + my @uri_operator_array = (); + my @user_group = (); + my @user_tour = (); + my $fetch_hash = {}; + while (my ($key, $value) = each %{ $globalconf{operator} }) { + my $ret_json = ""; + #print $key;# like sharee_fr01 + if($value->{operatorApp} && ($project eq $value->{project} || $project eq "all")){ + $bw->log("--> LOOP-start jsonclient loop_sharees $key by operatorApp: $value->{operatorApp}, netloc: $netloc if($project eq $value->{project} || $project eq \"all\")\n","",""); + $ret_json = $self->fetch_operator_json($value->{operatorApp},$rest); + if($ret_json){ + push(@uri_operator_array, $value->{operatorApp}); + eval { + my $response_in = decode_json($ret_json); + + #collect OP user_group + if($response_in->{shareejson}->{user_group}){ + push (@user_group, @{$response_in->{shareejson}->{user_group}}); + } + #collect OP user_tour + if($response_in->{shareejson}->{user_tour}){ + push (@user_tour, @{$response_in->{shareejson}->{user_tour}}); + } + + if($q->param('request') && $q->param('request') =~ /stations_all|stations_available/){ + foreach my $result (keys (%{ $response_in->{shareejson}->{stations} })) { + $fetch_hash->{$result} = $response_in->{shareejson}->{stations}->{$result}; + } + } + if($q->param('request') && $q->param('request') =~ /bikes_all|bikes_available/){ + foreach my $result (keys (%{ $response_in->{shareejson}->{bikes} })) { + $fetch_hash->{$result} = $response_in->{shareejson}->{bikes}->{$result}; + } + } + if($q->param('request') && $q->param('request') =~ /user_bikes_occupied/){ + foreach my $result (keys (%{ $response_in->{shareejson}->{bikes_occupied} })) { + $fetch_hash->{$result} = $response_in->{shareejson}->{bikes_occupied}->{$result}; + } + } + }; + if ($@){ + $bw->log("Failure, eval json from jsonclient","",""); + warn $@; + } + }else{ + $bw->log("NO json ","",""); + } + } + $bw->log("--> LOOP-end jsonclient loop_sharees user_group:\n",\@user_group,""); + } + #print "ALL:" . Dumper($fetch_hash); + # + return ($fetch_hash,\@uri_operator_array,\@user_group,\@user_tour); +} + +sub fetch_operator_json { + my $self = shift; + my $operator_server = shift || ""; + my $rest = shift || ""; + my $operator_request = "$operator_server/APIjsonserver?$rest"; + + $bw->log("fetch_operator_json >> ","$operator_request",""); + + my $req = HTTP::Request->new(GET => "$operator_request"); + $req->content_type('application/x-www-form-urlencoded'); + $req->content($rest); + + my $res = $ua->request($req); + if ($res->is_success) { + #print $res->content; + return $res->content; + }else { + return ""; + } +} + +1; diff --git a/copri4/main/src/Mod/APIjsonserver.pm b/copri4/main/src/Mod/APIjsonserver.pm new file mode 100644 index 0000000..a6d3a70 --- /dev/null +++ b/copri4/main/src/Mod/APIjsonserver.pm @@ -0,0 +1,881 @@ +package Mod::APIjsonserver; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +#Server for sharee json api +# +#use lib qw(/var/www/copri4/tinkdms/src); +# +##In DB context $q->escapeHTML must always done by API +# +use warnings; +use strict; +use Exporter; +our @ISA = qw (Exporter); + +use POSIX; +use CGI; +use Apache2::Const -compile => qw(OK ); +use JSON; +use Scalar::Util qw(looks_like_number); +use Config::General; + +use Lib::Config; +use Mod::DBtank; +use Mod::Basework; +use Mod::Shareework; +use Mod::APIfunc; +use Mod::APIjsonclient; +use Data::Dumper; +use Sys::Hostname; +my $hostname = hostname; + +sub handler { + my ($r) = @_; + my $q = new CGI; + my $netloc = $q->url(-base=>1); + #$q->import_names('R'); + my $json = JSON->new->allow_nonref; + my $cf = new Config; + my $dbt = new DBtank; + my $bw = new Basework; + my $tk = new Shareework; + my $apif = new APIfunc; + my $jsc = new APIjsonclient; + + + my %varenv = $cf->envonline(); + my $oprefix = $dbt->{operator}->{$varenv{dbname}}->{oprefix}; + my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; + my $lang="de"; + my $owner=188;#default via API if authcookie doesn't match merchant_id + my @keywords = $q->param; + my $debug=1; + my $user_agent = $q->user_agent(); + +$bw->log("APIjsonserver request:\n--> user-agent '$user_agent'",$q,""); + +print $q->header(-type => "application/json", -charset => "utf-8", -'Access-Control-Allow-Origin' => "*"); + +my $respreq = $q->param('request') || ""; +my $apiserver = $q->url(-base=>1) || ""; +my $copri_version = "4.1.8.31"; + +my $response = { + apiserver => "$apiserver", + user_id => "", + authcookie => "", + new_authcoo => "0", + clearing_cache => "0", + agb_checked => "0", + user_group => [], + user_tour => [], + response => "$respreq", + uri_primary => "$varenv{uri_primary}", + copri_version => "$copri_version", + response_state => "OK, nothing todo", + privacy_html => "site/privacy.html", + agb_html => "site/agb.html", + impress_html => "site/impress.html", + tariff_info_html => "site/tariff_info_1.html", + bike_info_html => "site/bike_info.html", + initMap => { + center => { latitude => "", longitude => "" }, + radius => "" + }, + last_used_operator => { + operator_name => "sharee.bike | TeilRad GmbH", + operator_color => "#009699", + operator_email => "hotline\@sharee.bike", + operator_phone => "+49 761 45370097", + operator_hours => "Bürozeiten: Montag, Mittwoch, Freitag 9-12 Uhr", + }, + lang => "DE" +}; +#user_agent => "$user_agent" + +my $merchanized = 0; +my $merchant_conf = ""; +#while (($merchant_conf, my $value) = each %{ $dbt->{merchant_ids}}) { +# if($merchant_conf && $value->{user_agent} && $user_agent && $user_agent =~ /$value->{user_agent}/){ +# #$owner = join("", map { $_ } keys %{ $value }); +# $owner = $value->{id}; +# $merchanized = 1; +# $response->{initMap} = "$value->{initMap}"; +# $bw->log("APIjsonserver merchant select by user_agent: if($value->{user_agent} && $user_agent && $user_agent =~ /$value->{user_agent}/){",$merchant_id,""); +# last; +# } +#} + +if(!$merchanized){ + while (($merchant_conf, my $value) = each %{ $dbt->{merchant_ids}}) { + if($merchant_conf && (($R::authcookie && $R::authcookie =~ /$merchant_conf$/) || ($R::merchant_id && $R::merchant_id eq $merchant_conf))){ + $owner = $value->{id}; + $merchanized = 1; + $value->{initMap} =~ s/\s//g; + my ($lat,$lng) = split(/,/,$value->{initMap}); + $response->{initMap}->{center}->{latitude} = $lat; + $response->{initMap}->{center}->{longitude} = $lng; + $response->{initMap}->{radius} = "2.9"; + #$response->{initMap} = "$value->{initMap}"; + $bw->log("APIjsonserver merchant select by authcookie OR merchant_id: if($merchant_conf && (($R::authcookie && $R::authcookie =~ /$merchant_conf$/) || ($R::merchant_id && $R::merchant_id eq $merchant_conf))){",$merchant_conf,""); + last; + } + } +} + +if(!$merchanized && ($R::authcookie || $R::merchant_id)){ + $response->{response_state} = "Failure 9900: no authcookie or merchant_id defined"; + $response->{response_text} = "Authentifizierung fehlgeschlagen."; + $bw->log("NO authcookie or merchant_id defined",$R::merchant_id,""); + my $jrout = $json->pretty->encode({shareejson => $response}); + print $jrout; + return Apache2::Const::OK; + exit 0; +} + +#If param>40 || value > 200 then exit +foreach(@keywords){ + if(length($_) > 40 || length($q->param($_)) > 400){ + $response->{response_state} = "Failure 9000: amount of characters in $_ exceeds"; + my $jrout = $json->pretty->encode({shareejson => $response}); + print $jrout; + return Apache2::Const::OK; + exit 0; + } +} + + +#RESTful bikeAPP ------------------------------------------------------------------ + +if($q->param('user_device_manufaturer') || $q->param('user_device_model') || $q->param('user_device_platform') || $q->param('user_device_version') || $q->param('user_device_id')){ + my $user_device = $q->param('user_device_manufaturer') . ";" . $q->param('user_device_model') . ";" . $q->param('user_device_platform') . ";" . $q->param('user_device_version') . ";" . $q->param('user_device_id'); + $q->param(-name=>'user_device',-value=>"$user_device"); + $bw->log("user_device",$q->param('user_device'),""); +} + + +#just auth_verify +if($q->param('request') eq "auth_verify"){ + my ($auth,$authraw) = $apif->auth_verify($q); + $response = { %$response, %$auth }; + if(ref($auth) eq "HASH" && $auth->{authcookie}){ + $response = { %$response, %$auth }; + }else{ + $response->{response_state} = "Failure: cannote match authcookie"; + $response->{response_text} = "Entschuldigung, die Session wurde unterbrochen"; + } +} + +#authout +elsif($q->param('request') eq "authout"){ + my ($auth,$authraw) = $apif->authout($q); + $response = { %$response, %$auth }; + if(ref($auth) eq "HASH" && $auth->{authcookie}){ + $response->{authcookie} = "$auth->{authcookie}"; + $response->{response_state} = "OK, logout"; + $response->{response_text} = "Auf Wiedersehen."; + }else{ + $response->{response_state} = "Failure 1001: authcookie not defined"; + $response->{response_text} = "Entschuldigung, die Session wurde unterbrochen"; + } +} +#authorization +elsif($q->param('request') eq "authorization"){ + my ($auth,$authraw) = $apif->authorization($q,"","",$owner); + if(ref($auth) eq "HASH" && $auth->{authcookie}){ + $response = { %$response, %$auth }; + $response->{response_text} = "Herzlich willkommen im Fahrradmietsystem"; + }else{ + $response->{response_state} = "Failure: cannot generate authcookie"; + $response->{response_text} = "Entschuldigung, die Anmeldung schlug fehl"; + } +} + +#booking request +elsif($q->param('request') eq "booking_request"){ + my ($auth,$authraw) = $apif->auth_verify($q); + $response = { %$response, %$auth }; + if(ref($auth) eq "HASH" && $auth->{authcookie}){ + if($q->param('bike')){ + #check count of occcupied/requested bikes + my $record = $apif->user_bikes_occupied($q,$authraw); + my $bikes_occupied = $apif->rentals($record,$authraw,"1"); + my $count=0; + foreach my $id (keys(%$bikes_occupied)){ + $count++; + } + if($count >= 3){ + $response->{response_state} = "Failure: booking_request declined. max count of 3 occupied bikes has been reached"; + $response->{response_text} = "Die maximale Anzahl von 3 Reservierungen wurde erreicht"; + }else{ + my $gps = ""; + my $latitude = ""; + my $longitude = ""; + #old + if($q->param('gps')){ + my $gps_input = $q->param('gps'); + $gps_input =~ s/\s//g if($gps_input); + $latitude = $q->escapeHTML($1) if($gps_input =~ /^(\d+\.\d+),\d+/); + $longitude = $q->escapeHTML($1) if($gps_input =~ /\d+,(\d+\.\d+)$/); + $gps = "$latitude,$longitude" if($latitude && $longitude); + } + #new + if($q->param('latitude') && $q->param('longitude')){ + my $latitude_in = $q->param('latitude'); + my $longitude_in = $q->param('longitude'); + $latitude = $1 if($latitude_in =~ /(\d+\.\d+)/); + $longitude = $1 if($longitude_in =~ /(\d+\.\d+)/); + $gps = "$latitude,$longitude" if($latitude && $longitude); + } + + my $response_book = $tk->net_booking($authraw,$q->param('bike'),$owner,$gps); + + #just in time booking + if(ref($response_book) eq "HASH" && $response_book->{response_state} =~ /OK/ && $q->param('state') && $q->param('state') =~ /occupied/){ + (my $rows, my $booking_values) = $apif->booking_update($q,$authraw,$owner); + $response = {%$response, %$booking_values}; + }else{ + $response = {%$response, %$response_book}; + } + } + + $record = $apif->user_bikes_occupied($q,$authraw); + $bikes_occupied = $apif->rentals($record,$authraw,"1"); + + foreach my $id (keys(%$bikes_occupied)){ + if($bikes_occupied->{$id}->{bike} eq $q->param('bike')){ + if($bikes_occupied->{$id}->{int10} == 2){ + $response->{response_state} = "OK, bike " . $q->param('bike') . " requested"; + $response->{response_text} = "Fahrrad Nr. " . $q->param('bike') . " ist reserviert"; + }elsif($bikes_occupied->{$id}->{int10} == 3){ + $response->{response_state} = "OK, bike " . $q->param('bike') . " requested and occupied"; + $response->{response_text} = "Fahrrad Nr. " . $q->param('bike') . " ist gemietet"; + } + } + } + #return list of occupied/requested bikes + $record = $apif->user_bikes_occupied($q,$authraw); + $response->{bikes_occupied} = $apif->rentals($record,$authraw,"1");#returns JSON rental values + + }else{ + $response->{response_state} = "Failure: no bike defined"; + $response->{response_text} = "Abbruch, es wurde kein Fahrrad ausgewählt"; + $response->{timeCode} = 0;#if fails + } + }else{ + $response->{response_state} = "Failure 1002: authcookie not defined"; + $response->{response_text} = "Entschuldigung, die Session wurde unterbrochen"; + } +} + +#booking cancel/update +elsif($q->param('request') eq "booking_cancel" || $q->param('request') eq "booking_update"){ + if($q->param('request') eq "booking_cancel"){ + $q->param(-name=>'request',-value=>"booking_update"); + $q->param(-name=>'state',-value=>"canceled"); + } + my ($auth,$authraw) = $apif->auth_verify($q); + my $rows = 0; + $response = { %$response, %$auth }; + + if(ref($auth) eq "HASH" && $auth->{authcookie}){ + if($q->param('bike')){ + if($q->param('request') eq "booking_update" && $q->param('state') && $q->param('state') =~ /canceled/){ + ($rows, my $booking_values) = $apif->booking_update($q,$authraw,$owner); + $response = {%$response, %$booking_values}; + }elsif($q->param('request') eq "booking_update" && (($q->param('state') && $q->param('state') =~ /occupied|available/) || ($q->param('lock_state') && $q->param('lock_state') =~ /locking|locked|unlocked/))){ + ($rows, my $booking_values) = $apif->booking_update($q,$authraw,$owner); + $response = {%$response, %$booking_values}; + + #keep in mind, it works on operator dependency + $bw->log("user_miniquery via $varenv{dbname} exist count:",$authraw->{int23},""); + #Nur für project=Bayern und für Entwickler aktiviert + if($booking_values->{state} eq "available" && (($dbt->{operator}->{$varenv{dbname}}->{project} eq "Bayern" && $authraw->{int23} >= 1 && $authraw->{int23} < 4) || ($authraw->{c_id} == 1842 || $authraw->{c_id} == 5781 || $authraw->{c_id} == 11765 || $authraw->{c_id} == 1843))){ + + #TODO $ user_miniquery have to be in db table on primary + $bw->log("user_miniquery communicated to user ID",$authraw->{c_id},""); + my $user_miniquery = { + title => "Bitte unterstützen Sie unsere Begleitforschung", + subtitle => "Ihre drei Antworten werden anonym gespeichert.", + footer => "Herzlichen Dank und viel Spaß bei der nächsten Fahrt!", + questions => { + q1 => { + type => "check_one", + quest_text => "1. Was war der Hauptzweck dieser Ausleihe?", + query => { + opt1 => "a. Einkauf", + opt2 => "b. Kinderbeförderung", + opt3 => "c. Lastentransport", + opt4 => "d. Freizeit", + opt5 => "e. Ausprobieren", + opt6 => "f. Sonstiges" + } + }, + q2 => { + type => "check_one", + quest_text => "2. Welches Verkehrsmittel hätten Sie ansonsten benutzt?", + query => { + opt1 => "a. Auto", + opt2 => "b. Motorrad oder Motorroller", + opt3 => "c. Bus oder Bahn", + opt4 => "d. Eigenes Fahrrad", + opt5 => "e. Zu Fuß", + opt6 => "f. Keines (ich hätte die Fahrt sonst nicht gemacht)", + opt7 => "g. Sonstige" + } + }, + q3 => { + type => "text", + quest_text => "3. Haben Sie Anmerkungen oder Anregungen?", + query => { + opt1 => "" + } + } + } + }; + + $response->{user_miniquery} = $user_miniquery; + }#end mini_quest + + #user_miniquest_count + my $user_miniquest_count = $authraw->{int23} || 0; + if($q->param('request') && $q->param('request') eq "booking_update" && $q->param('state') eq "available" && $user_miniquest_count <= 4){ + $user_miniquest_count++; + my $update_op = { + table => "contentadr", + int23 => $user_miniquest_count, + atime => "now()", + owner => "198", + }; + my $dbh = ""; + my $rows = $dbt->update_record($dbh,$update_op,$authraw); + } + } + + my $record = $apif->user_bikes_occupied($q,$authraw); + $response->{bikes_occupied} = $apif->rentals($record,$authraw,"1"); + + }else{ + $response->{response_state} = "Failure: no bike defined"; + $response->{response_text} = "Abbruch, es wurde keine Fahrrad Nummer angegeben"; + $response->{timeCode} = 0;#if fails + } + }else{ + $response->{response_state} = "Failure 1001: authcookie not defined"; + $response->{response_text} = "Entschuldigung, die Session wurde unterbrochen"; + } +} + +#user_rental_history +elsif($q->param('request') eq "user_rentals_history"){ + my ($auth,$authraw) = $apif->auth_verify($q); + $response = { %$response, %$auth }; + + if(ref($auth) eq "HASH" && $auth->{authcookie}){ + my ($record,$operator_hash) = $apif->user_rentals_history($q,$authraw); + $response->{rentals} = $apif->rentals($record,$authraw,"0"); + }else{ + $response->{response_state} = "Failure 1001: authcookie not defined"; + $response->{response_text} = "Entschuldigung, die Session wurde unterbrochen"; + } +} + +#user_bikes_occupied +elsif($q->param('request') eq "user_bikes_occupied"){ + if($varenv{syshost} eq "shareeapp-primary"){ + + my ($auth,$authraw) = $apif->auth_verify($q); + if(ref($auth) eq "HASH" && $auth->{authcookie}){ + $response = { %$response, %$auth }; + ($response->{bikes_occupied},$response->{uri_operator_array},$response->{user_group},$response->{user_tour}) = $jsc->loop_sharees($q,$auth,$owner); + }else{ + $response->{response_state} = "Failure 1001: authcookie on primary not defined"; + $response->{response_text} = "Entschuldigung, die Session wurde unterbrochen"; + } + + }else{ + + my ($auth,$authraw) = $apif->auth_verify($q); + if(ref($auth) eq "HASH" && $auth->{authcookie}){ + $response = { %$response, %$auth }; + my $record = $apif->user_bikes_occupied($q,$authraw); + $response->{bikes_occupied} = $apif->rentals($record,$authraw,"1"); + }else{ + $response->{response_state} = "Failure 1001: authcookie on operator not defined"; + $response->{response_text} = "Entschuldigung, die Session wurde unterbrochen"; + } + + } +} + +#bikes_available +elsif($q->param('request') eq "bikes_available"){ + #use Time::HiRes qw/gettimeofday/; + if($varenv{syshost} eq "shareeapp-primary"){ + my ($auth,$authraw) = $apif->auth_verify($q); + $response = { %$response, %$auth }; + ($response->{bikes},$response->{uri_operator_array},$response->{user_group},$response->{user_tour}) = $jsc->loop_sharees($q,$auth,$owner); + #my $stamp = gettimeofday; + #$bw->log("X bikes_available $varenv{syshost} $stamp: $response->{user_group}",$response,""); + }else{ + my ($auth,$authraw) = $apif->auth_verify($q);#on operator loop select, operator adr must be select to get user_group + $response = { %$response, %$auth }; + $bw->log("Y bikes_available by c_id $authraw->{c_id}, Tarif:",$authraw->{txt30},""); + $response->{bikes} = $apif->bikes_available($q,$authraw); + } + if(ref($response->{bikes}) ne "HASH"){ + $response->{response_state} = "Failure 5003: cannot find any user defined bike tariff"; + $response->{response_text} = "Abbruch, es konnte kein gültiger Tarif gefunden werden"; + } +} + +#bikes_all with service_state calculater +#cronjob for maintanance update runs at ~ 7:00 +elsif($q->param('request') eq "bikes_all"){ + if($varenv{syshost} eq "shareeapp-primary"){ + my ($auth,$authraw) = $apif->auth_verify($q); + $response = { %$response, %$auth }; + ($response->{bikes},$response->{uri_operator_array},$response->{user_group},$response->{user_tour}) = $jsc->loop_sharees($q,$auth,$owner); + }else{ + my ($auth,$authraw) = $apif->auth_verify($q); + $response = { %$response, %$auth }; + $response->{response_text} = "Vorsicht, das ist die Liste aller Leihräder unabhängig von der Verfügbarkeit"; + + #on servicetool only stations on user_tour + my $stations_allraw = {}; + (my $stations_not_used,$stations_allraw) = $apif->stations_all($q,"",$authraw) if($q->param('authcookie') =~ /_cleeJet3$|_34567890$/); + + my ($bikes_all,$bikes_allraw,$bikes_on_station) = $apif->bikes_all($q,$authraw,$stations_allraw); + + my $bike = "all"; + my $interval = $q->param('interval') || "31"; + my $service_state_debug = "\n"; + my $pos_record = {}; + my $response_work = {}; + + if($q->param('authcookie') =~ /cleeJet3|34567890$/){ + (my $xresponse, $pos_record, my $node_template, my $crecord) = $apif->service_select($q,$authraw,"",$interval); + + ($response_work, my $node) = $apif->service_work($pos_record,$bikes_allraw,"",$node_template); + #Pseudocode -- Calculate service_state: + #if (state == "defekt") -> service_state=1-rot + #else if (1 harte Wartung fällig und ( mind. 1 weiche Wartung fällig -oder- Aufgabe Text eingetragen )) -> service_state=2-Blau + #else if ( mind. 1 harte Wartung fällig ) -> service_state=3-grün + #else service_state=4-grau + } + + my $i=0; + foreach my $bid (sort { $bikes_allraw->{$a}->{mtime} cmp $bikes_allraw->{$b}->{mtime} } keys (%$bikes_allraw)){ + my $biselect = $bikes_allraw->{$bid}->{barcode}; + $i++; + #service_state Calculator + $bikes_all->{$oprefix . $bid}->{todo_info} = "0"; + $bikes_all->{$oprefix . $bid}->{service_state} = "0"; + $bikes_allraw->{$bid}->{service_state_blue} = 0; + $bikes_allraw->{$bid}->{service_state_green} = 0; + $bikes_allraw->{$bid}->{service_state_exist} = 0; + + #print "bid:$bid|$bikes_allraw->{$bid}->{mtime}\n"; + + #disabled, needs also to much cpu-time + #if(ref($response_work->{$biselect}) ne "HASH" || $response_work->{$biselect}->{int01}->{c_id} !~ /\d/ && $q->param('authcookie') =~ /cleeJet3|34567890$/){ + # my $pos_record_bi = $apif->service_work_select($biselect,"",""); + # (my $response_work_bi, my $node) = $apif->service_work($pos_record_bi,$bikes_allraw); + # $response_work->{$biselect} = $response_work_bi->{$biselect}; + #print "Rad:$biselect " . Dumper($response_work->{$biselect}); + #} + + #2019-02-14, fixed + if(ref($response_work->{$biselect}) eq "HASH" && $q->param('authcookie') =~ /cleeJet3|34567890$/){ + #print "$biselect: $response_work->{$biselect}->{mtime}\n"; + $bikes_allraw->{$bid}->{service_state_exist} = 1; + + foreach my $id (keys(%{$response_work->{$biselect}})){ + + $bw->log("response_work:$biselect","|$id|$response_work->{$biselect}->{$id}->{mtime}|$response_work->{$biselect}->{$id}->{service_type}|$response_work->{$biselect}->{$id}->{time_over}|$response_work->{$biselect}->{$id}->{work_val}",""); + + #time_over && (service_type || Aufgaben) + if(($response_work->{$biselect}->{$id}->{time_over} == 1 && $response_work->{$biselect}->{$id}->{service_type} >= 1) || ($id eq "txt01" && $response_work->{$biselect}->{$id}->{work_val})){ + #print $id . ":" . $response_work->{$biselect}->{$id}->{work_val} . "\n"; + if($id eq "txt01" && $response_work->{$biselect}->{$id}->{work_val} && $response_work->{$biselect}->{$id}->{work_val} ne "NaN" && $response_work->{$biselect}->{$id}->{work_val} !~ /::erledigt::/){ + $bikes_all->{$oprefix . $bid}->{todo_info} = "1"; + } + + if(($response_work->{$biselect}->{$id}->{time_over} == 1 && $response_work->{$biselect}->{$id}->{service_type} == 1) || ($id eq "txt01" && $response_work->{$biselect}->{$id}->{work_val} && $response_work->{$biselect}->{$id}->{work_val} ne "NaN" && $response_work->{$biselect}->{$id}->{work_val} !~ /::erledigt::/)){ + $bikes_allraw->{$bid}->{service_state_blue}++; + } + if($response_work->{$biselect}->{$id}->{time_over} == 1 && $response_work->{$biselect}->{$id}->{service_type} == 2){ + $bikes_allraw->{$bid}->{service_state_green}++; + } + + } + }#end response_work service_state calc + + if($bikes_allraw->{$bid}->{service_state_exist} == 1 && $bikes_all->{$oprefix . $bid}->{state} eq "defect"){ + $bikes_all->{$oprefix . $bid}->{service_state} = "1"; + + $service_state_debug .= "$bid: service_state 1\n"; + #$bw->log("defect service_state bike: $bid:",$bikes_all->{$oprefix . $bid}->{service_state},""); + } + elsif($bikes_allraw->{$bid}->{service_state_blue} >= 1 && $bikes_allraw->{$bid}->{service_state_green} >= 1){ + #print "$bikes_allraw->{$bid}->{service_state_blue}|$bikes_allraw->{$bid}->{service_state_green}" if($bid eq "5"); + #$bikes_all->{$oprefix . $bid}->{service_state} = "$bikes_allraw->{$bid}->{service_state_blue}"; + $bikes_all->{$oprefix . $bid}->{service_state} = "2"; + $bikes_all->{$oprefix . $bid}->{state} = "maintanance"; + #if($bikes_allraw->{$bid}->{txt10} && $bikes_allraw->{$bid}->{txt10} !~ /defect|maintanance|requested|occupied/) + if($bikes_allraw->{$bid}->{int10} && ($bikes_allraw->{$bid}->{int10} == 1 || $bikes_allraw->{$bid}->{int10} == 6)){ + $service_state_debug .= "$bid: service_state 2\n"; + #$bw->log("maintanance service_state bike: $bid:",$bikes_all->{$oprefix . $bid}->{service_state},""); + #4 = "maintanance" + $apif->bikestate_update($authraw,$bikes_allraw->{$bid}->{c_id},"4"); + } + } + elsif($bikes_allraw->{$bid}->{service_state_green} >= 1){ + #$bikes_all->{$oprefix . $bid}->{service_state} = "$bikes_allraw->{$bid}->{service_state_green}"; + $bikes_all->{$oprefix . $bid}->{service_state} = "3"; + $bikes_all->{$oprefix . $bid}->{state} = "maintanance"; + #if($bikes_allraw->{$bid}->{txt10} && $bikes_allraw->{$bid}->{txt10} !~ /defect|maintanance|requested|occupied/){ + if($bikes_allraw->{$bid}->{int10} && ($bikes_allraw->{$bid}->{int10} == 1 || $bikes_allraw->{$bid}->{int10} == 6)){ + + $service_state_debug .= "$bid: service_state 3\n"; + #$bw->log("maintanance service_state bike: $bid:",$bikes_all->{$oprefix . $bid}->{service_state},""); + #4 = "maintanance" + $apif->bikestate_update($authraw,$bikes_allraw->{$bid}->{c_id},"4"); + } + }elsif($bikes_allraw->{$bid}->{service_state_exist} == 1){ + #if($bikes_allraw->{$bid}->{txt10} && $bikes_allraw->{$bid}->{txt10} =~ /maintanance/) + if($bikes_allraw->{$bid}->{int10} && $bikes_allraw->{$bid}->{int10} == 4){ + $service_state_debug .= "$bid: 0\n"; + #$bw->log("maintanance TO available service_state bike: $bid:",$bikes_all->{$oprefix . $bid}->{service_state},""); + #1 = "available" + $apif->bikestate_update($authraw,$bikes_allraw->{$bid}->{c_id},"1"); + } + } + #workaround to get todo_info on defect + #else NOT if(ref($response_work->{$biselect}) eq "HASH" && $response_work->{$biselect}->{int01}->{c_id}) ---> because 31 day select + } + if($bikes_all->{$oprefix . $bid}->{state} eq "defect"){ + $bikes_all->{$oprefix . $bid}->{service_state} = "1"; + my $search = { key => "txt01", + val => "%", + }; + my $pos_record_bi = $apif->service_work_search($biselect,"","",$search); + if($pos_record_bi->{txt01} && $pos_record_bi->{txt01} ne "NaN" && $pos_record_bi->{txt01} !~ /::erledigt::/){ + #$bikes_all->{$oprefix . $bid}->{todo_info} = "$pos_record_bi->{txt01}"; + $bikes_all->{$oprefix . $bid}->{todo_info} = "1"; + } + $service_state_debug .= "$bid: service_state 1\n"; + } + } + + #print "all:$i\n"; + + #if($q->param('authcookie') =~ /_cleeJet3$|_34567890$/){ + # $bw->log("on bikes_all: kmlGenerator","",""); + #require "Mod/KMLout.pm"; + #my $kmlfile = Mod::KMLout::kmlGenerator("",""); + #} + + $bw->log("service_state_debug",$service_state_debug,""); + $response->{bikes} = $bikes_all; + } +} + +#stations_all +elsif($q->param('request') eq "stations_all"){ + if($varenv{syshost} eq "shareeapp-primary"){ + my ($auth,$authraw) = $apif->auth_verify($q); + $response = { %$response, %$auth }; + ($response->{stations},$response->{uri_operator_array},$response->{user_group},$response->{user_tour}) = $jsc->loop_sharees($q,$auth,$owner); + }else{ + my ($auth,$authraw) = $apif->auth_verify($q); + $response = { %$response, %$auth }; + my ($bikes_all,$bikes_allraw,$bikes_on_station) = $apif->bikes_all($q,$authraw,""); + ($response->{stations},my $stations_allraw) = $apif->stations_all($q,$bikes_on_station,$authraw); + } +} + +#stations_available +elsif($q->param('request') eq "stations_available"){ + if($varenv{syshost} eq "shareeapp-primary"){ + my ($auth,$authraw) = $apif->auth_verify($q); + #Mein konrad App + #if($dbt->{merchant_ids}->{$varenv{merchant_id}}->{id} eq "176"){ + if($owner && $owner eq "176"){ + $response->{merchant_message} = "Herzlich Willkommen bei der neuen konrad App! Die App ist zwar schon installierbar, bis zur vollständigen Umstellung des Systems sind aber noch keine Räder ausleihbar. Das ist erst voraussichtlich Ende Januar der Fall und wird den Nutzern noch mitgeteilt. Danke für Ihr Verständnis! Ihr konrad-Team"; + } + $response = { %$response, %$auth }; + ($response->{stations},$response->{uri_operator_array},$response->{user_group},$response->{user_tour}) = $jsc->loop_sharees($q,$auth,$owner); + }else{ + my ($auth,$authraw) = $apif->auth_verify($q); + $response = { %$response, %$auth }; + ($response->{stations}, my $response_raw) = $apif->stations_available($q,$authraw); + } +} + +#user_feedback / user_minianswer of user_miniquery +elsif($q->param('request') eq "user_feedback" || $q->param('request') eq "user_minianswer"){ + my ($auth,$authraw) = $apif->auth_verify($q); + $response = { %$response, %$auth }; + $response->{uri_operator} = "$varenv{wwwhost}"; + + if(ref($auth) eq "HASH" && $auth->{authcookie}){ + my $customer = $auth->{c_id}; + #print Dumper($auth); + (my $xresponse->{$customer}, my $responseraw, my $node_template, my $crecord) = $apif->service_select($q,$authraw,"","1"); + $bw->log("c_id: $crecord->{c_id} |user_feedback OR user_minianswer node_template",$node_template,""); + + my $back_id = ""; + my $rows=0; + #if(!$back_id){#disabled because of every feedback have to be saved + if(1==1){ + #INSERT just dadaset + $back_id = $apif->service_insert($q,$authraw,$node_template,$crecord,$owner); + $rows = $apif->service_update($q,$authraw,$node_template,$back_id); + if($rows && $rows > 0){ + $response->{response_state} = "OK, feedback insert and update"; + $response->{response_text} = "Danke für die Nachricht."; + }else{ + $response->{response_state} = "Failure 3606, feedback_update"; + $response->{response_text} = "Die Nachricht konnte leider nicht gespeichert werden."; + } + } + #($xresponse->{$customer}, $responseraw, $node_template, $crecord) = $apif->service_select($q,$authraw,$back_id,"") if($back_id); + #my $response_work = {}; + #$response_work->{feedback} = $apif->feedback_response($responseraw,$node_template); + #$response = { %$response, %$response_work }; + } + +} + +#service_done +#insert and/or update +elsif($q->param('request') eq "service_done"){ + my ($auth,$authraw) = $apif->auth_verify($q); + my $station_id = $1 if($q->param('station') =~ /(\d+)/); + my $bike_id = $1 if($q->param('bike') =~ /(\d+)/); + $response->{uri_operator} = "$varenv{wwwhost}"; + + if(ref($auth) eq "HASH" && $auth->{authcookie}){ + if(looks_like_number($bike_id) || looks_like_number($station_id)){ + my $article = looks_like_number($bike_id) || looks_like_number($station_id); + + #select services with max work_duration of 1 day and service_worker alias contentadr.c_id = contenttranspo.owner match + (my $xresponse->{$article}, my $responseraw, my $node_template, my $crecord) = $apif->service_select($q,$authraw,"","1"); + $bw->log("service_done OOO: node",$node_template,""); + + if(ref($xresponse->{$article}) eq "HASH"){ + $bw->log("service_done xresponse",$xresponse->{$article},""); + + my $service_id = ""; + #select last service_id with work_duration < 1 day + foreach my $id (sort { $xresponse->{$article}->{$a}->{mtime} cmp $xresponse->{$article}->{$b}->{mtime} } keys (%{$xresponse->{$article}})){ + $service_id = $id if($id > 1); + } + + my $rows=0; + $service_id = $1 if($q->param('service_id') =~ /(\d+)/); + if(!$service_id){ + + #INSERT just dadaset (without work values) + ($response->{service_id}) = $apif->service_insert($q,$authraw,$node_template,$crecord); + $bw->log("service insert ",$response,""); + + #once again to get node_record template + ($xresponse->{$article}, $responseraw, $node_template, $crecord) = $apif->service_select($q,$authraw,"","1"); + + #UPDATE + $service_id = $response->{service_id}; + $rows = $apif->service_update($q,$authraw,$node_template,$response->{service_id}); + $response->{response_state} = "OK" if($rows > 0); + $response->{response_text} = "OK, service_insert and update" if($rows > 0); + }else{ + #UPDATE + $rows = $apif->service_update($q,$authraw,$node_template,$service_id); + $response->{response_state} = "OK" if($rows > 0); + $response->{response_text} = "OK, service_update" if($rows > 0); + } + + #UPDATE bike content state + if($q->param('work_id') eq "state" && looks_like_number($bike_id) && $q->param('work_val') =~ /available|maintanance|defect/){ + #once again to get node_record template + ($xresponse->{$article}, $responseraw, $node_template, $crecord) = $apif->service_select($q,$authraw,"","1"); + while (my ($key, $value) = each %{ $dbt->{copri_conf}->{bike_state} }) { + if($q->param('work_val') eq $value){ + $rows = $apif->bikestate_update($authraw,$responseraw->{$service_id}->{cc_id},$key); + $response->{response_state} = "OK"; + $response->{response_text} = "OK, bikestate_update to state=$value"; + } + } + + } + if(($q->param('work_id') eq "int04" || $q->param('work_id') eq "station") && looks_like_number($bike_id) && ($q->param('work_val') || looks_like_number($q->param('work_val')))){ + $q->param(-name=>'work_id',-value=>"int04") if($q->param('work_id') eq "station");#station db-field is int04 + my $to_station_id = $1 if($q->param('work_val') =~ /(\d+)/); + my ($bikes_all,$bikes_allraw,$bikes_on_station) = $apif->bikes_all($q,$authraw,""); + + #add-on to log redistribute#TODO dedicated db-fieled + my $action = "txt10=" . $oprefix . $bikes_allraw->{$bike_id}->{int04} . " - " . $q->param('work_val'); + + $apif->service_update($q,$authraw,$node_template,$service_id,$action); + + my ($stations_all,$stations_allraw) = $apif->stations_all($q,$bikes_on_station,$authraw); + if(looks_like_number($stations_allraw->{$to_station_id}->{int04})){ + ($xresponse->{$article}, $responseraw, $node_template, $crecord) = $apif->service_select($q,$authraw,"","1"); + my $update_hash = { int04 => "$to_station_id" }; + $rows = $apif->bikestate_update($authraw,$responseraw->{$service_id}->{cc_id},"",$update_hash); + $response->{response_state} = "OK" if($rows > 0); + $response->{response_text} = "OK, bikestate_update to_station_id $to_station_id" if($rows > 0); + }elsif($to_station_id == 0){#werkstatt + ($xresponse->{$article}, $responseraw, $node_template, $crecord) = $apif->service_select($q,$authraw,"","1"); + my $update_hash = { int04 => "$to_station_id" }; + #5 = "defect" + $rows = $apif->bikestate_update($authraw,$responseraw->{$service_id}->{cc_id},"5",$update_hash); + $response->{response_state} = "OK" if($rows > 0); + $response->{response_text} = "OK, bikestate_update to Werkstatt $to_station_id" if($rows > 0); + }else{ + $bw->log("service_update fails to_station_id: $to_station_id",$stations_allraw->{$to_station_id}->{int04},""); + $response->{response_state} = "Failure 3003: service_update fails"; + } + } + + if($rows != 1){ + $response->{response_state} = "Failure 3004: service_update fails"; + } + $response->{service_id_done} = $service_id; + }else{ + $response->{response_state} = "Failure 3009: service_update fails because of can not find bike or station"; + $response->{response_text} = "Fehler, angefragte Artikel konnte nicht gefunden werden!"; + } + + my $response_work = {}; + my $node = {}; + my ($bikes_all,$bikes_allraw,$bikes_on_station) = $apif->bikes_all($q,$authraw,""); + if(looks_like_number($bike_id)){ + (my $xresponse, my $pos_record, my $node_template, my $crecord) = $apif->service_select($q,$authraw,"","100");#check interval + + ($response_work, $node) = $apif->service_work($pos_record,$bikes_allraw,"",$node_template); + } + elsif(looks_like_number($station_id)){ + my ($stations_all,$stations_allraw) = $apif->stations_all($q,$bikes_on_station,$authraw); + (my $xresponse, my $pos_record, my $node_template, my $crecord) = $apif->service_select($q,$authraw,"","100");#check interval + + ($response_work, $node) = $apif->service_work($pos_record,$stations_allraw,"",$node_template); + } + + #inject oprefix + my $op_response_work = {}; + foreach my $key (keys %$response_work){ + $op_response_work->{$oprefix . $key} = $response_work->{$key}; + } + $response = { %$response, %$op_response_work, %$auth }; + my $node_template_id = 0; + $node_template_id = $node_template->{template_id} if(ref($node_template) eq "HASH" && $node_template->{template_id}); + $response->{service_template} = "$node_template_id"; + }else{ + $response->{response_state} = "Failure 3002: no bike OR station ID defined"; + } + }else{ + $response->{response_state} = "Failure 1001: authcookie not defined"; + } +}#end service_done + +#service_work +#service_work. select last service by bike-id +elsif($q->param('request') eq "service_work"){ + my ($auth,$authraw) = $apif->auth_verify($q); + my $station_id = ""; + my $bike_id = ""; + $station_id = $1 if($q->param('station') =~ /(\d+)/); + $bike_id = $1 if($q->param('bike') =~ /(\d+)/); + $response->{uri_operator} = "$varenv{wwwhost}"; + my $node = {}; + my $history = 0; + $history = $q->param('history') if(looks_like_number($q->param('history'))); + if(ref($auth) eq "HASH" && $auth->{authcookie}){ + if(looks_like_number($bike_id)){ + my ($bikes_all,$bikes_allraw,$bikes_on_station) = $apif->bikes_all($q,$authraw,""); + (my $xresponse, my $pos_record, my $node_template, my $crecord) = $apif->service_select($q,$authraw,"",$history); + + #$bw->log("service_work bike_id $bike_id pos_record",$pos_record,""); + (my $response_work, $node) = $apif->service_work($pos_record,$bikes_allraw,$history,$node_template); + $bw->log("service_work bike_id $bike_id response_work",$response_work,""); + if(ref($response_work) ne "HASH"){#if fails + $response->{response_state} = "Failure 4010: no service found"; + } + my $op_response_work = {}; + foreach my $key (keys %$response_work){ + $op_response_work->{$oprefix . $key} = $response_work->{$key}; + } + $response = { %$response, %$op_response_work, %$auth }; + }elsif($q->param('bike') && $q->param('bike') eq "all"){ + my ($bikes_all,$bikes_allraw,$bikes_on_station) = $apif->bikes_all($q,$authraw,""); + my $bike = $q->param('bike'); + (my $xresponse, my $pos_record, my $node_template, my $crecord) = $apif->service_select($q,$authraw,"",$history); + (my $response_work, $node) = $apif->service_work($pos_record,$bikes_allraw,$history,$node_template); + if(ref($response_work) ne "HASH"){#if fails + $response->{response_state} = "Failure 4011: no service found"; + } + my $op_response_work = {}; + foreach my $key (keys %$response_work){ + $op_response_work->{$oprefix . $key} = $response_work->{$key}; + } + $response = { %$response, %$op_response_work, %$auth }; + }elsif(looks_like_number($station_id)){ + my ($bikes_all,$bikes_allraw,$bikes_on_station) = $apif->bikes_all($q,$authraw,""); + my ($stations_all,$stations_allraw) = $apif->stations_all($q,$bikes_on_station,$authraw); + (my $xresponse, my $pos_record, my $node_template, my $crecord) = $apif->service_select($q,$authraw,"",$history); + (my $response_work, $node) = $apif->service_work($pos_record,$stations_allraw,$history,$node_template); + if(ref($response_work) ne "HASH"){#if fails + $response->{response_state} = "Failure 4013: no service found"; + } + my $op_response_work = {}; + foreach my $key (keys %$response_work){ + $op_response_work->{$oprefix . $key} = $response_work->{$key}; + } + $response = { %$response, %$op_response_work, %$auth }; + }elsif($q->param('station') && $q->param('station') eq "all"){ + my ($bikes_all,$bikes_allraw,$bikes_on_station) = $apif->bikes_all($q,$authraw,""); + my ($stations_all,$stations_allraw) = $apif->stations_all($q,$bikes_on_station,$authraw); + my $station = $q->param('station'); + (my $xresponse, my $pos_record, my $node_template, my $crecord) = $apif->service_select($q,$authraw,"",$history); + (my $response_work, $node) = $apif->service_work($pos_record,$stations_allraw,$history,$node_template); + if(ref($response_work) ne "HASH"){#if fails + $response->{response_state} = "Failure 4014: no service found"; + } + my $op_response_work = {}; + foreach my $key (keys %$response_work){ + $op_response_work->{$oprefix . $key} = $response_work->{$key}; + } + $response = { %$response, %$response_work, %$auth }; + }else{ + $response->{response_state} = "Failure 3002: no bike OR station ID defined"; + } + }else{ + $response->{response_state} = "Failure 1001: authcookie not defined"; + } + $response->{service_template} = "$node->{template_id}"; +}#end service_work + + +#last if request not defined +else{ + $response->{'response_state'} = "Failure: request not defined"; +} + +#end RESTful ------------------------------------------------------------ + +#FINAL JSON response OUTPUT ---------------------------------------------------------- +my $jrout = $json->pretty->encode({shareejson => $response}); +print $jrout; + +$bw->log("APIjsonserver response by $user_agent mapped owner:$owner",$jrout,""); +#end JSON ---------------------------------------------------------------------------- + + return Apache2::Const::OK; +}#end handler +1; + + diff --git a/copri4/main/src/Mod/APIvelo.pm b/copri4/main/src/Mod/APIvelo.pm new file mode 100644 index 0000000..b03787d --- /dev/null +++ b/copri4/main/src/Mod/APIvelo.pm @@ -0,0 +1,161 @@ +package Mod::APIvelo; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +#Server for velofaktur +# +#curl -d '{"Typ":"Statusmeldung","Station":8,"Slot":1,"Fahrzeug":{"Buchbar":false,"Id":"200008","LadezustandBatterie":"75"}}' -H "Content-Type: application/json" -X POST https://shareeapp-fr01.copri4.de/APIvelo +# +#ATTENTION +##In DB context $q->escapeHTML must always done by API +# +#use lib qw(/var/www/copri4/shareeapp-fr01/src); +use warnings; +use strict; +use POSIX; +use Exporter; +our @ISA = qw (Exporter); + +#use POSIX; +use CGI; +use Apache2::Const -compile => qw(OK ); +use JSON; +use Scalar::Util qw(looks_like_number); +use Config::General; + +use Lib::Config; +use Mod::DBtank; +use Mod::Basework; +use Mod::APIfunc; +use Mod::APIjsonclient; +use Data::Dumper; + +sub handler { + my ($r) = @_; + my $q = new CGI; + my $json = JSON->new->allow_nonref; + my $cf = new Config; + my $dbt = new DBtank; + my $bw = new Basework; + + + my %varenv = $cf->envonline(); + my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; + my $lang="de"; + my $owner=182;#velofactur API + my $debug=1; + my $user_agent = $q->user_agent(); + my $dbh = ""; + + $bw->log("APIvelo POST:\n--> user-agent: '$user_agent' to syshost: $varenv{syshost}\n",$q,""); + +print $q->header(-type => "application/json", -charset => "utf-8", -'Access-Control-Allow-Origin' => "*"); + +open(FILE,">>$varenv{logdir}/APIvelo.log") if($debug); +print FILE "\n*** $now_dt user-agent: '$user_agent' to syshost: $varenv{syshost}\n" if($debug); +print FILE "<=== veloDUMP\n " . Dumper($q) . "\n" if($debug); +print FILE "<=== DUMP postdata:\n " . Dumper($q->param('POSTDATA')) . "\n" if($debug); + +my $jrout = "seems to be not valid"; +eval { + my $response_in = decode_json( $q->param('POSTDATA')); + + + #- int19=bike charge + #- int27=velofactur bike ID + #- int28=station_lock_state (station lock velofactur) + #- int29=velofactur Buchbar (true|false) + #- int30=velofactur station ID + #- int31=velofactur slot ID + #- txt25=velofactur last station message (error or success) + + my $jrout = $json->pretty->encode({ fakturjson => $response_in }); + print FILE "<=== JSON POST from velofactur:\n$jrout\n" if($debug); + + my $record_cc = { c_id => 0 }; + + if($response_in->{Typ} eq "Statusmeldung" && $response_in->{Fahrzeug}->{Id} =~ /(\d+)/){ + my $velo_id = $1; + print FILE "condition: : $response_in->{Typ} && $response_in->{Fahrzeug}->{Id}\n" if($debug); + my $pref_cc = { + table => "content", + fetch => "one", + template_id => "205", + int27 => $velo_id, + }; + + #loop operators to get velofactur bike Id + while (my ($mandant_conf, $value) = each %{ $dbt->{operator} }) { + if($value->{database}->{dbname} && $value->{hwtype} eq "velofactur"){ + my $rows = 0; + + my $sharee_operator = $value->{database}->{dbname}; + my $dbh_operator = $dbt->dbconnect_extern($sharee_operator); + $record_cc = $dbt->fetch_record($dbh_operator,$pref_cc); + + if($record_cc->{c_id}){ + my $update_cc = { + table => "content", + mtime => "now()", + owner => "$owner", + }; + + #$update_cc->{int28} = 0;#where is the key=value for station_lock_state? Buchbar? + $update_cc->{int19} = $response_in->{Fahrzeug}->{LadezustandBatterie} if(looks_like_number($response_in->{Fahrzeug}->{LadezustandBatterie})); + $update_cc->{int27} = $1 if($response_in->{Fahrzeug}->{Id} && $response_in->{Fahrzeug}->{Id} =~ /(\d+)/); + $update_cc->{int30} = $1 if($response_in->{Station} && $response_in->{Station} =~ /(\d+)/); + $update_cc->{int31} = $1 if($response_in->{Slot} && $response_in->{Slot} =~ /(\d+)/); + $update_cc->{txt25} = $response_in->{Status} if($response_in->{Status}); + + #velofactur false|true boeelan + #set bike_state to maintanance + #only if saved! velofactur Buchbar_state = true and bike_state = available + $update_cc->{int10} = 4 if($update_cc->{int29} == 1 && $update_cc->{int10} == 1); + $update_cc->{int29} = 0; + + if($response_in->{Fahrzeug}->{Buchbar}){ + #set bike_state to available + #only if saved! velofactur Buchbar_state = false and bike_state = maintanance + $update_cc->{int10} = 1 if($update_cc->{int29} == 0 && $update_cc->{int10} == 4); + $update_cc->{int29} = 1; + } + + $rows = $dbt->update_record($dbh_operator,$update_cc,$record_cc); + $bw->log("velofactur updates dbname: $sharee_operator, c_id=$record_cc->{c_id} by fakturjson $response_in->{Typ} | rows:$rows",$update_cc,""); + print FILE "---> velofactur updates dbname: $sharee_operator, c_id=$record_cc->{c_id} by fakturjson $response_in->{Typ} | rows:$rows\n" . Dumper($update_cc) . "\n" if($debug); + } + } + } + + ############ + #stdout printed JSON to velofactur endpoint + my %jsonout; + $jsonout{Typ} = "sharee Befehlsmeldung"; + $jsonout{Status} = "DONE"; + + foreach my $resp (keys (%{ $response_in })) { + #print $resp . ":" . $response_in->{$resp} . "\n"; + $jsonout{$resp} = $response_in->{$resp} if($resp eq "Id"); + } + my $rest_json = $json->pretty->encode(\%jsonout); + print $rest_json; + ############ + + }else{ + print FILE "condition anywhere an for selftests\n" if($debug); + print $jrout; + } + + + +}; +if ($@){ + print FILE "failure! can not decode POST json, POSTDATA:\n" . Dumper($q->param('POSTDATA')) . "\n" if($debug); + warn $@; +} + +close(FILE) if($debug); +return Apache2::Const::OK; +} +1; diff --git a/copri4/main/src/Mod/APIxmlserver.pm b/copri4/main/src/Mod/APIxmlserver.pm new file mode 100644 index 0000000..01aa1fc --- /dev/null +++ b/copri4/main/src/Mod/APIxmlserver.pm @@ -0,0 +1,207 @@ +package Mod::APIxmlserver; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +#Server for sharee xml api +# +##In DB context $q->escapeHTML must always done by API +# +#use lib qw(/var/www/copri4/shareeapp-primary/src); +use warnings; +use strict; +use Exporter; +our @ISA = qw (Exporter); + +use POSIX; +use CGI; +use Apache2::Const -compile => qw(OK ); +use Scalar::Util qw(looks_like_number); +use LWP::UserAgent; +use XML::Simple qw(:strict); + +use Lib::Config; +use Mod::DBtank; +use Mod::Basework; +use Mod::Shareework; +use Mod::APIfunc; +use Digest::MD5 qw(md5 md5_hex); +use Data::Dumper; +use Sys::Hostname; +my $hostname = hostname; + +sub handler { + my ($r) = @_; + my $q = new CGI; + my $netloc = $q->url(-base=>1); + #$q->import_names('R'); + my $cf = new Config; + my $dbt = new DBtank; + my $bw = new Basework; + my $tk = new Shareework; + my $apif = new APIfunc; + + my %varenv = $cf->envonline(); + my $oprefix = $dbt->{operator}->{$varenv{dbname}}->{oprefix}; + my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; + my $lang="de"; + my $owner=199;#LastenVelo api (LV api) + my @keywords = $q->param; + my $debug=1; + my $user_agent = $q->user_agent(); + my $dbh = ""; + + if(1==1){ + foreach(@keywords){ + if(length($_) > 20 || length($q->param($_)) > 400){ + print "Failure 19900: amount of characters in $_ exceeds"; + return Apache2::Const::OK; + exit 0; + } + } + } + + + $bw->log("APIxmlserver request:\n--> user-agent '$user_agent'",$q,""); + + print $q->header(-type => "application/xml", -charset => "utf-8", -'Access-Control-Allow-Origin' => "*"); + #print "Content-type: text/xml\n\n"; + if($q->param('POSTDATA')){ + my $xmlref = {}; + $xmlref = XMLin($q->param('POSTDATA'), ForceArray => ['sharee_LastenVelo'], KeyAttr => [ ] ); + + $xmlref->{userID} =~ s/\s//g; + if(ref($xmlref) eq "HASH" && $xmlref->{todo} && looks_like_number($xmlref->{userID}) && $xmlref->{userID} =~ /^\d+$/){ + + # + # + # add_LVuser + # 12345678 + # ragu@gnu-systems.de + # geheim123 + # + + #für update: + #update_LVuser + #12345678delete_LVuser + #12345678 "contentadr", + fetch => "one", + template_id => "202", + int01 => "$xmlref->{userID}", + }; + + my $record = $dbt->fetch_record($dbh,$pref); + + my $c_id = ""; + $bw->log("$xmlref->{todo}",$xmlref,""); + if($xmlref->{userID} && $xmlref->{emailID} && $xmlref->{pwID}){ + if($xmlref->{todo} =~ /add_LVuser|update_LVuser/ && !$record->{c_id}){ + my $teltime = time; + my $pwmd5 = md5_hex($q->escapeHTML($xmlref->{pwID})); + #$c_id = $tk->create_account($owner); + my $insert = { + table => "contentadr", + main_id => "200011", + template_id => "202", + mtime => 'now()', + atime => 'now()', + owner => "$owner", + int01 => $q->escapeHTML($xmlref->{userID}), + txt08 => $q->escapeHTML($xmlref->{emailID}), + txt11 => "$pwmd5", + txt17 => "sharee_lv", + int03 => "1", + txt22 => "DE11111111111111111111", + txt23 => "FRSPDE11111", + int04 => "1", + int13 => "1", + txt30 => "5511", + int05 => "1", + int14 => "1", + int16 => "null", + txt01 => "no name", + txt03 => "fake str. 1", + txt06 => "79999 freiburg", + txt07 => "$teltime", + ct_name => "LV-12345678", + }; + $c_id = $dbt->insert_contentoid($dbh,$insert); + }elsif($xmlref->{todo} eq "update_LVuser" && $record->{c_id}){ + + my $pwmd5 = md5_hex($xmlref->{pwID}); + my $update = { + table => "contentadr", + mtime => 'now()', + owner => "$owner", + int01 => "$xmlref->{userID}", + txt08 => "$xmlref->{emailID}", + txt11 => "$pwmd5", + }; + my $rows = $dbt->update_record($dbh,$update,$record); + + }elsif($xmlref->{todo} eq "delete_LVuser"){ + $dbt->delete_content($dbh,"contentadr",$record->{c_id}); + } + + foreach my $item (keys(%$xmlref)){ + print "<$item>$xmlref->{$item}\n"; + } + } + + }elsif(ref($xmlref) eq "HASH" && $xmlref->{todo} && $xmlref->{todo} eq "available" && $xmlref->{bikeID} =~ /\d+/){ + + # + # + #available + #17 + # + + my $bike_id = $1 if($xmlref->{bikeID} =~ /(\d+)/); + my $pref_cc = { + table => "content", + fetch => "one", + template_id => "205", + barcode => $bike_id, + int10 => "!=::1",#if not available + }; + + my $record_cc = $dbt->fetch_record($dbh,$pref_cc); + + my $update_cc = { + table => "content", + int10 => "1", + mtime => "now()", + owner => "$owner", + }; + + $bw->log("APIxmlserver update to available",$update_cc,""); + $dbt->update_record($dbh,$update_cc,$record_cc) if($record_cc->{c_id}); + + }elsif(ref($xmlref) eq "HASH" && $xmlref->{todo} && $xmlref->{todo} eq "requested" && $xmlref->{bikeID} =~ /\d+/){ + + # + # + #requested + #17 + #123456 + #mail@here.de + # + + }#end if(ref($xmlref) + else{ + print "Hossa, kein valides xml"; + } + }#end if($q->param('POSTDATA')) + else{ + print "NO DATA"; + } + + return Apache2::Const::OK; +} +1; diff --git a/copri4/main/src/Mod/Basework.pm b/copri4/main/src/Mod/Basework.pm new file mode 100644 index 0000000..e3f2c80 --- /dev/null +++ b/copri4/main/src/Mod/Basework.pm @@ -0,0 +1,61 @@ +package Basework; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# + +use strict; +use warnings; +use POSIX; +use CGI; # only for debugging +use Lib::Config; + +use Data::Dumper; +use Sys::Hostname; +my $hostname = hostname; +my $cf = new Config; +my $q = new CGI; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +my $time = time; +my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; +my $now_date = strftime "%Y-%m-%d", localtime; + + +#logging +sub log { + my $self = shift; + my ($what,$message,$stdout) = @_; + #my ($package, $filename, $line) = caller; + my %varenv = $cf->envonline(); + + $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; + my $logfile = "/var/log/copri4/$varenv{syshost}-process.log"; + if($varenv{debug}){ + warn "$what" . "\n" . Dumper($message) . "\n";#to apache2/error.log + + #2021-07-21 disabled. error.log is enough + if(1==2){ + open(FILE,">> $logfile"); + print FILE "\n--- $now_dt $0 ---\n"; + print FILE "$what" . "\n" . Dumper($message) . "\n"; + close FILE; + } + #also to stdout + if($stdout){ + #print "\n--- $now_dt $0 ---\n"; + print "$what" . "\n" . Dumper($message) . "\n"; + } + + } + +} + + +1; diff --git a/copri4/main/src/Mod/Buttons.pm b/copri4/main/src/Mod/Buttons.pm new file mode 100644 index 0000000..1df4d9a --- /dev/null +++ b/copri4/main/src/Mod/Buttons.pm @@ -0,0 +1,781 @@ +package Buttons; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +# +use strict; +use warnings; +use Lib::Config; +use Data::Dumper; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +my $cf = new Config; +my %varenv = $cf->envonline(); +my $icon = "/icon"; + +#my standard internationalize submit buttons +sub ibuttons(){ + my $self = shift; + my %ib = ( + 'service_done' => 'Wartungsprotokoll für ausgewähltes Rad einfügen/bearbeiten', + 'post_email' => 'submit', + 'barcode' => 'Barcode Label drucken', + 'buchen' => 'buchen', + 'send_invoice_again' => 'senden', + 'order_state' => 'Auftragsstatus', + 'new_contenttver' => 'Neues Arbeitsprofil', + 'new_content' => 'NEUER Datensatz', + 'new_content_2' => 'Add New Optical Instrument', + 'new_adr' => 'Kunde anlegen', + 'new_trans' => 'NEUE Transaktion', + 'new_tver' => 'NEU', + 'new_nel' => 'NEUE Nachricht', + 'new_transdate' => 'NEUER Kalendereintrag', + 'new_time' => 'NEUER Termin', + 'new_dmsusers' => 'NEUER DMS Account', + 'new_relation' => 'NEUES Menue anlegen', + 'new_relation4sub' => 'NEUES Sub-Menue anlegen', + 'save_content' => 'Speichern', + 'save_tver' => 'Kurs speichern', + 'save_nel' => 'Nachricht speichern', + 'context_copy_content' => 'Kopie im Kontext der internen Barcode Nummer', + 'copy_content' => 'Kopie fuer neuen Datensatz', + 'move_relation' => 'Menue verschieben', + 'move_content' => 'Datensatz in anderen Ordner verschieben', + 'save_adr' => 'Kunden speichern', + 'save_text' => 'Text speichern', + 'save_dmsusers' => 'DMS Account speichern', + 'save_relation' => 'Menue speichern', + 'remove_chk4rel' => 'löschen', + 'delete_content' => 'löschen', + 'delete_adr' => 'Kunden löschen', + 'delete_nel' => 'Nachricht löschen', + 'newsletter_mailman' => 'Nachricht senden', + 'delete_dmsusers' => 'DMS Account löschen', + 'delete_trans' => 'löschen', + 'delete_relation' => 'Menue löschen', + 'save_pos' => 'Datensatz speichern', + 'delete_pos' => 'Datensatz löschen', + 'save_name' => 'Kunden speichern', + 'search' => 'suchen', + 'search_product' => 'Search', + 'search_calendar' => 'anzeigen', + 'search_export' => 'suchen / +auswerten', + 'search_adr' => 'Kunden suchen', + 'search_extrakt' => 'extrakt', + 'change_login' => 'ID', + 'print_pdf' => 'Print PDF', + 'set_relation' => 'Formular', + 'set_workflow' => 'Workflow', + 'relate_content' => 'Content-Menu Relation', + 'relate_dialog' => 'Relation herstellen', + 'relate_dialog4menu' => 'Relation herstellen', + 'save_media' => 'Foto speichern', + 'delete_media' => 'Foto löschen', + 'save_database' => 'Datenbank Sicherung', + 'XLSout_contentadr' => 'XLS Export', + 'more' => 'more', + 'Login' => 'Login', + 'login' => 'login' + ); + return %ib; +} + +my %ib = ibuttons(); + +#buttons for jvbasel +sub ibuttons_arch(){ + my $self = shift; + my ($counter) = @_; + my %ib = ( + 'reload_search' => 'Reload', + 'new_content_1' => 'NEU', + 'new_content_2' => 'Objekt hinzufuegen', + 'new_relation4sub' => 'Ordner hinzufuegen', + 'new_relation4sub_collection' => 'Sammlung hinzufuegen', + 'new_attrtpl_int' => 'Checkbox/Integer Datenfeld erzeugen', + 'new_attrtpl_txt' => 'Text Datenfeld erzeugen', + 'new_adr' => 'NEUE Adresse', + 'move_dnd' => 'Objekt verschieben', + 'relate_dnd' => 'Objekt verlinken', + 'copy_dnd' => 'Objekt kopieren', + 'remove_chk4rel' => 'Objekt löschen', + 'remove_chk4rel_en' => 'Delete Content', + 'save_content' => 'Objekt speichern', + 'relate_dialog4menu' => 'Relation herstellen', + 'save_content_en' => 'Save Content', + 'save_attrtpl' => 'Eigenschaft speichern', + 'remove_chk4attr' => 'Eigenschaft löschen', + 'delete_content' => 'löschen', + 'XLSout' => 'XLS Export', + 'PDFout' => 'PDF Export', + 'object' => 'Ansicht', + 'list_view' => 'Ansicht', + 'object_view' => 'Ansicht', + 'search' => 'suchen', + 'more' => 'more', + 'Login' => 'Login', + 'login' => 'login' + ); + return %ib; +} + + +# Language Icons +sub langicon_pic(){ + my $self = shift; + my ($script,$lang_name,$lang,$view) = @_; + if($script =~ /(\/src\/index\.pl)/){ + $script = $1 + }else{ + $script = "/src"; + } + my $icon = "$icon/$lang.gif"; + my $lang_href = "$script/$lang/$view"; + my $langicon = "$lang_name\n"; + return $langicon; +} + +sub langicon_txt(){ + my $self = shift; + my ($script,$lang_name,$main_id,$lang,$view) = @_; + if($script =~ /(\/src\/index\.pl)/){ + $script = $1 + }else{ + $script = "/src"; + } + my $lang_href = "$script/$lang/$view"; + my $langicon = "$lang_name\n"; + return $langicon; +} + +# Head Main Menue Button +sub head_button(){ + my $self = shift; + my ($node_path,$node_name,$style) = @_; + my $button = "\n"; + return $button; +} + +# Top Main Menue Button +sub top_button(){ + my $self = shift; + my ($node_path,$node_name,$main_id,$style) = @_; + my $txt_color; + $txt_color = "color: black;" if($style =~ /white/); + my $button = "
  • $node_name
  • \n"; + return $button; +} +# a link for Top2 +sub a_button(){ + my $self = shift; + my ($node_path,$node_name,$main_id,$mstyle) = @_; + my $txt_color; + #$txt_color = "color: black;" if($mstyle =~ /white/); + my $button = "$node_name|\n"; + #my $button = "$node_name|"; + return $button; +} + +#with mousevent +sub event_button(){ + my $self = shift; + my ($node_path,$node_name,$main_id,$class,$style,$owner,$url,$icon,$icon_style) = @_; + my $debug = $main_id if($owner && $owner eq $varenv{superu_id}); + my $image = "" if($icon) || ""; + my $button = "
  • $image $node_name
  • "; + return $button; +} + +sub event_button2(){ + my $self = shift; + my ($node_path,$node,$class,$style,$owner,$url,$icon,$icon_style) = @_; + $node->{change} =~ s/\.\d.*//; + my $title = "($node->{change})"; + $title .= " | main_id: $node->{main_id}" if($owner && $owner eq $varenv{superu_id}); + my $image = "" if($icon) || ""; + my $button = "
  • $image $node->{node_name}
  • "; + return $button; +} + +#just a without li +sub lo_button(){ + my $self = shift; + my ($node_path,$node_name,$main_id,$class,$style,$owner,$script,$mtop,$mleft,$icon,$icon_style) = @_; + my $debug = $main_id if($owner && $owner eq $varenv{superu_id}); + my $image = "" if($icon) || ""; + my $button; + if($script){ + $button = "$image $node_name"; + }else{ + $button = "$image $node_name"; + } + return $button; +} + +#with mousevent over/out +sub lo_button2(){ + my $self = shift; + my ($node_path,$node_name,$node_name_int,$main_id,$class,$style,$owner) = @_; + my $debug = $main_id if($owner && $owner eq $varenv{superu_id}); + my $button = "$node_name"; + return $button; +} +#mit li +sub lia_button(){ + my $self = shift; + my ($node_path,$node_name,$main_id,$class,$style,$owner) = @_; + my $debug = $main_id if($owner && $owner eq $varenv{superu_id}); + my $target = "_self"; + $target = "_blank" if($node_path =~ /http/); + my $button = "
  • $node_name
  • \n"; + return $button; +} + + + +# select tag +sub selector_color() { + my $self = shift; + my $colname = shift; + my $style = shift; + my $value = shift; + my @selval = @_; + + my @selopt = (); + foreach my $id (@selval) { + my $ostyle; + $ostyle = "background-color:$id" if($style =~ /background-color/); + if ($id eq $value) { + push @selopt, "\n"; + } + else { + push @selopt, "\n"; + } + } + my $selret; + if($style =~ /background-color/){ + $selret = "\n"; + } + return $selret; +} + + +# select tag +sub selector(){ + my $self = shift; + my $tbl_columne = shift; + my $width = shift || ""; + my $sel = shift || ""; + my @selval = @_; + + my @selopt = (); + foreach my $opt (@selval){ + my $id = $opt; + my $value = $opt; + ($id,$value) = split /:/,$opt if($opt =~ /\w+\:.*/); + if($sel eq $id){ + push @selopt, "\n"; + }else{ + push @selopt, "\n"; + } + } + my $selret = "\n"; + return $selret; +} + +# select tag with class +sub selector_class(){ + my $self = shift; + my ($column,$class,$style,$sel,@selval) = @_; + + my @selopt = (); + foreach my $opt (@selval){ + my $des_style = ""; + my $id = $opt; + my $value = $opt; + ($id,$value) = split /:/,$opt if($opt =~ /\:/); + $des_style = "color:grey;" if(!$id); + if("$sel" eq "$id"){ + push @selopt, "\n"; + }else{ + push @selopt, "\n"; + } + } + my $selret = "\n"; + return $selret; +} + +# select tag by id and class onChange +sub selector_byidclass(){ + my $self = shift; + my ($column,$byid,$class,$style,$sel,@selval) = @_; + + my @selopt = (); + foreach my $opt (@selval){ + my $id = $opt; + my $value = $opt; + ($id,$value) = split /:/,$opt if($opt =~ /\w+\:.*/); + if("$sel" eq "$id"){ + push @selopt, "\n"; + }else{ + push @selopt, "\n"; + } + } + #my $selret = "\n"; + my $selret = "\n"; + return $selret; +} + +# select onChange +sub userselector_onchange(){ + my $self = shift; + my $key = shift; + my $selected = shift; + my $users_all = shift; + my $admin_name = shift || ""; + my $class = shift || ""; + my $style = shift || ""; + + my @selopt = (); + foreach my $c_id (sort { $users_all->{$a}->{txt08} cmp $users_all->{$b}->{txt08} } keys (%$users_all)){ + #print $c_id . "|" . $users_all->{$c_id}->{txt08} . "\n"; + $users_all->{$c_id}->{txt08} .= " (Ferien)" if($users_all->{$c_id}->{txt08} eq $admin_name); + if($selected eq $c_id){ + push @selopt, "\n"; + }else{ + push @selopt, "\n"; + } + } + my $selret = "\n"; + return $selret; +} + +# select2 tag +sub selector2(){ + my $self = shift; + my $tbl_columne = shift; + my $width = shift; + my $height = shift; + my $sel = shift; + my @selval = @_; + + my @selopt = (); + foreach my $opt (@selval){ + my $id = $opt; + my $value = $opt; + ($id,$value) = split /:/,$opt if($opt =~ /\d\:.*/); + #print "$sel eq $id || ($sel && $sel =~ /$id|$opt/
    "; + if($sel && $id && (("$sel" eq "$id") || ("$sel" =~ /$id|$opt/))){ + push @selopt, "\n"; + }else{ + push @selopt, "\n"; + } + } + my $selret = "\n"; + return $selret; +} + +# select3 tag with id:value +sub selector3(){ + my $self = shift; + my $tbl_columne = shift; + my $width = shift; + my $height = shift; + my $sel = shift; + my @selval = @_; + + my @selopt = (); + foreach my $opt (@selval){ + my $id = $opt; + my $value = $opt; + ($id,$value) = split /:/,$opt if($opt =~ /\d\:.*/); + #print "$sel =~ /\w+/ && $sel =~ /$id|$value/)
    "; + if($sel && "$sel" =~ /$id|$value/){ + push @selopt, "\n"; + }else{ + push @selopt, "\n"; + } + } + my $multiple = ""; + $multiple = "multiple" if($height > 1); + my $selret = "\n"; + return $selret; +} + + +#with onchange event +sub selector_onchange(){ + my $self = shift; + my $key = shift; + my $width = shift; + my $path = shift; + my $jscript = shift; + my $sel = shift; + my $todo = shift; + my @selval = @_; + + my @selopt = (); + foreach my $opt (@selval){ + my $id = $opt; + my $value = $opt; + ($id,$value) = split /:/,$opt if($opt =~ /\d\:.*/); + my $rid = "$id"; + $rid = "$path?change_login=$value" if($todo eq "change_login"); + $rid = "$value?$path\&$key=$id" if($key =~ /set_main_id/); + if("$sel" eq "$id"){ + push @selopt, "\n"; + }else{ + push @selopt, "\n"; + } + } + my $selret = "\n"; + return $selret; +} + +sub checkbox_style() { + my $self = shift; + my ($sid_key,$dialog) = @_; + my $ck_style = "\n"; + return $ck_style; +} + +#checkbox +sub checkbox(){ + my $self = shift; + my ($val,$check_name,$checked,$title,$required) = @_; + $checked = "checked" if($checked); + $required = "required" if($required); + my $checkb = ""; + return $checkb; +} + +#reverse checkbox +sub rev_checkbox(){ + my $self = shift; + my ($val,$check_name,$checked,$title) = @_; + if(!$checked){ + $checked = "checked"; + } + my $checkb = ""; + return $checkb; +} + +#radio (seems not working!!) +sub radiobox(){ + my $self = shift; + my ($val,$check_name,$checked) = @_; + $checked = "checked" if($checked); + my $checkb = ""; + return $checkb; +} + +#radio +#$but->radiobox2("$key","$ctrel->{$key}","$a","$b","$c") +sub radiobox2(){ + my $self = shift; + my ($key,$val,$a_name,$b_name,$c_name) = @_; + my $a_checked; + my $b_checked; + my $c_checked; + $a_checked = "checked" if(!$val); + $b_checked = "checked" if($val==1); + $c_checked = "checked" if($val==2); + my $checkb = "$a_name $b_name "; + $checkb .= " $c_name " if($c_name); + return $checkb; +} + +#radio reverse +sub radiobox2reverse(){ + my $self = shift; + my ($key,$val,$a_name,$b_name) = @_; + my $a_checked; + my $b_checked; + $a_checked = "checked" if($val); + $b_checked = "checked" if(!$val); + my $checkb = "$a_name $b_name "; + return $checkb; +} + +#Returns one radiobox ... you need min two to get a radioboxe +sub radiobox_vertical(){ + my $self = shift; + my ($key,$val,$checked,$boxname) = @_; + $checked = "checked" if($checked); + my $radiobox = ""; + return $radiobox; +} + +# Submit Buttons +sub singlesubmit(){ + my $self = shift; + my ($function,$b_name,$jscript) = @_; + my $button; + if($jscript){ + $button = ""; + }else{ + $button = ""; + } + return $button; +} + +# Submit Buttons with db based button +sub singlesubmit10(){ + my $self = shift; + my ($function,$b_val,$b_name) = @_; + my $button = ""; + return $button; +} + +# international hack. Vorsicht, aendert Parameter +sub singlesubmit1(){ + my $self = shift; + my ($function,$b_name,$class,$style,$title) = @_; + $class = "ebutton" if(!$class); + my ($key,$val,$ibv); + while (($key,$val) = each(%ib)) { + $ibv = $val if($b_name eq $key); + } + my $button = ""; + return $button; +} + +# with counter field +sub singlesubmit6(){ + my $self = shift; + my ($function,$b_name,$counter) = @_; + %ib = &ibuttons("","$counter"); + my ($key,$val,$ibv); + while (($key,$val) = each(%ib)) { + #print "$val if($b_name eq $key)
    "; + $ibv = $val if($b_name eq $key); + } + my $button = ""; + return $button; +} + +# international hack +sub singlesubmit3(){ + my $self = shift; + my ($function,$b_name,$b_img,$style,$title) = @_; + my ($key,$val,$ib_key,$ib_value); + #my %ib = ibuttons_arch(); + my %ib = ibuttons(); + while (($key,$val) = each(%ib)) { + if($b_name eq $key){ + $ib_key = $key; + $ib_value = $val; + } + } + my $button = ""; + if("$b_name" =~ /delete/){ + $button = ""; + }elsif($b_img){ + $button = ""; + }elsif($b_name){ + $button = ""; + } + return $button; +} + +# without grafic +sub singlesubmit7(){ + my $self = shift; + my ($function,$b_name,$title,$set_style,$jscript,$ebutton) = @_; + $ebutton = "ebutton" if(!$ebutton); + my ($b_img,$a_key); + $b_img = "Barcode" if("$b_name" =~ /barcode/); + $b_img = "Copy" if("$b_name" =~ /copy/); + $b_img = "Relate" if("$b_name" =~ /relate/); + $b_img = "Move" if("$b_name" =~ /move_/); + $b_img = "Delete" if("$b_name" =~ /delete|remove/); + $b_img = "Delete" if("$b_name" =~ /delete_media/); + $b_img = "Save" if("$b_name" =~ /save|service_done|_contenttverpos/); + $a_key = "y" if("$b_name" =~ /save/); + $b_img = "Save Texts" if("$b_name" =~ /save_text/); + $b_img = "Delete All" if("$b_name" =~ /delete_all/); + $b_img = "Search" if("$b_name" =~ /search/); + $b_img = "New" if("$b_name" =~ /^new/); + $b_img = "Open" if("$b_name" eq "open"); + $b_img = "Close" if("$b_name" eq "close"); + $b_img = "Print" if("$b_name" eq "print_sheet"); + $b_img = "Change Login" if("$b_name" eq "change_login"); + $b_img = "Senden" if("$b_name" =~ /send_newsletter/); + $b_img = "XLS Export" if("$b_name" =~ /XLSout/); + $b_img = "Save & Close" if("$b_name" =~ /_and_close/); + $b_img = "Save & Close & Print " if("$b_name" =~ /_print_and_close/); + $b_img = "Print" if("$b_name" =~ /_print_only/); + $b_img = "Kunde" if("$b_name" =~ /client/); + $b_img = "Artikel" if("$b_name" =~ /part/); + $b_img = "speichern & schließen" if("$b_name" =~ /save_tver_close/); + + my $button = " "; + if($b_name){ + if("$b_name" =~ /delete/){ + $button = ""; + }elsif($jscript){ + $button = ""; + }else{ + $button = ""; + } + } + return $button; +} + +#without submit +sub singlesubmit17(){ + my $self = shift; + my ($function,$b_name,$title,$set_style,$jscript,$ebutton) = @_; + $ebutton = "ebutton" if(!$ebutton); + my ($b_img,$a_key); + $b_img = "Barcode" if("$b_name" =~ /barcode/); + $b_img = "Copy" if("$b_name" =~ /copy/); + $b_img = "Relate" if("$b_name" =~ /relate/); + $b_img = "Move" if("$b_name" =~ /move_/); + $b_img = "Delete" if("$b_name" =~ /delete|remove/); + $b_img = "Delete" if("$b_name" =~ /delete_media/); + $b_img = "Save" if("$b_name" =~ /save/); + $a_key = "y" if("$b_name" =~ /save/); + $b_img = "Save Texts" if("$b_name" =~ /save_text/); + $b_img = "Delete All" if("$b_name" =~ /delete_all/); + $b_img = "Search" if("$b_name" =~ /search/); + $b_img = "New" if("$b_name" =~ /^new/); + $b_img = "Open" if("$b_name" eq "open"); + $b_img = "Close" if("$b_name" eq "close"); + $b_img = "Print" if("$b_name" eq "print_sheet"); + $b_img = "Change Login" if("$b_name" eq "change_login"); + $b_img = "Senden" if("$b_name" =~ /send_newsletter/); + $b_img = "XLS Export" if("$b_name" =~ /XLSout/); + $b_img = "Save & Close" if("$b_name" =~ /_and_close/); + $b_img = "Save & Close & Print " if("$b_name" =~ /_print_and_close/); + $b_img = "Print" if("$b_name" =~ /_print_only/); + $b_img = "Kunde" if("$b_name" =~ /client/); + $b_img = "Artikel" if("$b_name" =~ /part/); + + my $button = " "; + if($b_name){ + $button = "
    $b_img
    "; + } + return $button; +} + +# Grafic Submit Buttons +sub singlesubmit2glyph(){ + my $self = shift; + my ($function,$b_name,$title,$set_style,$jscript) = @_; + my $b_img; my $a_key; + $b_img = "submit.png" if("$b_name" =~ /post_email/); + $b_img = "actions/view-barcode.png" if("$b_name" =~ /barcode/); + $b_img = "actions/edit-copy.png" if("$b_name" =~ /copy|relate/); + $b_img = "actions/edit-paste.png" if("$b_name" =~ /move_/); + $b_img = "glyphicons/glyphicons-151-edit.png" if("$b_name" =~ /delete|remove/); + $b_img = "actions/edit-delete.png" if("$b_name" =~ /delete_media/); + $b_img = "actions/document-save.png" if("$b_name" =~ /save/); + $a_key = "y" if("$b_name" =~ /save/); + $b_img = "edittrash.png" if("$b_name" =~ /delete_all/); + $b_img = "search.png" if("$b_name" =~ /search/); + $b_img = "glyphicons/glyphicons-151-edit.png" if("$b_name" =~ /_done|_contenttverpos/); + $b_img = "glyphicons/glyphicons-703-file-plus.png" if("$b_name" =~ /new/); + $b_img = "glyphicons/glyphicons-151-edit.png" if("$b_name" =~ /open|client/); + $b_img = "fileclose.png" if("$b_name" eq "close"); + $b_img = "actions/view-media-artist.png" if("$b_name" eq "change_login"); + my $button = " "; + if($b_name){ + if("$b_name" =~ /delete/ && "$b_name" !~ /delete_verposdate/){ + if($jscript){ + $button = ""; + }else{ + $button = ""; + } + }else{ + $button = ""; + } + } + return $button; +} + +# Grafic Submit Buttons +sub singlesubmit2(){ + my $self = shift; + my ($function,$b_name,$title,$set_style,$jscript) = @_; + my $b_img; my $a_key; + $b_img = "submit.png" if("$b_name" =~ /post_email/); + $b_img = "actions/view-barcode.png" if("$b_name" =~ /barcode/); + $b_img = "actions/edit-copy.png" if("$b_name" =~ /copy|relate/); + $b_img = "actions/edit-paste.png" if("$b_name" =~ /move_/); + $b_img = "actions/archive-remove.png" if("$b_name" =~ /delete|remove/); + $b_img = "actions/edit-delete.png" if("$b_name" =~ /delete_media/); + $b_img = "actions/document-save.png" if("$b_name" =~ /save/); + $a_key = "y" if("$b_name" =~ /save/); + $b_img = "edittrash.png" if("$b_name" =~ /delete_all/); + $b_img = "search.png" if("$b_name" =~ /search/); + $b_img = "actions/document-new.png" if("$b_name" =~ /new/); + $b_img = "actions/document-properties.png" if("$b_name" =~ /open|client/); + $b_img = "fileclose.png" if("$b_name" eq "close"); + $b_img = "actions/view-media-artist.png" if("$b_name" eq "change_login"); + my $button = " "; + if($b_name){ + if("$b_name" =~ /delete/ && "$b_name" !~ /delete_verposdate/){ + if($jscript){ + $button = ""; + }else{ + $button = ""; + } + }else{ + $button = ""; + } + } + return $button; +} + +#with onclick +sub singlesubmit4(){ + my $self = shift; + my ($function,$b_name,$title,$jscript,$url) = @_; + my $b_img; + $b_img = "search.png";# if("$title" =~ /suchen/); + my $button = ""; + return $button; +} + +#with onclick +sub singlesubmit5(){ + my $self = shift; + my ($function,$b_name,$jscript,$url) = @_; + my ($key,$val,$ibv); + while (($key,$val) = each(%ib)) { + $ibv = $val if($b_name eq $key); + } + my $button = ""; + return $button; +} + +#with onclick script +sub singlesubmit9(){ + my $self = shift; + my ($function,$b_name,$main_id,$class,$style,$owner) = @_; + my $debug = $main_id if($owner && $owner eq $varenv{superu_id}); + my $button = "\n"; + return $button; +} + +sub singlesubmit8(){ + my $self = shift; + my ($function,$b_name,$jscript,$url) = @_; + my $button = ""; + return $button; +} +1; diff --git a/copri4/main/src/Mod/Callib.pm b/copri4/main/src/Mod/Callib.pm new file mode 100644 index 0000000..e5fe13a --- /dev/null +++ b/copri4/main/src/Mod/Callib.pm @@ -0,0 +1,217 @@ +package Callib; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; +use POSIX; +use DBI; +use CGI; # only for debugging + +#Deb libcalendar-simple-perl +use Calendar::Simple; +use Date::Calc qw(:all); +use Scalar::Util qw(looks_like_number); +use Mod::Buttons; +use Lib::Config; +use Mod::Basework; + +my $cf = new Config; +my $but = new Buttons; +my $bw = new Basework; + +my $q = new CGI; +$q->import_names('R'); + +sub new { + my $class = shift; + my $self = {}; + bless( $self, $class ); + return $self; +} + +my %varenv = $cf->envonline(); +my $now_time = strftime "%Y-%m-%d %H:%M", localtime; +my $day = strftime "%d", localtime; +my $mon = strftime "%m", localtime; +my $year = strftime "%Y", localtime; + +#start- end- date time +sub datetime_defaults(){ + my $self = shift; + my ($in_date,$in_time,$lang) = @_; + my $now_date_time = strftime "%Y-%m-%d %H:%M", localtime; + my $now_date = strftime "%Y-%m-%d", localtime; + my $now_time = strftime "%H:%M", localtime; + + if($in_date =~ /(\d{4})-(\d+)-(\d+)/){ + $now_date = "$1-$2-$3"; + }elsif($in_date =~ /(\d+)\.(\d+)\.(\d+)/){ + $now_date = "$3-$2-$1"; + } + + my ( $year, $month, $day ) = split( /-/, $now_date ); + + my ($nyear,$nmonth,$nday) = Add_Delta_YMD($year,$month,$day, 0,0,1); + $nday = "0" . $nday if ( $nday < 10 ); + $nmonth = "0" . $nmonth if ( $nmonth < 10 ); + my $start_datetime = "$year-$month-$day"; + my $end_datetime = "$nyear-$nmonth-$nday"; + $start_datetime = "$day.$month.$year" if(lc($lang) eq "de"); + $end_datetime = "$nday.$nmonth.$nyear" if(lc($lang) eq "de"); + $start_datetime .= " $now_time" if(!$in_time); + $end_datetime .= " $now_time" if(!$in_time); + return ($start_datetime,$end_datetime); +} + +#month map +sub monthmap(){ + my @_months = ("Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"); + return @_months; +} + +#day map +sub daymap(){ + my @_days = ("So","Mo","Di","Mi","Do","Fr","Sa"); + return @_days; +} + +#hour map +sub hourmap(){ + my @_hours = ( + "00:00", "01:00", "02:00", "03:00", "04:00", "05:00", + "06:00", "07:00", "08:00", "09:00", "10:00", "11:00", + "12:00", "13:00", "14:00", "15:00", "16:00", "17:00", + "18:00", "19:00", "20:00", "21:00", "22:00", "23:00" + ); + return @_hours; +} + +#english input date_time check +sub checkdate_time() { + my $self = shift; + my $date_time = shift; + $date_time =~ s/:\d{2}\..*$//; + my $date = $date_time; + my $time = "00:00:00"; + ($date, $time) = split(/ /, $date_time) if($date_time =~ /\d+\s\d+/); + my ( $y, $m, $d ) = split( /-/, $date ); + my ( $hour, $min, $sec ) = split( /\:/, $time ); + + my $check_time = 1; + $check_time = 0 if(looks_like_number($hour) && $hour > 24); + $check_time = 0 if(looks_like_number($min) && $min > 60); + $check_time = 0 if(looks_like_number($sec) && $sec > 60); + #print "$y, $m, $d && $check_time"; + if ( check_date( $y, $m, $d ) && $check_time) { + return $date_time; + }else{ + return 0; + } +} + +# input date check +sub checkdate() { + my $self = shift; + my ( $date, $time ) = @_; + my $d_chck = 1; + $date =~ s/,/-/g; + $date =~ s/\./-/g; + my ( $y, $m, $d ) = split( /-/, $date ); + if ( check_date( $y, $m, $d ) ) { + return "$y-$m-$d"; + } + else { + return "$year-$mon-$day"; + } +} + + +#split date +sub split_date(){ + my $self = shift; + my ($time_db) = @_; + $time_db =~ s/:\d{2}\..*$// if($time_db); + my ($date,$time) = split(/ /,$time_db); + my ($yy,$mo,$dd) = split(/-/,$date) if($date =~ /-/); + my ($hh,$mi) = split(/\:/,$time); + return ($yy,$mo,$dd,$hh,$mi); +} + +#time and date format for DE +sub time4de(){ + my $self = shift; + my ($time_db,$hhmi,$decode) = @_; + $time_db =~ s/:\d{2}\..*$// if($time_db); + my ($date,$time) = split(/ /,$time_db); + my ($yy,$mo,$dd) = split(/-/,$date); + my ($hh,$mi) = split(/\:/,$time); + my $date_de = " "; + $date_de = "$dd.$mo.$yy"; + $date_de = "$dd.$mo.$yy $hh:$mi" if($hhmi); + + #Deutsch (German) ==> 3 + $date_de = Date_to_Text_Long($yy,$mo,$dd,3) if($decode eq "Date_to_Text_Long"); + $date_de =~ s/M.*rz/März/; + return $date_de; +} + + +#Prepares contenttranspos start_time, end_time and count/Menge +sub contenttranspos_dating() { + my $self = shift; + my ($pos_id,$pos_start_time,$pos_end_time,$today4db,$hours,$ctt_start,$ctt_end,$owner) = @_; + my $menge = 0; + my $s_up; + my $e_up; + + $bw->log("sub contenttranspos_dating call from Callib:",\@_,""); + + my $start_datetime = $today4db; + my $end_datetime = $today4db; + $start_datetime = "$1-$2-$3 $4:$5" if($pos_start_time =~ /(\d{4})-(\d{2})-(\d{2})\s(\d{2}):(\d{2})/); + $start_datetime = "$3-$2-$1 $4:$5" if($pos_start_time =~ /(\d{2})\.(\d{2})\.(\d{4})\s(\d{2}):(\d{2})/); + $end_datetime = "$1-$2-$3 $4:$5" if($pos_end_time =~ /(\d{4})-(\d{2})-(\d{2})\s(\d{2}):(\d{2})/); + $end_datetime = "$3-$2-$1 $4:$5" if($pos_end_time =~ /(\d{2})\.(\d{2})\.(\d{4})\s(\d{2}):(\d{2})/); + + if($start_datetime && $end_datetime){ + my ($s_yy,$s_mo,$s_dd,$s_hh,$s_mi) = &split_date("",$start_datetime); + my $s_time = Mktime($s_yy,$s_mo,$s_dd,$s_hh,$s_mi,0); + + my ($e_yy,$e_mo,$e_dd,$e_hh,$e_mi) = &split_date("",$end_datetime); + + #Add 1hour and rebuild end_datetime + my $sec=0; + ($e_yy,$e_mo,$e_dd,$e_hh,$e_mi,$sec) = Add_Delta_DHMS($e_yy,$e_mo,$e_dd,$e_hh,$e_mi,0, 0,$hours,0,0) if($hours =~ /^\d+$/); + my $e_time = Mktime($e_yy,$e_mo,$e_dd,$e_hh,$e_mi,0); + $end_datetime = "$e_yy-$e_mo-$e_dd $e_hh:$e_mi"; + + #$menge not used via Transposition and at last Prelogic.pm, + #we believe setting by manually insert of int03=$menge + if(1==1){ + #Count Menge in hours + my $diff_time = $e_time - $s_time; + $menge = $diff_time / 3600;#to get hours + #$menge = $lb->round($menge); + my $s_cttime; + my $e_cttime; + if($ctt_start && $ctt_end){ + my ($s_yy,$s_mo,$s_dd,$s_hh,$s_mi) = &split_date("",$ctt_start); + my ($e_yy,$e_mo,$e_dd,$e_hh,$e_mi) = &split_date("",$ctt_end); + $s_cttime = Mktime($s_yy,$s_mo,$s_dd,$s_hh,$s_mi,0); + $e_cttime = Mktime($e_yy,$e_mo,$e_dd,$e_hh,$e_mi,0); + } + #Never used calc of min max time + $s_up = 1 if(!$s_cttime || $s_time < $s_cttime); + $e_up = 1 if(!$e_cttime || $e_time > $e_cttime); + } + } + + my @return_array = ($pos_id,$start_datetime,$end_datetime,$s_up,$e_up,$menge); + $bw->log("sub contenttranspos_dating return from Callib:",\@return_array,""); + + return ($start_datetime,$end_datetime,$s_up,$e_up,$menge); +} + +1; diff --git a/copri4/main/src/Mod/DBtank.pm b/copri4/main/src/Mod/DBtank.pm new file mode 100644 index 0000000..7458445 --- /dev/null +++ b/copri4/main/src/Mod/DBtank.pm @@ -0,0 +1,1298 @@ +package DBtank; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; +use POSIX; +use DBI; +use DBI::Const::GetInfoType; +use CGI ':standard'; +use Lib::Config; +use Mod::Basework; +use Scalar::Util qw(looks_like_number); +use Config::General; +use Data::Dumper; + +my $cf = new Config; +my $bw = new Basework; +my $q = new CGI; +$q->import_names('R'); +my $debug = 1; + +sub new { + my $class = shift; + my $self = {}; + + my $globalconf_file = "/var/www/copri4/shareeconf/global.cfg"; + my $conf = Config::General->new($globalconf_file); + my %globalconf = $conf->getall; + $self = \%globalconf; + + bless($self,$class); + return $self; +} + +my $today = strftime("%d.%m.%Y",localtime(time)); +my $date_time = strftime("%d.%m.%Y %H:%M",localtime(time)); +my %varenv = $cf->envonline(); + +#dbconnect_intern, on default $dbh_intern will be used +my $dbh_intern = &dbconnect(""); +sub dbconnect { + my $self = shift; + my $options =""; + my $database = "dbi:Pg:dbname=$varenv{dbname};host=$varenv{dbhost};port=5432;options='$options'"; + my $dbh = DBI->connect($database, $varenv{dbuser}, $varenv{dbpassw},{ RaiseError => 1, AutoCommit => 1 }) or die "Can't connect to $varenv{dbname}: $DBI::errstr"; + my $source = $dbh->get_info( $GetInfoType{SQL_DATABASE_NAME} ); + $bw->log("--> dbconnect_intern --> $varenv{syshost} $source",$database,""); + return $dbh if($dbh); +} + + +#dbconnect_extern for copri operator instance +sub dbconnect_extern { + my $self = shift; + my $dbname = shift; + my $instance_type = "operator"; + $instance_type = "primary" if($dbname eq "sharee_primary"); + + my $globalconf_file = "/var/www/copri4/shareeconf/global.cfg"; + my $conf = Config::General->new($globalconf_file); + my %globalconf = $conf->getall; + + $bw->log("dbconnect_extern call with instance_type:$instance_type and copri_instance:",$dbname,""); + + #keep in mind, only one DB can be returned by this way + #while (my ($key, $value) = each %{ $self->{$instance_type} }) { + while (my ($key, $value) = each %{ $globalconf{$instance_type} }) { + if($key eq $dbname){ + $bw->log("dbconnect_XX",$value->{database},""); + my $database = "dbi:Pg:dbname=$value->{database}->{dbname};host=$value->{database}->{host};port=$value->{database}->{port};options='$value->{database}->{options}'"; + $database .= ";sslmode=$value->{database}->{sslmode}" if($value->{database}->{sslmode} && $value->{database}->{host} ne "localhost"); + my $dbh = DBI->connect($database, $value->{database}->{user}, $value->{database}->{passwd},{ RaiseError => 0, AutoCommit => 1 }); + $bw->log("--> dbconnect_extern success --> $database, $value->{database}->{user}, $value->{database}->{passwd}",$database,""); + return $dbh if($dbh); + } + } + $bw->log("ERROR, dbconnect_extern call with dbname: $dbname |instance_type:$instance_type","",""); + return ""; +} + +#get operator conf by oprefix +sub get_operator_conf { + my $self = shift; + my $oprefix = shift || ""; + + my $globalconf_file = "/var/www/copri4/shareeconf/global.cfg"; + my $conf = Config::General->new($globalconf_file); + my %globalconf = $conf->getall; + + while (my ($key, $operator) = each %{ $globalconf{operator} }) { + if($oprefix && $oprefix eq $operator->{oprefix}){ + $bw->log("get operator conf by oprefix: $oprefix",$operator->{oprefix},""); + return $operator; + } + } + $bw->log("Cannot get operator conf by oprefix: $oprefix","",""); + return 0; +} + +#get dbname because varenv{dbname} seems not stable +sub get_dbname { + my $self = shift; + my $dbh = shift || $dbh_intern; + my $source = $dbh->get_info( $GetInfoType{SQL_DATABASE_NAME} ); + return $source; +} + + +#loop extern operator db's for specific tablefield sync +sub update_operatorsloop { + my $self = shift; + my $dbname = shift || ""; + my $adrc_id = shift || 0; + my $todo = shift || "update"; + + use DBI::Const::GetInfoType; + my $authref = { + table => "contentadr", + fetch => "one", + template_id => "202", + c_id => "$adrc_id", + }; + my $dbh_primary = $self->dbconnect_extern("sharee_primary"); + my $source_primary = $dbh_primary->get_info( $GetInfoType{SQL_DATABASE_NAME} ); + my $record_primary = { c_id => 0 }; + $record_primary = $self->fetch_record($dbh_primary,$authref) if($adrc_id && $adrc_id > 0); + + $bw->log("update_operatorsloop by copri_instance-dbname: $dbname | owner: $record_primary->{owner} | get_info-dbname: $source_primary","",""); + + my $rows = 0; + if($record_primary->{c_id}){ + + my %operator_hash = (); + #keep in mind, shareedms-operators updates sharee_primary, that's because we have to also loop + #if($dbname eq "sharee_primary"){ + if($record_primary->{txt17}){ + if($record_primary->{txt17} =~ /\w\s\w/){ + %operator_hash = map { $_ => "$self->{operator}{$_}->{operatorApp}" } split(/\s+/,$record_primary->{txt17}); + }else{ + %operator_hash = ( "$record_primary->{txt17}" => "$self->{operator}{$record_primary->{txt17}}->{operatorApp}" ); + } + foreach my $sharee_operator (keys (%operator_hash)){ + if($sharee_operator =~ /sharee_/){ + $sharee_operator =~ s/\s//g; + my $dbh_operator = $self->dbconnect_extern("$sharee_operator"); + if($todo eq "update"){ + + #this will be saved by operator DMS and have to keep intividual + $bw->log("disabled condition: if($sharee_operator ne $dbname || $record_primary->{owner} == 197 || $dbname eq \"sharee_primary\"","",""); + #if($sharee_operator ne "$dbname" || $record_primary->{owner} == 197 || $dbname eq "sharee_primary"){ + delete $record_primary->{txt17};#operators + delete $record_primary->{txt30} if($dbname ne "sharee_lv" && $record_primary->{txt30} ne "5511");#Tarif, exception sharee_lv;#Tarif + delete $record_primary->{txt15};#Bonusnr + delete $record_primary->{int07};#Rabatt + delete $record_primary->{txt18};#Service tour + delete $record_primary->{int05};#Web-Login + delete $record_primary->{int16};#payone-cron-interval + delete $record_primary->{int19};#Ilockit Admin + #delete $record_primary->{int12};#Vde (remove delete for global setting) + delete $record_primary->{int23};#mini_answer count will be saved on operator + delete $record_primary->{txt29};#Sonstiges + #} + + my $update = { + %$record_primary, + table => "contentadr", + }; + $bw->log("--> save_account update_operatorsloop $sharee_operator by $source_primary",$update->{c_id},""); + + $bw->log("UPDATE adr from record_primary to operator on loop $sharee_operator",$record_primary->{c_id},""); + $rows = $self->update_record($dbh_operator,$update,$record_primary); + if($rows != 1){ + $bw->log("INSERT adr from record_primary to operator on loop $sharee_operator",$record_primary->{c_id},""); + my $insert = { + %$record_primary, + table => "contentadr", + mtime => 'now()', + }; + #owner => "198", + + my $c_id = $self->insert_contentoid($dbh_operator,$insert,""); + $rows = 1 if($c_id); + #pseudo code copied fom net_booking. have to be done elsewehre because of $apif + if(1==2){ + my $ctadr = { c_id => $c_id }; + my ($bike_group,$user_group,$tariff_content,$user_tour);# = $apif->fetch_tariff($ctadr,""); + foreach my $id (keys (%$tariff_content)){ + # #int18 + # + # 2 = "public" + # 3 = "private" + # 4 = "hidden-lv" + # + my $update_op = { + table => "contentadr", + }; + if($tariff_content->{$id}->{int18} && ($tariff_content->{$id}->{int18} == 2 || $tariff_content->{$id}->{int18} == 3 || $tariff_content->{$id}->{int18} == 4)){ + #if($tariff_content->{$id}->{int12} && $tariff_content->{$id}->{int12} == $ct->{main_id} && $tariff_content->{$id}->{barcode}){ + $update_op->{txt30} = $tariff_content->{$id}->{barcode}; + $rows = $self->update_record($dbh_operator,$update,$ctadr); + #} + } + } + } + } + }elsif($todo eq "delete"){ + $bw->log("DELETE adr from operators and at last primary $sharee_operator",$record_primary,""); + $rows += $self->delete_content($dbh_operator,"contentadr",$record_primary->{c_id}); + } + } + } + } + #} + } + return $rows; +} + +#return system and contentadr username by c_id (owner last change) +sub sys_username { + my $self = shift; + my $dbh = shift || $dbh_intern; + my $owner = shift || ""; + my $u_name = ""; + + if(looks_like_number($owner)){ + my $channel_map = $self->channel_map(); + + foreach my $id (sort { $channel_map->{$a} cmp $channel_map->{$b} } keys (%$channel_map)){ + if($id == $owner){ + $u_name = $channel_map->{$id}; + } + } + + if(!$u_name){ + my $users_pref = { + table => "contentadr", + fetch => "one", + c_id => $owner, + }; + my $ct_users = $self->fetch_tablerecord($dbh,$users_pref); + $u_name = $ct_users->{txt01}; + } + + } + return $u_name; +} + +#collect serviceapp and DMS users for search select username u_id mapping +sub users_map(){ + my $self = shift; + my $dbh = shift || $dbh_intern; + my $mapref = shift || ""; + + my $and = ""; + if(ref($mapref) eq "HASH"){ + foreach my $key (keys (%$mapref)){ + $and = " and u.$key=$mapref->{$key}" if($key =~ /int/); + } + } + + my $sql = "SELECT ct.* FROM contentadr ct, users u WHERE ct.c_id=u.u_id $and"; + my $sth = $dbh->prepare($sql); + my $rc = $sth->execute(); + my $users_rec = $sth->fetchall_hashref('c_id'); + $bw->log("DBtank users_map:",$sql,"") if($debug); + + return $users_rec; +} + + +#booking channel id's +#TODO migrate all to global.cfg +sub channel_map(){ + my $self = shift; + my $channel = { + 173 => "merchant fallback",#mig + 174 => "example Web",#mig + 175 => "example App",#mig + 176 => "Mein konrad App",#mig + 177 => "LastenradBay App",#mig + 179 => "cronjob", + 178 => "payone API", + 181 => "SMS API", + 182 => "velofactur API", + 183 => "Ilockit API", + 184 => "web App",#mig + 185 => "konstanz App",#mig + 186 => "sharee App",#mig + 187 => "shareetool App",#mig + 188 => "sys API", + 196 => "DMS Form",#mig + 197 => "Web Form",#mig + 198 => "primary",#mig + 199 => "LV API",#mig + }; + return $channel; +} + + +#get tpl +sub get_tpl { + my $self = shift; + my $dbh = shift || $dbh_intern; + my $tpl_id = shift || 0; + my $sth = $dbh->prepare("SELECT * FROM template WHERE tpl_id='$tpl_id'"); + my $rc = $sth->execute(); + my $tpl = $sth->fetchrow_hashref(); + return $tpl; +} + +#get uri_path and meta data like tpl_order by menue path +sub get_node_meta { + my $self = shift; + my $dbh = shift || $dbh_intern; + my $viewsel = shift; + my $source = $dbh->get_info( $GetInfoType{SQL_DATABASE_NAME} ); + + my $node_name1 = $q->escapeHTML(@{$viewsel}[-1]); + my @node_path = ("$node_name1"); + + my $where = "WHERE n.main_id=rel.main_id and rel.template_id=tpl.tpl_id and node_name = '$node_name1'"; + pop @{$viewsel}; + my @reverse_viewsel = reverse(@{$viewsel}); + #print Dumper(@reverse_viewsel) . "
    \n"; + + #bsp + #SELECT * FROM nodes n,relation rel, template tpl WHERE n.main_id=rel.main_id and rel.template_id=tpl.tpl_id and n.node_name = 'Firma' and n.parent_id IN (SELECT n.main_id from nodes n where n.node_name='Einstellung' and n.parent_id IN (SELECT n.main_id from nodes n where n.node_name='JBW')); + + foreach(@reverse_viewsel){ + #print $_ . "
    \n"; + my $node_nameX = $q->escapeHTML($_); + push(@node_path, $node_nameX); + $where .= " and n.parent_id IN (SELECT n.main_id from nodes n where n.node_name='$node_nameX'"; + } + + foreach(@reverse_viewsel){ + $where .= ")"; + } + my $sql = "SELECT * FROM nodes n,relation rel, template tpl $where"; + my $sth = $dbh->prepare($sql); + my $rc = $sth->execute(); + my $nrt = $sth->fetchrow_hashref(); + + my @reverse_node_path = reverse(@node_path); + my $uri_path = ""; + foreach(@reverse_node_path){ + $uri_path .= "$_/"; + } + $uri_path =~ s/\/$//; + $bw->log("get_node_meta $uri_path | $source",$sql,"") if($debug); + #print Dumper($nrt); + return $nrt; +} + +sub get_node { + my $self = shift; + my $dbh = shift || $dbh_intern; + my $main_id = shift; + my $sth = $dbh->prepare("SELECT * FROM nodes WHERE main_id=$main_id"); + my $rc = $sth->execute(); + my $node = $sth->fetchrow_hashref(); + return $node; +} + +# Nodes einer Ebene +sub collect_node { + my $self = shift; + my $dbh = shift || $dbh_intern; + my $main_id = shift; + my $sth = $dbh->prepare("SELECT * FROM nodes WHERE parent_id=$main_id"); + my $rc = $sth->execute(); + my $nodes = $sth->fetchall_hashref("main_id"); + my $rows = $sth->rows; + return ($nodes,$rows); +} + +# Nodes einer Ebene mit relation +sub collect_noderel { + my $self = shift; + my $dbh = shift || $dbh_intern; + my $main_id = shift; + my $template_id = shift || ""; + my $where = "WHERE n.main_id=rel.main_id and rel.content_id=0 and n.parent_id=$main_id"; + $where .= " and rel.template_id=$template_id" if($template_id); + my $sth = $dbh->prepare("SELECT * FROM nodes n, relation rel $where"); + my $rc = $sth->execute(); + my $nodes = $sth->fetchall_hashref("main_id"); + my $rows = $sth->rows; + return ($nodes,$rows); +} + +#recursive node runner to get node path +sub recurse_select { + my $self = shift; + my $dbh = shift || $dbh_intern; + my $main_id = shift || ""; + my $sth = $dbh->prepare("SELECT parent_id,node_name FROM nodes where main_id=$main_id"); + my $rc = $sth->execute(); + my $node = $sth->fetchrow_hashref(); + return ($node->{parent_id},$node->{node_name}); +} +sub recurse_node { + my $self = shift; + my $dbh = shift || $dbh_intern; + my $main_id = shift || ""; + my $depth=$1 if($main_id =~ /^(\d)/); + my $uri_path = "?failure=recurse_node"; + my @nodes = (); + if($main_id && $main_id > 20000){ + $uri_path = ""; + for(my $i=0; $i<$depth;$i++){ + ($main_id,my $node_name) = $self->recurse_select($dbh,$main_id) if($main_id); + push(@nodes, $node_name); + #print $main_id . "|$node_name\n"; + } + my @node_path = reverse(@nodes); + foreach(@node_path){ + $uri_path .= "$_/"; + } + $uri_path =~ s/\/$//; + } + return $uri_path; +} +############################### + + +#get one subnode +#ex. get contentpos template_id from subnode +#select n.n_id,n.parent_id,n.main_id,rel.template_id from nodes n, relation rel where n.main_id=rel.main_id and n.parent_id=300029; +# n_id | parent_id | main_id | template_id +#------+-----------+---------+------------- +# 431 | 300029 | 400004 | 401 +sub get_subrelnode { + my $self = shift; + my $dbh = shift || $dbh_intern; + my $main_id = shift; + my $template_id = shift || ""; + my $node_name = shift || ""; + my $where = ""; + $where .= " and rel.template_id = $template_id" if($template_id); + $where .= " and n.node_name = '$node_name'" if($node_name); + my $sql = "SELECT * FROM nodes n, relation rel where n.main_id=rel.main_id and n.parent_id=$main_id $where"; + my $sth = $dbh->prepare($sql); + my $rc = $sth->execute(); + my $node = $sth->fetchrow_hashref(); + $bw->log("get_subrelnode",$sql,""); + return $node; +} + +#because of different and dynamic pos templates we need template grouping +sub pos_template_group { + my $self = shift; + my $dbh = shift || $dbh_intern; + my $fetch = shift; + my $ctcp_where = "1=1"; + + if($fetch->{table} eq "content" && $fetch->{table_pos} eq "contentpos"){ + $ctcp_where .= " and ct.c_id=cp.cc_id"; + }elsif($fetch->{table} eq "contentadr" && $fetch->{table_pos} eq "contentadrpos"){ + $ctcp_where .= " and ct.c_id=cp.ca_id"; + } + + my $sql = "SELECT tpl_id,tpl_order from template where tpl_id IN (SELECT cp.template_id from $fetch->{table_pos} cp, $fetch->{table} ct where $ctcp_where group by cp.template_id)"; + + my $sth = $dbh->prepare($sql); + my $rc = $sth->execute(); + my $templates = $sth->fetchall_hashref("tpl_id"); + + $bw->log("pos_template_group",$sql,""); + return $templates; +} + +#fetch relation, template, nodes +sub fetch_rel4tpl4nd(){ + my $self = shift; + my $dbh = shift || $dbh_intern; + my $fetch = shift; + my $source = $dbh->get_info( $GetInfoType{SQL_DATABASE_NAME} ); + + $fetch->{content_id}=0 if($fetch->{content_id} eq "null"); + my $where = "WHERE nodes.main_id=relation.main_id and relation.template_id=template.tpl_id"; + $where .= " and nodes.parent_id=$fetch->{parent_id}" if($fetch->{parent_id}); + $where .= " and relation.main_id=$fetch->{main_id}" if($fetch->{main_id}); + $where .= " and relation.content_id=$fetch->{content_id}" if($fetch->{content_id}); + $where .= " and relation.template_id=$fetch->{template_id}" if($fetch->{template_id}); + if($fetch->{template_id1} && $fetch->{template_id2}){ + $where .= " and relation.template_id >= $fetch->{template_id1} and relation.template_id <= $fetch->{template_id2}"; + } + $where .= " and relation.rel_id=$fetch->{rel_id}" if($fetch->{rel_id}); + $where .= " order by content_id $fetch->{ascdesc}" if($fetch->{ascdesc}); + + my $sql = "SELECT * FROM relation,template,nodes $where"; + my $sth = $dbh->prepare($sql); + my $rc = $sth->execute(); + + my $rel = { main_id => 0 }; + if($fetch->{fetch} eq "all" && $fetch->{keyfield}){ + $rel = $sth->fetchall_hashref($fetch->{keyfield}); + }else{ + $rel = $sth->fetchrow_hashref(); + } + $bw->log("fetch_rel4tpl4nd $source",$sql,"") if($debug); + + return $rel; +} + +#azn time worktime from Von Bis +sub select_worktime { + my $self = shift; + my $dbh = shift || $dbh_intern; + my $fetch = shift; + + my $sql = "SELECT $fetch->{end_at} - $fetch->{start_at} AS worktime FROM $fetch->{table} where ct_id = $fetch->{ct_id} and barcode = $fetch->{barcode} and $fetch->{end_at} is not null and $fetch->{start_at} is not null"; + my $sth = $dbh->prepare($sql); + my $rc = $sth->execute(); + my $record = $sth->fetchrow_hashref(); + $bw->log("DBtank select_worktime: ",$sql,"") if($debug); + + return $record; +} + +#Collect table ...post +sub collect_post(){ + my $self = shift; + my $dbh = shift || $dbh_intern; + my $fetch = shift; + my $count = shift || ""; + + my $source = $dbh->get_info( $GetInfoType{SQL_DATABASE_NAME} ); + my $table; + my $table_pos; + my $ct_where = "1=1"; + my $cp_where = "1=1"; + my $ctcp_where = "1=1"; + my $poscid; + + if($fetch->{table} eq "content" && $fetch->{table_pos} eq "contentpos"){ + #*2 + $ctcp_where .= " and ct.c_id=cp.cc_id"; + $poscid = "cp.cc_id"; + }elsif($fetch->{table} eq "contentadr" && $fetch->{table_pos} eq "contentadrpos"){ + #*1 + $ctcp_where .= " and ct.c_id=cp.ca_id"; + $poscid = "cp.ca_id"; + }elsif(($fetch->{table} eq "contenttrans" && $fetch->{table_pos} eq "contenttranspos") || ($fetch->{table} eq "contenttver" && $fetch->{table_pos} eq "contenttverpos")){ + #*3 + $ctcp_where .= " and ct.c_id=cp.ct_id"; + $poscid = "cp.ct_id"; + }else{ + return; + } + + foreach my $key (keys %$fetch){ + if($fetch->{$key}){ + $fetch->{$key} =~ s/^\s//g; + $fetch->{$key} =~ s/\s$//g; + my $op = "="; + my $value = $fetch->{$key}; + ($op, $value) = split(/::/, $fetch->{$key}) if($fetch->{$key} =~ /::/); + if($key =~ /^(ct_name|txt\d+)$/ && $value){ + if($op eq "IN"){ + $cp_where .= " and cp.$key $op $value"; + }else{ + if($key eq "txt01" && $value =~ /NaN/){ + $cp_where .= " and $value"; + }else{ + $cp_where .= " and cp.$key $op '$value'"; + } + } + }elsif($key =~ /ct\.close_time|ct\.state|ct\.int14/ && $value){#used to get open invoices + $ct_where .= " and $key $op $value"; + }elsif($key =~ /time/ && $value){ + if($value =~ /interval/){ + $cp_where .= " and cp.$key $op $value";#format like (now() - integer '7 day') + }elsif($key eq "time_range"){ + $cp_where .= " and $value";#look at only_first_free + }else{ + $cp_where .= " and cp.$key $op '$value'"; + } + }elsif($varenv{systype} && $varenv{systype} eq "azn"){ + if($key =~ /^ct\.(contentadr_id|owner|barcode|int\d+)$/ && $value){ + $ct_where .= " and $key $op $value"; + }elsif($key eq "barcode" && $fetch->{fetch} eq "all"){ + if($value =~ /\d-\d/){ + my ($start_val,$end_val) = split(/-/, $value); + $cp_where .= " and (cp.$key >= $start_val AND cp.$key <= $end_val)"; + }else{ + my $start_val = $value . "01"; + my $end_val = $value . "31"; + $cp_where .= " and (cp.$key >= $start_val AND cp.$key <= $end_val)"; + } + }elsif($key =~ /^(c_id|ca_id|ct_id|owner|barcode|int\d+)$/ && $value){ + $cp_where .= " and cp.$key $op $value"; + } + }elsif($key =~ /^(c_id|ca_id|ct_id|owner|barcode|int\d+)$/ && $value){ + $cp_where .= " and cp.$key $op $value"; + }elsif($fetch->{catch} && $key eq "template_id" && $value){ + $cp_where .= " and cp.$key $op $value"; + }elsif(!$fetch->{catch} && $key =~ /main_id|template_id/ && $value){ + $ct_where .= " and rel.$key $op $value"; + } + } + } + + my $sth; + my $sql; + my $limit = ""; + $limit = "LIMIT $count" if(looks_like_number($count)); + if($fetch->{catch} && $fetch->{catch} eq "content_contentpos"){ + $sql = "SELECT cp.* from $fetch->{table_pos} cp, $fetch->{table} ct where $ctcp_where and $cp_where and $ct_where order by cp.mtime DESC $limit"; + $sth = $dbh->prepare($sql); + #+3 + }else{ + #adapated from search_content3 to get Category-Menue + $sql = "SELECT cp.* FROM $fetch->{table_pos} cp WHERE $cp_where and $poscid IN (SELECT ct.c_id FROM relation rel, $fetch->{table} ct WHERE rel.content_id=ct.c_id and $ct_where) order by cp.mtime ASC";#mtime aufsteigend get last (newest) entry + $sth = $dbh->prepare($sql); + } + my $rc = $sth->execute(); + $bw->log("DBtank collect_post $source",$sql,"") if($debug); + + my $record = { c_id => 0 }; + if($fetch->{fetch} eq "all" && $fetch->{keyfield}){ + $record = $sth->fetchall_hashref($fetch->{keyfield}); + }elsif($fetch->{fetch} eq "one"){ + $record = $sth->fetchrow_hashref(); + } + return $record; +} + +#fetch all|one content + relation + nodes +sub fetch_record(){ + my $self = shift; + my $dbh = shift || $dbh_intern; + my $fetch = shift; + my $fetch_sql = shift || ""; + my $source = $dbh->get_info( $GetInfoType{SQL_DATABASE_NAME} ); + + my $where = "where ct.c_id=rel.content_id and nd.main_id=rel.main_id"; + $where .= "$fetch_sql" if($fetch_sql);#enhancement to get bike_group OR + my $order = ""; + + foreach my $key (keys %$fetch){ + if($fetch->{$key}){ + $fetch->{$key} =~ s/^\s//g; + $fetch->{$key} =~ s/\s$//g; + my $op = "="; + my $value = $fetch->{$key}; + ($op, $value) = split(/::/, $fetch->{$key}) if($fetch->{$key} =~ /::/); + #$value = $q->escapeHTML($value);#In DB context will always done by API + #can also be "rel.main_id IN (300005,300024)" + $where .= " and rel.$key $op $value" if($key =~ /^(parent_id|main_id|template_id|rel_id)$/ && $value); + if($key =~ /^(ct_name$|txt\d+|uri\d+|state)$/ && $value){ + if($value =~ /length/){ + $where .= " and $value"; + }elsif($value eq "null"){ + $where .= " and (ct.$key is null OR ct.$key = '')"; + }else{ + $where .= " and ct.$key $op '$value'"; + } + } + if($key =~ /^(c_id|barcode|int\d+|owner|contentadr_id)$/){ + if(looks_like_number($value) || $value eq "null"){ + if($value eq "null"){ + $where .= " and (ct.$key is null OR ct.$key = 0)"; + }else{ + $where .= " and ct.$key $op $value"; + } + }elsif($op eq "IN"){ + $where .= " and ct.$key $op $value"; + } + } + if($varenv{systype} && $varenv{systype} eq "azn" && $key =~ /start_time|end_time/){ + if($key =~ /start_time/){ + $where .= " and (ct.end_time >= '$fetch->{start_time}' AND ct.start_time <= '$fetch->{end_time}')"; + $order = " order by ct.start_time DESC";#because to get ct_id for contenttverpos Übertrag + } + }elsif($key =~ /close_time$/ && $value){ + $where .= " and ct.$key $op $value"; + }elsif($key =~ /time$/ && $value){ + if($value =~ /interval/){ + $where .= " and ct.$key $op $value"; + }else{ + $where .= " and ct.$key $op '$value'"; + } + } + } + } + + #ct.* because of nd.txt01 and ct.txt01 . + my $sql = "SELECT ct.*,rel.*,nd.node_name,nd.parent_id FROM $fetch->{table} ct, relation rel, nodes nd $where $order"; + my $sth = $dbh->prepare($sql); + my $rc = $sth->execute(); + $bw->log("DBtank fetch_record $source: $rc",$sql,"") if($debug); + + my $record = { c_id => 0 }; + if($fetch->{fetch} eq "all" && $fetch->{keyfield}){ + $record = $sth->fetchall_hashref($fetch->{keyfield}); + }elsif($fetch->{fetch} eq "one"){ + $record = $sth->fetchrow_hashref(); + } + return $record; +} + +#fetch just in one table --> without relation ... +sub fetch_tablerecord(){ + my $self = shift; + my $dbh = shift || $dbh_intern; + my ($fetch) = @_; + my $source = $dbh->get_info( $GetInfoType{SQL_DATABASE_NAME} ); + my $where = "where 1=1"; + + foreach my $key (keys %$fetch){ + if($fetch->{$key}){ + $fetch->{$key} =~ s/^\s//g; + $fetch->{$key} =~ s/\s$//g; + my $op = "="; + my $value = $fetch->{$key}; + ($op, $value) = split(/::/, $fetch->{$key}) if($fetch->{$key} =~ /::/); + #print "$key: $fetch->{$key}|$op, $value\n"; + #$value = $q->escapeHTML($value);#In DB context will always done by API + + if($key =~ /ct_name/ && $value =~ /CAST/){#CAST(c_id AS text) + $where .= " and $key $op $value"; + }elsif($key =~ /^(ct_name$|txt\d+|uri\d+|state)$/ && $value){ + $where .= " and $key $op '$value'"; + }elsif($key =~ /_itime$/ && $value){ + $where .= " and itime $op '$value'"; + }elsif($key =~ /time$/ && $value && $value =~ /interval/){#<= (now() - interval '15 minutes') + $where .= " and $key $op $value"; + }elsif($key =~ /time$/ && $value){ + $where .= " and $key $op '$value'"; + }elsif($key =~ /^(c_id|u_id|ct_id|ca_id|barcode|int\d+|owner|template_id)$/ && $value){ + if($value eq "null"){ + $where .= " and ($key is null OR $key = 0)"; + }else{ + $where .= " and $key $op $value"; + } + } + } + } + + $where .= " order by end_time DESC" if($fetch->{table} eq "contenttranspos");#prio data with newest end_time + my $sql = "SELECT * FROM $fetch->{table} $where"; + my $sth = $dbh->prepare($sql); + my $rc = $sth->execute(); + $bw->log("DBtank fetch_tablerecord $source:",$sql,"") if($debug); + + my $record = { c_id => 0 }; + if($fetch->{fetch} eq "all" && $fetch->{keyfield}){ + $record = $sth->fetchall_hashref($fetch->{keyfield}); + }elsif($fetch->{fetch} eq "one"){ + $record = $sth->fetchrow_hashref(); + } + return $record; +} + +#update sql +sub update_sql(){ + my $self = shift; + my $dbh = shift || $dbh_intern; + my $update_sql = shift; + my $source = $dbh->get_info( $GetInfoType{SQL_DATABASE_NAME} ); + my $rows = 0; + + my $sql = "$update_sql"; + + my $sth = $dbh->prepare($sql); + $rows = $sth->execute(); + + $bw->log("DBtank update_sql $source: $rows",$sql,"") if($debug); + + return $rows; + +} + +#update one value +sub update_one(){ + my $self = shift; + my $dbh = shift || $dbh_intern; + my $update = shift; + my $one = shift; + my $c_id = shift || ""; + + my $source = $dbh->get_info( $GetInfoType{SQL_DATABASE_NAME} ); + my $rows = 0; + my $where = ""; + if($c_id){ + $where = "where c_id = $c_id"; + }elsif($update->{c_id}){ + $where = "where c_id = $update->{c_id}"; + } + + if($update->{table} eq "users" && $update->{u_id}){ + $where = "where u_id = $update->{u_id}"; + } + if($update->{table} eq "nodes" && $update->{main_id}){ + $where = "where main_id = $update->{main_id}"; + } + if($update->{table} eq "relation" && $update->{main_id}){ + $where = "where main_id = $update->{main_id} and content_id=0"; + } + if($update->{table} eq "relation" && $update->{rel_id}){ + $where = "where rel_id = $update->{rel_id}"; + } + + if($update->{table} =~ /^users|relation|node/){ + $one .= ",change='now()'"; + }else{ + $one .= ",mtime='now()'"; + } + $one .= ",owner=$update->{owner}" if($update->{owner}); + + if($where){ + my $sql = "UPDATE $update->{table} set $one $where"; + my $sth = $dbh->prepare($sql); + $rows = $sth->execute(); + $bw->log("DBtank update_one $source: $rows",$sql,"") if($debug); + } + return $rows; +} + + +#update all +sub update_record(){ + my $self = shift; + my $dbh = shift || $dbh_intern; + my $update = shift; + my $record = shift; + my $source = $dbh->get_info( $GetInfoType{SQL_DATABASE_NAME} ); + my $where = ""; + my $set = "set"; + my $rows = 0; + + #print Dumper($update); + if(looks_like_number($record->{c_id})){ + $where = "where c_id = $record->{c_id}"; + foreach my $key (keys %$update){ + $update->{$key} =~ s/^\s//g if($update->{$key}); + $update->{$key} =~ s/\s$//g if($update->{$key}); + my $value = $update->{$key} || ""; + $value = "$update->{$key}" if(looks_like_number($update->{$key})); + #my $value = $q->escapeHTML($update->{$key});#In DB context will always done by API + #print "$key=$value|$update->{$key}
    \n"; + if($key =~ /^(ct_name$|txt\d+|state|start_time|end_time|byte)/){ + if($value && $value eq "null"){ + $set .= " $key=$value,"; + }else{ + $set .= " $key='$value',"; + } + } + if($key =~ /^(barcode|contentadr_id|int\d+|owner|owner_end|start_at\d+|end_at\d+)$/){ + $value =~ s/,/\./ if($value); + if($key =~ /int\d+|start_at\d+|end_at\d+/ && $value && $value =~ /\d+:\d+/){#azn time format + $set .= " $key='$value',"; + }elsif(looks_like_number($value) || ($value && $value eq "null")){ + $set .= " $key=$value,"; + }elsif($key =~ /int\d+/ && !$value){ + $set .= " $key=null,";#we need this for null values in operators loop + } + } + if($key =~ /(mtime|atime)$/){ + if($value && $value =~ /^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}$/){ + $set .= " $key='$value',"; + }else{ + $set .= " $key='now()',"; + } + } + } + } + $set =~ s/,$//; + my $sql = "UPDATE $update->{table} $set $where"; + my $sth = $dbh->prepare($sql); + $rows = $sth->execute(); + $bw->log("DBtank update_record $source: $rows",$sql,"") if($debug); + + return $rows; +}#update_record + +#insert content +sub insert_users { + my $self = shift; + my $dbh = shift || $dbh_intern; + my $u_id = shift; + my $owner = shift; + my $source = $dbh->get_info( $GetInfoType{SQL_DATABASE_NAME} ); + + my $sql = "INSERT INTO users (u_id,itime,mtime,owner) VALUES ('$u_id','now()','now()','$owner')"; + my $sth = $dbh->prepare($sql); + my $rows = $sth->execute(); + $bw->log("DBtank INSERT DMS users $source $rows",$sql,"") if($debug); + return $u_id; +} + +sub select_users(){ + my $self = shift; + my $dbh = shift || $dbh_intern; + my $u_id = shift || 0; + my $sqlcon = shift || "";#used with "and int09=1" + my $source = $dbh->get_info( $GetInfoType{SQL_DATABASE_NAME} ); + + my $sql = "SELECT * FROM users WHERE u_id=$u_id $sqlcon"; + my $sth = $dbh->prepare($sql); + my $rc = $sth->execute(); + my $users = $sth->fetchrow_hashref(); + $bw->log("DBtank SELECT DMS users $source u_id: $users->{u_id}",$sql,"") if($debug); + return $users; +} + +#insert content +sub insert_contentoid { + my $self = shift; + my $dbh = shift || $dbh_intern; + my $insert = shift; + my $reset_keys = shift || ""; + my $source = $dbh->get_info( $GetInfoType{SQL_DATABASE_NAME} ); + + if($reset_keys eq "reset_adropkeys"){ + delete $insert->{txt17};#operators + delete $insert->{txt30} if($source ne "sharee_lv" && $insert->{txt30} ne "5511");#Tarif, exception sharee_lv + delete $insert->{txt15};#Bonusnr + delete $insert->{int07};#Rabatt + delete $insert->{txt18};#Service tour + delete $insert->{int05};#Web-Login + delete $insert->{int16};#payone-cron-interval + delete $insert->{int19};#Ilockit Admin + #delete $insert->{int12};#Vde (remove delete for global setting) + delete $insert->{txt29};#Sonstiges + } + + my $columns = ""; + my $values = ""; + + foreach my $key (keys(%$insert)){ + $insert->{$key} =~ s/^\s//g if($insert->{$key}); + $insert->{$key} =~ s/\s$//g if($insert->{$key}); + #because of time format without of looks_like_number + if($varenv{systype} && $varenv{systype} eq "azn" && $insert->{table} eq "contenttverpos" && $key =~ /start_at|end_at|int/){ + $columns .= "$key,"; + if(!$insert->{$key} || $insert->{$key} eq "null"){ + $values .= "null,"; + }else{ + $values .= "'$insert->{$key}',"; + } + } + #elsif($key =~ /contentadr_id|cc_id|ct_id|barcode|txt|int|time|owner/){ + #2021-03-04 changed with c_id, ct_name and only insert if value + elsif($key =~ /^c_id|ct_name|barcode|txt|int|time|owner/ && ($insert->{$key} || looks_like_number($insert->{$key}))){ + $columns .= "$key,"; + if($key =~ /_id|barcode|int|owner/ && !looks_like_number($insert->{$key})){ + $values .= "null,"; + }else{ + $values .= "'$insert->{$key}',"; + } + } + elsif($key =~ /template_id|cc_id|ct_id|ca_id/ && $insert->{table} =~ /contentpos|contentadrpos|contenttranspos/){ + $columns .= "$key,"; + $values .= "'$insert->{$key}',"; + } + } + + $columns =~ s/,$//; + $values =~ s/,$//; + + my $sql = "INSERT INTO $insert->{table} ($columns) VALUES ($values) RETURNING c_id"; + my $sth = $dbh->prepare($sql); + my $rows = $sth->execute(); + + my $last_id; + $sth->bind_columns(\$last_id); + my $c_id = $sth->fetchrow_array(); + $bw->log("insert_contentoid $source c_id: $c_id",$sql,"") if($debug); + + if($insert->{table} =~ /content$|contentadr|contenttrans$|contenttver$|contentusers$/ && $insert->{main_id} && $insert->{template_id}){ + my $foreignkey = ""; + $foreignkey = "ca_id" if($insert->{table} eq "contentadr"); + $foreignkey = "cc_id" if($insert->{table} eq "content"); + $foreignkey = "ct_id" if($insert->{table} eq "contenttrans"); + $foreignkey = "cu_id" if($insert->{table} eq "contentusers"); + $foreignkey = "cv_id" if($insert->{table} eq "contenttver"); + my $sql_rel = "INSERT INTO relation (main_id,content_id,template_id,change,$foreignkey) VALUES('$insert->{main_id}','$c_id','$insert->{template_id}','now()','$c_id')"; + my $sth3 = $dbh->prepare($sql_rel); + $sth3->execute(); + $bw->log("insert_contentoid relation $source c_id: $c_id",$sql_rel,"") if($debug); + } + + return $c_id; +} + + +#delete content +sub delete_content(){ + my $self = shift; + my $dbh = shift || $dbh_intern; + my $table = shift; + my $c_id = shift || 0; + my $template_id = shift || ""; + + my $source = $dbh->get_info( $GetInfoType{SQL_DATABASE_NAME} ); + my $rows = 0; + if($c_id){ + my $where = "c_id=$c_id"; + $where = "template_id = $template_id" if($table eq "contentpos" && $template_id && $c_id eq "all"); + $where = "u_id=$c_id" if($table eq "users"); + my $sql = "DELETE FROM $table WHERE $where"; + my $sth = $dbh->prepare($sql); + $rows = $sth->execute(); + $bw->log("delete_content $source: $rows",$sql,"") if($debug); + } + return $rows; +} + + +#collect contenttranspos with contenttrans +sub collect_transpos { + my $self = shift; + my $dbh = shift || $dbh_intern; + my $search = shift; + + $search->{offset} = 0 if(!$search->{offset}); + my $updown = "ASC"; + $updown = "DESC" if($search->{cal_sort_updown} eq "down"); + + my $where = "where cp.ct_id=ct.c_id"; + foreach my $key (%$search){ + $search->{$key} =~ s/\s//g; + $where .= " and cp.c_id = $search->{$key}" if($key eq "cttpos_id" && $search->{$key}); + $where .= " and cp.end_time >= '$search->{$key}'" if($key eq "start_date_time"); + $where .= " and cp.end_time <= '$search->{$key}'" if($key eq "end_date_time"); + $where .= " and cp.start_time <= '$search->{$key}'" if($key eq "end_date_time"); + $where .= " and cp.$key ilike '%$search->{$key}%'" if($key eq "txt08" && $search->{$key}); + $where .= " and (cp.int04 = $search->{$key} OR cp.int06 = $search->{$key})" if($key eq "int04" && looks_like_number($search->{$key})); + $where .= " and cp.ct_name = '$search->{$key}'" if($key eq "cp_ct_name" && $search->{$key}); + $where .= " and ct.ct_name = '$search->{$key}'" if($key eq "ct_ct_name" && $search->{$key}); + $where .= " and ct.txt06 ilike '$search->{$key}%'" if($key eq "ct_txt06" && $search->{$key});#PLZ + $where .= " and cp.$key = $search->{$key}" if($key eq "int10" && looks_like_number($search->{$key}));#bike_state + $where .= " and cp.$key = $search->{$key}" if($key eq "int20" && looks_like_number($search->{$key}));#lock_state + $where .= " and cp.$key = $search->{$key}" if($key eq "barcode" && looks_like_number($search->{$key})); + $where .= " and cp.$key = $search->{$key}" if($key eq "int12" && looks_like_number($search->{$key}));#bike_group + $where .= " and cp.$key = $search->{$key}" if($key eq "owner" && looks_like_number($search->{$key})); + } + $where .= " ORDER BY cp.end_time $updown LIMIT $search->{limit} OFFSET $search->{offset}" if($search->{limit}); + my $sth = $dbh->prepare("SELECT cp.* from $search->{table} cp, contenttrans ct $where"); + my $rc = $sth->execute(); + my $ct = $sth->fetchall_hashref("c_id"); + $sth->finish; + return $ct; +} + +#collect contenttheftpos +sub collect_theftpos { + my $self = shift; + my $dbh = shift || $dbh_intern; + my $search = shift; + + $search->{offset} = 0 if(!$search->{offset}); + my $updown = "ASC"; + $updown = "DESC" if($search->{cal_sort_updown} eq "down"); + + my $where = "where 1=1"; + foreach my $key (%$search){ + $search->{$key} =~ s/\s//g; + $where .= " and cp.c_id = $search->{$key}" if($key eq "cttpos_id" && $search->{$key}); + $where .= " and cp.end_time >= '$search->{$key}'" if($key eq "start_date_time"); + $where .= " and cp.end_time <= '$search->{$key}'" if($key eq "end_date_time"); + $where .= " and cp.start_time <= '$search->{$key}'" if($key eq "end_date_time"); + $where .= " and cp.$key ilike '%$search->{$key}%'" if($key eq "txt06" && $search->{$key}); + $where .= " and cp.$key = $search->{$key}" if($key eq "int10" && looks_like_number($search->{$key}));#bike_state + $where .= " and cp.$key = $search->{$key}" if($key eq "int20" && looks_like_number($search->{$key}));#lock_state + $where .= " and cp.$key = $search->{$key}" if($key eq "barcode" && looks_like_number($search->{$key})); + $where .= " and cp.$key = $search->{$key}" if($key eq "int12" && looks_like_number($search->{$key}));#bike_group + $where .= " and cp.$key = $search->{$key}" if($key eq "int13" && looks_like_number($search->{$key}));#deviceId + $where .= " and cp.$key = $search->{$key}" if($key eq "owner" && looks_like_number($search->{$key})); + } + $where .= " ORDER BY cp.end_time $updown LIMIT $search->{limit} OFFSET $search->{offset}" if($search->{limit}); + my $sth = $dbh->prepare("SELECT cp.* from $search->{table} cp $where"); + my $rc = $sth->execute(); + my $ct = $sth->fetchall_hashref("c_id"); + $sth->finish; + return $ct; +} + +# new node +sub insert_nodeoid(){ + my $self = shift; + my $dbh = shift || $dbh_intern; + my $insert = shift; + #my ($parent_id,$main_id,$node_name,$lang,$sort,$template_id,$c_id,$owner) = @_; + my $node_name = $insert->{node_name}; + my $node_path = $insert->{node_name}; + ($node_name,$node_path) = split(/\|/,$node_name) if($node_name =~ /\|/); + + my $sth2 = $dbh->prepare("INSERT INTO nodes (main_id,parent_id,lang,node_name,node_path,n_sort,owner) VALUES('$insert->{main_id}','$insert->{parent_id}','$insert->{lang}','$node_name','$node_path','$insert->{n_sort}','$insert->{owner}')"); + my $rc = $sth2->execute(); + $sth2 = $dbh->prepare("INSERT INTO relation (main_id,template_id,content_id,lang,change) VALUES('$insert->{main_id}','$insert->{template_id}','$insert->{content_id}','$insert->{lang}','now()') RETURNING rel_id"); + $rc = $sth2->execute(); + + my $last_id; + $sth2->bind_columns(\$last_id); + my $rel_id = $sth2->fetchrow_array(); + + return $rel_id; +} + +# Delete node and relation! (without content) +sub delete_noderel(){ + my $self = shift; + my $dbh = shift || $dbh_intern; + my $main_id = shift; + + my $sth = $dbh->prepare("DELETE FROM relation WHERE main_id=$main_id and content_id=0"); + my $rc = $sth->execute(); + $sth = $dbh->prepare("DELETE FROM nodes WHERE main_id=$main_id"); + $rc = $sth->execute(); + $sth->finish(); + return $rc; +} + +sub delete_template(){ + my $self = shift; + my $dbh = shift || $dbh_intern; + my $tpl_id = shift; + my $sth = $dbh->prepare("DELETE FROM template WHERE tpl_id=$tpl_id"); + my $rc = $sth->execute(); + return $rc; +} + +# get next free node +sub get_freenode(){ + my $self = shift; + my $dbh = shift || $dbh_intern; + my $prefix_id = shift; + + my $s_id = "$prefix_id"; + my $e_id = "$prefix_id"; + $s_id .= "00001"; + $e_id .= "99999"; + my $main_id = ""; + for (my $x_id=$s_id; $x_id < $e_id; $x_id++){ + my $sth1 = $dbh->prepare("SELECT main_id from nodes where main_id='$x_id'"); + my $rc1 = $sth1->execute(); + $main_id = $sth1->fetchrow_array(); + if(!$main_id){ + return $x_id; + } + } +} +# + +# get next free template id +sub get_freetpl(){ + my $self = shift; + my $dbh = shift || $dbh_intern; + my ($s_id,$e_id) = @_; + my $tpl_id = ""; + for (my $x_id=$s_id; $x_id < $e_id; $x_id++){ + my $sth1 = $dbh->prepare("SELECT tpl_id from template where tpl_id='$x_id'"); + my $rc1 = $sth1->execute(); + $tpl_id = $sth1->fetchrow_array(); + if(!$tpl_id){ + return $x_id; + } + } +} +# + +# copy template +sub copy_template(){ + my $self = shift; + my $dbh = shift || $dbh_intern; + my $master_tpl_id = shift; + my $new_tpl_id = shift; + my $owner = shift; + my $source = $dbh->get_info( $GetInfoType{SQL_DATABASE_NAME} ); + + my $columns = "tpl_name,tpl_order,ct_table,tpl_height,tpl_width,bg_color"; + my $sql = "INSERT INTO template ($columns) SELECT $columns from template where tpl_id=$master_tpl_id RETURNING tpl_id"; + my $sth = $dbh->prepare($sql); + my $rows = $sth->execute(); + + my $last_id; + $sth->bind_columns(\$last_id); + my $auto_tpl_id = $sth->fetchrow_array(); + $bw->log("DBtank copy_template $source: $rows",$sql,"") if($debug); + + my $sth2 = $dbh->prepare("UPDATE template set tpl_id=$new_tpl_id, change='now()',owner=$owner where tpl_id=$auto_tpl_id"); + $rows = $sth2->execute(); + + return $new_tpl_id; +} + + +#content of txt08 changed to ctadr->{txt01} Name +sub insert_pos(){ + my $self = shift; + my $dbh = shift || $dbh_intern; + my $ctt_id = shift; + my $ct = shift; + my $ctadr = shift; + my $ct_tariff = shift || ""; + my $endRental = shift || "0000-00-00"; + my $artikelnr = shift; + my $status = shift; + my $owner = shift; + + $artikelnr = $ct->{barcode} if(!$artikelnr);#RadID + my $user_name = $ctadr->{txt01}; + $user_name = $ctadr->{txt08} if(!$user_name || $user_name eq "no name"); + + my $deviceId = $ct->{int13} || 0; + my $bike_charge = $ct->{int19} || 0; + my $trackon = $ct->{int25} || 0; + my $from_main_id = $ct->{main_id} || 0; + my $station = $ct->{int04} || 0; + my $rabatt = 0; + my $unit_price = $ct->{int02} || 0; + my $day_maxprice = 0; + my $abo_price = 0; + my $tariff_nr = 0; + my $tariff_desc; + my $free_hours = 0; + my $sharing_type = 0; + my $menge = 0; + if(ref($ct_tariff) eq "HASH"){ + $rabatt = $ctadr->{int07} || 0; + $unit_price = $ct_tariff->{int02} || 0; + $tariff_nr = $ct_tariff->{barcode} || 0; + $tariff_desc = $ct_tariff->{ct_name}; + $day_maxprice = $ct_tariff->{int17} || 0; + $abo_price = $ct_tariff->{int15} || 0; + $free_hours = $ct_tariff->{int16} || 0; + $sharing_type = $ct_tariff->{int18} || 0; + } + + my $sth; + #Verleihräder + if($ct->{template_id} && $ct->{template_id} == 205){#Leihrad_list + $sth = $dbh->prepare("INSERT INTO contenttranspos (ct_id,cc_id,ca_id,ct_name,barcode,txt01,txt08,txt02,txt09,itime,start_time,end_time,int02,int03,int06,int04,txt05,txt06,txt07,int10,int12,int13,owner,int07,txt04,int09,int17,int15,int16,int11,int18,int19,txt17,txt18,int20,int25) VALUES ('$ctt_id','$ct->{c_id}','$ctadr->{c_id}','$artikelnr','$ct->{barcode}','$ct->{txt01}','$user_name','$ct->{txt02}','$ctadr->{txt09}',now(),now(),'$endRental','$unit_price','$menge','$station','$station','$ct->{txt06}','$ct->{txt06}','$ct->{txt07}','$status','$from_main_id','$deviceId','$owner','$rabatt','$tariff_desc','$tariff_nr','$day_maxprice','$abo_price','$free_hours','$ct->{int11}','$sharing_type','$bike_charge','$ct->{txt17}','$ct->{txt18}','$ct->{int20}','$trackon') RETURNING c_id"); + }else{ + $sth = $dbh->prepare("INSERT INTO contenttranspos (ct_id,cc_id,ca_id,ct_name,barcode,txt08,txt09,itime,int02,int03,txt01,txt06,txt07,int10,int12,owner) VALUES ('$ctt_id','$ct->{c_id}','$ctadr->{c_id}','$artikelnr','0','$user_name','$ctadr->{txt09}',now(),'$unit_price','1','$ct->{txt01}','$ct->{txt06}','$ct->{txt07}','0','$from_main_id','$owner') RETURNING c_id"); + } + my $rows = $sth->execute(); + my $last_id; + $sth->bind_columns(\$last_id); + my $c_id = $sth->fetchrow_array(); + + if($c_id && $status){ + #update Leihräder in Stammdaten + my $set2 = "owner=$owner" if($owner); + $set2 .= ",int10='$status'" if($status); + $set2 .= ",mtime='now()'"; + my $sth2 = $dbh->prepare("UPDATE content SET $set2 where barcode='$ct->{barcode}'"); + my $rows2 = $sth2->execute(); + } + + return $c_id; +} + +# insert contenttrans +sub insert_contenttrans(){ + my $self = shift; + my $dbh = shift || $dbh_intern; + my $ctadr = shift; + my $main_id = shift; + my $tpl_id = shift; + my $invoice_nr = shift || "----"; + my $owner = shift || 0; + + $owner="199" if(!$owner); + my $sth = $dbh->prepare("INSERT INTO contenttrans (ct_name,txt00,int10,int03,txt02,txt01,txt03,txt06,txt07,txt08,txt09,txt15,txt17,txt18,txt19,owner,itime) VALUES('$invoice_nr','Rechnung','$ctadr->{c_id}','$ctadr->{int03}','$ctadr->{txt02}','$ctadr->{txt01}','$ctadr->{txt03}','$ctadr->{txt06}','$ctadr->{txt07}','$ctadr->{txt08}','$ctadr->{txt09}','$ctadr->{txt15}','$ctadr->{txt17}','$ctadr->{txt18}','$ctadr->{txt19}','$owner','now()') RETURNING c_id"); + + my $rows = $sth->execute(); + my $last_id; + $sth->bind_columns(\$last_id); + my $c_id = $sth->fetchrow_array(); + + my $sth3 = $dbh->prepare("INSERT INTO relation (ca_id,main_id,content_id,template_id,change) VALUES('$ctadr->{c_id}','$main_id','$c_id','$tpl_id','now()')"); + $sth3->execute(); + return $c_id; +} + +#compute amount of wawi content +sub update_content4comp(){ + my $self = shift; + my $dbh = shift || $dbh_intern; + my $c_id = shift || 0; + my $op = shift; + my $amount = shift; + + my $where = "c_id=$c_id"; + my $ct_set = "int03=(int03 $op $amount)"; + my $sth = $dbh->prepare("UPDATE content SET $ct_set where $where"); + my $rows = $sth->execute(); + return $rows; +} + +1; diff --git a/copri4/main/src/Mod/Failure.pm b/copri4/main/src/Mod/Failure.pm new file mode 100644 index 0000000..ec3f523 --- /dev/null +++ b/copri4/main/src/Mod/Failure.pm @@ -0,0 +1,96 @@ +package Failure; +# +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; +use CGI::Carp qw(fatalsToBrowser); +use CGI ':standard'; +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Libenzdb; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my ($main_id,$u_id,$lang,$bg_color1,$bg_color2,$level,$failure) = @_; + + my $q = new CGI; + my $cf = new Config; + my $lb = new Libenz; + my $db = new Libenzdb; + my $but = new Buttons; + my %varenv = $cf->envonline(); + my $path = $q->path_info(); + $path =~ s/\/user|\/manager|\/admin//; + my $script = $q->script_name(); + my %ib = $but->ibuttons(); + $failure =~ s/failure:://g; + my ($link,$lname,$link2,$lname2); + ($failure,$link,$lname,$link2,$lname2) = split(/::/,$failure); + my $width="600"; + my $height="300"; + #my $bg_color = $varenv{background_color} || "white"; + #my $bg_color2 = $varenv{background_color2} || ""; + + if($failure =~ /Newsletter Versandt/){ + $width="600"; + $height="700"; + } + +print< + .ui-dialog .ui-dialog-content { + background: $bg_color1; + } + .ui-dialog > .ui-widget-header { + color:red; + font-weight:normal; + border:1px solid $bg_color2; + background: $bg_color2; + } + + + +EOF +; + + my $title = "Achtung"; + my $back = "zurück"; + my $font_size = ""; + print "
    "; + + + print "
    \n"; + print $q->div("$failure"); + + print "\n"; + + print $q->div({-style=>'float:left;padding:1em;'}, $q->a({-class=>"linknav2",-href=>"$link",-title=>''}, " $lname ")) if($lname); + print $q->div({-style=>'float:left;padding:1em;'}, $q->a({-class=>"linknav2",-href=>"$link2",-title=>''}, " $lname2 ")) if($lname2); + print $q->div({-style=>'float:left;padding:1em;'},$q->a({-class=>"linknav2",-href=>'javascript:history.back()'}, " $back ")); + print "
    \n"; + + print "
    "; +} +1; diff --git a/copri4/main/src/Mod/FileOut.pm b/copri4/main/src/Mod/FileOut.pm new file mode 100644 index 0000000..db4227c --- /dev/null +++ b/copri4/main/src/Mod/FileOut.pm @@ -0,0 +1,44 @@ +package Mod::FileOut; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings FATAL => 'all'; + +use CGI::Cookie (); +use CGI ':standard'; +use Apache2::RequestUtil (); +use Apache2::RequestIO (); +use Apache2::Const -compile => qw(OK); + +use File::Path qw(make_path remove_tree); +use File::Copy; +use File::Copy::Recursive qw(fcopy rcopy dircopy fmove rmove dirmove); + +use Lib::Config; + + +sub handler { + my $r = shift; + my $q = new CGI(); + my $coo = $q->cookie(-name=>'domcookie') || $q->param('sessionid') || 'zvzfcxd578'; + + my $cf = new Config; + my %varenv = $cf->envonline(); + my $filesuff = $q->param('file'); + + my $dir = $varenv{data}; + $dir = $varenv{pdfinvoice} if($varenv{pdfinvoice}); + rcopy("$dir/$filesuff","$varenv{basedir}/cache/$coo/$filesuff"); + print $q->redirect(-uri=>"$varenv{metahost}/cache/$coo/$filesuff", -type=>"application/octet-stream"); + #remove_tree("$varenv{basedir}/cache/$coo"); + # + #my $file = $varenv{data} . "/" . $filesuff; + #my $status = $r->sendfile($file); + + return Apache2::Const::OK; + +} + +1; diff --git a/copri4/main/src/Mod/Indexsharee.pm b/copri4/main/src/Mod/Indexsharee.pm new file mode 100644 index 0000000..abc55a9 --- /dev/null +++ b/copri4/main/src/Mod/Indexsharee.pm @@ -0,0 +1,812 @@ +package Mod::Indexsharee; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +# +use strict; +use warnings; + +use POSIX; +use CGI::Cookie (); +use CGI ':standard'; +use DateTime; +use DateTime::Format::Pg; +use DBI; +use Apache2::RequestUtil (); +use Apache2::RequestIO (); +use Apache2::Const -compile => qw(OK); +use LWP::UserAgent; +use Digest::MD5 qw(md5 md5_hex); +#use Encode; +#use URI::Encode qw(uri_encode uri_decode); + +use Lib::Config; +use Mod::Buttons; +use Mod::Prelogic; +use Lib::Mlogic; +use Mod::Basework; +use Mod::Premain; +use Mod::DBtank; +use Mod::Libenzdb; +use Mod::APIfunc; +use Mod::Shareework; +use Mod::Prelib; +use Mod::Payment; +use Mod::Modalbox; +use Mod::Modalbox3; +use Data::Dumper; + +sub handler { + my $re = shift; + my $q = new CGI(); + $q->import_names('R'); + my $cf = new Config; + my $ml = new Mlogic; + my $bw = new Basework; + my $pre = new Prelogic; + my $pm = new Premain; + my $tk = new Shareework; + my $dbt = new DBtank; + my $db = new Libenzdb; + my $apif = new APIfunc; + my $but = new Buttons; + my $pl = new Prelib; + my $payone = new Payment; + + my %varenv = $cf->envonline(); + my $netloc = $q->url(-base=>1); + #main datadir is main config directive like "shareeapp-kn" and catched by syshost name + if($netloc =~ /:\/\/(sharee\w+-\w+)\.copri/){ + #$bw->log("Indexsharee merchant select by netloc:",$netloc,""); + $varenv{syshost} = $1 if( -d "/var/www/copri4/$1"); + } + die "no configuration available" if(!$varenv{syshost}); + + my $dbh = ""; + my $script = $q->script_name(); + my $path = $q->path_info(); + $path = "$script" . "$path"; + my $refer = $ENV{HTTP_REFERER}; + my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; + my $return = ""; + my $returnwww = ""; + my $html_charset = "utf-8"; + my $user_agent = $q->user_agent(); + $path =~ s/\.html//; + + #$mode is used to set GUI features like "maintainer" contextmenue + my $modes = $dbt->{shareedms_conf}->{modes}; + my $mode = ""; + if($R::mode && length($R::mode) >= 5 && $R::mode =~ /($modes)/){ + $mode = "$R::mode"; + }elsif($path && $path =~ /\/($modes)$/){ + $mode = $1; + }elsif($path && $path =~ /\/($modes)\?\w/){ + $mode = $1; + } + + my $aowner = 197;#user agent access_owner --> Web Formular + $varenv{merchant_id} = "niejeiC7iu";#2021-12-08 merchant fallback + if($varenv{syshost} =~ /shareedms-/){ + $aowner = 196; + $varenv{merchant_id} = "Ohmeew0gie"; + $mode = "manager" if(!$mode); + } + + if($varenv{orga} ne "dms" && $path =~ /DMS|Waren|Kunden\/|Einstellung|journal|Faktur/i){ + print redirect("$varenv{wwwhost}"); + exit 0; + } + + my $lang = "de"; + my $dyn_js = ""; + my $users_dms = {}; + my $users_sharee = {}; + my $api_return = {}; + + print $q->header(-charset=>"$html_charset"); + + my $coo = $q->cookie('domcookie') || $R::sessionid || ""; + #Prio sessionid if also domcookie is set ... and s.u. + if($R::sessionid && $R::sessionid ne $q->cookie('domcookie')){ + $coo = $q->param('sessionid'); + my $cookie = CGI::Cookie->new(-name => 'domcookie',-value => $coo); + print $q->header(-charset=>"$html_charset", -cookie=>$cookie); + } + + ($api_return,$users_sharee) = $apif->auth_verify($q,$coo,""); + +my $merchanized = 0; +my $merchant_conf = ""; +#merchant select by user_agent -> disabled +#while (($merchant_conf, my $value) = each %{ $dbt->{merchant_ids}}) { +# if($merchant_conf && $value->{user_agent} && $user_agent && $user_agent =~ /$value->{user_agent}/){ +# $aowner = $value->{id}; +# $varenv{merchant_id} = $merchant_conf; +# $merchanized = 1; +# $bw->log("Indexsharee merchant select by user_agent: if($merchant_conf && $value->{user_agent} && $user_agent && $user_agent =~ /$value->{user_agent}/){",$varenv{merchant_id},""); +# last; +# } +#} + +if(!$merchanized){ + while (($merchant_conf, my $value) = each %{ $dbt->{merchant_ids}}) { + if($merchant_conf && (($coo && $coo =~ /$merchant_conf$/) || ($R::sessionid && $R::sessionid =~ /$merchant_conf$/) || ($R::authcookie && $R::authcookie =~ /$merchant_conf$/) || ($R::merchant_id && $R::merchant_id eq $merchant_conf))){ + $aowner = $value->{id}; + $varenv{merchant_id} = $merchant_conf; + $merchanized = 1; + $bw->log("Indexsharee merchant select by authcookie OR merchant_id: if($merchant_conf && (($R::sessionid && $R::sessionid =~ /$merchant_conf$/) || ($R::authcookie && $R::authcookie =~ /$merchant_conf$/) || ($R::merchant_id && $R::merchant_id eq $merchant_conf))){",$merchant_conf,""); + last; + } + } +} + +if(!$merchanized){ + if($varenv{syshost} eq "shareeapp-primary"){ + $aowner = $dbt->{primary}->{sharee_primary}->{owner}; + $varenv{merchant_id} = $dbt->{primary}->{sharee_primary}->{merchant_id}; + $merchanized = 1; + $bw->log("Indexsharee merchant select by $varenv{syshost} eq 'shareeapp-primary':",$varenv{merchant_id},""); + } + if($varenv{syshost} =~ /shareeweb-/){ + $aowner = $dbt->{website}->{$varenv{syshost}}->{owner}; + $varenv{merchant_id} = $dbt->{website}->{$varenv{syshost}}->{merchant_id}; + $merchanized = 1; + $bw->log("Indexsharee merchant select by syshost=$varenv{syshost}:",$varenv{merchant_id},""); + } +} + + $bw->log("Indexsharee merchant select used with access_owner $aowner",$varenv{merchant_id},""); + + #login-screen should only be available if auth_verify fails + if($R::login_sharee || $R::login_dms){ + + #1. logout + $apif->authout($q,$coo); + + my $hw_id = unpack ('H*', pack('Nc', time, $$ % 0xff));#old $co + #3. authorize + my $author = $apif->authorization($q,$varenv{merchant_id},$hw_id,$aowner);#$co like browser hw_id + #4. verify and get user values + ($api_return,$users_sharee) = $apif->auth_verify($q,$author->{authcookie},"",$author->{new_authcoo}); + + #5. domcookie by authcookie substr (cut first 15 chars), AND also sessionid + if($author->{authcookie} && length($author->{authcookie}) > 30){ + # take last 21 chars + $coo = substr $author->{authcookie}, 15; + my $cookie = CGI::Cookie->new(-name => 'domcookie',-value => $coo); + print $q->header(-charset=>"$html_charset", -cookie=>$cookie); + + #DMS login + if($users_sharee->{c_id} && $varenv{orga} eq "dms" && $R::login_dms eq "Login" && $coo && length($coo) > 20){ + $users_dms = $dbt->select_users($dbh,$users_sharee->{c_id}); + my $update_users = { + table => "users", + owner => $aowner, + u_id => $users_dms->{u_id} + }; + $dbt->update_one($dbh,$update_users,"cookie='$coo'") if($users_dms->{u_id}); + + print redirect("$varenv{wwwhost}$path"); + exit 0; + } + } + } + + my $session=""; + my $session_and=""; + if(length($coo) > 20 && !$q->cookie(-name=>'domcookie')){ + $session = "?sessionid=$coo"; + $session_and = "&sessionid=$coo"; + } + + #DMS + if($users_sharee->{c_id} && $varenv{orga} eq "dms" && $coo && length($coo) > 20){ + $users_dms = $dbt->select_users($dbh,$users_sharee->{c_id},"and cookie='$coo'"); + } + + + #Save anyway on create ... and hopefully delete it later + if($R::sharee_edit && $R::sharee_edit =~ /create_account/ && $R::txt04 && $R::txt04 =~ /\w+/ && $R::txt08 && $R::txt08 =~ /\w+\@\w+/){ + + #1. logout + $apif->authout($q,$coo); + + #create_account. 2. inserts contentadr + my $tinkc_id = $tk->create_account($aowner); + ($returnwww,$return) = $tk->save_account($tinkc_id,"",$aowner); + + #Like login_sharee, redundant + my $hw_id = unpack ('H*', pack('Nc', time, $$ % 0xff));#old $co + #3. authorize + my $author = $apif->authorization($q,$varenv{merchant_id},$hw_id,$aowner);#$co like browser hw_id + #print "3. authorize: " . $author->{authcookie} . " -- " . $q->param('authcookie') . " ++ " . $coo . "
    "; + + #4. verify and get user values + ($api_return,$users_sharee) = $apif->auth_verify($q,$author->{authcookie},"",$author->{new_authcoo}); + #print "4. verifyize: " . $author->{authcookie} . " -- c_id: " . $users_sharee->{c_id} . " ++ " . $coo . "
    "; + + #5. domcookie by authcookie substr (cut first 15 chars), AND also sessionid + if($author->{authcookie} && length($author->{authcookie}) > 30){ + # take last 21 chars + $coo = substr $author->{authcookie}, 15; + my $cookie = CGI::Cookie->new(-name => 'domcookie',-value => $coo); + print $q->header(-charset=>"$html_charset", -cookie=>$cookie); + #print "5. set cookie: " . $author->{authcookie} . " -- " . $q->param('authcookie') . " ++ " . $coo . "
    "; + + #2020-07-09 if user-pw authorized, then ignore conflict_ because it matches exist user-data + if($tinkc_id && $returnwww && $returnwww =~ /conflict_txt07|conflict_txt08/){ + #delete user-pw conflict registration and going on with existing data + $db->delete_content("contentadr",$tinkc_id); + $apif->authout($q,$coo) if($coo); + print redirect("$varenv{wwwhost}/$varenv{mandant}/Anmelden?conflict_failure=1"); + exit 0; + } + elsif(length($coo) > 20){ + #we need this to get $R::sessionid to FormEdit + #if(length($coo) > 20 && !$q->cookie(-name=>'domcookie')){ + ($api_return,$users_sharee) = $apif->auth_verify($q,$author->{authcookie},""); + if($R::failure =~ /\w+/ || ($users_sharee->{txt31} && $users_sharee->{txt31} =~ /\w/)){ + print redirect("$varenv{wwwhost}/$varenv{mandant}/Account/$varenv{accounting_1}?sessionid=$coo"); + exit 0; + }else{ + print redirect("$varenv{wwwhost}/$varenv{mandant}/Account/$varenv{accounting_1_5}?sessionid=$coo"); + exit 0; + } + } + } + } + + my $payable_check=0; + if($users_sharee->{int03} && $users_sharee->{ct_name} && ($users_sharee->{int03} == 1 && $users_sharee->{ct_name} =~ /\w{2}-\d+/) || ($users_sharee->{int03} == 2 && length($users_sharee->{ct_name}) >= 19)){ + $payable_check=1; + } + + + # Logout + if($mode =~ /logout/){ + if($mode =~ /logout_sharee/){ + $apif->authout($q,$coo); + }else{ + $db->cook_out($coo); + } + print redirect("$varenv{wwwhost}"); + exit 0; + } + + my $tpl = $dbt->get_tpl($dbh,"302001");#Kundendaten template + $tpl->{tpl_order} .= ",txt04,txt08"; + + + if($R::login_sharee){ + if($users_sharee->{c_id} && (($users_sharee->{int03} != 1 && $users_sharee->{int03} != 2)|| ($users_sharee->{txt31} && $tpl->{tpl_order} =~ /$users_sharee->{txt31}/))){ + my $row = $db->updater("contentadr","c_id","$users_sharee->{c_id}","int12","1");#Vde + print redirect("$varenv{wwwhost}/$varenv{mandant}/Account/$varenv{accounting_1}$session"); + exit 0; + }elsif($users_sharee->{c_id} && !$payable_check){ + #print redirect("$varenv{wwwhost}/$varenv{mandant}/$varenv{profile}"); + #print redirect("$varenv{wwwhost}/$varenv{mandant}/$varenv{start}"); + print redirect("$varenv{wwwhost}/$varenv{mandant}/Account/$varenv{accounting_2}$session"); + exit 0; + }elsif(!$users_sharee->{c_id} || ($users_sharee->{c_id} && $users_sharee->{c_id} !~ /^\d+$/)){ + print redirect("$varenv{wwwhost}/$varenv{mandant}/Anmelden?failure=1$session_and"); + exit 0; + }else{ + print redirect("$varenv{wwwhost}/$varenv{mandant}/$varenv{profile}$session"); + exit 0; + } + } + + my $oncontextmenu=""; + $oncontextmenu="return false;";# if($mode =~ /maintainer/); + $oncontextmenu="" if(!$users_dms->{u_id}); + + + #Menu & node_path handling + my ($view,$view_post); + my @viewsel = ("shareestart"); + if($path =~ /^\/(.*)/){ + @viewsel = split /\//,$1; + if("$path" =~ /\/($modes)$/){ + pop @viewsel; + } + $view_post = $viewsel[-1] || "root"; + #$view_post = encode('iso-8859-1',decode('utf-8', $view_post)); + $view = $viewsel[0]; + } + my $depth = scalar(@viewsel); + $view = "root" if(!$view); + + my $node_meta = $dbt->get_node_meta($dbh,\@viewsel); + + #DMS & Tools + if($varenv{orga} eq "dms" && $users_dms->{u_id}){ + if($R::cal_delta_start){ + use Date::Calc qw(Add_Delta_YMD); + my $day = strftime "%d", localtime; + my $mon = strftime "%m", localtime; + my $year = strftime "%Y", localtime; + $users_dms->{cal_start} =~ s/\s.*//; + ($year,$mon,$day) = split(/-/,$users_dms->{cal_start}) if($users_dms->{cal_start}); + my ($year1,$mon1,$day1) = split(/:/,$R::cal_delta_start); + my ($Dy,$Dm,$Dd) = Add_Delta_YMD($year,$mon,$day, $year1,$mon1,$day1); + $db->users_up("cal_start","$Dy-$Dm-$Dd",$users_dms->{u_id}); + } + if($R::cal_today){ + my $today4db = strftime("%Y-%m-%d %H:%M",localtime(time)); + $db->users_up("cal_start","$today4db",$users_dms->{u_id}); + } + if($R::col_sort){ + $db->users_up("col_sort",$R::col_sort,$users_dms->{u_id}); + } + if($R::sort_updown){ + $db->users_up("sort_updown",$R::sort_updown,$users_dms->{u_id}); + } + if($R::cal_sort_updown){ + $db->users_up("cal_sort_updown",$R::cal_sort_updown,$users_dms->{u_id}); + } + + #base_edit implements new DMS methodes without Pre* things + #permissions + #DMS Kunden rw + if($R::base_edit && $node_meta->{ct_table} eq "contentadr"){ + if($R::c_id && $R::base_edit eq "remove_chk4rel"){ + my $delete_key = "delete_content"; + $delete_key = "delete_adr"; + $return = "failure::Datensatz wirklich löschen. ::?base_edit=$delete_key\&exit_box2=1\&c_id=$R::c_id ::löschen"; + }elsif($users_dms->{int02} == 2 && $R::c_id && $R::base_edit eq "save_adr"){ + ($returnwww,$return) = $tk->save_account($R::c_id,$coo,$users_dms->{u_id}); + }elsif($users_dms->{int02} == 2 && $R::c_id && $R::base_edit eq "delete_adr"){ + $return = $tk->delete_account($R::c_id,$users_dms->{u_id}); + }else{ + $return = "failure::Abbruch. Schreibender Zugriff \"Kunden Stammdaten\" verweigert."; + } + } + + #DMS users accounts + if($R::base_edit && $node_meta->{ct_table} eq "users"){#DMS-Account rw + if($R::u_id && $R::base_edit eq "remove_chk4rel"){#users + my $delete_key = "delete_dmsusers"; + $return = "failure::Datensatz wirklich löschen. ::?base_edit=$delete_key\&exit_box2=1\&u_id=$R::u_id ::löschen"; + }elsif($users_dms->{int07} == 2 && ($R::u_id || $R::c_idadr) && $R::base_edit =~ /_dmsusers/){ + my $u_id = $1 if($R::u_id && $R::u_id =~ /(\d+)/); + $u_id = $1 if($R::c_idadr && $R::c_idadr =~ /(\d+)/ && $R::base_edit eq "new_dmsusers"); + $return = $tk->manage_dmsusers($R::base_edit,$u_id,$users_dms); + }else{ + $return = "failure::Abbruch. Schreibender Zugriff \"DMS-Account\" verweigert."; + } + } + + #DMS Waren || Einstellung/Service* rw + if($node_meta->{ct_table} eq "content" || $node_meta->{ct_table} eq "contentuser"){ + if(($node_meta->{ct_table} eq "content" && $users_dms->{int01} == 2) || ($node_meta->{ct_table} eq "contentuser" && $users_dms->{int08} == 2)){ + if($R::rel_edit eq "save_relation" && $R::main_id && $R::main_id >= 200000){ + $return = $pl->save_relation($R::main_id,$users_dms->{u_id}); + }elsif($R::rel_edit eq "delete_relation" && $R::main_id && $R::main_id >= 200000){ + $return = $pl->delete_relation($R::main_id,$users_dms->{u_id}); + }elsif($R::rel_edit eq "new_relation" && $R::main_id && $R::main_id >= 200000){ + $return = $pl->new_relation($R::main_id,$users_dms->{u_id}); + }else{ + $return = $pm->maininit($users_dms); + } + }elsif($R::rel_edit){ + $return = "failure::Abbruch. Schreibender Zugriff \"Waren Stammdaten\" verweigert."; + } + } + + #DMS Faktura + if($node_meta->{ct_table} eq "contenttrans"){ + if($users_dms->{int03} == 1 && $R::ct_trans eq "open"){#DMS Faktura read + $db->update_users4trans($R::c_id4trans,$R::tpl_id4trans,$R::kind_of_trans,$users_dms->{u_id}); + }elsif($users_dms->{int03} == 2){#DMS Faktura rw + $return .= "|"; + $return .= $pre->preinit($users_dms,$lang);#transactions logic + }elsif($R::ct_trans){ + $return = "failure::Abbruch. Schreibender Zugriff \"Faktura\" verweigert."; + } + } + + #none DMS hosts ---------------------------------------------------- + }elsif($varenv{orga} ne "dms"){ + + + + + #save_account. 3. updates contentadr + if($users_sharee->{c_id} && $R::sharee_edit && $R::sharee_edit =~ /save_account/){ + ($returnwww,$return) = $tk->save_account($users_sharee->{c_id},$coo,$aowner); + } + + if($users_sharee->{c_id} && $R::sharee_edit && $R::sharee_edit =~ /save_transact/){ + $returnwww = $tk->save_transact($users_sharee->{c_id},$coo,$aowner); + } + + if($returnwww && $returnwww =~ /failure::(.*)/){ + $returnwww =~ s/::/=/g; + ($api_return,$users_sharee) = $apif->auth_verify($q,$coo,""); + + if($returnwww =~ /txt22|txt23/){ + print redirect("$varenv{wwwhost}/$varenv{mandant}/Account/$varenv{accounting_2}?cum=1$session_and\&$returnwww"); + }elsif($returnwww =~ /int03/){ + print redirect("$varenv{wwwhost}/$varenv{mandant}/Account/$varenv{accounting_1_5}?cum=1$session_and\&$returnwww"); + }elsif($returnwww =~ /txt09|txt16/){ + print redirect("$varenv{wwwhost}/$varenv{mandant}/Account/$varenv{accounting_3}?cum=1$session_and\&$returnwww"); + }elsif($returnwww =~ /int01/ && $R::radID){ + print redirect("$varenv{wwwhost}/?ask_radID=$R::radID\&failure=not-synced$session_and"); + }else{ + print redirect("$varenv{wwwhost}/$varenv{mandant}/Account/$varenv{accounting_1}?cum=1$session_and\&$returnwww"); + } + exit 0; + }else{ + ($api_return,$users_sharee) = $apif->auth_verify($q,$coo,""); + + + #Payone Response POST (TransactionStatus) + #payone response ($R::pseudocardpan || $R::status) + if($users_sharee->{c_id} && ($R::pseudocardpan || $R::status)){ + my $payone_return; + open(FILE,">>$varenv{logdir}/payone-return-post.log"); + print FILE "<--- $now_dt from Indextink.pm \nPayone return-way by ajaxCall: $R::status\n"; + my @keywords = $q->param; + foreach(@keywords){ + my $val = $q->param($_); + print FILE "$_=$val\n"; + #TODO, check errormessages. At first we have do indicate what comes from payone! + $payone_return .= "$_=$val\n";# if($_ =~ /error|message/i); + } + close(FILE); + + my $update_adr = { + table => "contentadr", + mtime => "now()", + owner => $aowner, + c_id => $users_sharee->{c_id} + }; + my $vde_on_fail = $users_sharee->{int12} || 3;#keep last or set 3 + + #SEPA, done in payone Payment + #CC + if($R::pseudocardpan && length($R::pseudocardpan) >= 19){#done by payone AJAX return + #if($R::status eq "APPROVED") + $update_adr->{txt22} = ""; + $update_adr->{txt23} = ""; + $update_adr->{ct_name} = $q->escapeHTML($R::pseudocardpan); + $update_adr->{txt27} = $q->escapeHTML($R::status); + $update_adr->{txt28} = ""; + $update_adr->{int12} = 0; + $update_adr->{int03} = 2; + $dbt->update_record($dbh,$update_adr,$users_sharee) if($users_sharee->{c_id} > 0); + ($api_return,$users_sharee) = $apif->auth_verify($q,$coo,""); + + #define fictiv invoice to get 1 € test + my $epoche = time(); + my $ctt = { + c_id => 1, + int01 => 0,#capture amount + int15 => 1,#preauth amount + txt16 => "", + reference => "$users_sharee->{c_id}_$epoche", + renewed => '' + }; + my $payone_txid = ""; + $payone_txid = $payone->preauthorizationCC_main(\%varenv,$users_sharee,$ctt,$aowner); + if($payone_txid){ + $ctt->{txt16} = "$payone_txid"; + $payone_txid = $payone->captureCC_main(\%varenv,$users_sharee,$ctt,$aowner); + }else{ + $dbt->update_one($dbh,$update_adr,"int12=$vde_on_fail");#Vde + } + + $tk->emailack($users_sharee->{c_id}) if($users_sharee->{int04} != 1); + $dbt->update_operatorsloop($varenv{dbname},$users_sharee->{c_id},"update"); + + print redirect("$varenv{wwwhost}/$varenv{mandant}/$varenv{profile}?$returnwww$session_and"); + exit 0; + }else{ + $update_adr->{txt28} = $q->escapeHTML($payone_return); + $update_adr->{int12} = $vde_on_fail; + $dbt->update_record($dbh,$update_adr,$users_sharee) if($users_sharee->{c_id} > 0); + $dbt->update_operatorsloop($varenv{dbname},$users_sharee->{c_id},"update"); + } + } + } + + + my $debug=0; + $debug=1; + #send confirm codes + if($users_sharee->{c_id} && $users_sharee->{txt34} && length($users_sharee->{txt34}) > 20 && $payable_check && $R::sharee_edit && $R::sharee_edit =~ /save_account|send_email|send_sms/){ + + if(($users_sharee->{int04} != 1 || $R::sharee_edit =~ /send_email/) && ($users_sharee->{txt08} =~ /\w\@\w/)){ + $tk->emailack($users_sharee->{c_id}); + } + if(($users_sharee->{int13} != 1 || $R::sharee_edit =~ /send_sms/) && ($users_sharee->{txt07} =~ /\d{9}/ && length($users_sharee->{txt07}) <= 16 && $users_sharee->{txt07} =~ /\+[1-9]{3}/)){ + $tk->smsack($users_sharee); + } + }#send confirm code + + #email and sms acknowledgments, check and save confirm states + if($R::confirm_userid && $R::confirm_userid =~ /^\d+$/ && ($R::confirm_code && length($R::confirm_code) >= 5 || $R::confirm_smscode && length($R::confirm_smscode) >= 5)){ + + #keep in mind, for now and just for testing confirm codes are just c_id + open(FILE,">>$varenv{logdir}/confirm.log") if($debug); + print FILE "\n\n*--> $now_dt done by $0\n" if($debug); + print FILE "confirm_userid:$R::confirm_userid\nconfirm_code:$R::confirm_code\nconfirm_smscode:$R::confirm_smscode\n" if($debug); + $R::confirm_code =~ s/\s//g; + $R::confirm_smscode =~ s/\s//g; + my $confirm_code = $q->escapeHTML($R::confirm_code); + my $confirm_smscode = $q->escapeHTML($R::confirm_smscode); + + #confirm email + if($confirm_code){ + my $authref = { + table => "contentadr", + fetch => "one", + template_id => "202", + c_id => $R::confirm_userid, + txt34 => "ilike::$confirm_code%", + }; + my $confirmed_email = $dbt->fetch_record($dbh,$authref); + + #($api_return,$users_sharee) = $apif->auth_verify($q,"",$R::confirm_code); + if($confirmed_email->{c_id}){ + $db->updater("contentadr","c_id","$confirmed_email->{c_id}","int04","1"); + #save verified email + $db->updater("contentadr","c_id","$confirmed_email->{c_id}","txt32","$confirmed_email->{txt08}"); + print FILE "confirmed_email: $confirmed_email->{c_id} update because confirm_code:$confirm_code\n" if($debug); + + #after mailAck, delete all douple adr with no mailAck and no invoices + my $ctadr = $db->collect_ct4rel3("contentadr","","","ilike","txt08","$confirmed_email->{txt08}","","",""); + foreach my $aid (keys(%$ctadr)){ + if(!$ctadr->{$aid}->{int04}){ + my $ctctt = $db->get_content6("contenttrans","int10",$ctadr->{$aid}->{c_id}); + $db->delete_content("contentadr",$ctadr->{$aid}->{c_id}) if(!$ctctt->{c_id}); + print FILE "c_id $ctadr->{$aid}->{c_id} $confirmed_email->{txt08} delete because of dopplel\n" if($debug); + } + } + } + } + #confirm sms + if($confirm_smscode){ + my $authref = { + table => "contentadr", + fetch => "one", + template_id => "202", + c_id => $R::confirm_userid, + txt34 => "ilike::%$confirm_smscode", + }; + my $confirmed_sms = $dbt->fetch_record($dbh,$authref); + + #($api_return,$users_sharee) = $apif->auth_verify($q,"",$R::confirm_smscode); + if($confirmed_sms->{c_id}){ + $db->updater("contentadr","c_id","$confirmed_sms->{c_id}","int13","1"); + #save verified telnr + $db->updater("contentadr","c_id","$confirmed_sms->{c_id}","txt33","$confirmed_sms->{txt07}"); + print FILE "confirmed_sms: $confirmed_sms->{c_id} update because confirm_smscode:$confirm_smscode\n" if($debug); + } + } + + ($api_return,$users_sharee) = $apif->auth_verify($q,"",$users_sharee->{c_id}) if($users_sharee->{c_id}); + + if($users_sharee->{int12} != 2 && $users_sharee->{int04} && $users_sharee->{int13}){ + my $row = $db->updater("contentadr","c_id","$users_sharee->{c_id}","int12","0");#Vde + $dbt->update_operatorsloop($varenv{dbname},$users_sharee->{c_id},"update"); + }else{ + my $field = "int13"; + $field = "int04" if(!$users_sharee->{int04}); + print redirect("$varenv{wwwhost}/$varenv{mandant}/Account/$varenv{accounting_3}?cum=3$session_and\&failure=$field#top"); + exit 0; + } + + if(!$coo){ + print FILE "c_id: $users_sharee->{c_id} empty auth because of no cookie\n" if($debug); + $users_sharee = { c_id => 0 }; + } + close(FILE) if($debug); + if($users_sharee->{c_id} && $users_sharee->{int04} && $users_sharee->{int13}){ + print redirect("$varenv{wwwhost}/$varenv{mandant}/Account/$varenv{accounting_3}?confirm_success=1"); + exit 0; + } + }#end confirm + + if($R::email && $R::sharee_edit =~ /password_forgotten/){ + my $hw_id = unpack ('H*', pack('Nc', time, $$ % 0xff));#old $co + $tk->send_password($R::email,$hw_id,$aowner); + } + + #redirections + if($users_sharee->{c_id} && ($path =~ /$varenv{mandant}\/$varenv{profile}/ || $path =~ /$varenv{mandant}\/Account/)){ + + if($R::sharee_edit =~ /save_account/){ + $returnwww =~ s/::/=/g if($returnwww && $returnwww =~ /success::\w+/); + + if((!$users_sharee->{int14}) || ($users_sharee->{txt31} && $tpl->{tpl_order} =~ /$users_sharee->{txt31}/)){ + #failure redirect should do the delete job + print redirect("$varenv{wwwhost}/$varenv{mandant}/Account/$varenv{accounting_1}?failure=$users_sharee->{txt31}$session_and#top"); + exit 0; + } + elsif(!$users_sharee->{int03}){ + print redirect("$varenv{wwwhost}/$varenv{mandant}/Account/$varenv{accounting_1_5}$session"); + exit 0; + } + elsif($payable_check && (!$users_sharee->{int04} || !$users_sharee->{int13})){ + print redirect("$varenv{wwwhost}/$varenv{mandant}/Account/$varenv{accounting_3}?cum=2$session_and\&$returnwww"); + exit 0; + } + elsif($users_sharee->{int03} && (($users_sharee->{int03} == 1 && $users_sharee->{ct_name} !~ /\w{2}-\d+/) || ($users_sharee->{int03} == 2 && length($users_sharee->{ct_name}) < 19))){ + print redirect("$varenv{wwwhost}/$varenv{mandant}/Account/$varenv{accounting_2}$session"); + exit 0; + } + elsif($payable_check){ + print redirect("$varenv{wwwhost}/$varenv{mandant}/Account/$varenv{accounting_3}?cum=2$session_and\&$returnwww"); + exit 0; + } + }elsif($path =~ /$varenv{mandant}\/$varenv{profile}/){ + if((!$users_sharee->{int14}) || ($users_sharee->{txt31} && $tpl->{tpl_order} =~ /$users_sharee->{txt31}/)){ + print redirect("$varenv{wwwhost}/$varenv{mandant}/Account/$varenv{accounting_1}?failure=$users_sharee->{txt31}$session_and#top"); + exit 0; + }elsif(!$payable_check){ + print redirect("$varenv{wwwhost}/$varenv{mandant}/Account/$varenv{accounting_1_5}$session"); + exit 0; + }else{ + print redirect("$varenv{wwwhost}/$varenv{mandant}/Account/$varenv{accounting_3}?cum=2$session_and\&$returnwww"); + exit 0; + } + } + }elsif($users_sharee->{c_id} && ($path =~ /$varenv{mandant}\/Anmelden|$varenv{mandant}\/$varenv{profile}/)){ + print redirect("$varenv{wwwhost}/$varenv{mandant}/Account/$varenv{accounting_3}?cum=2$session_and\&$returnwww"); + exit 0; + } + ### + } + + my $nodev = $db->get_node("$view_post","$lang"); + #Printpreview + if($view =~ /Printpreview/){ + require "Lib/Printpreview.pm"; + &Printpreview::printpre(); + exit 0; + } + elsif($view =~ /PDFGenerator/){ + require "Lib/PDFGenerator.pm"; + &PDFGenerator::printpre(); + exit 0; + } + + #else global REDIRECT. Availability check for redirect + #elsif(!$nodev->{main_id} || ($nodev->{main_id} == 100 && $R::rel_edit eq "save_content")){ + #print redirect("$varenv{wwwhost}$session"); + #exit 0; + #} + + + #CSVout + if($R::rel_edit && $R::rel_edit =~ /XLSout/){ + $users_dms = $dbt->select_users($dbh,$users_dms->{u_id}); + if(-f "$dbt->{copri_conf}->{basedir}/pdf/$users_dms->{owner}-$users_dms->{time4csv}.xls"){ + print $q->redirect(-uri=>"$varenv{metahost}/pdf/$users_dms->{owner}-$users_dms->{time4csv}.xls", -type=>"application/octet-stream", -target=>'_blank'); + exit 0; + } + } + + my $dyn_css = ""; + if(1==1){ + my $background = ""; + $background = "$varenv{metahost}/img/$varenv{background_image}" if($varenv{background_image}); + $dyn_css = " + html,body { + background-image:url('$background'); + background-repeat: $varenv{background_repeat}; + background-position: right bottom; + background-attachment:fixed; + background-size:$varenv{background_size}; + font-family: $varenv{font_family}; + font-size: $varenv{font_size}; + line-height: $varenv{line_height}; + margin: 0; padding: 0; + text-align:$varenv{background_align}; + + }\n"; + } + + + my $url = "$varenv{wwwhost}/$path"; + #my $onload="onLoad();"; + my $onload=""; + + my $local_style = "$varenv{metahost}/$dbt->{shareeapp_conf}->{local_style}"; + my $jquery = "$varenv{metahost}/$dbt->{shareeapp_conf}->{jquery}"; + my $js_bootstrap = "$varenv{metahost}/$dbt->{shareeapp_conf}->{js_bootstrap}"; + my $style_bootstrap = "$varenv{metahost}/$dbt->{shareeapp_conf}->{style_bootstrap}"; + if($varenv{wwwhost} =~ /shareedms/){ + $local_style = "$varenv{metahost}/$dbt->{shareedms_conf}->{local_style}"; + $jquery = "$varenv{metahost}/$dbt->{shareedms_conf}->{jquery}"; + $js_bootstrap = "$varenv{metahost}/$dbt->{shareedms_conf}->{js_bootstrap}"; + $style_bootstrap = "$varenv{metahost}/$dbt->{shareedms_conf}->{style_bootstrap}"; + } + + my $base_uri = "true"; + my $title = ""; + $title .= $dbt->{primary}->{$varenv{dbname}}->{pprefix} if($dbt->{primary}->{$varenv{dbname}}->{pprefix}); + $title .= $dbt->{operator}->{$varenv{dbname}}->{project} if($dbt->{operator}->{$varenv{dbname}}->{project}); + $title .= " " . $dbt->{operator}->{$varenv{dbname}}->{oprefix} if($dbt->{operator}->{$varenv{dbname}}->{oprefix}); + $title .= $dbt->{website}->{$varenv{syshost}}->{project} if($dbt->{website}->{$varenv{syshost}}->{project}); + $title .= " DEVEL $varenv{dbname}" if($dbt->{copri_conf}->{stage} eq "test"); + my $html5 = $q->start_html(-title=>"$title", + -lang=>'de', + -onload=>"$onload", + -oncontextmenu=>"$oncontextmenu", + #-id=>"page-top", + #'-data-spy'=>"scroll", + #'-data-target'=>".navbar-fixed-top", + -encoding=>"$html_charset", + -base=>"$base_uri", + -target=>"", + -head=>[ + Link({ + -rel=>'shortcut icon', + -type=>'image/x-icon', + -href=>"$varenv{metahost}/css/favicon.ico" + }) + ], + -meta=>{ + 'viewport'=>"width=device-width,initial-scale=1,user-scalable=yes", + 'author'=>"Rainer Gümpelein", + 'publisher'=>"TeilRad GmbH", + 'copyright'=>"TeilRad GmbH", + 'keywords'=>"", + 'description'=>"sharee.bike Mietradmanagementsystem" + }, + -script=>[ + {-language=>'JAVASCRIPT', + -src=>"$jquery"}, + {-language=>'JAVASCRIPT', + -src=>"$varenv{metahost}/$dbt->{copri_conf}->{jquery_ui}"}, + {-language=>'JAVASCRIPT', + -src=>"$varenv{metahost}/$dbt->{copri_conf}->{jquery_resize}"}, + {-language=>'JAVASCRIPT', + -src=>"$varenv{metahost}/$dbt->{copri_conf}->{jsscript}"}, + {-language=>'JAVASCRIPT', + -code=>"$dyn_js"} + ], + -STYLE=>{ + -code=>"$dyn_css", + -src=>[ + "$local_style", + "$style_bootstrap", + "$varenv{metahost}/$dbt->{copri_conf}->{style_bootstrap_icons}", + "$varenv{metahost}/$dbt->{copri_conf}->{style_jquery_ui}" + ], + -verbatim=>"\@import url(\"$local_style\");", + -media=>'screen' + } + ); + # CGI.pm doesn't support HTML5 DTD; replace the one it puts in. + $html5 =~ s{}{}s; + $html5 =~ s{}{}s; + print $html5; + + print $q->div({-style=>'background-color:black;color:white;'},""),"\n"; + + $ml->tpl($node_meta,$users_dms,$mode,\%varenv,$users_sharee,$return); + +if(ref($api_return) eq "HASH" && $api_return->{response_text}){ +print<div#retm_konrad {position:fixed;right:40%;top:0;padding:5px;text-align:center;color:black;background-color:white;z-index:110;} + +EOF +; + print $q->div({-id=>'retm_konrad'},"$api_return->{response_text}"),"\n"; +} + + print "\n"; + + print $q->end_html; + return Apache2::Const::OK; +} +1; diff --git a/copri4/main/src/Mod/KMLout.pm b/copri4/main/src/Mod/KMLout.pm new file mode 100644 index 0000000..8fef90e --- /dev/null +++ b/copri4/main/src/Mod/KMLout.pm @@ -0,0 +1,258 @@ +package Mod::KMLout; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +#without login only public Stations have to be viewable: +#https://shareeapp-primary.copri-bike.de/KMLout +# +#with login and valid autcookie: +#https://shareeapp-primary.copri-bike.de/KMLout?sessionid=a49aba2b5440be72816db2_rafo87znqx +# +# +use warnings; +use strict; +use POSIX; +use Exporter; +our @ISA = qw (Exporter); +use CGI::Cookie (); +use CGI ':standard'; +use Apache2::Const -compile => qw(OK ); +use Scalar::Util qw(looks_like_number); +use JSON; +use LWP::UserAgent; + +use Lib::Config; +use Mod::DBtank; +use Mod::APIfunc; +use Mod::Basework; +use Data::Dumper; +my $bw = new Basework; + +sub handler { + my $r = shift; + my $q = new CGI; + my $apif = new APIfunc; + my $cf = new Config; + my %varenv = $cf->envonline(); + + my $coo = $q->cookie('domcookie') || $q->param('sessionid') || "rafo87znqx"; + my $users_sharee = { c_id => 0 }; + my $api_return = { authcookie => 'rafo87znqx' }; + + ($api_return,$users_sharee) = $apif->auth_verify($q,$coo,""); + + my $kmlfile = kmlGenerator($api_return,\%varenv,$users_sharee); + + #print out test with kml file + if(1==2){ + print $q->header(-type => "application/vnd.google-earth.kml+xml", -charset=>"utf-8"); + + if (open(my $fh, '<', "$varenv{basedir}/xml/$kmlfile")) { + while (my $row = <$fh>) { + print "$row"; + } + } + } + + return Apache2::Const::OK; +} + +sub kmlGenerator { + my $authcookie = shift || { authcookie => '' }; + my $varenv = shift; + my $users_sharee = shift || { c_id => 0 }; + + my $q = new CGI; + my $dbt = new DBtank; + my $json = JSON->new->allow_nonref; + my $cf = new Config; + #my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; + my $lang="de"; + my $dbh = ""; + + #my $netloc = $q->url(-base=>1); + #print "kmlGenerator accessed by netlocation: " . $netloc; + my $project = "all"; + $project = "Bayern" if($varenv->{syshost} eq "shareeweb-bayern"); + $project = "Konstanz" if($varenv->{syshost} eq "shareeweb-konstanz"); + + my $timestamp = strftime "%Y%m%d%H%M%S", localtime; + my $kmlfile = "sharee-$timestamp-$users_sharee->{c_id}.kml"; + $bw->log("kmlGenerator with: ",$kmlfile,""); + + my $uri_primary = $dbt->{primary}->{sharee_primary}->{primaryApp}; + my $rest_stations = "request=stations_available&project=$project&authcookie=$authcookie->{authcookie}"; + my $rest_bikes = "request=bikes_available&project=$project&authcookie=$authcookie->{authcookie}"; + + my $station_hash = {}; + my $bike_hash = {}; + my $lastenrad = 300101; + my $e_lastenrad = 300102; + my $stadtrad = 300103; + + my %place_name; + my %place_desc; + my %place_pin; + my %place_longitude; + my %place_latitude; + + #reading shareejson + my $stations_json = fetch_primary_json("",$uri_primary,$rest_stations); + my $bikes_json = fetch_primary_json("",$uri_primary,$rest_bikes); + + open(XML,">$varenv->{basedir}/xml/$kmlfile") || die "$0 can not write $!"; + + print XML "\n"; + print XML "\n"; + print XML "\n"; + print XML "sharee.bike\n"; + print XML "bike stations for $users_sharee->{c_id}\n"; + + + if($stations_json && $bikes_json){ + #decode json to hash + my $response_stations = decode_json($stations_json); + my $response_bikes = decode_json($bikes_json); + + #BIG LOOP + #loop stations hash + foreach my $station (keys (%{ $response_stations->{shareejson}->{stations} })) { + $station_hash->{$station} = $response_stations->{shareejson}->{stations}->{$station}; + + $place_pin{$station} = "Open_Red.png"; + my $station_desc = "Mietradstation $station"; + if($response_stations->{shareejson}->{stations}->{$station}->{description}){ + $station_desc = "Mietradstation: $response_stations->{shareejson}->{stations}->{$station}->{description} $station"; + #$bw->log("KMLout station_desc: ",$station_desc,""); + } + $place_name{$station} = "$station_desc"; + + if($response_stations->{shareejson}->{stations}->{$station}->{state} eq "available" && $response_stations->{shareejson}->{stations}->{$station}->{gps}->{latitude} =~ /\d{1,2}\.\d+/ && $response_stations->{shareejson}->{stations}->{$station}->{gps}->{longitude} =~ /\d{1,2}\.\d+/){ + $place_latitude{$station} = $response_stations->{shareejson}->{stations}->{$station}->{gps}->{latitude}; + $place_longitude{$station} = $response_stations->{shareejson}->{stations}->{$station}->{gps}->{longitude}; + $place_desc{$station} = ""; + #print "\n--- Station $station hat folgende Räder ---\n"; + + #loop station_group array + foreach my $station_group (@{ $response_stations->{shareejson}->{stations}->{$station}->{station_group} }){ + #print "station_group ($station): " . $station_group . "\n"; + my $station_groupID = 0; + + #loop bikes hash + foreach my $bike (keys (%{ $response_bikes->{shareejson}->{bikes} })) { + $bike_hash->{$bike} = $response_bikes->{shareejson}->{bikes}->{$bike}; + + #loop bike_group array + foreach my $bike_group (@{ $response_bikes->{shareejson}->{bikes}->{$bike}->{bike_group} }){ + #print "bike_group ($bike): " . $bike_group . "\n"; + my $bike_groupID = 0; + + $station_groupID = $1 if($station_group =~ /(\d+)/); + $bike_groupID = $1 if($bike_group =~ /(\d+)/); + + + #if Lastenrad + if($station_groupID == $lastenrad && $station_groupID == $bike_groupID && $station eq $response_bikes->{shareejson}->{bikes}->{$bike}->{station}){ + $place_pin{$station} = "Open_Green.png"; + $place_desc{$station} .= "

    • Lastenrad vorrätig: $response_bikes->{shareejson}->{bikes}->{$bike}->{description} $bike

    "; + #print "($station) Lastenrad $bike\n"; + } + #if E-Lastenrad + if($station_groupID == $e_lastenrad && $station_groupID == $bike_groupID && $station eq $response_bikes->{shareejson}->{bikes}->{$bike}->{station}){ + $place_pin{$station} = "Open_Green.png"; + $place_desc{$station} .= "

    • E-Lastenrad vorrätig: $response_bikes->{shareejson}->{bikes}->{$bike}->{description} $bike

    "; + #print "($station) E-Lastenrad $bike\n"; + } + #if Stadtrad + if($station_groupID == $stadtrad && $station_groupID == $bike_groupID && $station eq $response_bikes->{shareejson}->{bikes}->{$bike}->{station}){ + $place_pin{$station} = "Open_Green.png"; + $place_desc{$station} .= "

    • Stadtrad vorrätig: $response_bikes->{shareejson}->{bikes}->{$bike}->{description} $bike

    "; + #print "($station) Stadtrad $bike\n"; + } + + } + } + } + + print XML " \n"; + print XML " \n"; + print XML " $place_name{$station}\n"; + print XML " \n"; + print XML " #$place_pin{$station}\n"; + print XML " \n"; + print XML " $place_longitude{$station}, $place_latitude{$station}\n"; + print XML " \n"; + print XML " \n"; + + } + }#end BIG LOOP + }#end if json + + print XML "
    \n"; + print XML "
    \n"; + close(XML); + + chmod 0666, "$varenv->{basedir}/xml/$kmlfile"; + + #my $update_kml = {}; + #if($users_sharee->{c_id} > 0){ + # $update_kml = { + # table => "contentadr", + # atime => "now()", + # c_id => $users_sharee->{c_id}, + # }; + #}else{ + # $update_kml = { + # table => "content", + # mtime => "now()", + # c_id => "3", + # }; + #} + #my $dbh_primary = $dbt->dbconnect_extern("sharee_primary"); + #$dbt->update_one($dbh_primary,$update_kml,"txt20='$kmlfile'"); + + #print "station_hash ALL:" . Dumper($station_hash); + #print "bike_hash ALL:" . Dumper($bike_hash); + # + return $kmlfile; + +}#end kmlGenerator + +#requestor +sub fetch_primary_json { + my $self = shift; + my $primary_server = shift || ""; + my $rest = shift || ""; + my $primary_request = "$primary_server/APIjsonserver?$rest"; + $bw->log("kmlGenerator primary_request: ",$primary_request,""); + #print "GET_json >> " . $primary_request . "\n"; + + my $ua = LWP::UserAgent->new; + $ua->agent("sharee KMLout"); + + my $req = HTTP::Request->new(GET => "$primary_request"); + $req->content_type('application/x-www-form-urlencoded'); + $req->content($rest); + + #Pass request to the user agent and get a response back + my $res = $ua->request($req); + # Check the outcome of the response + if ($res->is_success) { + #print $res->content; + return $res->content; + #print $res->status_line, "\n"; + }else { + return ""; + #print $res->status_line, "\n"; + } +} + + +1; diff --git a/copri4/main/src/Mod/Libenz.pm b/copri4/main/src/Mod/Libenz.pm new file mode 100644 index 0000000..b532bdb --- /dev/null +++ b/copri4/main/src/Mod/Libenz.pm @@ -0,0 +1,756 @@ +package Libenz; +# +#Deprecated module, better use Prelib.pm or Basework.pm +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# + +use strict; +use warnings; +use POSIX; +use File::Path qw(make_path remove_tree); +use File::Copy; +use File::Copy::Recursive qw(fcopy rcopy dircopy fmove rmove dirmove); +use Getopt::Long; +use CGI; # only for debugging +use CGI::Carp qw(fatalsToBrowser); +use Calendar::Simple; +use Date::Calc qw(:all); +use Mod::Callib; +use Mod::Libenzdb; +use Mod::Buttons; +use Lib::Config; +use Digest::MD5 qw(md5 md5_hex); +use Scalar::Util qw(looks_like_number); + +my $cf = new Config; +my $cb = new Callib; +my $but = new Buttons; +my $db = new Libenzdb; +my $q = new CGI; + +#my $pi = new Image::Magick; +$q->import_names('R'); + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +my %varenv = $cf->envonline(); +my $lang="de"; +my $now_time = strftime "%Y-%m-%d %H:%M", localtime; +my @months = $cb->monthmap(); +my @days = $cb->daymap(); + +my $i_rows=0; +my $u_rows=0; +my $d_rows=0; +my $nall; + +sub grep_filecontent(){ + my $self = shift; + my ($filename,$content,$pattern) = @_; + my $match = ""; + if (open(my $fh, '<:encoding(UTF-8)', $filename)) { + while (my $row = <$fh>) { + $row =~ s/\n//; + $row =~ s/\r//; + if($content && $row eq $content){ + $match = $content; + }elsif($pattern && $row =~ /$pattern/){ + $match = $row; + } + } + } + return $match; +} + +# calculates the distance between two latitude, longitude points +sub geo_fencing { + my $self = shift; + my ($lat1, $lon1, $lat2, $lon2) = @_; + + my $pi = atan2(1,1) * 4; + + if (($lat1 == $lat2) && ($lon1 == $lon2)) { + return 0; + } + else { + my $theta = $lon1 - $lon2; + my $dist = sin($lat1 * $pi / 180) * sin($lat2 * $pi / 180) + cos($lat1 * $pi / 180) * cos($lat2 * $pi / 180) * cos($theta * $pi / 180); + $dist = atan2(sqrt(1 - $dist**2), $dist); + $dist = $dist * 180 / $pi; + + $dist = $dist * 60 * 1.1515;#Miles + $dist = $dist * 1.609344 * 1000;#Meters + $dist = sprintf('%.0f',$dist); + return ($dist); + } +} + + +sub country_code(){ + my $self = shift; + my $country = { + 'DE' => 'Deutschland', + 'BE' => 'Belgien', + 'BG' => 'Bulgarien', + 'CH' => 'Schweiz', + 'CZ' => 'Tschechische Republik', + 'DK' => 'Dänemark', + 'EE' => 'Estland', + 'IE' => 'Irland', + 'EL' => 'Griechenland', + 'ES' => 'Spanien', + 'FR' => 'Frankreich', + 'HR' => 'Kroatien', + 'IT' => 'Italien', + 'CY' => 'Zypern', + 'LV' => 'Lettland', + 'LT' => 'Litauen', + 'LU' => 'Luxemburg', + 'HU' => 'Ungarn', + 'MT' => 'Malta', + 'NL' => 'Niederlande', + 'AT' => 'Österreich', + 'PL' => 'Polen', + 'PT' => 'Portugal', + 'RO' => 'Rumänien', + 'SI' => 'Slowenien', + 'SK' => 'Slowakei', + 'FI' => 'Finnland', + 'SE' => 'Schweden', + 'GB' => 'Vereinigtes Königreich' + }; + return $country; +} + + +#read directory +sub read_dirfiles(){ + my $self = shift; + my ($dir,$extensions,$dirOfile,$not) = @_; + my @dirfiles; + if( -d "$dir" || -l "$dir"){ + opendir(DIR, "$dir") or die "could not open $dir $!"; + foreach(sort(readdir(DIR))){ + if($dir =~ /INBOX/){ + if($_ =~ /^$extensions/){ + push(@dirfiles,$_) if(-f "$dir/$_" && $dirOfile eq "file"); + push(@dirfiles,$_) if(-d "$dir/$_" && $dirOfile eq "dir"); + } + } + elsif($not){ + if(uc($_) !~ /$extensions/){ + push(@dirfiles,$_) if(-f "$dir/$_" && $dirOfile eq "file"); + push(@dirfiles,$_) if(-d "$dir/$_" && $dirOfile eq "dir"); + } + }else{ + if(uc($_) =~ /$extensions/ || $_ =~ /$extensions/){ + push(@dirfiles,$_) if(-f "$dir/$_" && $dirOfile eq "file"); + push(@dirfiles,$_) if(-d "$dir/$_" && $dirOfile eq "dir"); + } + } + + } + closedir DIR; + }else{ + print "\ndirectory: $dir does not exist\n $!\n"; + } + return @dirfiles; +} + +#return message +sub return_feedback(){ + my $self = shift; + my ($return,$kind_of_trans,$owner,$terminal) = @_; + + if($owner > 0){ +print< + \$(document).ready(function(){ + \$( "#retm" ).fadeOut(7000); + }) + +EOF +; + $return = $R::return if($R::return); + my ($ret_pm,$ret_pl,$ret_er) = split(/\|/,$return); + my ($i_pm,$s_pm,$d_pm) = split(/-/,$ret_pm); + my ($i_pl,$s_pl,$d_pl) = split(/-/,$ret_pl); + my $pre = ""; + $kind_of_trans = "Transaktions" if(!$kind_of_trans); + my $feedb = ""; + $feedb = "neue $pre Daten eingefuegt" if($i_pm); + $feedb = "insert successfully " if($i_pm && $varenv{html_lang} eq "en"); + $feedb = "$pre Daten gespeichert" if($s_pm); + $feedb = "saved successfully" if($s_pm && $varenv{html_lang} eq "en"); + $feedb = "$pre Daten geloescht" if($d_pm); + $feedb = "deleted successfully" if($d_pm && $varenv{html_lang} eq "en"); + $feedb = "neue $kind_of_trans Daten eingefuegt" if($i_pl); + $feedb = "$kind_of_trans Daten gespeichert" if($s_pl); + $feedb = "$kind_of_trans Daten geloescht" if($d_pl); + $feedb = "Artikel eingefügt" if($i_pl =~ /ctpos_id=\d+/); + my $debug; + $debug = "($ret_pm|$ret_pl)" if($owner eq "101"); + if($return !~ /failure/ && $feedb){ + print $q->div({-id=>'retm'},"$feedb $debug"),"\n"; + } + } + + $return = $1 if($return =~ /(failure.*)/); + return $return; +} + + +#Quersumme +sub quersum(){ + my $self = shift; + my ($kecks) = @_; + my $laenge = length($kecks); + my $quersum = 0; + for(my $i=0; $i<$laenge; $i++) { + my $signs = substr($kecks, $i, 1); + $quersum = $quersum + int(ord($signs)); + } + return $quersum; +} + + +#Calfkt to get a scalable line of days per month +sub month_line(){ + my $self = shift; + my ($users) = @_; + + #my $users = $db->select_users($u_id); + my $hh;my $mm; + my $day = strftime "%d", localtime; + my $mon = strftime "%m", localtime; + my $year = strftime "%Y", localtime; + my $day_today = $day; + my $mon_today = $mon; + my $year_today = $year; + + ($year,$mon,$day,$hh,$mm) = &split_date("",$users->{cal_start}) if($users->{cal_start}); + #print "$year,$mon,$day,$hh,$mm"; + + my $month_days = Days_in_Month($year,$mon); + my $factor = 100 / $month_days; + + my @month = calendar($mon, $year); + my $raster_mmpx = $factor . "%"; #bsp.: 100% / 31days + my $day4month; + my $bg; + my @week; + my $i=0; + my $j=0; + #month, week loop + foreach (@month) { + $i=0; + $j++; + #print map { $_ ? sprintf "%2d ", $_ : '  x  ' } @$_; + #day-of-week loop + foreach(@$_){ + if($_){ + $_ = "0$_" if($_ < "10"); + $week[$j] .= "$_,"; + #print $q->th({-nowrap=>1},"$days[$i] $_"); + if("$_" eq "$day_today" && "$mon" eq "$mon_today"){ + $bg="#86cb00"; + }else{ + $bg="silver"; + } + $day4month .= "
    |$days[$i] $_
    \n"; + } + $i++; + } + } + + my $daycounter = $day_today - 1; + my $daymarker = $raster_mmpx * $daycounter; + $daymarker .= "%"; + + return ($daymarker,$raster_mmpx,$day4month); +} + +#rent scale +sub rent_scale(){ + my $self = shift; + my ($users,$year_st,$mon_st,$day_st,$hh_st,$mm_st,$year_en,$mon_en,$day_en,$hh_en,$mm_en) = @_; + #print "
    ($u_id,$year_st,$mon_st,$day_st,$hh_st,$mm_st,$year_en,$mon_en,$day_en,$hh_en,$mm_en)
    "; + #my $users = $db->select_users($u_id); + my $hh;my $mm; + my $day = strftime "%d", localtime; + my $mon = strftime "%m", localtime; + my $year = strftime "%Y", localtime; + + ($year,$mon,$day,$hh,$mm) = &split_date("",$users->{cal_start}) if($users->{cal_start}); + my $month_days = Days_in_Month($year,$mon); + my $factor = 100 / $month_days; + my @month = calendar($mon, $year); + my $doy_mon_st=0;my $doy_mon_en=0;my $doy_st=0;my $doy_en=0; + + my $day_stpx = 0; + my $rent_day_px = 0; + if(looks_like_number($year_st) && looks_like_number($mon_st) && looks_like_number($day_st) && looks_like_number($year_en) && looks_like_number($mon_en) && looks_like_number($day_en)){ + + #print "if(($year == $year_st) && ($mon == $mon_st)){
    "; + if(($year == $year_st) && ($mon == $mon_st)){ + $doy_mon_st = Day_of_Year($year_st,$mon_st,1);#JahresTage bis Monatsanfang + $doy_st = Day_of_Year($year_st,$mon_st,$day_st); + }else{ + $doy_mon_st = Day_of_Year($year,$mon,1); + $doy_st = Day_of_Year($year,$mon,1); + } + if(($year == $year_en) && ($mon == $mon_en)){ + $doy_en = Day_of_Year($year_en,$mon_en,$day_en); + }elsif($year_en && $mon_en){ + my $month_days_en = Days_in_Month($year_en,$mon_en); + $doy_en = Day_of_Year($year_en,$mon_en,$month_days_en);# wenn ausserhalb --> cal_start + } + if(($mon != $mon_en) && ($mon != $mon_st)){ + $doy_mon_st=0;$doy_mon_en=0;$doy_st=0;$doy_en=0; + } + + my $day_st_new = $doy_st - $doy_mon_st; + #print "
    $day_st_new = $doy_st - $doy_mon_st|"; + + #day rent-duration + my $rent_day = ($doy_en - $doy_st + 1); + #print "$rent_day = ($doy_en - $doy_st + 1)
    "; + #$rent_day_px = $rent_day * $multi if($doy_en && $doy_st); + #$rent_day_px .= "px"; + $rent_day_px = $rent_day * $factor if($doy_en && $doy_st); + $rent_day_px .= "%"; + + #debug + #print "$ct_n --- start: $day_st_new = $doy_st - $doy_mon_st | länge: $rent_day = $doy_en - $doy_st |
    "; + + #start day align left + #$day_stpx = ($day_st_new + 0) * $multi if($day_st_new); + #$day_stpx .= "px"; + $day_stpx = $day_st_new * $factor; + $day_stpx .= "%"; + } + + #print "$day_stpx,$rent_day_px
    "; + return ($day_stpx,$rent_day_px); +} + +#check if barcodeable +sub barcodeable(){ + my $self = shift; + my ($table,$number) = @_; + my $oGdBar = GD::Barcode->new("Code39", "$number"); + my $ct_name = $oGdBar->{text}; + my $barcode = $oGdBar->{text}; + return ($ct_name,$barcode); +} + +#FIXME or change to barcode=c_id +#get free barcode +sub get_freenr(){ + my $self = shift; + my ($table,$barcode_last) = @_; + my $freenr = $db->collect_content3($table); + my $s_id = $barcode_last; + my $e_id = "100000"; + $freenr->{$s_id}->{barcode} = "1000" if(!$freenr->{$s_id}->{barcode} || $freenr->{$s_id}->{barcode} == 0); + for (; $s_id < $e_id; $s_id++){ + if($freenr->{$s_id}->{barcode} != $s_id){ + return $s_id; + } + } +} + +#get free Rechnungs Nummer +sub get_freeReNr(){ + my $self = shift; + my ($table,$barcode_start,$barcode_end,$column,$content) = @_; + my $now_time = strftime "%Y-%m-%d %H:%M:%S", localtime; + my $freenr = $db->collect_content3("$table","$column","$content"); + my $s_id = $barcode_start; + my $e_id = $barcode_end || 100000; + $freenr->{$s_id}->{barcode} = "1000" if(!$freenr->{$s_id}->{barcode}); + for (; $s_id < $e_id; $s_id++){ + #if($freenr->{$s_id}->{barcode} != $s_id){ + if($freenr->{$s_id}->{ct_name} && $freenr->{$s_id}->{ct_name} !~ /^$s_id/){ + open(RENR, ">> $varenv{logdir}/get_freeReNr.log"); + print RENR "* $now_time --------------- \n"; + print RENR "$table,$barcode_start,$barcode_end,$column,$content\n"; + print RENR "for (; $s_id < $e_id; $s_id++){\n"; + print RENR "if($freenr->{$s_id}->{ct_name} && $freenr->{$s_id}->{ct_name} !~ /^$s_id/){\n"; + print RENR "return $s_id;\n"; + close RENR; + return $s_id; + } + } + return 0; +} + +#CAsh +sub cashme(){ + my $self = shift; + my ($cash,$comma) = @_; + $cash = "0\.00" if($cash !~ /\d/); + $cash = "$cash\.00" if($cash !~ /\./); + $cash = $cash . 0 if($cash =~ /\.\d{1}$/); + $cash =~ s/\./$comma/ if($comma); + return $cash; +} + +#umst breaking date 16 19 % +sub umst_breaking(){ + my $self = shift; + my $ctt = shift; + my $now_dt = shift || "";#used by payone_cron.pl, because there is no mtime-update on start + + #invoice_time will be set by Printpreview.pm invoice generation! + my $i_datetime = $now_dt || $ctt->{invoice_time} || $ctt->{mtime}; + my $umst1619 = 19; + my ($i_date,$i_time) = split(/ /,$i_datetime); + my ($yy,$mo,$dd) = split(/-/,$i_date); + my $breaking_date = $yy . $mo . $dd; + $umst1619 = 16 if($breaking_date >= 20200701 && $breaking_date < 20210101); + return $umst1619; +} + +#integer check +sub checkint(){ + my $self = shift; + my ($int) = @_; + $int =~ s/,/./; + if($int =~ /([-\d]+)\.(\d+)/){ + $int = "$1" . "." . "$2"; + }elsif($int =~ /([-\d]+)/){ + $int = "$1"; + } + return $int; +} + +# input character check +sub checkinput(){ + my $self = shift; + my $node_name = shift; + if($node_name =~ /^[a-zA-Z0-9äöüÄÖÜ_\-\.\ ]+$/){ + return 0; + }else{ + return "failure::Für die Menue- Ordner Benennung sind nur alphanumerische Zeichen und - . erlaubt ($node_name)."; + } +} + + +# input date check. returns english date and 1 if true +sub true_date(){ + my $self = shift; + my ($date,$time) = @_; + $date =~ s/,/./g; + my $d_chck = 0; + + if($date =~ /(\d{4})-(\d{2})-(\d{2})/){ + $d_chck = 1 if(check_date($1,$2,$3)); + $date = "$1-$2-$3"; + }elsif($date =~ /(\d{2})\.(\d{2})\.(\d{4})/){ + $d_chck = 1 if(check_date($3,$2,$1)); + $date = "$3-$2-$1"; + } + return ($date,$d_chck); +} + + +# input date check +sub checkdate(){ + my $self = shift; + my ($date,$time) = @_; + $date =~ s/,/./g; + my $d_chck = 1; + my ($c_dd,$c_mm,$c_yy); + + + if($date =~ /(\d{4})-(\d+)-(\d+)/){ + $d_chck = 0 if(check_date($1,$2,$3)); + $date = "$1-$2-$3"; + }elsif($date =~ /(\d+)\.(\d+)\.(\d+)/){ + $d_chck = 0 if(check_date($3,$2,$1)); + $date = "$1.$2.$3"; + } + return ($date,$d_chck); +} + + + +#collect node_name and builds path +sub make_uri2(){ + my $self = shift; + my ($main_id,$lang,$mandantsub_id,$start_id) = @_; + my $gpath; + my $m_id; + my @genpath; + my $i=$1 if($main_id =~ /^(\d)/); + foreach my $id (sort {$nall->{$b}->{main_id} <=> $nall->{$a}->{main_id}} keys (%$nall)){ + #print "xxxx ($main_id =~ /^($i\d+)/) && ($start_id && $main_id >= $start_id) && ($main_id == $nall->{$id}->{main_id})
    "; + if(($main_id =~ /^($i\d+)/) && ($start_id && $main_id >= $start_id) && ($main_id == $nall->{$id}->{main_id})){ + ## wegen multible mandanten sub-sub-level, bsp. Waren/[300] Sonstiges + if($mandantsub_id && $i==3){ + if($mandantsub_id == $nall->{$id}->{parent_id}){ + $i--; + $main_id = $nall->{$id}->{parent_id}; + $m_id = $nall->{$id}->{main_id} if(!$m_id); + $genpath[$i] = "/$nall->{$id}->{node_name}"; + #print "$i x/$nall->{$id}->{node_name} ($nall->{$id}->{main_id})
    "; + } + ## + }else{ + $i--; + $main_id = $nall->{$id}->{parent_id}; + $main_id = $start_id if($start_id && $i==1); + $m_id = $nall->{$id}->{main_id} if(!$m_id); + $genpath[$i] = "/$nall->{$id}->{node_name}"; + #print "$i /$nall->{$id}->{node_name} ($nall->{$id}->{main_id})
    "; + } + } + } + + foreach (@genpath){ + #print "$_|"; + $_ =~ s/\/root//; + $gpath .= "$_"; + } + return ("$m_id","$gpath"); +} + +#new init for make_uri3 with returning nall object +sub init_nodes5uri(){ + my $self = shift; + $nall = $db->collect_node4all(); + return $nall; +} + +#5. collect node_name and builds path without mandant-logic +sub make_uri5(){ + my $self = shift; + my ($main_id,$nall,$depth_start) = @_; + $depth_start = 0 if(!$depth_start); + my $gpath; + my $m_id; + my @genpath; + my $depth=$1 if($main_id =~ /^(\d)/ && $main_id >= 100000); + foreach my $id (sort {$nall->{$b}->{main_id} <=> $nall->{$a}->{main_id}} keys (%$nall)){ + if(($main_id =~ /^($depth\d+)/) && ($main_id == $nall->{$id}->{main_id})){ + $depth--; + $main_id = $nall->{$id}->{parent_id}; + $m_id = $nall->{$id}->{main_id} if(!$m_id); + $genpath[$depth] = "/$nall->{$id}->{node_name}" if($depth > $depth_start); + #print "$depth|$main_id /$nall->{$id}->{node_name} ($nall->{$id}->{main_id})
    "; + } + } + + foreach (@genpath){ + #print "$_|"; + $_ =~ s/\/root//; + $gpath .= "$_"; + } + return ("$m_id","$gpath"); +} + + +sub sub4txt(){ + my $self = shift; + my ($txt,$index,$length,$cut,$cut_last) = @_; + my $substrtxt = substr($txt, $index, $length); + #$substrtxt =~ s/
    /\n/g; + #$substrtxt =~ s///g; + #$substrtxt =~ s/^[<|\\|\/|>|:|,|\.|\\n]+//g; + #$substrtxt =~ s/^\w+\s// if($index > 20); + + #entferne das erste teil-wort ... + if($cut){ + $substrtxt =~ s/^[äöü]+//; + $substrtxt =~ s/^\w+//; + $substrtxt =~ s/^\,//; + $substrtxt =~ s/^\.//; + } + + #entferne das letzte teil-wort ... + if($cut_last){ + $substrtxt =~ s/[äöü]+$//; + $substrtxt =~ s/\w+$//; + $substrtxt =~ s/\,$//; + $substrtxt =~ s/\.$//; + } + + #entferne das letzte teil-wort ... + if($index && ($index > $length)){ + $substrtxt =~ s/\w+$//; + } + #$substrtxt =~ s/\s\w+$//; + return $substrtxt; +} + +sub newline(){ + my $self = shift; + my $txtxx = shift; + my $not_used = shift || "";#old + my $editor = shift || ""; + $txtxx =~ s/\r\n/
    /g if(!$editor); + return $txtxx; +} + +#der tiny_mce editor init +sub wyedit(){ + my $self = shift; + my ($users_tiny_mce) = @_; + my $wy=""; + if($varenv{js4tiny_mce} && $users_tiny_mce){ + $wy = ""; + } + return $wy; +} + +#Komplettset compset logic +sub compsum(){ + my $self = shift; + my ($main_id,$lang,$owner) = @_; + my $ct4rel = $db->collect_ct4rel("content",$main_id,$lang);#hash + my $ctpers4rel = $db->collect_ctpers4rel($main_id,$lang,$owner);#hash + %$ct4rel = (%$ctpers4rel, %$ct4rel);#hash slice + return $ct4rel; +} + + +# Rounding like "Kaufmannsrunden" +# Descr. http://de.wikipedia.org/wiki/Rundung +# Inspired by +# http://www.perl.com/doc/FAQs/FAQ/oldfaq-html/Q4.13.html +sub round(){ + my $self = shift; + my ($amount) = @_; + $amount = $amount * (10**(2)); + my $rounded = int($amount + .5 * ($amount<=> 0)) / (10**(2)); + return $rounded; +} + +#rounding to half or integer +sub round_half(){ + my $self = shift; + my $amount = shift; + $amount = $amount * (10**(2)); + my $rounded = int($amount + .5 * ($amount<=> 0)) / (10**(2)); + if($rounded =~ /\.\d+/){ + $rounded = sprintf('%.2f',$rounded); + my $int = 0; + ($int, my $dez) = split(/\./,$rounded) if($rounded =~ /\.\d/); + if($dez > 0 && $dez <= 50){ + $dez = 50; + } + elsif($dez > 50 && $dez <= 99){ + $dez = 00; + $int++; + } + $rounded = $int . "." . $dez; + } + return $rounded; +} + +#split date (moved partly to Callib) +sub split_date(){ + my $self = shift; + my ($time_db) = @_; + $time_db =~ s/:\d{2}\..*$// if($time_db); + my ($date,$time) = split(/ /,$time_db); + my ($yy,$mo,$dd); + ($yy,$mo,$dd) = split(/-/,$date) if($date =~ /\d{4}-/); + ($dd,$mo,$yy) = split(/\./,$date) if($date =~ /\d{2}\./); + my ($hh,$mi) = split(/\:/,$time); + return ($yy,$mo,$dd,$hh,$mi); +} + +#time and date format for DE (moved partly to Callib) +sub time4de(){ + my $self = shift; + my ($time_db,$hhmi,$decode) = @_; + $time_db =~ s/:\d{2}\..*$// if($time_db); + my ($date,$time) = split(/ /,$time_db); + my ($yy,$mo,$dd) = split(/-/,$date); + my ($hh,$mi) = split(/\:/,$time); + my $date_de = " "; + $date_de = "$dd.$mo.$yy"; + $date_de = "$dd.$mo.$yy $hh:$mi" if($hhmi); + + #Deutsch (German) ==> 3 + $date_de = Date_to_Text_Long($yy,$mo,$dd,3) if($decode eq "Date_to_Text_Long"); + $date_de =~ s/M.*rz/März/; + return $date_de; +} + +#error window +sub failure(){ + my $self = shift; + my ($failure,$back) = @_; + print "
    \n"; + print $q->div("$failure"); + print $q->div($q->a({-class=>"linknav3",-href=>'javascript:history.back()'}, "[ $back ]")) if($back); + print "
    \n"; + exit 0; +} + +sub failure2(){ + my $self = shift; + my ($failure,$back) = @_; + print "
    \n"; + print $q->div("$failure"); + print $q->div($q->a({-class=>"linknav3",-href=>'javascript:history.back()'}, "[ $back ]")) if($back); + print "
    \n"; + #exit 0; +} + +sub failure3(){ + my $self = shift; + my ($failure,$back) = @_; + print "
    \n"; + print $q->div("$failure"); + print $q->div($q->a({-class=>"linknav3",-href=>'javascript:history.back()'}, "[ $back ]")) if($back); + print "
    \n"; +} + +#for site-head navigation with breadcrumb and close button +sub pathrun(){ + my $self = shift; + my $path = shift; + my @menu = (""); + if($path =~ /^\/(.*)/){ + @menu = split /\//,$1; + } + my $node_active; + my $crumb; + my $h=0; + my $backlink; + foreach(@menu){ + $node_active=$_; + $crumb = "$menu[0]" if($h==0); + $backlink = "/" if($h==0); + $crumb .= " | $menu[1]" if($h==1); + $backlink = "/$menu[0]#$menu[1]" if($h==1); + #cut long link-name + my $length=length($menu[2]); + my $cut_last; + $cut_last = 1 if($length >= 30); + my $menu2 = &sub4txt("",$menu[2],0,30,"","$cut_last"); + $crumb .= " | $menu2" if($h==2); + $backlink = "/$menu[0]/$menu[1]#$menu[2]" if($h==2); + $h++; + } + return ("$node_active","$crumb","$backlink"); +} + +1; diff --git a/copri4/main/src/Mod/Libenzdb.pm b/copri4/main/src/Mod/Libenzdb.pm new file mode 100644 index 0000000..9dcee93 --- /dev/null +++ b/copri4/main/src/Mod/Libenzdb.pm @@ -0,0 +1,2274 @@ +package Libenzdb; +# +#Deprecated module, please use DBtank.pm +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +#uncomment for perl -cw src/Mod/Libenzdb.pm +#use lib qw(/var/www/copri4/main/src); +# +use strict; +use warnings; +use POSIX; +use DBI; +use CGI; +use CGI ':standard'; +use Text::CSV_XS; +use Spreadsheet::WriteExcel; +use Lib::Config; +use Scalar::Util qw(looks_like_number); +use Digest::MD5 qw(md5 md5_hex); +use Date::Calc qw(check_date); +use Mod::DBtank; +use Data::Dumper; + + +my $cf = new Config; +my $dbt = new DBtank; +my $q = new CGI; +$q->import_names('R'); + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +my $today = strftime("%d.%m.%Y",localtime(time)); +my $date_time = strftime("%d.%m.%Y %H:%M",localtime(time)); +my %varenv = $cf->envonline(); + +my $dbh = $dbt->dbconnect(); + +sub dbdisconnect { + my $self = shift; + $dbh->disconnect; + return; +} + + +#get table column info +sub table_info(){ + my $self = shift; + my ($table,$dbinit) = @_; + $dbh = $dbt->dbconnect() if($dbinit);#because of ajax + my $sth = $dbh->prepare("SELECT attnum,attname FROM pg_class c join pg_attribute a on c.oid = a.attrelid WHERE c.relname = '$table' AND a.attnum >= 0;"); + my $rc = $sth->execute(); + my $column = $sth->fetchall_hashref("attnum"); + $sth->finish; + $dbh->disconnect if($dbinit); + return $column; +} + +# new node +sub insert_node(){ + my $self = shift; + my ($parent_id,$main_id,$node_name,$lang,$sort,$template_id,$c_id,$owner) = @_; + + my $node_path = $node_name; + #für sub-menü hack + $node_path =~ s/\!/\//; + $node_name =~ s/\!.*//; + #split name path + ($node_name,$node_path) = split(/\?/,$node_name) if($node_name =~ /\?/); + + $template_id = "0" if(!$template_id); + $c_id = "0" if(!$c_id); + $sort = "0" if(!$sort); + $owner = "0" if(!$owner); + my ($sth2,$rc); + $sth2 = $dbh->prepare("INSERT INTO nodes (main_id,parent_id,lang,node_name,node_path,n_sort,owner) VALUES('$main_id','$parent_id','$lang',trim('$node_name'),trim('$node_path'),'$sort','$owner')"); + $rc = $sth2->execute(); + $sth2 = $dbh->prepare("INSERT INTO relation (main_id,template_id,content_id,lang,change) VALUES('$main_id','$template_id','$c_id','$lang','now()') RETURNING rel_id"); + $rc = $sth2->execute(); + + my $last_id; + $sth2->bind_columns(\$last_id); + my $rel_id = $sth2->fetchrow_array(); + + return $rel_id; +} +########################## + + +# get next free node +sub get_freenode(){ + my $self = shift; + my $prefix_id = shift; + my $s_id = "$prefix_id"; + my $e_id = "$prefix_id"; + $s_id .= "00001"; + $e_id .= "99999"; + my $main_id; + #print "$s_id - $e_id"; + for (my $x_id=$s_id; $x_id < $e_id; $x_id++){ + my $sth1 = $dbh->prepare("SELECT main_id from nodes where main_id='$x_id'"); + my $rc1 = $sth1->execute(); + $main_id = $sth1->fetchrow_array(); + if(!$main_id){ + #print "$x_id"; + return $x_id; + } + } +} +# + +# get next free template id +sub get_freetpl(){ + my $self = shift; + my ($s_id,$e_id) = @_; + my $tpl_id; + for (my $x_id=$s_id; $x_id < $e_id; $x_id++){ + my $sth1 = $dbh->prepare("SELECT tpl_id from template where tpl_id='$x_id'"); + my $rc1 = $sth1->execute(); + $tpl_id = $sth1->fetchrow_array(); + if(!$tpl_id){ + return $x_id; + } + } +} +# + + +# Delete node and relation! (without content) +sub delete_node(){ + my $self = shift; + my ($main_id,$lang) = @_; + my $sth = $dbh->prepare("DELETE FROM relation WHERE main_id='$main_id' and lang='$lang' and content_id='0'"); + my $rc = $sth->execute(); + $sth = $dbh->prepare("DELETE FROM nodes WHERE main_id='$main_id' and lang='$lang'"); + $rc = $sth->execute(); + #$dbh->commit or die $dbh->errstr; + $sth->finish(); + return $rc; +} + +#all nodes +sub collect_node4all(){ + my $self = shift; + my ($main_id,$lang,$u_id,$min_main_id,$max_main_id) = @_; + my $where = "where 1=1"; + #$where .= " and node_public='1'" if(!$u_id && $varenv{mlogic} eq "web"); + $where .= " and parent_id = '$main_id'" if($main_id); + $where .= " and main_id >= '$min_main_id'" if($min_main_id); + $where .= " and main_id <= '$max_main_id'" if($max_main_id); + my $sth = $dbh->prepare("SELECT * FROM nodes $where"); + my $rc = $sth->execute(); + my $nodes = $sth->fetchall_hashref("n_id"); + $sth->finish; + return $nodes; +} + +# Nodes einer Ebene +sub collect_node(){ + my $self = shift; + my ($main_id,$lang,$u_id,$dbinit) = @_; + $dbh = $dbt->dbconnect() if($dbinit); + my $where = ""; + #$where = " and node_public='1'" if(!$u_id && $varenv{mlogic} eq "web"); + my $sth = $dbh->prepare("SELECT * FROM nodes WHERE parent_id='$main_id' and lang='$lang' $where"); + my $rc = $sth->execute(); + my $nodes = $sth->fetchall_hashref("main_id"); + $sth->finish; + $dbh->disconnect if($dbinit); + return $nodes; +} + +# Nodes with relation +sub collect_noderel(){ + my $self = shift; + my ($main_id,$lang,$u_id,$dbinit) = @_; + $dbh = $dbt->dbconnect() if($dbinit); + my $where=""; + #$where = " and nd.node_public='1'" if(!$u_id && $varenv{mlogic} eq "web"); + my $sth = $dbh->prepare("SELECT * FROM nodes nd, relation rel WHERE nd.main_id=rel.main_id and nd.parent_id='$main_id' and nd.lang='$lang' and rel.content_id=0 $where"); + my $rc = $sth->execute(); + my $nodes = $sth->fetchall_hashref("main_id"); + $sth->finish; + $dbh->disconnect if($dbinit); + return $nodes; +} + + +# Nodes recursive +sub collect_noderec(){ + my $self = shift; + my ($main_id,$lang,$excluded,$u_id,$hashref) = @_; + $main_id =~ s/,$//; + my $main_ids = "$main_id,"; + my $main_ids_ref; + my $main_collect = &collect_node("",$main_id,$lang,$u_id,"",""); + if(ref($main_collect) eq "HASH"){ + #$main_ids_ref = { $main_collect }; + foreach my $id (keys (%$main_collect)){ + if($main_collect->{$id}->{node_name} !~ /$excluded/){ + $main_ids .= "$main_collect->{$id}->{main_id},"; + #print "$main_id:$main_collect->{$id}->{main_id}
    "; + my $main_collect2 = &collect_node("",$main_collect->{$id}->{main_id},$lang,$u_id,"") if($main_collect->{$id}->{main_id}); + if(ref($main_collect2) eq "HASH"){ + #$main_ids_ref = { $main_collect, $main_collect2 }; + foreach my $id (keys (%$main_collect2)){ + $main_ids .= "$main_collect2->{$id}->{main_id},"; + my $main_collect3 = &collect_node("",$main_collect2->{$id}->{main_id},$lang,$u_id,"") if($main_collect2->{$id}->{main_id}); + if(ref($main_collect3) eq "HASH"){ + #$main_ids_ref = { $main_collect, $main_collect2, $main_collect3 }; + foreach my $id (keys (%$main_collect3)){ + $main_ids .= "$main_collect3->{$id}->{main_id},"; + } + } + } + } + } + } + } + $main_ids =~ s/,$//; + if($hashref){#disabled and never uesd + return $main_ids_ref; + }else{ + return $main_ids; + } +} + +# Nodes +sub collect_node2(){ + my $self = shift; + my $main_ids = shift; + $main_ids =~ s/,$//; + my $sth = $dbh->prepare("SELECT * FROM nodes WHERE main_id IN ($main_ids)"); + my $rc = $sth->execute(); + my $nodes = $sth->fetchall_hashref("main_id"); + $sth->finish; + return $nodes; +} + +# Nodes with variable +sub collect_node3(){ + my $self = shift; + my ($column1,$op1,$content1,$column2,$op2,$content2,$main_ids) = @_; + $main_ids =~ s/,$//; + my $where = "$column1 $op1 '$content1'"; + $where .= " and $column2 $op2 '$content2'" if($content2); + $where .= " and main_id IN ($main_ids)"; + my $sth = $dbh->prepare("SELECT * FROM nodes WHERE $where"); + my $rc = $sth->execute(); + my $nodes = $sth->fetchall_hashref("main_id"); + $sth->finish; + return $nodes; +} + +# Nodes Anhand der main_id +sub get_node4all(){ + my $self = shift; + my ($main_id) = @_; + my $sth = $dbh->prepare("SELECT * FROM nodes WHERE main_id='$main_id'"); + my $rc = $sth->execute(); + my $nodes = $sth->fetchall_hashref("lang"); + $sth->finish; + return $nodes; +} + +# Node Anhand der main_id für multilang +sub get_node4multi(){ + my $self = shift; + my ($main_id,$lang,$owner,$parent_id,$dbinit) = @_; + $dbh = $dbt->dbconnect() if($dbinit); + $owner=0 if(!$owner); + my $sel=""; + $sel .= " and owner='$owner'" if($owner > 0); + $sel .= " and parent_id='$parent_id'" if($parent_id && $parent_id =~ /^\d+$/ && $parent_id > 0); + $sel .= " order by parent_id $parent_id" if($parent_id && $parent_id =~ /ASC|DESC/);#workaround Verleihräder + my $sth = $dbh->prepare("SELECT * FROM nodes WHERE main_id='$main_id' and lang='$lang' $sel"); + my $rc = $sth->execute(); + my $node = $sth->fetchrow_hashref(); + $dbh->disconnect if($dbinit); + return $node; +} + + +# get child node +sub get_subnode(){ + my $self = shift; + my ($main_id,$lang,$n_sort) = @_; + my $where; + $where = "and n_sort = '$n_sort'" if($n_sort); + my $sth = $dbh->prepare("SELECT * FROM nodes WHERE parent_id='$main_id' and lang='$lang' $where"); + my $rc = $sth->execute(); + my $node = $sth->fetchrow_hashref(); + return $node; +} + + +# Node Anhand des node_name und parent_id +sub get_nodeset(){ + my $self = shift; + my ($parent_id,$node_name,$lang,$dbinit) = @_; + $dbh = $dbt->dbconnect() if($dbinit); + $node_name = $q->escapeHTML($node_name); + my $sel_node_name; + $sel_node_name = "and (nodes.node_path='$node_name' OR nodes.node_name='$node_name')" if($node_name); + my $sth = $dbh->prepare("SELECT * FROM nodes, relation WHERE nodes.main_id=relation.main_id $sel_node_name and nodes.lang='$lang' and nodes.parent_id='$parent_id'"); + my $rc = $sth->execute(); + my $node = $sth->fetchrow_hashref(); + $dbh->disconnect if($dbinit); + return $node; +} + +# Node Anhand des node_name and parent_id +sub get_node(){ + my $self = shift; + my ($node_name,$lang,$operator,$parent_id) = @_; + #print "($node_name,$lang,$operator,$parent_id)"; + $node_name = $q->escapeHTML($node_name); + my $where = "lang='$lang'"; + $where .= " and parent_id $operator '$parent_id'" if($parent_id); + my $sth = $dbh->prepare("SELECT * FROM nodes WHERE (node_path='$node_name' OR node_name='$node_name') and $where"); + #print "SELECT * FROM nodes WHERE (node_path='$node_name' OR node_name='$node_name') and $where"; + my $rc = $sth->execute(); + my $node = $sth->fetchrow_hashref(); + return $node; +} + +# Node main_id and template_id and node_name +sub get_node4rel(){ + my $self = shift; + my ($main_id,$template_id,$node_name,$content_id) = @_; + my $where = "no.main_id=rel.main_id"; + $where .= " and rel.template_id=$template_id" if($template_id); + $where .= " and no.main_id=$main_id" if($main_id); + $where .= " and no.node_name ilike '$node_name'" if($node_name); + $where .= " and no.node_public = '1'" if($varenv{wwwhost} =~ /tinkdms/); + $where .= " and rel.content_id = '0'" if($content_id eq "null"); + my $sth = $dbh->prepare("SELECT * FROM nodes no, relation rel WHERE $where "); + my $rc = $sth->execute(); + my $node = $sth->fetchrow_hashref(); + return $node; +} + + +# Node Anhand des node_name und parent-node_name +sub get_node2(){ + my $self = shift; + my ($parentsel,$node_name,$lang) = @_; + $node_name = $q->escapeHTML($node_name); + my $sth = $dbh->prepare("SELECT * FROM nodes WHERE (node_path='$node_name' OR node_name='$node_name') and lang='$lang' and parent_id IN (SELECT main_id from nodes where (node_path='$parentsel' OR node_name='$parentsel') and lang='$lang')"); + my $rc = $sth->execute(); + my $node = $sth->fetchrow_hashref(); + return $node; +} +# Node Anhand des node_name und parent_id +sub get_node3(){ + my $self = shift; + my ($parent_id,$node_name,$lang) = @_; + my $sth = $dbh->prepare("SELECT * FROM nodes WHERE node_name='$node_name' and lang='$lang' and parent_id='$parent_id'"); + my $rc = $sth->execute(); + my $node = $sth->fetchrow_hashref(); + return $node; +} + +# all templates +sub collect_tpl(){ + my $self = shift; + my ($tpl_ids,$key) = @_; + my $where = "where tpl_id != 98 and tpl_id != 97";#without meta-Config and EditNode + $where .= " and tpl_id IN ($tpl_ids)" if($tpl_ids); + $where .= " and tpl_order like '%$key%'" if($key); + my $sth = $dbh->prepare("SELECT * FROM template $where"); + my $rc = $sth->execute(); + my $tpl_all = $sth->fetchall_hashref("tpl_id"); + $sth->finish; + return $tpl_all; +} + +# get template row +sub get_tpl(){ + my $self = shift; + my ($template_id) = @_; + $template_id= 0 if(!$template_id); + my $sth = $dbh->prepare("SELECT * FROM template WHERE tpl_id='$template_id'"); + my $rc = $sth->execute(); + my $tpl = $sth->fetchrow_hashref(); + return $tpl; +} + +# get template row +sub get_tpl2(){ + my $self = shift; + my ($tpl_name) = @_; + my $sth = $dbh->prepare("SELECT * FROM template WHERE tpl_name='$tpl_name'"); + my $rc = $sth->execute(); + my $tpl = $sth->fetchrow_hashref(); + return $tpl; +} + + + +# get all relation from main_id +sub get_rel4all(){ + my $self = shift; + my ($main_id) = @_; + my $sth = $dbh->prepare("SELECT * FROM relation WHERE main_id='$main_id'"); + my $rc = $sth->execute(); + my $rel = $sth->fetchall_hashref("lang"); + $sth->finish; + return $rel; +} + + +# get relation row +sub get_relation(){ + my $self = shift; + my ($main_id,$lang,$rel_id) = @_; + my $where = "1=1"; + $where .= " and main_id='$main_id' and lang='$lang'" if($main_id); + $where .= " and rel_id='$rel_id'" if($rel_id); + my $sth = $dbh->prepare("SELECT * FROM relation WHERE $where"); + my $rc = $sth->execute(); + my $rel = $sth->fetchrow_hashref(); + return $rel; +} + +#NO isnt't consistent, because of after delete, we need a empty relation +#get empty relation row +sub get_rel4empty(){ + my $self = shift; + my ($main_id,$lang,$content_id,$template_id) = @_; + my $where = "main_id='$main_id' and lang='$lang'"; + $where .= " and (content_id = '0' OR content_id is null)"; + $where .= " and template_id='$template_id'" if($template_id > 0); + my $sth = $dbh->prepare("SELECT * FROM relation WHERE $where"); + my $rc = $sth->execute(); + my $rel = $sth->fetchrow_hashref(); + return $rel; +} + + + +# get relation with template +sub get_rel4tpl(){ + my $self = shift; + my ($main_id,$lang,$content_id,$template_id,$ascdesc,$rel_id,$realct) = @_; + $content_id=0 if(!$content_id); + my $where = "WHERE relation.template_id=template.tpl_id and lang='$lang'"; + $where .= " and relation.main_id='$main_id'" if($main_id > 0); + $where .= " and relation.content_id='$content_id'" if($content_id > 0); + $where .= " and relation.template_id='$template_id'" if($template_id > 0); + $where .= " and relation.rel_id='$rel_id'" if($rel_id > 0); + $where .= " and content_id $realct" if($realct);# MandantConf >0 + $where .= " order by content_id $ascdesc" if($ascdesc); + my $sth = $dbh->prepare("SELECT * FROM relation,template $where"); + my $rc = $sth->execute(); + my $rel = $sth->fetchrow_hashref(); + return $rel; +} + +# get relation, template, nodes +sub get_rel4tpl4nd(){ + my $self = shift; + my ($main_id,$lang,$content_id,$template_id,$ascdesc,$rel_id) = @_; + $content_id=0 if(!$content_id); + my $where = "WHERE nodes.main_id=relation.main_id and relation.template_id=template.tpl_id"; + $where .= " and relation.main_id='$main_id'" if($main_id > 0); + $where .= " and relation.content_id='$content_id'" if($content_id > 0); + $where .= " and relation.template_id='$template_id'" if($template_id > 0); + $where .= " and relation.rel_id='$rel_id'" if($rel_id > 0); + $where .= " order by content_id $ascdesc" if($ascdesc); + my $sth = $dbh->prepare("SELECT * FROM relation,template,nodes $where"); + my $rc = $sth->execute(); + my $rel = $sth->fetchrow_hashref(); + return $rel; +} + + + +# get content based by owner +sub get_content4owner(){ + my $self = shift; + my ($table,$owner) = @_; + my $where = "WHERE owner='$owner'"; + my $sth = $dbh->prepare("SELECT * FROM $table $where"); + my $rc = $sth->execute(); + my $rel = $sth->fetchrow_hashref(); + return $rel; +} + +# delete relation (without node) +sub delete_relation(){ + my $self = shift; + my ($main_id,$lang,$rel_id) = @_; + my $sth = $dbh->prepare("DELETE FROM relation WHERE main_id='$main_id' and lang='$lang' and rel_id='$rel_id'"); + my $rc = $sth->execute(); + $sth->finish(); + return $rc; +} + +# delete template (without node) +sub delete_template(){ + my $self = shift; + my ($tpl_id) = @_; + my $sth = $dbh->prepare("DELETE FROM template WHERE tpl_id='$tpl_id'"); + my $rc = $sth->execute(); + $sth->finish(); + return $rc; +} + +# insert relation +sub insert_relation(){ + my $self = shift; + my ($table,$main_id,$lang,$c_id,$tpl_id,$offer_id) = @_; + my $foreign_key=""; + my $foreign_id = $c_id;#alle bis auf offer + $foreign_key = "cc_id" if("$table" eq "content"); + $foreign_key = "cp_id" if("$table" eq "contentpers"); + $foreign_key = "cu_id" if("$table" eq "contentuser"); + $foreign_key = "co_id" if("$table" eq "offer"); + $foreign_id = 0 if(!$c_id); + $foreign_id = $offer_id if("$table" eq "offer"); + $c_id = 0 if(!$c_id); + $offer_id = 0 if(!$offer_id); + $tpl_id = 0 if(!$tpl_id); + my $sth = $dbh->prepare("INSERT INTO relation ($foreign_key,main_id,content_id,offer_id,template_id,lang,change) VALUES('$foreign_id','$main_id','$c_id','$offer_id','$tpl_id','$lang','now()') RETURNING rel_id"); + my $rows = $sth->execute(); + + my $last_id; + $sth->bind_columns(\$last_id); + my $rel_id = $sth->fetchrow_array(); + + return $rel_id; +} + +# insert relationlist for multi relation in listing mode +sub insert_relationlist(){ + my $self = shift; + my ($table,$main_id,$lang,$c_id,$tpl_id,$foreign_key,$mastermain_id,$dbinit) = @_; + $dbh = $dbt->dbconnect() if($dbinit);#because of ajax + $c_id = 0 if(!$c_id); + $tpl_id = 0 if(!$tpl_id); + $mastermain_id = 0 if(!$mastermain_id); + my $sth = $dbh->prepare("INSERT INTO relation (main_id,content_id,$foreign_key,template_id,lang,change,mastermain_id) VALUES('$main_id','$c_id','$c_id','$tpl_id','$lang','now()',$mastermain_id) RETURNING rel_id"); + my $rows = $sth->execute(); + + my $last_id; + $sth->bind_columns(\$last_id); + my $rel_id = $sth->fetchrow_array(); + + $dbh->disconnect if($dbinit); + return $rel_id; +} + +# obsolet +# update relation +sub update_relation(){ + my $self = shift; + my ($main_id,$lang,$new_main_id,$template_id,$c_id,$rel_id,$foreign_key) = @_; + my $foreign_id = $c_id; + $foreign_id = 0 if(!$c_id); + $c_id = 0 if(!$c_id); + my $rel_set = "change='now()'"; + $rel_set .= ",main_id='$new_main_id'" if($new_main_id); + $rel_set .= ",template_id='$template_id'" if($template_id =~ /\d/); + $rel_set .= ",content_id='$c_id'" if($c_id =~ /\d/); + $rel_set .= ",$foreign_key='$foreign_id'" if($foreign_key && $foreign_id); + $rel_set .= ",template_id='0'" if(!$template_id); + $rel_set .= ",content_id='0'" if(!$c_id); + + my $where = "where main_id='$main_id' and lang='$lang' and rel_id='$rel_id'"; + my $sth = $dbh->prepare("UPDATE relation SET $rel_set $where"); + my $rows = $sth->execute(); + return $rows; +} + +sub update_relation2(){ + my $self = shift; + my ($main_id,$lang,$new_main_id,$new_template_id,$rel_id,$dbinit) = @_; + $dbh = $dbt->dbconnect() if($dbinit);#because of ajax + my $rel_set = "change='now()'"; + $rel_set .= ",main_id='$new_main_id'" if($new_main_id); + $rel_set .= ",template_id='$new_template_id'" if($new_template_id); + my $where = "where lang='$lang' and rel_id='$rel_id'"; + $where .= " and main_id='$main_id'" if($main_id); + my $sth = $dbh->prepare("UPDATE relation SET $rel_set $where"); + my $rows = $sth->execute(); + $dbh->disconnect if($dbinit); + return $rows; +} + +#change all relations of main_id (maybe changeing template ore node) +sub update_relation3(){ + my $self = shift; + my ($main_id,$lang,$new_main_id,$template_id) = @_; + my $rel_set = "change='now()'"; + $rel_set .= ",main_id='$new_main_id'" if($new_main_id); + $rel_set .= ",template_id='$template_id'" if($template_id =~ /\d/); + my $where = "where lang='$lang' and main_id='$main_id'"; + my $sth = $dbh->prepare("UPDATE relation SET $rel_set $where"); + my $rows = $sth->execute(); + return $rows; +} + + +sub update_users4trans(){ + my $self = shift; + my ($c_id4trans,$tpl_id4trans,$kind_of_trans,$u_id) = @_; + my $sth = $dbh->prepare("UPDATE users SET + c_id4trans='$c_id4trans', + tpl_id4trans='$tpl_id4trans', + ctpos_activ='0', + kind_of_trans='$kind_of_trans' + where u_id=$u_id"); + my $rows = $sth->execute(); + return $rows; +} + +sub cleanup_users(){ + my $self = shift; + my $u_id = shift; + my $sth = $dbh->prepare("UPDATE users SET + c_id4trans='0', + tpl_id4trans='0', + ctpos_activ='0', + c_id4package='0', + kind_of_trans='', + parts_uri='', + address_uri='', + project_uri='', + transaction_uri='', + nel_uri='' + where u_id=$u_id"); + my $rows = $sth->execute(); + return $rows; +} + +# final users_update +sub users_up(){ + my $self = shift; + my ($column,$value,$u_id) = @_; + #if($value){ + my $sth = $dbh->prepare("UPDATE users SET $column='$value' where u_id='$u_id'"); + my $rows = $sth->execute(); + return $rows; + #} +} + +# all content +sub collect_content(){ + my $self = shift; + my $sth = $dbh->prepare("SELECT c_id,ct_name FROM content"); + my $rc = $sth->execute(); + my $ct_all = $sth->fetchall_hashref("c_id"); + $sth->finish; + return $ct_all; +} + +# all content or tt_news_cat +sub collect_content2(){ + my $self = shift; + my ($table,$column,$content,$id_key) = @_; + $id_key="c_id" if(!$id_key); + my $sel=""; + $sel = "where $column='$content'" if($content); + my $sth = $dbh->prepare("SELECT * FROM $table $sel"); + my $rc = $sth->execute(); + my $ct_all = $sth->fetchall_hashref("$id_key"); + $sth->finish; + return $ct_all; +} + +# all content, mainly used by get_freenr +sub collect_content3(){ + my $self = shift; + my ($table,$column,$content,$key) = @_; + $key = "barcode" if(!$key); + my $where; + $where = "where $column = '$content'" if($content); + my $sth = $dbh->prepare("SELECT * FROM $table $where"); + my $rc = $sth->execute(); + my $ct_all = $sth->fetchall_hashref("$key"); + $sth->finish; + return $ct_all; +} + + +#collect relation nodes +sub collect_rel4nodes(){ + my $self = shift; + my ($main_ids,$content_id,$template_id,$key) = @_; + my $where; + $where .= " and parent_id IN ($main_ids)" if($main_ids); + if($content_id =~ /\d\s\d/){ + $content_id =~ s/\s/,/g; + $where .= " and rel.content_id IN ($content_id)"; + }elsif($content_id){ + $where .= " and rel.content_id='$content_id'"; + } + $where .= " and rel.template_id='$template_id'" if($template_id); + my $sth = $dbh->prepare("SELECT * FROM relation rel, nodes nd where rel.main_id=nd.main_id $where"); + my $rc = $sth->execute(); + $key = "main_id" if(!$key); + my $rel4nd = $sth->fetchall_hashref("$key"); + $sth->finish; + return $rel4nd; +} + +#collect relation templates +sub collect_rel4tpl(){ + my $self = shift; + my ($main_id) = @_; + my $where; + $where .= " and rel.main_id='$main_id'" if($main_id); + my $sth = $dbh->prepare("SELECT * FROM relation rel, template tpl where rel.template_id=tpl.tpl_id $where"); + my $rc = $sth->execute(); + my $rel4tpl = $sth->fetchall_hashref("main_id"); + $sth->finish; + return $rel4tpl; +} + +# all content4relation +sub collect_ct4rel(){ + my $self = shift; + my ($table,$main_ids,$lang,$scol,$offset,$limit,$sort4edit,$tplids,$relids,$sort_updown,$content_ids,$id) = @_; + $main_ids =~ s/,$//; + $tplids =~ s/,$//; + $relids =~ s/,$//; + $content_ids =~ s/,$//; + my $updown = "ASC"; + $updown = "DESC" if($sort_updown eq "down"); + + my $where; + if($relids =~ /\d/){ + $where .= " and rel.rel_id IN ($relids)"; + }elsif($table eq "contenttrans"){ + $where .= " and ct.close_time is null"; + } + #$where .= " and rel.main_id='$main_id'" if($main_id); + $where .= " and rel.main_id IN ($main_ids)" if($main_ids); + $where .= " and rel.template_id IN ($tplids)" if($tplids =~ /\d/); + $where .= " and rel.content_id IN ($content_ids)" if($content_ids =~ /\d/); + $where .= " and sort like '$sort4edit%'" if($sort4edit); + $where .= " ORDER BY $scol $updown" if($scol); + $where .= " LIMIT $limit" if($limit); + $where .= " OFFSET $offset" if($offset); + my $sth = $dbh->prepare("SELECT * FROM $table ct, relation rel where ct.c_id=rel.content_id and rel.lang='$lang' $where"); + my $rc = $sth->execute(); + $id = "c_id" if(!$id); + my $ct4rel = $sth->fetchall_hashref("$id"); + $sth->finish; + return $ct4rel; +} + +# all content4relation for main_ids +sub collect_ct4rel2(){ + my $self = shift; + my ($table,$main_ids,$lang,$scol,$offset,$limit,$owner,$id,$u_id,$trader) = @_; + $main_ids =~ s/,$//; + my $where; + $where = " and ct.close_time is null" if($table eq "contenttrans"); + $where .= " and ct.owner = '$owner'" if($owner); + $where = " and ct.trader = '$trader'" if($trader); + #$where .= " and ct.content_public = '1'" if($u_id !~ /\d|always_public/); + $where .= " and ct.content_public = '1'" if($u_id == 0 || $u_id !~ /\d/); + if($scol && $limit){ + $where .= " ORDER BY $scol LIMIT $limit OFFSET $offset"; + }elsif($scol){ + $where .= " ORDER BY $scol"; + } + my $sth = $dbh->prepare("SELECT * FROM $table ct, relation rel where ct.c_id=rel.content_id and rel.main_id IN ($main_ids) $where"); + my $rc = $sth->execute(); + $id="c_id" if(!$id); + #$id="rel_id" if(!$id && $varenv{mlogic} eq "web"); #impliziert mehrfach-einträge, siehe Kacheln + #$id="main_id" if($varenv{mlogic} eq "web"); + my $ct4rel = $sth->fetchall_hashref("$id"); + $sth->finish; + return $ct4rel; +} + + +# all content4relation with optional c_ids and operator +sub collect_ct4rel3(){ + my $self = shift; + my ($table,$column1,$content1,$op2,$column2,$content2,$tpl_ids,$c_ids,$id) = @_; + $tpl_ids =~ s/,$//; + $c_ids =~ s/,$//; + my $where="where ct.c_id=rel.content_id"; + if($content1 =~ /\d+,\d+/){ + $where .= " and rel.$column1 IN ($content1)"; + }elsif($content1){ + $where .= " and rel.$column1='$content1'"; + } + if("$content2" || "$content2" eq "0"){ + $where .= " and ct.$column2 $op2 $content2" if($column2 =~ /int/); + $where .= " and ct.$column2 $op2 '$content2'" if($column2 !~ /int/); + } + $where .= " and rel.template_id IN ($tpl_ids)" if($tpl_ids); + $where .= " and ct.c_id IN ($c_ids)" if($c_ids); + my $sth = $dbh->prepare("SELECT * FROM $table ct, relation rel $where"); + my $rc = $sth->execute(); + $id="c_id" if(!$id); + my $ct_all = $sth->fetchall_hashref($id); + $sth->finish; + return $ct_all; +} + +# all content + relation + nodes +sub collect_ct4rel4nd(){ + my $self = shift; + my ($table,$main_ids,$lang,$scol,$offset,$limit,$colname,$colval,$tpl_ids,$rel_ids,$id,$parent_id) = @_; + $tpl_ids =~ s/,$//; + $main_ids =~ s/,$//; + $rel_ids =~ s/,$//; + my $where; + if($colname && $colname =~ /int/ && $colval eq "null"){ + $where .= " and $colname is $colval"; + }elsif($colname && $colval){ + $where .= " and $colname = '$colval'"; + } + $where .= " and rel.template_id IN ($tpl_ids)" if($tpl_ids); + $where .= " and rel.main_id IN ($main_ids)" if($main_ids); + $where .= " and nd.parent_id = '$parent_id'" if($parent_id); + $where .= " and rel.rel_id IN ($rel_ids)" if($rel_ids); + $where .= " and nd.node_public='1'" if($varenv{wwwhost} =~ /k9/); + + my $scol_table = "ct"; + $scol_table = "nd" if($scol eq "n_sort"); + if($scol && $limit){ + $where .= " ORDER BY $scol_table.$scol LIMIT $limit OFFSET $offset"; + }elsif($scol){ + $where .= " ORDER BY $scol_table.$scol"; + } + my $sth = $dbh->prepare("SELECT * FROM $table ct, relation rel, nodes nd where ct.c_id=rel.content_id and nd.main_id=rel.main_id $where"); + my $rc = $sth->execute(); + my $ct4rel = $sth->fetchall_hashref("$id"); + $sth->finish; + return $ct4rel; +} + + +#collect content with contenttranspos by c.c_id... +sub collect_postime(){ + my $self = shift; + my ($table,$start_date_time,$end_date_time,$start_date2,$end_date2) = @_; + $start_date_time =~ s/,/./g; + $end_date_time =~ s/,/./g; + my $where = "where cp.cc_id=c.c_id"; + $where .= " and cp.start_time >= $start_date_time"; + $where .= " and cp.end_time <= $end_date_time"; + $where .= " and (cp.start_time >= '$start_date2' OR cp.end_time >= '$start_date2')" if($start_date2 && $end_date2); + my $sth = $dbh->prepare("SELECT cp.* from content c, $table cp $where order by cp.end_time"); + my $rc = $sth->execute(); + my $ct = $sth->fetchall_hashref("cc_id"); + $sth->finish; + return $ct; +} + + +#all position of contenttrans +sub collect_contentpos(){ + my $self = shift; + my ($table,$c_id) = @_; + my $tb = "contenttrans"; + my $tbpos = "contenttranspos"; + if($table eq "contenttver"){ + $tb = "contenttver"; + $tbpos = "contenttverpos"; + } + my $where = "where ctt.c_id=pos.ct_id and ctt.c_id='$c_id'"; + + if($c_id){ + my $sth = $dbh->prepare("SELECT pos.* FROM $tbpos pos, $tb ctt $where"); + my $rc = $sth->execute(); + my $cpos = $sth->fetchall_hashref("c_id"); + my $rows = $sth->rows; + $sth->finish; + return ($cpos,$rows); + }else{ + my $cpos = { c_id => 0 }; + my $rows = 0; + return ($cpos,$rows); + } +} + +# get content 4 time row where c_id +sub get_time4ct(){ + my $self = shift; + my ($table,$ctpos_id,$cvpos_id,$owner) = @_; + my $pos_key = "ctpos_id"; + my $pos_id = $ctpos_id; + $pos_id = "0" if(!$ctpos_id); + if($cvpos_id){ + $pos_key = "cvpos_id"; + $pos_id = $cvpos_id; + } + + $owner=0 if(!$owner); + my $ownersel=""; + $ownersel = "and owner='$owner'" if($owner > 0); + my $sth = $dbh->prepare("SELECT * FROM $table ct,timetable WHERE ct.c_id='$pos_id' and ct.c_id=timetable.$pos_key $ownersel"); + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + return $ct; +} + +# get content row where c_id +sub get_content(){ + my $self = shift; + my ($c_id,$owner) = @_; + $c_id=0 if(!$c_id); + $owner=0 if(!$owner); + my $ownersel=""; + $ownersel = "and owner='$owner'" if($owner > 0); + my $sth = $dbh->prepare("SELECT * FROM content WHERE c_id='$c_id' $ownersel"); + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + return $ct; +} + + +sub get_contentrow(){ + my $self = shift; + my ($table,$c_id,$column,$content,$column2,$content2,$column3,$content3) = @_; + my $where = "1 = 1"; + if($c_id){ + $where .= " and c_id='$c_id'"; + }elsif($column && $content){ + $where .= " and $column='$content'"; + }else{ + exit 1; + } + if($column2 && $content2){ + $where .= " and $column2='$content2'"; + } + if($column3 && $content3){ + $where .= " and $content3"; # length(ct_name) >= 11 matches PO-14058223 and 9550010000059998099 + $where .= " and (int03=1 OR int03=2)" if($column3 eq "ct_name"); + } + + my $sth = $dbh->prepare("SELECT * FROM $table WHERE $where"); + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + return $ct; +} + +#get not closed contenttrans row +sub get_contenttrans(){ + my $self = shift; + my ($userID,$main_id,$main_id_ch) = @_; + my $sth = $dbh->prepare("SELECT * FROM contenttrans ct, relation rel WHERE ct.c_id=rel.content_id and rel.main_id IN ($main_id,$main_id_ch) and ct.txt08 ilike '$userID' and (ct.state is null OR ct.state = '') and ct.close_time is null"); + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + return $ct; +} + +# insert contenttrans +# only used in Prelogic and should be deleted. +sub insert_contenttrans(){ + my $self = shift; + my ($ctadr,$main_id,$tpl_id,$owner) = @_; + $owner="199" if(!$owner); + my $sth = $dbh->prepare("INSERT INTO contenttrans (ct_name,txt00,int10,int03,txt02,txt01,txt03,txt06,txt07,txt08,txt09,txt15,txt17,txt18,txt19,owner,itime) VALUES('----','Rechnung','$ctadr->{c_id}','$ctadr->{int03}','$ctadr->{txt02}','$ctadr->{txt01}','$ctadr->{txt03}','$ctadr->{txt06}','$ctadr->{txt07}','$ctadr->{txt08}','$ctadr->{txt09}','$ctadr->{txt15}','$ctadr->{txt17}','$ctadr->{txt18}','$ctadr->{txt19}','$owner','now()') RETURNING c_id"); + + my $rows = $sth->execute(); + my $last_id; + $sth->bind_columns(\$last_id); + my $c_id = $sth->fetchrow_array(); + + my $sth3 = $dbh->prepare("INSERT INTO relation (ca_id,main_id,content_id,template_id,change) VALUES('$ctadr->{c_id}','$main_id','$c_id','$tpl_id','now()')"); + $sth3->execute(); + return $c_id; +} + +# get content row where c_id +sub get_content1(){ + my $self = shift; + my ($table,$c_id,$owner,$mtime) = @_; + $c_id=0 if(!$c_id); + $owner=0 if(!$owner); + #my $ownersel; + #$ownersel = "and owner='$owner'" if($owner > 0); + my $sel = "1 = 1"; + $sel .= " and c_id='$c_id'"; + $sel .= " and owner='$owner'" if($owner > 0); + $sel .= " and mtime <= '$mtime'" if($mtime); + #my $sth = $dbh->prepare("SELECT * FROM $table WHERE c_id='$c_id' $ownersel"); + my $sth = $dbh->prepare("SELECT * FROM $table WHERE $sel"); + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + return $ct; +} + +# get content row +sub get_content2(){ + my $self = shift; + my ($table,$ct_name,$owner,$mtime,$column,$content,$op) = @_; + $owner=0 if(!$owner); + my $sel = "1 = 1"; + $sel .= " and ct_name='$ct_name'" if($ct_name); + $sel .= " and owner='$owner'" if($owner > 0); + $sel .= " and mtime >= '$mtime'" if($mtime); + $op="=" if(!$op); + $sel .= " and $column $op '$content'" if($content && $content ne "null"); + $sel .= " and $column $op $content" if($content && $content eq "null"); + my $sth = $dbh->prepare("SELECT * FROM $table WHERE $sel order by c_id DESC"); + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + return $ct; +} + +sub get_content4new(){ + my $self = shift; + my ($table,$ct_name,$barcode,$txt11) = @_; + my $sel = "ct_name = '$ct_name'"; + $sel .= " OR barcode='$barcode'" if($barcode =~ /^\d+$/); + $sel .= " OR txt11='$txt11'" if($txt11); + my $sth = $dbh->prepare("SELECT * FROM $table WHERE $sel order by c_id DESC"); + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + return $ct; +} + + +# get content row where ct_name and ct_id +sub get_content5(){ + my $self = shift; + my ($table,$ct_name,$c_id,$ct_id,$operator) = @_; + my $sel = "1 = 1"; + my $op="="; + $op="!=" if($operator eq "not"); + $sel .= " and ct_name = '$ct_name'" if($ct_name); + $sel .= " and c_id $op '$c_id'" if($c_id); + $sel .= " and ct_id = '$ct_id'" if($ct_id); + my $sth = $dbh->prepare("SELECT * FROM $table WHERE $sel order by c_id DESC"); + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + return $ct; +} + + +# get content row where column content +sub get_content6(){ + my $self = shift; + my ($table,$column1,$content1,$column2,$content2,$column3,$content3,$column4,$content4,$owner) = @_; + my $where = "$column1 = '$content1'"; + $where = "$column1 is $content1" if($content1 eq "null"); + $where .= " and $column2 = '$content2'" if($content2); + $where .= " and $column3 = '$content3'" if($content3); + $where .= " and $column4 <= $content4" if($content4); + $where .= " and owner = '$owner'" if($owner); + my $sth; + if($table eq "timetable"){ + $sth = $dbh->prepare("SELECT * FROM $table WHERE $where"); + }else{ + $sth = $dbh->prepare("SELECT * FROM $table WHERE $where order by c_id DESC"); + } + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + return $ct; +} + + +# get last content row via c_id and operator +sub get_content7(){ + my $self = shift; + my ($table,$column,$content,$column2,$op2,$content2) = @_; + my $where = "1 = 1"; + $where .= " and $column = '$content'" if($content && $content > 0); + $where .= " and $column2 $op2 '$content2'" if("$content2" || "$content2" eq "0"); + my $sth = $dbh->prepare("SELECT * FROM $table where $where order by mtime DESC"); + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + return $ct; +} + +# get last content row for sorted insert +sub get_content2sort(){ + my $self = shift; + my ($table,$sort,$sortop,$col1,$val1,$col2,$val2) = @_; + $sortop = "=" if(!$sortop); + my $where = "1 = 1"; + $where .= " and sort $sortop '$sort'" if($sort > 0); + $where .= " and $col1 = '$val1'" if($val1); + $where .= " and $col2 != '$val2'" if($val2); + my $sth = $dbh->prepare("SELECT * FROM $table where $where order by sort DESC"); + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + return $ct; +} + +# get last content,relation! row for sorted insert +sub get_content3sort(){ + my $self = shift; + my ($table,$main_id) = @_; + my $where = "$table.c_id=relation.content_id"; + $where .= " and relation.main_id= '$main_id'" if($main_id); + my $sth = $dbh->prepare("SELECT * FROM $table,relation where $where order by $table.sort DESC"); + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + return $ct; +} + +# get last content row via c_id like for sorted insert +sub get_like2sort(){ + my $self = shift; + my ($table,$column,$content,$column2,$op2,$content2,$column3,$op3,$content3) = @_; + my $where = "1 = 1"; + $where .= " and $column ilike '$content%'" if($content && $content > 0); + $where .= " and $column2 $op2 '$content2'" if("$content2" || "$content2" eq "0"); + $where .= " and $column3 $op3 '$content3'" if("$content3"); + #my $sth = $dbh->prepare("SELECT * FROM $table where $where order by $column DESC"); + my $sth = $dbh->prepare("SELECT * FROM $table where $where order by mtime DESC"); + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + return $ct; +} + +# get last barcode row +sub get_barcode(){ + my $self = shift; + my ($table,$bc4table) = @_; + my $min_content = "0"; + $min_content = "1000" if($table eq "contentadr"); + my $sth = $dbh->prepare("SELECT * FROM $table where $bc4table >= '$min_content' order by $bc4table DESC"); + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + return $ct; +} + + +# get content row where cookie +sub get_content3(){ + my $self = shift; + my ($table,$ct_name,$owner,$coo) = @_; + $owner=0 if(!$owner); + my $sel = "1 = 1"; + $sel .= " and ct_name='$ct_name'" if($ct_name); + $sel .= " and owner='$owner'" if($owner > 0); + $sel .= " and coo='$coo'" if($coo); + my $sth = $dbh->prepare("SELECT * FROM $table WHERE $sel"); + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + return $ct; +} + +sub get_ctnode(){ + my $self = shift; + my ($table,$tpl_id,$nd_col,$nd_con,$ct_col,$ct_op,$ct_con,$rel_col,$rel_con) = @_; + $ct_op = "=" if(!$ct_op); + my $where = "nd.main_id=rel.main_id and rel.content_id=ct.c_id"; + $where .= " and rel.template_id='$tpl_id'" if($tpl_id); + $where .= " and nd.$nd_col='$nd_con'" if($nd_col && $nd_con); + $where .= " and ct.$ct_col $ct_op '$ct_con'" if($ct_col && $ct_con); + $where .= " and rel.$rel_col = '$rel_con'" if($rel_col && $rel_con); + my $sth = $dbh->prepare("SELECT * FROM nodes nd, relation rel, $table ct WHERE $where"); + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + return $ct; +} + +# get content row over relation where nodes n_id +sub get_ct4node(){ + my $self = shift; + my ($tpl_id,$nd_column,$nd_content,$ct_column,$ct_content) = @_; + + my $where = "nd.main_id=rel.main_id and rel.content_id=ct.c_id"; + $where .= " and rel.template_id='$tpl_id'" if($tpl_id); + $where .= " and nd.$nd_column='$nd_content'" if($nd_column && $nd_content); + $where .= " and ct.$ct_column >= '$ct_content'" if($ct_column && $ct_content); + my $sth = $dbh->prepare("SELECT * FROM nodes nd, relation rel, content ct WHERE $where"); + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + return $ct; +} + +# get content row over relation +sub get_ctrel(){ + my $self = shift; + my ($table,$main_id,$lang,$rel_id,$c_id,$tpl_id,$sort,$dbinit) = @_; + $dbh = $dbt->dbconnect() if($dbinit);#because of ajax + my $sel = "rel.lang='$lang' and rel.content_id=ct.c_id"; + $sel .= " and rel.main_id='$main_id'" if ($main_id && $main_id > 0); + $sel .= " and rel.rel_id='$rel_id'" if ($rel_id && $rel_id > 0); + $sel .= " and rel.rel_id='0'" if ($rel_id && $rel_id eq "null"); + $sel .= " and rel.content_id='$c_id'" if ($c_id && $c_id > 0); + $sel .= " and rel.template_id='$tpl_id'" if ($tpl_id && $tpl_id > 0); + $sel .= " and ct.sort='$sort'" if ($sort); + my $sth = $dbh->prepare("SELECT * FROM relation rel, $table ct WHERE $sel"); + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + $dbh->disconnect if($dbinit); + return $ct; +} + + +# get content row over relation +sub get_ctrel2(){ + my $self = shift; + my ($table,$ct_name,$main_id,$lang,$rel_id,$c_id,$tpl_id,$zcolumn,$zcontent,$zcoperator,$orderby,$adesc) = @_; + my $sel = "rel.lang='$lang' and rel.content_id=ct.c_id"; + if("$zcolumn" eq "barcode" && $zcontent =~ /^\d+$/ && $zcontent < 9223372036854775807){ + $sel .= " and (ct_name='$ct_name' OR $zcolumn='$zcontent')"; + }elsif("$zcolumn" eq "start_time"){ + if($zcontent && $varenv{dataflow} =~ /wiki/ && $zcoperator && $zcoperator eq "="){ + $sel .= " and start_time='$zcontent'"; + }elsif($zcontent){ + $sel .= " and start_time>='$zcontent'"; + } + }else{ + $sel .= " and ct_name='$ct_name'" if($ct_name); + } + $sel .= " and rel.main_id='$main_id'" if ($main_id > 0); + $sel .= " and rel.rel_id='$rel_id'" if ($rel_id > 0); + $sel .= " and rel.content_id='$c_id'" if ($c_id > 0); + #$sel .= " and (ct.txt12 ilike '$pre_lager%' OR ct.txt12 like '_')" if($pre_lager); + + if($tpl_id =~ /\d,\d/){ + $sel .= " and rel.template_id IN ($tpl_id)"; + }elsif($tpl_id > 0){ + $sel .= " and rel.template_id='$tpl_id'"; + } + + #It must be available (Gutschein oder RFID) + # $sel .= " and ct.int03 > 0"; + my $order = ""; + $order = "order by $orderby $adesc" if($orderby); + my $sth = $dbh->prepare("SELECT * FROM relation rel, $table ct WHERE $sel $order"); + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + return $ct; +} + +# with like and tplids +sub get_ctrel3(){ + my $self = shift; + my ($table,$column,$content,$column2,$op2,$content2,$tplids,$sum) = @_; + my $rval="*"; + $rval = "sum(ct.int03) AS int03" if($sum eq "sum_kaution"); + my $where; + $where .= " and $column ilike '$content%'" if($content && $content > 0); + $where .= " and $column2 $op2 '$content2'" if("$content2" || "$content2" eq "0"); + my $sth = $dbh->prepare("SELECT $rval FROM relation rel, $table ct WHERE rel.content_id=ct.c_id and rel.template_id IN ($tplids) and rel.lang='de' $where"); + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + return $ct; +} + +# get content row over relation and start_time +sub get_ctrel4(){ + my $self = shift; + my ($table,$ct_name,$main_id,$lang,$rel_id,$c_id,$tpl_id,$column,$op,$content) = @_; + $op = "=" if(!$op); + my $sel = "rel.lang='$lang' and rel.content_id=ct.c_id"; + $sel .= " and $column $op '$content'" if($column && $content); + $sel .= " and ct_name='$ct_name'" if($ct_name); + $sel .= " and rel.main_id='$main_id'" if ($main_id > 0); + $sel .= " and rel.rel_id='$rel_id'" if ($rel_id > 0); + $sel .= " and rel.content_id='$c_id'" if ($c_id > 0); + $sel .= " and rel.template_id='$tpl_id'" if($tpl_id > 0); + my $sth = $dbh->prepare("SELECT * FROM relation rel, $table ct WHERE $sel"); + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + return $ct; +} + +# search nodes +sub search_nodes(){ + my $self = shift; + my ($search_pattern,$lang) = @_; + $search_pattern =~ s/\s/\%/g; + my $sth = $dbh->prepare("SELECT * from nodes nd where nd.lang='$lang' and nd.node_name ilike '%$search_pattern%'"); + my $rc = $sth->execute(); + my $search = $sth->fetchall_hashref("main_id"); + $sth->finish; + return $search; +} + +#search json contentuser for automcomplete +sub get_jsoncuser(){ + my $self = shift; + my ($table,$lang,$mandant_id,$key,$value) = @_; + my $dbh = $dbt->dbconnect();#because of ajax external handle request + + my $sel = "c_id = '$mandant_id'"; + my $sth = $dbh->prepare("SELECT ct.$key FROM $table ct WHERE $sel"); + my $rc = $sth->execute(); + my $rows = $sth->rows; + + $dbh->disconnect; + return $sth; +} + + +#search json address for automcomplete +sub search_jsonadr(){ + my $self = shift; + my ($table,$lang,$search,$mandant_id,$retype) = @_; + my $dbh = $dbt->dbconnect();#because of ajax external handle request + my $template_id=200;#$table eq content + $template_id=202 if($table eq "contentadr"); + $template_id=203 if($table eq "contentuser"); + + my $mjkey; + $mjkey = $1 if($retype =~ /combobox_(txt\d+)/); + my $sth; + if($retype =~ /combobox_txt/ && $search =~ /^\d+$/ && $mjkey =~ /txt\d+/){ + my $sel = "c_id = '$search'"; + $sth = $dbh->prepare("SELECT ct.c_id AS id ,ct.$mjkey AS name FROM $table ct, relation rel WHERE ct.c_id=rel.content_id and rel.template_id=$template_id and $sel"); + }else{ + my $sel = "txt01 ilike '%$search%'"; + $sth = $dbh->prepare("SELECT ct.txt01 || ' ,Nr. ' || ct.ct_name AS value, ct.txt01 AS vorname_name, ct.c_id FROM $table ct, relation rel WHERE ct.c_id=rel.content_id and rel.template_id=$template_id and $sel"); + } + my $rc = $sth->execute(); + my $rows = $sth->rows; + + $dbh->disconnect; + return $sth; +} + + +#search json for automcomplete +sub search_json(){ + my $self = shift; + my ($table,$lang,$ct_name,$mandant_id) = @_; + my $dbh = $dbt->dbconnect();#because of ajax external handle request + #my $sel = "rel.lang='$lang' and rel.content_id=ct.c_id"; + my $sel = "1=1"; + my $sel2; + + #pre_lager select only + if($mandant_id){ + my $lager_id = $mandant_id . "0"; + my $sth2 = $dbh->prepare("SELECT ct_name from contentuser where c_id='$lager_id'"); + my $rc = $sth2->execute(); + my $rel = $sth2->fetchrow_hashref(); + my $pre_lager = "$rel->{ct_name}" || ""; + $sel2 = " and (txt12 ilike '$pre_lager%' OR txt12 like '_')" if($pre_lager); + } + + if($ct_name =~ /^\d+$/ && $table eq "content"){ + $sel .= " and (ct_name ilike '$ct_name%' OR CAST(barcode AS text) like '$ct_name%')"; + }else{ + $sel .= " and ct_name ilike '$ct_name%'"; + } + my $sth; + #$sel .= " and rel.template_id IN ($tpl_ids)"; + #my $sth = $dbh->prepare("SELECT ct.ct_name || ' , Lager ' || ct.txt12 AS label, ct.ct_name AS value, ct.c_id FROM relation rel, content ct WHERE $sel"); + #my $sth = $dbh->prepare("SELECT ct.ct_name || ' , Lager ' || ct.txt12 AS label, ct.ct_name AS value, ct.c_id FROM content ct WHERE $sel"); + + #If select only mandant specific warenstamm + if($varenv{waren_main_id}){ + my $main_ids = &collect_noderec("",$varenv{waren_main_id},$lang,"nothing"); + $sth = $dbh->prepare("SELECT ct.ct_name || ' , ' || ct.barcode || ' , ' || ct.txt12 AS value, ct.ct_name AS spart_ct_name, ct.c_id FROM $table ct, relation rel WHERE ct.c_id=rel.content_id and rel.main_id IN ($main_ids) and $sel $sel2"); + }else{ + $sth = $dbh->prepare("SELECT ct.ct_name || ' , ' || ct.barcode || ' , ' || ct.txt12 AS value, ct.ct_name AS spart_ct_name, ct.c_id FROM $table ct WHERE $sel $sel2"); + } + my $rc = $sth->execute(); + my $rows = $sth->rows; + + #if false lager (txt12) then global + if(!$varenv{waren_main_id} && $rows < 1){ + $sth = $dbh->prepare("SELECT ct.ct_name || ' , Lager ' || ct.txt12 AS value, ct.ct_name AS spart_ct_name, ct.c_id FROM $table ct WHERE $sel"); + $rc = $sth->execute(); + $rows = $sth->rows; + } + + $dbh->disconnect; + return $sth; +} + +sub search_content3(){ + my $self = shift; + my ($searchref,$table,$mandant_id,$trans_module,$owner,$lang,$main_ids,$tplids,$ct_ids,$v_journal,$time,$kontext,$scol,$sort_updown,$offset,$limit,$export,$todo,$ck4ex,$opos) = @_; + + $main_ids =~ s/,$//; + $tplids =~ s/,$//; + $ct_ids =~ s/,$//; + + my $stamp_time = strftime("%d.%m.%Y %H:%M",localtime(time)); + my $debug; + $debug=1; + open(FILE,">>$varenv{logdir}/Liste3.log") if($debug); + print FILE "*** $stamp_time Libenzdb.search_content3 ***\n" if($debug); + print FILE Dumper($searchref) if($debug); + print FILE "$table,$mandant_id,$trans_module,$owner,$lang,$main_ids,$tplids,$ct_ids,$v_journal,$time,$kontext,$scol,$sort_updown,$offset,$limit,$export,$todo,$ck4ex,$opos\n" if($debug); + close(FILE) if($debug); + + + my $table_pos = $searchref->{table_pos} || ""; + my $txt_where; + my $cptxt_where; + my $cpgroup_where; + + my $valref = {}; + my $opref = {}; + foreach my $key (keys(%$searchref)){ + if($searchref->{$key} || $searchref->{$key} eq "0"){ + $valref->{$key} = $searchref->{$key};#because of escapeHTML manipulates special chars + $opref->{$key} = "="; + if($key =~ /table_pos/){ + $table_pos = $valref->{$key}; + } + if($key =~ /c_id|int\d+|barcode|time|sort|owner/){ + $searchref->{$key} =~ s/,/./g; + if($searchref->{$key} =~ /(\<\=|\>\=|\<|\>|\=)/){ + $opref->{$key} = $1; + } + if($searchref->{$key} =~ /([-0-9\.]+)/){ + $valref->{$key} = $1; + } + if($searchref->{$key} =~ /null/){ + $opref->{$key} = "is"; + } + chomp($valref->{$key}); + } + $valref->{$key} = $q->escapeHTML($valref->{$key}); + #print $key . ":" . $opref->{$key} . ":" . $valref->{$key} . "\n"; + + if(($v_journal =~ /_parts/ && $kontext eq "Waren") || $table_pos =~ /contentpos|contentadrpos|users/){ + #my $tinfo = &table_info("","contenttranspos"); + if($key =~ /ct_name/){ + $cptxt_where .= " and cp.$key ilike '$valref->{$key}'"; + }elsif($key =~ /txt/){ + $cptxt_where .= " and cp.$key ilike '%$valref->{$key}%'"; + }elsif($key =~ /barcode|int|owner/ && (looks_like_number($valref->{$key}) || $valref->{$key} eq "null")){ + $cptxt_where .= " and cp.$key $opref->{$key} $valref->{$key}"; + } + $txt_where .= " and ct.txt11 ilike '%$valref->{$key}%'" if($key eq "txt11");#Rahmennr. hack + }else{ + if($key eq "ct_name" && $valref->{$key} =~ /^(\d+)(0\d)$/){#wg. strichcode ohne "-" + $txt_where .= " and (ct.$key ilike '$valref->{$key}' OR ct.barcode $opref->{$key} $valref->{$key})"; + }elsif($key eq "ct_name" && $varenv{wwwhost} =~ /regiox|woge/){ + $txt_where .= " and ct.$key ilike '%$valref->{$key}%'"; + }elsif($key eq "ct_name"){ + $txt_where .= " and ct.$key ilike '$valref->{$key}'"; + }elsif($key =~ /int01/ && $table eq "contenttrans" && looks_like_number($valref->{$key})){ + #$cpgroup_where .= " group by cp.ct_id HAVING sum(cp.int02*cp.int03) $opref->{$key} $valref->{$key}";#special calc pos sum + #TODO, set DB int03=Menge default to 1 and testing + $cpgroup_where .= " group by cp.ct_id HAVING sum(cp.int02) $opref->{$key} $valref->{$key}";#special calc pos sum + }elsif($key =~ /_id|barcode|int\d+|sort|owner/ && (looks_like_number($valref->{$key}) || $valref->{$key} =~ /null|0/)){ + $txt_where .= " and ct.$key $opref->{$key} $valref->{$key}"; + }elsif($key =~ /txt|uri/){ + $txt_where .= " and ct.$key ilike '%$valref->{$key}%'"; + }elsif($key eq "state"){ + #order_state hack + $txt_where .= " and (ct.state ilike '%$valref->{$key}%' OR ct.txt22 ilike '%$valref->{$key}%')"; + }elsif($key =~ /byte/){ + $txt_where .= " and ct.$key = '\\x$valref->{$key}'"; + } + } + + if($key =~ /end_itime|end_mtime|end_date_time/){ + $valref->{$key} .= " 23:59" if($valref->{$key} !~ /\d:\d/); + } + + + if(!$v_journal){ + if($table_pos =~ /contentpos|contentadrpos|users/ && $key =~ /mtime/ && $valref->{$key} =~ /\d+\.\d+\.\d+/){ + $cptxt_where .= " and cp.mtime >= '$valref->{$key}'" if($key =~ /start/); + $cptxt_where .= " and cp.mtime < '$valref->{$key}'" if($key =~ /end/); + } + elsif($table_pos =~ /contentpos|contentadrpos|users/ && $key eq "template_id_pos" && $valref->{$key}){ + $cptxt_where .= " and cp.template_id = $valref->{$key}"; + } + elsif($key =~ /mtime/ && $valref->{$key} =~ /\d+\.\d+\.\d+/){ + $txt_where .= " and ct.mtime >= '$valref->{$key}'" if($key =~ /start/); + $txt_where .= " and ct.mtime < '$valref->{$key}'" if($key =~ /end/); + } + elsif($key =~ /bctime/ && $valref->{$key} =~ /\d+\.\d+\.\d+/){ + $txt_where .= " and ct.bctime >= '$valref->{$key}'" if($key =~ /start/); + $txt_where .= " and ct.bctime < '$valref->{$key}'" if($key =~ /end/); + } + + }elsif($v_journal){ + if($key =~ /itime/ && $valref->{$key} =~ /\d+\.\d+\.\d+/){ + $txt_where .= " and ct.itime >= '$valref->{$key}'" if($key =~ /start/); + $txt_where .= " and ct.itime < '$valref->{$key}'" if($key =~ /end/); + } + if($key =~ /start_mtime/ && $valref->{$key} =~ /^\d+$/){ + $txt_where .= " and ct.int11 = '$valref->{$key}'";#int11 = c_id-abschluss key + }elsif($key =~ /start_mtime/ && $valref->{$key} =~ /date.*\d+\.\d+\.\d+/){ + $txt_where .= " and ct.mtime >= $valref->{$key}"; + }elsif($key =~ /start_mtime/ && $valref->{$key} =~ /\d+\.\d+\.\d+/){ + $txt_where .= " and ct.mtime >= '$valref->{$key}'"; + } + if($key =~ /end_mtime/ && $valref->{$key} =~ /\d+\.\d+\.\d+/){ + $txt_where .= " and ct.mtime < '$valref->{$key}'"; + } + } + + if($v_journal !~ /_parts/ || $kontext eq "Waren"){ + if($key =~ /long_rent/ && $valref->{$key} =~ /^\d+ (day|hour)/){ + $cptxt_where .= " and cp.end_time >= (cp.start_time + interval '$valref->{$key}')"; + } + + if($key =~ /start_date_time/ && $valref->{$key} =~ /^\d+\.\d+\.\d+/){ + $cptxt_where .= " and cp.start_time >= '$valref->{$key}'"; + } + if($key =~ /end_date_time/ && $valref->{$key} =~ /^\d+\.\d+\.\d+/){ + $cptxt_where .= " and cp.end_time <= '$valref->{$key}'"; + } + } + + } + }#end foreach($searchref) + + $txt_where .= " and ct.int03 < ct.int08" if($todo =~ /Mindermenge/); + if($v_journal =~ /Tagesbericht/){ + $txt_where .= " and (ct.state ~ '[a-z]') and ct.int01 is not null and ct.close_time is null"; + $txt_where .= " and ct.int14 is $opos" if($opos eq "null"); + } + #end valref --------------------------------------------------------------------------- + + $ck4ex =~ s/\s/,/g; + $txt_where = " and ct.c_id IN ($ck4ex)" if($export =~ /check4export/); + #$txt_where = " and rel.rel_id IN ($ck4ex)" if($export =~ /check4ex_rel/); + # + #SUM contenttranspos bsp + #SELECT cp.ct_id, sum(cp.int02*cp.int03) from contenttranspos cp WHERE 1=1 and cp.end_time <= '31.10.2017 23:59' and cp.start_time >= '01.10.2017' group by cp.ct_id,cp.int02,cp.int03 HAVING sum(cp.int02*cp.int03) > 10; + + #print "$v_journal|$table_pos\n"; + #print "txt_where: $txt_where
    \n"; + #print "cptxt_where: $cptxt_where
    \n"; + + my $sth; + my $updown = "ASC"; + $updown = "DESC" if($sort_updown eq "down"); + if($v_journal =~ /_parts/){#collects ct_ids + my $cp_scol = "ct_name"; + $cp_scol = $1 if($scol =~ /(ct_name|barcode|mtime|txt0[1-9]|int0[1-9])/); + $sth = $dbh->prepare("SELECT cp.* FROM contenttranspos cp WHERE cp.ct_id IN (SELECT ct.c_id FROM relation rel, contenttrans ct WHERE rel.content_id=ct.c_id and rel.main_id IN ($main_ids) and rel.template_id IN ($tplids) and rel.lang='$lang' $txt_where) $cptxt_where ORDER BY cp.$cp_scol $updown"); + }elsif($valref->{long_rent} || $valref->{start_date_time} =~ /^\d+\.\d+\.\d+/ || $valref->{end_date_time} =~ /^\d+\.\d+\.\d+/ || $cpgroup_where){ + $sth = $dbh->prepare("SELECT * FROM relation rel, $table ct WHERE rel.content_id=ct.c_id and rel.main_id IN ($main_ids) and rel.template_id IN ($tplids) and rel.lang='$lang' $txt_where and c_id IN (SELECT cp.ct_id from contenttranspos cp WHERE 1=1 $cptxt_where $cpgroup_where) ORDER BY $scol $updown LIMIT $limit OFFSET $offset"); + }elsif($v_journal && $ct_ids){#and executes ct_ids + $txt_where = "" if($kontext eq "Waren"); + $ct_ids = 0 if(!$ct_ids); + $sth = $dbh->prepare("SELECT * FROM relation rel, $table ct WHERE rel.content_id=ct.c_id and rel.main_id IN ($main_ids) and rel.template_id IN ($tplids) and rel.content_id IN ($ct_ids) and rel.lang='$lang' $txt_where ORDER BY $scol $updown LIMIT $limit OFFSET $offset"); + + }elsif($table_pos && $table_pos eq "contentpos"){ + $sth = $dbh->prepare("SELECT cp.* FROM contentpos cp WHERE cp.cc_id IN (SELECT ct.c_id FROM relation rel, content ct WHERE rel.content_id=ct.c_id and rel.main_id IN ($main_ids) and rel.template_id IN ($tplids) and rel.lang='$lang' $txt_where) $cptxt_where ORDER BY cp.$scol $updown LIMIT $limit OFFSET $offset"); + }elsif($table_pos && $table_pos eq "contentadrpos"){ + if($valref->{template_id_pos} eq 602){#because of user_minianswer have to be anonym + $sth = $dbh->prepare("SELECT cp.* FROM contentadrpos cp WHERE 1=1 $cptxt_where ORDER BY cp.$scol $updown LIMIT $limit OFFSET $offset"); + }else{ + $sth = $dbh->prepare("SELECT ct.txt01,ct.txt08,cp.c_id,cp.mtime,cp.barcode,cp.int01,cp.txt02 FROM contentadr ct, contentadrpos cp WHERE ct.c_id=cp.ca_id $txt_where $cptxt_where ORDER BY cp.$scol $updown LIMIT $limit OFFSET $offset"); + } + }elsif($table_pos && $table_pos eq "users"){ + $sth = $dbh->prepare("SELECT cp.* FROM contentadr ct, users cp WHERE ct.c_id=cp.u_id $txt_where $cptxt_where ORDER BY cp.$scol $updown LIMIT $limit OFFSET $offset"); + + }else{ + $sth = $dbh->prepare("SELECT * FROM relation rel, $table ct WHERE rel.content_id=ct.c_id and rel.main_id IN ($main_ids) and rel.template_id IN ($tplids) and rel.lang='$lang' $txt_where ORDER BY $scol $updown LIMIT $limit OFFSET $offset"); + } + + my $rc = $sth->execute(); + my $s_id = "c_id"; + $s_id = "u_id" if($table_pos && $table_pos eq "users");#because to view multi relation + my $search = $sth->fetchall_hashref("$s_id"); + $sth->finish; + + #save_query + #my $save_query = $q->escapeHTML("$txt_where"); + #&users_up("","windowtask",$save_query,$owner); + + #CSV/FiBu Export### + if($export && (("$kontext" ne "Waren" && "$export" ne "FiBu" && $v_journal !~ /_parts/) || ("$export" eq "FiBu" && $v_journal =~ /_parts/) || ("$kontext" eq "Waren" && $v_journal =~ /_parts/))){ + #print "$v_journal,$time,$kontext,$export
    "; + + my $ctf = &get_content1("","contentuser","$mandant_id"); + my $tpl_id = $1 if($tplids =~ /(\d+)/); + #my $source = "Waren"; + my $source = $trans_module; + if($v_journal){ + $tpl_id = $ctf->{txt26} if($trans_module eq "Verkauf"); + $tpl_id = $ctf->{txt27} if($trans_module eq "Einkauf"); + $tpl_id = $ctf->{txt28} if($trans_module =~ /Faktur|Verleih/); + $source = "Waren" if($v_journal =~ /_parts/); + } + my $tpl = &Libenzdb::get_tpl("",$tpl_id); + my @tpl_order = split /,/,$tpl->{tpl_order}; + + #wg. Buchungsgruppen bzw. Ursprung-nodes (int12) --> Konten im FiBu Export + my $users = &get_content4owner("","users",$owner); + my $cmain_id = $users->{fullurl};#changed in jvbasel to actual main_id + if($cmain_id =~ /[a-zA-Z]/){ + my $b_node = &get_node2("",$users->{fullurl},$source,$lang); + $cmain_id = $b_node->{main_id}; + } + my $colmain_ids = &collect_noderec("",$cmain_id,$lang,"999999"); + my $nodes = &Libenzdb::collect_node2("","$colmain_ids"); + my $ctt;my $ctadr;my $aw_ids; + my $what; + $what = "$export-" if($export =~ /CSV|FIBU/); + open(CSV, "> $varenv{pdf}/$what$owner-$time.csv") or die "Can't open $varenv{pdf}/$owner-$time.csv\n"; + + #workaround 2015-11-23 for formated FiBu export + $export = "FiBu" if("$kontext" eq "Waren" && $v_journal =~ /_parts/); + if("$export" eq "FiBu"){ + foreach my $id (keys (%$search)){ + $aw_ids .= "$search->{$id}->{ct_id}|" if("$search->{$id}->{ct_name}" eq "$ctf->{txt51}"); + } + #SOLL Zahlungsart + $ctt = &Libenzdb::collect_content2("","contenttrans"); + #$ctadr = &collect_content3("","contentadr");#wg Debitor/Kreditor + print CSV "SOLL;UMSATZ;USTNR;HABEN;GVC;BELDAT;BELEG;OPBELEG;SKONTO;KOSTNR;TEXT;TEXT2\n"; + + }else{ + #CSV Table Header + my $col_header="Ordner"; + foreach(@tpl_order){ + my ($key,$val) = split /=/,$_; + if($key eq "txt01"){ + $col_header .= ";Name-01;Name-02;Name-03"; + }else{ + $col_header .= ";$val"; + } + } + print CSV "$col_header\n"; + } + + #sort=ct_id nach Geschäftsvorgang + $scol = "ct_id" if("$export" eq "FiBu"); + foreach my $id (sort { + if($sort_updown eq "down"){ + if ($scol =~ /barcode|int/) { + $search->{$b}->{$scol} <=> $search->{$a}->{$scol} + }else{ + lc($search->{$b}->{$scol}) cmp lc($search->{$a}->{$scol}) + } + }else{ + if ($scol =~ /barcode|int/) { + $search->{$a}->{$scol} <=> $search->{$b}->{$scol} + }else{ + lc($search->{$a}->{$scol}) cmp lc($search->{$b}->{$scol}) + } + } + } keys(%$search)){ + + my $s_main_id = "$search->{$id}->{main_id}"; + $s_main_id = "$search->{$id}->{int12}" if(($v_journal && ($v_journal =~ /_parts/)) || ($trans_module =~ /Verkauf|Faktur|Verleih/)); + + #lxfibu vars + my ($l_soll,$l_umsatz,$l_ustnr,$l_haben,$l_gvc,$l_beldat,$l_beleg,$l_opbeleg,$l_skonto,$l_kostnr,$l_text,$l_text2); + #SOLL alias state/Zahlungsart + foreach my $tid (keys (%$ctt)){ + if($search->{$id}->{ct_id} == $ctt->{$tid}->{c_id}){ + my ($date,$time); + $ctt->{$tid}->{mtime} =~ s/:\d{2}\..*$//; + ($date,$time) = split(/ /,$ctt->{$tid}->{mtime}); + $l_beldat = "$date"; + $l_beleg = "$ctt->{$tid}->{txt00}" . "-" . "$ctt->{$tid}->{ct_name}"; + $l_opbeleg = "$ctt->{$tid}->{ct_name}" if(("$ctt->{$tid}->{txt00}" eq "Rechnung") && ($ctt->{$tid}->{state} =~ /Abbuchung|Überweisung|PayPal/)); + $ctf->{txt43} = $1 if($ctf->{txt43} =~ /(\d+)/); + $ctf->{txt44} = $1 if($ctf->{txt44} =~ /(\d+)/); + $ctf->{txt45} = $1 if($ctf->{txt45} =~ /(\d+)/); + $ctf->{txt46} = $1 if($ctf->{txt46} =~ /(\d+)/); + $ctf->{txt47} = $1 if($ctf->{txt47} =~ /(\d+)/); + $ctf->{txt48} = $1 if($ctf->{txt48} =~ /(\d+)/); + $ctf->{txt49} = $1 if($ctf->{txt49} =~ /(\d+)/); + $ctf->{txt50} = $1 if($ctf->{txt50} =~ /(\d+)/); + $l_soll = $ctf->{txt43} if($ctt->{$tid}->{state} eq "Bar"); + $l_soll = $ctf->{txt44} if($ctt->{$tid}->{state} eq "EC-Karte"); + $l_soll = $ctf->{txt45} if($ctt->{$tid}->{state} eq "Kreditkarte"); + $l_soll = $ctf->{txt46} if($ctt->{$tid}->{state} eq "Abbuchung"); + $l_soll = $ctf->{txt47} if($ctt->{$tid}->{state} eq "Überweisung"); + $l_soll = $ctf->{txt48} if($ctt->{$tid}->{state} eq "Geldkarte"); + $l_soll = $ctf->{txt50} if($ctt->{$tid}->{state} eq "PayPal"); + $ctf->{txt31} =~ s/,/|/; + $l_soll = $ctf->{txt49} if(($ctt->{$tid}->{state} eq "Bar") && ($ctf->{txt31} && $search->{$id}->{int12} =~ /$ctf->{txt31}/));#Bar Kaution Gegenkonto + + #2018-01-28, disabled because of not used anymore + #Debitor/Kreditor + #if(("$export" eq "FiBu" && $ctt->{$tid}->{txt14} =~ /\d/) && ($ctt->{$tid}->{state} =~ /Abbuchung|Überweisung|PayPal/)){ + #$ctadr = &get_content2("","contentadr","$ctt->{$tid}->{txt14}"); + #$l_soll = $ctadr->{int01} if($ctadr->{int01}); + #} + } + } + + my $line=""; + #Nodes alias Buchungsgruppen parameter + foreach my $nid (keys (%$nodes)){ + if($s_main_id == $nodes->{$nid}->{main_id}){ + #print "$s_main_id == $nodes->{$nid}->{main_id} $nodes->{$nid}->{node_name} $trans_module
    "; + $line = "$nodes->{$nid}->{node_name}"; + $l_text = "$nodes->{$nid}->{node_name}"; + + $ctf->{txt13} = $1 if($ctf->{txt13} =~ /(\d+)/);#VK Umst + $ctf->{txt14} = $1 if($ctf->{txt14} =~ /(\d+)/);#EK Umst + $ctf->{txt15} = $1 if($ctf->{txt15} =~ /(\d+)/);#Aufwandskonto + $ctf->{txt16} = $1 if($ctf->{txt16} =~ /(\d+)/);#Erlöskonto + $ctf->{txt40} = $1 if($ctf->{txt40} =~ /(\d+)/);#Kostenstelle + #FIXME, Kaution und Wertmarken main_id + my $ctf_txt40 = $ctf->{txt40}; + #$ctf_txt40 = "" if($nodes->{$nid}->{main_id} =~ /300087|400056|400054|400053|400063|300070|400048|400049|400047/); + $l_kostnr = "$nodes->{$nid}->{int05}";#Kostenstelle + $l_kostnr = "$ctf_txt40" if($nodes->{$nid}->{int05} !~ /\d/); + + #template definition in src/Tpl/EditMeta.pm + my $ustnr; + if($trans_module eq "Einkauf"){ + $ustnr = $nodes->{$nid}->{int04}; + $ustnr = $ctf->{txt14} if($nodes->{$nid}->{int04} !~ /\d/); + $l_soll = $nodes->{$nid}->{int02};#Aufwandskonto??? + $l_soll = $ctf->{txt15} if($nodes->{$nid}->{int02} !~ /\d/); + } + if($trans_module eq "Verkauf"){ + $ustnr = $nodes->{$nid}->{int03}; + $ustnr = $ctf->{txt13} if($nodes->{$nid}->{int03} !~ /\d/); + $l_haben = $nodes->{$nid}->{int01};#Verkauf Erlöskonto + $l_haben = $ctf->{txt16} if($nodes->{$nid}->{int01} !~ /\d/); + #sollte nicht mur an 999 geknüpft sein, sondern Warengruppen ... + #$l_soll = "$nodes->{$nid}->{int02}" if($search->{$id}->{ct_name} eq "999"); + } + if($trans_module =~ /Faktur|Verleih/){ + $ustnr = $nodes->{$nid}->{int03};#Verkauf = Verleih Umst + $ustnr = $ctf->{txt13} if($nodes->{$nid}->{int03} !~ /\d/); + $l_haben = $nodes->{$nid}->{int07};#Verleih Erlöskonto + $l_haben = $ctf->{txt16} if($nodes->{$nid}->{int07} !~ /\d/); + $l_kostnr = $nodes->{$nid}->{int08};#Verleih Kostenstelle + $l_kostnr = "$ctf_txt40" if($nodes->{$nid}->{int08} !~ /\d/); + #sollte nicht mur an 999 geknüpft sein, sondern Warengruppen ... + #$l_soll = "$nodes->{$nid}->{int02}" if($search->{$id}->{ct_name} eq "999"); + } + + $l_ustnr = "0" if($ustnr == "0" || !$ustnr); + $l_ustnr = "1" if($ustnr == "19"); + $l_ustnr = "2" if($ustnr == "7"); + + } + } + + #AW Kostenstelle + $aw_ids =~ s/\|$//; + if("$search->{$id}->{ct_name}" eq "$ctf->{txt51}"){ + $ctf->{txt41} = $1 if($ctf->{txt41} =~ /(\d+)/); + $l_kostnr = "$ctf->{txt41}"; + #AM Kostenstelle + }elsif($aw_ids && $search->{$id}->{ct_id} =~ /$aw_ids/){ + $ctf->{txt42} = $1 if($ctf->{txt42} =~ /(\d+)/); + $l_kostnr = "$ctf->{txt42}"; + } + + foreach(@tpl_order){ + my ($key,$val) = split /=/,$_; + $search->{$id}->{$key} = $q->unescapeHTML("$search->{$id}->{$key}"); + $search->{$id}->{$key} =~ s/:\d{2}\..*$// if($key =~ /time/); + if($search->{$id}->{$key} && $key =~ /int/){ + my $cash = &Libenz::cashme("","$search->{$id}->{$key}",","); + $line .= ";$cash"; + if("$export" eq "FiBu"){ + my $einzel = $search->{$id}->{int02}; + my $menge = $search->{$id}->{int03}; + my $rabatt_val = $search->{$id}->{int07}; + $cash = $einzel * $menge; + if($rabatt_val != 0){ + my $rabatt_eur = $rabatt_val; + $rabatt_eur = $einzel * $menge * $rabatt_val/100 if($search->{$id}->{int08} != 1); + $cash = $einzel * $menge - $rabatt_eur; + } + $l_umsatz = &Libenz::round("","$cash"); + } + }else{ + if($key eq "txt01"){ + my ($n01,$n02,$n03) = split(/\n/,$search->{$id}->{$key}); + $n02 =~ s/^\s//;#jbw fix + $line .= ";$n01;$n02;$n03"; + }elsif($key eq "date_time"){ + $search->{$id}->{start_time} =~ s/\s.*// if($search->{$id}->{start_time}); + $search->{$id}->{end_time} =~ s/\s.*// if($search->{$id}->{end_time}); + $line .= ";$search->{$id}->{start_time} - $search->{$id}->{end_time}"; + }else{ + $line .= ";$search->{$id}->{$key}"; + } + $l_text2 = "$search->{$id}->{$key}" if("$key" eq "ct_name"); + #$l_text2 = "" if("$key" eq "txt01"); + } + } + if("$export" eq "FiBu"){ + print CSV "$l_soll;$l_umsatz;$l_ustnr;$l_haben;$l_gvc;$l_beldat;$l_beleg;$l_opbeleg;$l_skonto;$l_kostnr;$l_text;$l_text2\n" if($l_umsatz != 0); + }else{ + $line =~ s/\n//g; + $line =~ s/\r//g; + print CSV "$line\n"; + } + } + close CSV; + + &csv2xls("",$owner,$time) if($export =~ /check4|FiBu/); + + #if($export eq "check4html"){ + # foreach my $id (keys (%$search)){ + # $c_ids .= "$search->{$id}->{c_id},"; + # } + # $c_ids =~ s/,$//; + # &export2html("","$table","$c_ids","$main_ids","$tpl_id","$owner","$time"); + #} + + }#end CSV/FiBu Export#### +# + return $search; +} + +# CSV to Excel. Needs first CSV to write XLS. +sub csv2xls(){ + my $self = shift; + my ($owner,$time) = @_; + open (CSVFILE, "<:encoding(utf8)","$varenv{pdf}/$owner-$time.csv");# or die "$varenv{pdf}/$owner-$time.csv: $!"; + my $workbook = Spreadsheet::WriteExcel->new("$varenv{pdf}/$owner-$time.xls"); + die "Problems creating new Excel file: $!" unless defined $workbook; + my $worksheet = $workbook->add_worksheet(); + #$worksheet->set_column(2, 3, 25); + my $csv = Text::CSV_XS->new({ + 'quote_char' => '', + 'escape_char' => '', + 'sep_char' => ';', + 'binary' => 1 + }); + + my $row = 0; + while () { + if ($csv->parse($_)) { + my @Fld = $csv->fields; + my $col = 0; + foreach my $token (@Fld) { + $token =~ s/[\=\'\"]//g; + $worksheet->write($row, $col, $token); + $col++; + } + $row++; + } + else { + my $err = $csv->error_input; + print "Text::CSV_XS parse() failed on argument: ", $err, "\n"; + } + } + return; +} + + +#with c_ids over tpl_ids. ct4tpl +sub collect_cid(){ + my $self = shift; + my ($table,$lang,$tpl_id,$rel_id,$barcode,$column2,$content2) = @_; + my $where = "where ct.c_id=rel.content_id and rel.lang='$lang' and rel.template_id='$tpl_id'"; + if($barcode && $barcode =~ /^\d+$/){ + $where .= " and ct.barcode='$barcode'"; + }elsif($rel_id){ + $where .= " and rel.rel_id='$rel_id'"; + } + $where .= " and ct.$column2='$content2'" if($content2); + my $sth = $dbh->prepare("SELECT * FROM $table ct, relation rel $where"); + #my $sth = $dbh->prepare("SELECT ct.barcode || '.' || ct.sort AS barcode_sort, * FROM $table ct, relation rel $where"); + my $rc = $sth->execute(); + my $ct = $sth->fetchall_hashref("c_id"); + $sth->finish; + return $ct; +} + + + +#counting +sub count_content(){ + my $self = shift; + my ($table,$main_ids,$tplids) = @_; + $main_ids =~ s/,$//; + $tplids =~ s/,$//; + my $where = "WHERE rel.content_id=ct.c_id and rel.main_id IN ($main_ids)"; + $where .= " and rel.template_id IN ($tplids)" if($tplids =~ /\d/); + my $sth = $dbh->prepare("SELECT DISTINCT(ct.c_id) FROM relation rel, $table ct $where"); + my $rc = $sth->execute(); + my $rows = $sth->rows; + return $rows; +} + + + +# copy content +sub copy_content(){ + my $self = shift; + my ($table,$key_id,$x_id,$columns,$dbinit) = @_; + $dbh = $dbt->dbconnect() if($dbinit);#because of ajax + $columns = "ct_name,barcode,txt01,txt02,txt03,txt04,txt05,txt06,txt07,txt08,txt09,int10,txt10,txt11,txt12,int01,int02,int03,int04,int05,int06,int07,int08" if(!$columns); + my $sth = $dbh->prepare("INSERT INTO $table ($columns) SELECT $columns from $table where $key_id='$x_id' RETURNING $key_id"); + my $rows = $sth->execute(); + + my $last_id; + $sth->bind_columns(\$last_id); + my $y_id = $sth->fetchrow_array(); + + $dbh->disconnect if($dbinit); + return $y_id; +} + +# insert content (init) +sub insert_content(){ + my $self = shift; + my ($table,$ct_name,$owner,$sort) = @_; + $owner="0" if(!$owner); + $sort="0" if(!$sort); + my $sth = $dbh->prepare("INSERT INTO $table (ct_name,owner,sort,itime) VALUES(trim('$ct_name'),'$owner','$sort','now()') RETURNING c_id"); + my $rows = $sth->execute(); + + my $last_id; + $sth->bind_columns(\$last_id); + my $c_id = $sth->fetchrow_array(); + + return $c_id; +} + + +#c_id must be serial primary-key +sub insert_content2(){ + my $self = shift; + my ($table,$ct_name,$owner,$state) = @_; + $owner="0" if(!$owner); + my $sql = "INSERT INTO $table (ct_name,owner) VALUES(trim('$ct_name'),'$owner') RETURNING c_id"; + $sql = "INSERT INTO $table (ct_name,owner,state) VALUES(trim('$ct_name'),'$owner','$state') RETURNING c_id" if($state); + my $sth = $dbh->prepare($sql); + my $rows = $sth->execute(); + + my $last_id; + $sth->bind_columns(\$last_id); + my $c_id = $sth->fetchrow_array(); + + return $c_id; +} + +#ADD Parts +#$cc_id = c_id from content (Waren) +#$foreign_key = c_id from contenttrans (Verkauf ...), maybe (c_id4trans) +#$from_main_id = mail_id from content relation (Waren) +sub insert_contenttranspos(){ + my $self = shift; + my ($table,$ct_name,$owner,$barcode,$cc_id,$foreign_key,$from_main_id,$txt01,$node_name,$unit,$int02,$int03,$umst,$int07,$mandant_id,$int08,$packaged,$txt06,$txt07,$email,$ca_id) = @_; + $owner="0" if(!$owner); + $barcode="0" if(!$barcode); + $int02="0" if(!$int02);#VK Einzel + $int03="0" if(!$int03);#Menge + $umst="null" if(!$umst);#UmSt + $int07="0" if(!$int07);#Rabatt + $int08="0" if(!$int08);#Rabatteinheit + $packaged="" if(!$packaged);#packaged + $txt06="" if(!$txt06);#cooordinates + $txt07="" if(!$txt07);#voltage + $foreign_key="0" if(!$foreign_key); + $from_main_id="0" if(!$from_main_id); + $ca_id="0" if(!$ca_id); + my $sth = $dbh->prepare("INSERT INTO $table (ct_name,owner,barcode,cc_id,ct_id,itime,txt01,txt00,txt03,int02,int03,int05,int07,int12,txt12,int08,txt05,txt06,txt07,txt08,ca_id) VALUES(trim('$ct_name'),'$owner','$barcode','$cc_id','$foreign_key','now()','$txt01','$node_name','$unit','$int02','$int03',$umst,'$int07','$from_main_id','$mandant_id','$int08','$packaged','$txt06','$txt07','$email','$ca_id') RETURNING c_id"); + my $rows = $sth->execute(); + + my $last_id; + $sth->bind_columns(\$last_id); + my $c_id = $sth->fetchrow_array(); + + my $set = "SET c_idpos=c_id"; + my $sth12 = $dbh->prepare("UPDATE $table $set WHERE c_id='$c_id'"); + my $rc12 = $sth12->execute(); + return $c_id; +} + +# update trivial +sub updater(){ + my $self = shift; + my ($table,$w_col,$w_val,$column,$content,$owner,$w_col2,$w_op2,$w_val2,$set_time) = @_; + my $ct_set = "mtime='now()'"; + if($set_time && $set_time eq "no_time"){ + $ct_set = ""; + }elsif($table !~ /content/){ + $ct_set = "change='now()'"; + } + + if("$content" eq "null" || (!$content && $content !~ /^0$/)){ + $ct_set .= ",$column=null"; + }elsif(($column ne "c_id") && ($content || $content == 0)){ + $ct_set .= ",$column='$content'"; + } + if($table eq "contenttranspos"){#to keep initial channel-ID + $ct_set .= ",owner_end='$owner'" if($owner); + }else{ + $ct_set .= ",owner='$owner'" if($owner); + } + $ct_set =~ s/^,/ /; + my $where = "$w_col='$w_val'"; + + if("$w_col2" && "$w_op2" && "$w_val2"){ + if($w_op2 =~ /IN/i){ + $where .= " and $w_col2 $w_op2 ($w_val2)"; + }else{ + $where .= " and $w_col2 $w_op2 '$w_val2'"; + } + } + + my $rows = 0; + if($w_col && $w_val){ + my $sth = $dbh->prepare("UPDATE $table SET $ct_set where $where"); + $rows = $sth->execute(); + } + return $rows; +} + +# update trivial in short +sub updater2(){ + my $self = shift; + my ($table,$w_col,$w_val,$column,$content,$owner,$set_time) = @_; + my $ct_set = "mtime='now()'"; + if($set_time && $set_time eq "no_time"){ + $ct_set = ""; + }elsif($table !~ /content/){ + $ct_set = "change='now()'"; + } + + if("$content" eq "null" || (!$content && $content !~ /^0$/)){ + $ct_set .= ",$column=null"; + }elsif(($column ne "c_id") && ($content || $content == 0)){ + $ct_set .= ",$column='$content'"; + } + $ct_set .= ",owner='$owner'" if($owner); + $ct_set =~ s/^,/ /; + my $where = "$w_col='$w_val'"; + + my $sth = $dbh->prepare("UPDATE $table SET $ct_set where $where"); + my $rows = $sth->execute(); + return $rows; +} +# update for barcode +sub update_barcode(){ + my $self = shift; + my ($table,$c_id,$ct_name,$barcode,$txt01) = @_; + my $ct_set = "mtime='now()'"; + $ct_set = "change='now()'" if($table !~ /content/); + if("$barcode" eq "null" || (!$barcode && $barcode != 0)){ + $ct_set .= ",barcode=null"; + }elsif($barcode || $barcode == 0){ + $ct_set .= ",barcode='$barcode'"; + } + + $ct_set .= ", txt01='$txt01'" if($txt01); + my $where = "c_id='$c_id'"; + my $sth = $dbh->prepare("UPDATE $table SET $ct_set where $where"); + my $rows = $sth->execute(); + $sth->finish; + return $rows; +} + +#for trivial ajax update +sub update_ajaxes(){ + my $self = shift; + my ($table,$w_key,$op,$w_val,$column,$value,$owner) = @_; + my $dbh = $dbt->dbconnect();#because of ajax external handle request + $op = "=" if(!$op); + my $where = "where 1=1"; + $where .= " and $w_key $op '$w_val'" if($w_key); + $where .= " and owner='$owner'" if($owner); + my $sth = $dbh->prepare("UPDATE $table SET $column='$value' $where"); + my $rows = $sth->execute(); + $dbh->disconnect; + return $rows; +} + +# update content like copy +sub update_content4change(){ + my $self = shift; + my ($table,$c_id,$ct_name,$content,$column,$owner) = @_; + my $ct_set = "mtime='now()'"; + #my $ct_set; + $ct_set .= ",ct_name='$ct_name'" if($ct_name); + if($content && $content eq "no"){ + $ct_set .= ",$column=''"; + }elsif($content && $content eq "null"){ + $ct_set .= ",$column=$content"; + }elsif($content || ($content && $content eq "0")){ + $ct_set .= ",$column='$content'" if($column ne "ct_name"); + } + if($column eq "mtime"){#überschreibt obiges + if($content =~ /\d/){#TODO real time + $ct_set = "mtime='$content'"; + }else{ + $ct_set = ""; + } + } + if($table eq "contenttranspos"){#to keep initial channel-ID + $ct_set .= ",owner_end='$owner'" if($owner); + }else{ + $ct_set .= ",owner='$owner'" if($owner); + } + if($ct_set){ + my $sth = $dbh->prepare("UPDATE $table SET $ct_set where c_id='$c_id'"); + my $rows = $sth->execute(); + return $rows; + } +} + + +# update content without mtime-change +sub update_content4change2(){ + my $self = shift; + my ($table,$c_id,$content,$column,$owner) = @_; + my $ct_set; + if("$content" eq "no"){ + $ct_set = "$column=''"; + }elsif($content || $content eq "0"){ + $ct_set = "$column='$content'"; + } + if($table eq "contenttranspos"){#to keep initial channel-ID + $ct_set .= ",owner_end='$owner'" if($owner); + }else{ + $ct_set .= ",owner='$owner'" if($owner); + } + if($ct_set){ + my $sth = $dbh->prepare("UPDATE $table SET $ct_set where c_id='$c_id'"); + my $rows = $sth->execute(); + return $rows; + } +} + +sub update_kasse(){ + my $self = shift; + my ($table,$c_id,$sum_kasse,$sum_start) = @_; + #set kassenbestand + my $sth = $dbh->prepare("UPDATE $table SET int01='$sum_kasse',int02='$sum_start' where c_id='$c_id'"); + my $rows = $sth->execute(); + return $rows; +} + +sub update_tagesabschluss(){ + my $self = shift; + my ($table,$c_idkasse,$journal_main_id,$tpl_journal,$tpl_vk,$mandant_main_id,$main_ids,$s_owner_id,$opos) = @_; + my $where; + $where = " and ct.owner='$s_owner_id'" if($s_owner_id); + $where = " and ct.int14 is $opos" if($opos eq "null"); + #close transactions #int11 zusätzlich für Kassenabschluss referenz c_id + my $sth = $dbh->prepare("UPDATE $table SET close_time='now()',int11=$c_idkasse where c_id IN (SELECT ct.c_id from $table ct, relation rel where ct.c_id=rel.content_id and (ct.state ~ '[a-z]') and ct.int01 is not null and rel.main_id IN ($main_ids) and ct.close_time is null $where)"); + my $rows = $sth->execute(); + #move/set to journal + $sth = $dbh->prepare("UPDATE relation SET main_id='$journal_main_id', template_id='$tpl_journal' where template_id='$tpl_vk' and content_id IN (SELECT ct.c_id from $table ct, relation rel where ct.c_id=rel.content_id and (ct.state ~ '[a-z]') and ct.int01 is not null and rel.main_id IN ($main_ids) $where)"); + #$sth = $dbh->prepare("UPDATE $table SET close_time='now()',int11='$c_idkasse' where (state ~ '[a-z]') and int01 is not null and int12 IN ($main_ids) and close_time is null $where"); + $rows = $sth->execute(); + return $rows; +} + +#X collect last journal abschluss to get workflow transactions +sub collect_Xlast(){ + my $self = shift; + my ($c_idkasse,$main_id,$tpl_id,$mandant_main_id) = @_; + my $sth = $dbh->prepare("SELECT ct.c_id,ct.ct_name FROM contenttrans ct, relation rel where ct.c_id=rel.content_id and rel.main_id = $main_id and rel.template_id = $tpl_id and rel.lang='de' and ct.int11 = $c_idkasse and ct.ct_name like '%-%'"); # Muster: RechnungNr-XBelegNr OR QuittungNr-XWorkflowNr + my $rc = $sth->execute(); + my $ct4rel = $sth->fetchall_hashref("c_id"); + $sth->finish; + return $ct4rel; +} + +sub update_Xabschluss(){ + my $self = shift; + my ($table,$c_idkasse,$journal_main_id,$tpl_journal,$tpl_vk,$mandant_main_id,$main_ids,$s_owner_id,$ct_name) = @_; + my $where; + $where = " and ct.owner='$s_owner_id'" if($s_owner_id); + my $sth = $dbh->prepare("UPDATE $table SET close_time='now()',int11='$c_idkasse' where c_id IN (SELECT ct.c_id from $table ct, relation rel where ct.c_id=rel.content_id and (ct.ct_name = '$ct_name' OR ct.ct_name like '$ct_name-%' OR ct.ct_name like '%-$ct_name') and ct.int01 is null and rel.main_id IN ($main_ids) and ct.close_time is null $where)"); + my $rows = $sth->execute(); + #move/set to journal + $sth = $dbh->prepare("UPDATE relation SET main_id='$journal_main_id', template_id='$tpl_journal' where template_id='$tpl_vk' and content_id IN (SELECT ct.c_id from $table ct, relation rel where ct.c_id=rel.content_id and (ct.ct_name = '$ct_name' OR ct.ct_name like '$ct_name-%' OR ct.ct_name like '%-$ct_name') and ct.int01 is null and rel.main_id IN ($main_ids) $where)"); + $rows = $sth->execute(); + return $rows; +} + + +#compute content +sub update_content4comp(){ + my $self = shift; + my ($table,$ct_name,$c_id,$operator,$menge,$kind_of_trans,$lager) = @_; + my $where; + + if($c_id){ + $where = "c_id='$c_id'"; + }elsif($ct_name =~ /(\d+)/ && ($table eq "content")){ + $ct_name = $1; + $where = "(ct_name='$ct_name' OR barcode='$ct_name')"; + }elsif($ct_name){ + $where = "where (ct_name='$ct_name')"; + } + my $val="0"; + $val=$menge if($menge); + $val = $val * -1 if($table eq "content" && $kind_of_trans eq "Einkauf"); + my $ct_set = "int03=(int03 $operator $val)"; + my $sth = $dbh->prepare("UPDATE $table SET $ct_set where $where") if($c_id || $ct_name); + my $rows = $sth->execute(); + return $rows; +} + +# Delete content +sub delete_content(){ + my $self = shift; + my ($table,$c_id,$owner,$sort) = @_; + my $where = "c_id='$c_id'"; + $where .= " and owner='$owner'" if($owner); + $where .= " and sort='$sort'" if($sort); + my $sth = $dbh->prepare("DELETE FROM $table WHERE $where"); + my $rc = $sth->execute(); + return $rc; +} + +# Delete time +sub delete_time(){ + my $self = shift; + my ($table,$t_id) = @_; + my $sth = $dbh->prepare("DELETE FROM $table WHERE t_id='$t_id'"); + my $rc = $sth->execute(); + return $rc; +} + +#delete users +sub delete_users(){ + my $self = shift; + my ($u_id,$owner) = @_; + my $sth = $dbh->prepare("DELETE from users where u_id = '$u_id'"); + my $rows = $sth->execute(); + if($owner){ + $sth = $dbh->prepare("DELETE from contentuser where owner = '$owner'"); + $rows = $sth->execute(); + } + #$sth = $dbh->prepare("DELETE from contentpers where owner = '$owner'"); + #$rows = $sth->execute(); + return $rows; +} + +# logout alias cook_out +sub cook_out(){ + my $self = shift; + my $coo = shift; + my $sth = $dbh->prepare("UPDATE users SET cookie='', change='now()' where cookie='$coo'"); + my $rc = $sth->execute(); + return $rc; +} + + +#just after checked if users.u_id=contentadr.c_id +sub select_users(){ + my $self = shift; + my $u_id = shift || 0; + my $sth = $dbh->prepare("SELECT * FROM users WHERE u_id=$u_id"); + my $rc = $sth->execute(); + my $auth = $sth->fetchrow_hashref(); + return $auth; +} + + +sub get_owner(){ + my $self = shift; + my ($owner,$dbinit) = @_; + $dbh = &dbconnect() if($dbinit);#because of ajax + my $sth = $dbh->prepare("SELECT * FROM users WHERE owner='$owner'"); + my $rc = $sth->execute(); + my $ner = $sth->fetchrow_hashref(); + $dbh->disconnect if($dbinit); + return $ner; +} + + +# collect all users +sub collect_users(){ + my $self = shift; + my $sth = $dbh->prepare("SELECT * FROM users"); + my $rc = $sth->execute(); + my $users = $sth->fetchall_hashref("owner"); + $sth->finish; + return $users; +} + +1; diff --git a/copri4/main/src/Mod/MailTransport.pm b/copri4/main/src/Mod/MailTransport.pm new file mode 100644 index 0000000..ad5db61 --- /dev/null +++ b/copri4/main/src/Mod/MailTransport.pm @@ -0,0 +1,163 @@ +package Mod::MailTransport; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +# new emailing module +# +#perl -cw src/Mod/MailTransport.pm +#use lib "/var/www/copri4/shareeapp-operator/src"; +# +use strict; +use warnings; +use POSIX; +use CGI ':standard'; +use Email::MIME; +use IO::All; +use Email::Sender::Simple qw(sendmail); +use Net::SMTP; +use Try::Tiny; +use Config::General; +use Sys::Hostname; +my $hostname = hostname; + +use Lib::Config; +use Mod::Basework; +use Mod::DBtank; +use Data::Dumper; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +my $q = new CGI; +my $cf = new Config; +my $bw = new Basework; +my $dbt = new DBtank; + +my $mailx_file = "/var/www/copri4/shareeconf/mailx.cfg"; +my $conf = Config::General->new($mailx_file); +my %mailxconf = $conf->getall; + +sub send_mail(){ + my $self = shift; + my $sendref = shift; + my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; + + my $mail_from = $sendref->{mail_from} || $mailxconf{mailx}->{mail_from}; + my $mail_to = $sendref->{mail_to} || $mailxconf{mailx}->{mail_to}; + my $subject = $sendref->{subject} || "subject fails"; + my $filename = $sendref->{filename} || ""; + my $message = $sendref->{message} || "Failure, no message\n"; + #If caller use utf8, message is encoded as utf-8 + #$message = Encode::encode('utf-8', Encode::decode('iso-8859-1', $message)); + + #Special tink statisk, readdir with filename + #$filename like "2018-12" + my @files = ($filename); + + #disabled because of zipping + #TODO, check what happens about Statistik-occubike_station_2019-1-konrad.csv + #Okay, send_mail breaks on verylong Statistik lines. CSV zipping is the solution + #@files = $lb->read_dirfiles("$dbt->{copri_conf}->{basedir}/csv",$filename,"file","") if($filename =~ /\d+-\d+/); + + if($dbt->{copri_conf}->{stage} eq "test"){ + $mail_to = $mailxconf{mailx}->{mail_to}; + $subject .= " * offline Test *"; + } + + $bw->log("Trying send_mail:$0",$sendref,""); + + + if(ref($sendref) eq "HASH"){ + + $mailxconf{mailx}->{sasl_password} = Encode::encode('iso-8859-1', Encode::decode('utf-8', $mailxconf{mailx}->{sasl_password})); + my $transport = Email::Sender::Transport::SMTPS->new( + host => "$mailxconf{mailx}->{mail_gateway}", + ssl => 'ssl', + port => 465, + sasl_username => "$mailxconf{mailx}->{sasl_username}", + sasl_password => "$mailxconf{mailx}->{sasl_password}", + helo => "$dbt->{primary}->{sharee_primary}->{live_hostname}", + debug => 0, + ); + + + #multipart message + #Email::MIME !!! + if(1==1){ + my @parts = (); + + my $parts_1 = ( + Email::MIME->create( + attributes => { + content_type => "text/plain", + #disposition => "attachment", + encoding => "quoted-printable", + charset => "UTF-8", + }, + body_str => "$sendref->{message}", + ), + ); + push(@parts,$parts_1); + + + foreach $filename (@files){ + if($filename){ + my $parts_0 = ( + Email::MIME->create( + attributes => { + filename => "$filename", + #content_type => "application/pdf", + #content_type => "text/csv", + content_type => "application/octet-stream", + disposition => "attachment", + encoding => "quoted-printable", + name => "$filename", + }, + body => io( "$dbt->{copri_conf}->{basedir}/csv/$filename" )->binary->all, + ), + ); + + $bw->log("Attachment:$dbt->{copri_conf}->{basedir}/csv/$filename","",""); + push(@parts,$parts_0); + } + } + + $message = Email::MIME->create( + header_str => [ From => "$mail_from", + To => "$mail_to", + Subject => "$subject", ], + parts => [ @parts ], + ); + #$message->charset_set( 'UTF-8' ); + print $message->as_string; + }#if not Email::Mime + else{ + + $message = Email::Simple->create( + header => [ + From => "$mail_from", + To => "$mail_to", + Subject => "$subject", + ], + body => "$sendref->{message}", + ); + } + + try { + sendmail($message, { transport => $transport }); + } catch { + $bw->log("FAILURE send_mail:$0",$sendref,""); + warn "Error sending mail: $_"; + }; + } + $bw->log("Success send_mail","",""); + + +}#end mail_send + +1; diff --git a/copri4/main/src/Mod/Modalbox.pm b/copri4/main/src/Mod/Modalbox.pm new file mode 100644 index 0000000..b5e6858 --- /dev/null +++ b/copri4/main/src/Mod/Modalbox.pm @@ -0,0 +1,123 @@ +package Modalbox; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# + +use strict; +use warnings; + +use CGI::Cookie (); +use CGI ':standard'; +use CGI::Carp qw(fatalsToBrowser); +use Scalar::Util qw(looks_like_number); +use Lib::Config; +use Mod::Buttons; +use Mod::Libenzdb; +use Mod::DBtank; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +sub mobox(){ + my ($node_meta,$users_dms,$mode,$return) = @_; + my $q = new CGI; + my $cf = new Config; + my $but = new Buttons; + my $db = new Libenzdb; + my $dbt = new DBtank; + $q->import_names('R'); + my @keywords = $q->param; + my %varenv = $cf->envonline(); + my $script = $q->script_name(); + my $path = $q->path_info(); + my $lang = "de"; + my $dbh = ""; + + #TODO do it BrowserTab save + #my $kind_of_trans = $R::kind_of_trans || $users->{kind_of_trans} || ""; + #my $c_id4trans = $R::c_id4trans || $users->{c_id4trans} || ""; + #my $tpl_id4trans = $R::tpl_id4trans || $users->{tpl_id4trans} || ""; + #my $kind_of_trans = $users_dms->{kind_of_trans} || ""; + #my $c_id4trans = $users_dms->{c_id4trans} || ""; + #my $tpl_id4trans = $users_dms->{tpl_id4trans} || ""; + + if($users_dms->{kind_of_trans} && looks_like_number($users_dms->{c_id4trans}) && looks_like_number($users_dms->{tpl_id4trans})){ + my $width = $node_meta->{tpl_width} || "990"; + my $bg_color = "white"; + my $bg_color2 = $varenv{term_active_color} || ""; + + my $table = "contenttrans"; + my $ctt = $db->get_content1($table,$users_dms->{c_id4trans}); + my ($address_wc,$table_wc) = split(/\./,$ctt->{int04}); + my $rows = $address_wc + $table_wc; + + my $height = "600"; + if($varenv{orga} eq "dms"){ + $rows = $rows - 0; + }else{ + $rows = $rows - 10; + } + $height += $rows * 15 if($rows > 0); + my $debug; + $debug = "(c_id: $users_dms->{c_id4trans} | tpl_id: $users_dms->{tpl_id4trans})" if($users_dms->{u_id} == $dbt->{copri_conf}->{superu_id}); + +print< + .ui-dialog .ui-dialog-content { + background: $bg_color; + } + .ui-dialog > .ui-widget-header { + color:$varenv{color}; + font-weight:normal; + border:1px solid $bg_color2; + background: $bg_color2; + } + .ui-widget-overlay { + background: #666 url("$varenv{metahost}/js/jquery-ui/images/ui-bg_diagonals-thick_20_666666_40x40.png") 50% 50% repeat; + opacity: .5; + filter: Alpha(Opacity=50); + } + + + +EOF +; + + print "
    "; + + if($users_dms->{kind_of_trans} && looks_like_number($users_dms->{c_id4trans}) && looks_like_number($users_dms->{tpl_id4trans})){ + if($table eq "contenttrans" && $varenv{orga} eq "dms"){ + require "Tpl/Address3.pm"; + &Address3::tpl($node_meta,$users_dms,$return); + } + }else{ + print $q->div({-style=>"padding:0.1em;margin:0em;background-color:white;font-size:0.81em;"}, "Ein neues Formular kann im COPRI Hauptfenster geöffnet werden (Code: $users_dms->{kind_of_trans} && $users_dms->{c_id4trans} && $users_dms->{tpl_id4trans})", + "\n"); + } + + print "
    \n"; + } +} +1; diff --git a/copri4/main/src/Mod/Modalbox3.pm b/copri4/main/src/Mod/Modalbox3.pm new file mode 100644 index 0000000..f643b16 --- /dev/null +++ b/copri4/main/src/Mod/Modalbox3.pm @@ -0,0 +1,140 @@ +package Modalbox3; + +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH + +use strict; +use warnings; + +use CGI::Cookie (); +use CGI ':standard'; +use CGI::Carp qw(fatalsToBrowser); +use Lib::Config; +use Mod::Buttons; +use Mod::DBtank; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +sub mobox3(){ + my ($node_meta,$users_dms,$mode,$return) = @_; + #my ($return) = @_; + my $q = new CGI; + my $cf = new Config; + my $dbt = new DBtank; + my $but = new Buttons; + $q->import_names('R'); + my @keywords = $q->param; + my %varenv = $cf->envonline(); + my $script = $q->script_name(); + my $path = $q->path_info(); + my $coo = $q->cookie(-name=>'domcookie'); + my $dbh = ""; + + if($node_meta->{main_id} > 100){ + + my $bg_color = "white"; + my $bg_color2 = $node_meta->{bg_color} || "grey"; + my $title = "Content Editor \"$node_meta->{tpl_name}\""; + $title = "Artikel Editor" if($node_meta->{ct_table} eq "content"); + $title = "Kunden Editor" if($node_meta->{ct_table} eq "contentadr"); + $title = "DMS-Account Zugriffsberechtigung" if($node_meta->{ct_table} eq "users"); + $title = "Service Editor" if($node_meta->{ct_table} eq "contentpos"); + my $height = $node_meta->{tpl_height} || "990"; + my $width = $node_meta->{tpl_width} || "990"; + + if($mode eq "maintainer"){ + $title = "Node Editor"; + $height = "300"; + $width = "600"; + }elsif($mode eq "supervisor"){ + $title = "Datenfeld Eigenschaft bearbeiten"; + $height = "450"; + $width = "500"; + }elsif($R::rel_edit =~ /dialog4menu|dialog4content/){ + $title = "Relation Editor"; + $height = "300"; + $width = "550"; + } + + +print< + .ui-dialog .ui-dialog-content { + background: $bg_color; + } + .ui-dialog > .ui-widget-header { + color:black; + font-weight:normal; + border:1px solid $bg_color2; + background: $bg_color2; + } + .ui-widget-overlay { + background: #666 url("$varenv{metahost}/js/jquery-ui/images/ui-bg_diagonals-thick_20_666666_40x40.png") 50% 50% repeat; + opacity: .5; + filter: Alpha(Opacity=50); + } + + + +EOF +; + + print "
    \n"; + + print $q->start_multipart_form(-name=>"editform"); + + if($R::node2edit && $R::node2edit =~ /new_relation|edit_relation/){ + if($node_meta->{ct_table} eq "content" && $node_meta->{template_id} eq "205"){ + require "Mod/NodeEdit.pm"; + &NodeEdit::admin_tpl($node_meta,$users_dms,$mode,$return); + }elsif($users_dms->{u_id} == $dbt->{copri_conf}->{superu_id}){ + require "Mod/NodeEdit.pm"; + &NodeEdit::admin_tpl($node_meta,$users_dms,$mode,$return,"only superu_id"); + }else{ + print $q->div("Dieses Menue ist zur Bearbeitung nicht freigegeben."); + } + } + #elsif($node_meta->{ct_table} eq "contentpos"){ + # require "Tpl/APIdialog.pm"; + # &APIdialog::tpl($node_meta,$users_dms,$mode,$return); + #} + elsif($R::relate_dialog || $R::rel_edit =~ /dialog4menu|dialog4content/){ + require "Mod/RelationEdit.pm"; + &RelationEdit::tpl($node_meta,$users_dms,$mode,$return); + } + elsif($mode eq "supervisor"){ + require "Tpl/AttributEdit.pm"; + &AttributEdit::tpl($node_meta,$users_dms,$mode,$return); + } + elsif(($R::node2edit && $R::node2edit =~ /editpart/) || ($R::base_edit && $R::base_edit !~ /delete/)){ + require "Tpl/BaseEdit.pm"; + &BaseEdit::tpl($node_meta,$users_dms,$mode,$return); + } + else{ + print $q->div("Zugriff verweigert."); + } + print $q->end_form; + + print "
    \n"; + } +} +1; diff --git a/copri4/main/src/Mod/NodeEdit.pm b/copri4/main/src/Mod/NodeEdit.pm new file mode 100644 index 0000000..2b1fc3a --- /dev/null +++ b/copri4/main/src/Mod/NodeEdit.pm @@ -0,0 +1,199 @@ +package NodeEdit; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +# +use strict; +use warnings; +use CGI::Carp qw(fatalsToBrowser); +use CGI ':standard'; +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Libenzdb; +use Mod::Basework; +use Mod::DBtank; +use Mod::Relation; +use Data::Dumper; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub admin_tpl(){ + my $node_meta = shift; + my $users_dms = shift; + my $u_group = shift; + my $return = shift; + my $superu_id = shift || ""; + + #print Dumper($node_meta);exit; + + my $q = new CGI; + my @keywords = $q->param; + my $cf = new Config; + my $lb = new Libenz; + my $db = new Libenzdb; + my $bw = new Basework; + my $dbt = new DBtank; + my $but = new Buttons; + my $relform = new Relation; + my %varenv = $cf->envonline(); + my $script = $q->script_name(); + my $path = $q->path_info(); + $path = "$script" . "$path"; + my $lang = "de"; + + #$path =~ s/\/login|\/user|\/manager|\/admin//; + my $coo = $q->cookie(-name=>'domcookie'); + my %ib = $but->ibuttons(); + my $dbh = ""; + + my $u_name = $node_meta->{owner}; + $u_name = $dbt->sys_username($dbh,$node_meta->{owner}); + + my $change = $lb->time4de($node_meta->{change},"1") if($node_meta->{change}); + my $subid = $1 if($node_meta->{main_id} =~ /^(\d)/); + + my $ctf = $db->get_content1("contentuser",$dbt->{shareedms_conf}->{parent_id}); + + #Node templates + my $tpl_id = 97;#Standard for CMS + #Selektierbare Tabellen Layout templates + my $tpl_lists4selection; + + #if($node_meta->{ct_table} eq "content" || $node_meta->{ct_table} eq "contentpos"){ + if($node_meta->{ct_table} eq "content"){ + $tpl_id = 100; + if($node_meta->{template_id} eq "205"){ + #$tpl_id = 102; + $tpl_lists4selection = 205; + }elsif($node_meta->{template_id} eq "225"){ + $tpl_lists4selection = 225; + }elsif($node_meta->{template_id} eq "210"){ + $tpl_lists4selection = 210; + }else{ + $tpl_lists4selection = "224,226,227,228,229"; + #$tpl_lists4selection .= "," . $ctf->{txt35} if($ctf->{txt35});#pos tpl-id's + } + }elsif($node_meta->{ct_table} eq "contenttrans"){ + $tpl_id = "101"; + $tpl_lists4selection = "218"; + }elsif($node_meta->{ct_table} eq "contenttranspos"){ + $tpl_id = "101"; + $tpl_lists4selection = "221,222"; + }elsif($node_meta->{ct_table} eq "contentadr" || $node_meta->{ct_table} eq "contentadrpos"){ + $tpl_id = "101"; + $tpl_lists4selection = $ctf->{txt38}; + $tpl_lists4selection .= "," . $ctf->{txt31} if($ctf->{txt31});#pos tpl-id's + } + + #Defaults to tpl_id=97 + my $tpl = $db->get_tpl($tpl_id); + my @tpl_order = (""); + @tpl_order = split /,/,$tpl->{tpl_order}; + + + my @_templates; + my $tpl_all = $db->collect_tpl($tpl_lists4selection); + foreach my $id (sort {$tpl_all->{$a}->{tpl_name} cmp $tpl_all->{$b}->{tpl_name}} keys (%$tpl_all)){ + push (@_templates, "$id:$tpl_all->{$id}->{tpl_name}") if($tpl_all->{$id}->{tpl_name} !~ /dummy/); + } + + #reading mounted project data-dir + #Test: mount /dev/sda2 data/Projekte + my @_projectdir; + #my $dir = "$varenv{data}/Projekte"; + my $dir = "$varenv{data}/fileserver"; + if( -d "$dir"){ + opendir(DIR, "$dir"); + foreach(sort(readdir(DIR))){ + push (@_projectdir, "$_"); + } + closedir DIR; + } + + #content container + print "
    $superu_id"; + print $q->start_table({-style=>'margin-top:6px;', -border=>'0', -width=>'100%', -align=>'left', -cellpadding=>'3', -cellspacing=>'3'}); + print $q->Tr(); + if(1==1){ + if(($users_dms->{u_id} > 0) || ($u_group eq "admin")){ + print "\n"; + #print "\n"; + print $but->singlesubmit7("rel_edit","save_relation","$ib{save_relation}","","modal_position(xpos,ypos)"); + #look at dialog4menu, it seems better. vise a verse + print $q->span({-style=>'margin:0 0.2em;'}," "); + print $but->singlesubmit7("rel_edit","delete_relation","$ib{delete_relation}","","modal_position(xpos,ypos)"); + print $q->span({-style=>'margin:0 0.2em;'}," "); + print $but->singlesubmit7("rel_edit","new_relation","$ib{new_relation}","","modal_position(xpos,ypos)"); + #$R::new_submenu = 1 if($subid < 4); + print $q->span({ -style=>'margin:4px 0 0 4px;'},$but->checkbox("1","new_submenu","$R::new_submenu"),"Submenu") if($subid < 3 && $node_meta->{template_id} !~ /205/);#no submenue if bikes); + print $q->span({-style=>'margin-left:5em; font-size:0.91em;'}, "$u_name / $change") if($u_name); + print "\n"; + + print $q->hidden(-name=>'last_node_name', -value=>"$node_meta->{node_name}"); + print $q->hidden(-name=>'owner', -value=>"$users_dms->{u_id}"); + print $q->hidden(-name=>'parent_id', -value=>"$node_meta->{parent_id}"); + print $q->hidden(-name=>'main_id', -value=>"$node_meta->{main_id}"); + print $q->hidden(-name=>'mode', -value=>"admin"); + + + print $q->Tr(); + print $q->td({-colspan=>'2',-style=>'padding:5px;font-style:italic;'},"Path: $path"); + foreach (@tpl_order){ + my ($key,$des,$isize) = split /=/,$_; + $des .= " ($key)" if($users_dms->{u_id} eq $varenv{superu_id}); + #print "$key, $des, $isize|"; + $isize = "20" if(!$isize); + + if($key =~ /node_public|footer/){ + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms'},$but->checkbox("1","$key","$node_meta->{$key}")),"\n"; + }elsif($key =~ /txt01/ && $isize =~ /select/){ + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms'},$but->selector("$key","250px","$node_meta->{$key}",@_projectdir)),"\n"; + + }elsif($key =~ /tpl_name/){ + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms'},$but->selector("template_id","200px",$node_meta->{template_id},@_templates)),"\n"; + }elsif($key eq "txt01" && $isize eq "select"){ + my @_valxx = (""); + #TODO + #foreach my $rid (sort { $bike_nodes->{$a}->{node_name} cmp $bike_nodes->{$b}->{node_name} } keys (%$bike_nodes)){ + # push (@_valxx, "$bike_nodes->{$rid}->{main_id}:$bike_nodes->{$rid}->{node_name} - $bike_nodes->{$rid}->{main_id}"); + #} + print $q->Tr(); + print $q->td({-class=>'left_italic_cms',-colspan=>'1'},"$des"); + print $q->td({-class=>'content1_cms',-colspan=>'1'},$but->selector_class("$key","eselect","width:250px;",$node_meta->{$key},@_valxx)); + }elsif($key =~ /node_name/){ + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"); + print $q->td({-class=>'content1_cms'},$q->textfield(-class=>'etxt',-name=>"$key",-default=>"$node_meta->{$key}",-override=>'1',-size=>"$isize",-maxlength=>120)),"\n"; + }elsif($key =~ /n_sort/){ + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"); + print $q->td({-class=>'content1_cms'},$q->textfield(-class=>'etxt',-name=>"$key",-default=>"$node_meta->{$key}",-override=>'1',-size=>"$isize",-maxlength=>120)),"\n"; + } + } + } + }else{ + print $q->div({-style=>'text-align:left;margin:0.5em;padding:1em;background-color:white;'},"Im \"admin\" Modus können die Gruppen-Ordner verwaltet werden.
    --> Dazu erst einen Gruppen-Ordner öffnen!"); + } + + print $q->end_table; + + my $debug; + $debug = "(ct_table: $node_meta->{ct_table} | main_id: $node_meta->{main_id} | tpl_id: $node_meta->{template_id} " if($users_dms->{u_id} == $dbt->{copri_conf}->{superu_id}); + print $q->div({-style=>'position:absolute;bottom:2%;right:2%;z-index:10;font-size:13px;'},"$debug"),"\n"; + print "
    "; +} +1; diff --git a/copri4/main/src/Mod/Payment.pm b/copri4/main/src/Mod/Payment.pm new file mode 100644 index 0000000..464094a --- /dev/null +++ b/copri4/main/src/Mod/Payment.pm @@ -0,0 +1,700 @@ +package Payment; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +#Adapted from Prelogic Rechnung "buchen" and "print_pdf" +#Adapted from payone_post.pl +# +#enable for syntax check +#use lib "/var/www/copri4/shareedms-primary/src"; + +use strict; +use warnings; +use POSIX; +use CGI; # only for debugging +use LWP::UserAgent; +use URI::Encode; +my $uri_encode = URI::Encode->new( { encode_reserved => 1 } ); + +use Scalar::Util qw(looks_like_number); +use Lib::Config; +use Mod::Libenz; +use Mod::Libenzdb; +use Mod::Callib; +use Mod::DBtank; +use Mod::Basework; +use Data::Dumper; + +my $q = new CGI; +my $cf = new Config; +my $lb = new Libenz; +my $db = new Libenzdb; +my $cal = new Callib; +my $dbt = new DBtank; +my $bw = new Basework; + + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +my $ua = LWP::UserAgent->new( + ssl_opts => { + SSL_version => 'TLSv12:!SSLv2:!SSLv3:!TLSv1:!TLSv11', + } +); +$ua->agent("sharee payone POST API"); +my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; + + +#ported from payone_post.pl +#SEPA +#Request "managemandate" +sub managemandate_main { + my $self = shift; + my $varenv = shift; + my $ctadr = shift; + my $ctt = shift || ""; + my $owner = shift || 0; + my $payoneret = ""; + my $payone_conf = $dbt->{operator}->{$varenv->{dbname}}->{payone_conf} || $dbt->{payone_conf}; + + if($ctadr->{c_id}){ + my $lastname = $ctadr->{txt01}; + (my $firstname,$lastname) = split(/\s+/,$ctadr->{txt01}) if($ctadr->{txt01} =~ /\w\s+\w/i); + chomp($firstname); + chomp($lastname); + my $city = $ctadr->{txt06}; + (my $zip, $city) = split(/\s+/,$ctadr->{txt06}) if($ctadr->{txt06} =~ /[\w\d]\s+[\w\d]/i); + chomp($zip); + chomp($city); + + $ctadr->{txt06} =~ s/[\d\s]+//g; + $ctadr->{txt22} =~ s/\s//g; + my $bcountry = uc($1) if($ctadr->{txt22} && $ctadr->{txt22} =~ /^(\w{2})/); + my $currency = "EUR"; + $currency = "CHF" if($bcountry eq "CH"); + $ctadr->{txt23} =~ s/\s//g; + my $preauth_request = { + request => 'managemandate', + clearingtype => 'elv', + salution => "$ctadr->{txt02}", + firstname => "$firstname", + lastname => "$lastname", + street => "$ctadr->{txt03}", + zip => "$zip", + city => "$city", + country => "$ctadr->{txt10}", + email => "$ctadr->{txt08}", + telephonenumber => "$ctadr->{txt07}", + currency => "$currency", + iban => uc($ctadr->{txt22}), + bic => uc($ctadr->{txt23}) + }; + + my $request = { %$payone_conf, %$preauth_request}; + $payoneret = $self->rpc("managemandate",$varenv,$request,$ctadr,$ctt,$owner) if($request); + } + return $payoneret; +} + + +#Request "preauthorizationSEPA" +sub preauthorizationSEPA_main { + my $self = shift; + my $varenv = shift; + my $ctadr = shift; + my $ctt = shift; + my $owner = shift || 0; + my $payoneret = ""; + my $payone_conf = $dbt->{operator}->{$varenv->{dbname}}->{payone_conf} || $dbt->{payone_conf}; + my $dbh = ""; + + #to get actual data + my $pref = { + table => "contenttrans", + fetch => "one", + template_id => 205, + c_id => $ctt->{c_id}, + }; + my $ctt_up = $dbt->fetch_record($dbh,$pref); + + $ctt->{ct_name} = $ctt_up->{ct_name}; + if($ctt->{renewed}){ + $ctt->{ct_name} = $ctt_up->{ct_name}; + if($ctt_up->{ct_name} =~ /\d+-\d+/){ + my ($ct_name,$subname) = split(/-/,$ctt_up->{ct_name}); + $subname++; + $ctt->{ct_name} = "$ct_name-$subname"; + }else{ + $ctt->{ct_name} = "$ctt_up->{ct_name}-1"; + } + } + if(!$ctt->{reference}){ + $ctt->{reference} = $dbt->{operator}->{$varenv->{dbname}}->{oprefix} . "-" . $ctt->{ct_name}; + } + + #2019-05-18, makes only sense if int15 alias $sum_preauth > 0 + if($ctadr->{c_id} && $ctt->{c_id} && $ctt->{int15} > 0){ + + my $lastname = $ctadr->{txt01}; + (my $firstname,$lastname) = split(/\s+/,$ctadr->{txt01}) if($ctadr->{txt01} =~ /\w\s+\w/i); + chomp($firstname); + chomp($lastname); + my $city = $ctadr->{txt06}; + (my $zip, $city) = split(/\s+/,$ctadr->{txt06}) if($ctadr->{txt06} =~ /[\w\d]\s+[\w\d]/i); + chomp($zip); + chomp($city); + + $ctadr->{txt22} =~ s/\s//g; + #my $bcountry = uc($1) if($ctadr->{txt22} && $ctadr->{txt22} =~ /^(\w{2})/); + my $currency = "EUR"; + #$currency = "CHF" if($bcountry eq "CH"); + $ctadr->{txt23} =~ s/\s//g; + my $amount = 0; + $amount = $ctt->{int15} * 100 if($ctt->{int15}); + my $preauth_request = { + request => 'preauthorization', + clearingtype => 'elv', + salution => "$ctadr->{txt02}", + firstname => "$firstname", + lastname => "$lastname", + street => "$ctadr->{txt03}", + zip => "$zip", + city => "$city", + country => "$ctadr->{txt10}", + email => "$ctadr->{txt08}", + telephonenumber => "$ctadr->{txt07}", + #sequencenumber => "0", + amount => "$amount", + currency => "$currency", + iban => uc($ctadr->{txt22}), + bic => uc($ctadr->{txt23}), + reference => "$ctt->{reference}" + }; + $preauth_request->{ip} = "$ctadr->{txt25}" if($ctadr->{txt25} && $ctadr->{txt25} =~ /\d+\.\d+\.\d+\.\d+/); + my $request = { %$payone_conf, %$preauth_request}; + $payoneret = $self->rpc("preauthorizationSEPA",$varenv,$request,$ctadr,$ctt,$owner) if($request); + } + return $payoneret; +} + + +#Request "captureSEPA" +sub captureSEPA_main { + my $self = shift; + my $varenv = shift; + my $ctadr = shift; + my $ctt = shift; + my $owner = shift || 0; + my $payoneret = ""; + my $payone_conf = $dbt->{operator}->{$varenv->{dbname}}->{payone_conf} || $dbt->{payone_conf}; + + if($ctt->{c_id} && (!$ctt->{state} || $ctt->{int14})){ + my $amount = 0; + $amount = $ctt->{int01} * 100 if($ctt->{int01}); + my $currency = "EUR"; + + my $preauth_request = { + request => 'capture', + amount => "$amount", + currency => "$currency", + txid => "$ctt->{txt16}" + }; + my $request = { %$payone_conf, %$preauth_request}; + $payoneret = $self->rpc("captureSEPA",$varenv,$request,$ctadr,$ctt,$owner) if($request); + } + return $payoneret; +} + +#CC +#Request "preauthorizationCC" +sub preauthorizationCC_main { + my $self = shift; + my $varenv = shift; + my $ctadr = shift; + my $ctt = shift; + my $owner = shift || 0; + my $payoneret = ""; + my $payone_conf = $dbt->{operator}->{$varenv->{dbname}}->{payone_conf} || $dbt->{payone_conf}; + my $dbh = ""; + + #to get actual data + my $pref = { + table => "contenttrans", + fetch => "one", + template_id => 218, + c_id => $ctt->{c_id}, + }; + my $ctt_up = $dbt->fetch_record($dbh,$pref); + + $ctt->{ct_name} = $ctt_up->{ct_name}; + if($ctt->{renewed}){ + $ctt->{ct_name} = $ctt_up->{ct_name}; + if($ctt_up->{ct_name} =~ /\d+-\d+/){ + my ($ct_name,$subname) = split(/-/,$ctt_up->{ct_name}); + $subname++; + $ctt->{ct_name} = "$ct_name-$subname"; + }else{ + $ctt->{ct_name} = "$ctt_up->{ct_name}-1"; + } + } + if(!$ctt->{reference}){ + $ctt->{reference} = $dbt->{operator}->{$varenv->{dbname}}->{oprefix} . "-" . $ctt->{ct_name}; + } + + #2019-05-18, makes only sense if int15 alias $sum_preauth > 0 + if($ctadr->{c_id} && $ctt->{c_id} && $ctt->{int15} > 0){ + my $lastname = $ctadr->{txt01}; + (my $firstname,$lastname) = split(/\s+/,$ctadr->{txt01}) if($ctadr->{txt01} =~ /\w\s+\w/); + chomp($firstname); + chomp($lastname); + my $city = $ctadr->{txt06}; + (my $zip, $city) = split(/\s+/,$ctadr->{txt06}) if($ctadr->{txt06} =~ /[\w\d]\s+[\w\d]/); + chomp($zip); + chomp($city); + + my $amount = 0; + $amount = $ctt->{int15} * 100 if($ctt->{int15}); + my $preauth_request = { + request => 'preauthorization', + clearingtype => 'cc', + salution => "$ctadr->{txt02}", + firstname => "$firstname", + lastname => "$lastname", + street => "$ctadr->{txt03}", + zip => "$zip", + city => "$city", + country => "$ctadr->{txt10}", + email => "$ctadr->{txt08}", + telephonenumber => "$ctadr->{txt07}", + #sequencenumber => '0', + amount => "$amount", + currency => 'EUR', + #Parameter ( personal data ) + lastname => "$ctadr->{txt01}", + country => "$ctadr->{txt10}", + pseudocardpan => "$ctadr->{ct_name}", + ecommercemode => "internet", # wird zu 3Dscheck, + reference => "$ctt->{reference}" + }; + # https://docs.payone.com/display/public/PLATFORM/Special+remarks+-+Recurring+transactions+credit+card + # https://docs.payone.com/display/public/INT/Best+Practices+for+PSD2#tab-3DS+2.0+Best+Case + $preauth_request->{ip} = "$ctadr->{txt25}" if($ctadr->{txt25} && $ctadr->{txt25} =~ /\d+\.\d+\.\d+\.\d+/); + my $request = { %$payone_conf, %$preauth_request}; + $payoneret = $self->rpc("preauthorizationCC",$varenv,$request,$ctadr,$ctt,$owner) if($request); + } + return $payoneret; +} + +#Request "captureCC" +sub captureCC_main { + my $self = shift; + my $varenv = shift; + my $ctadr = shift; + my $ctt = shift; + my $owner = shift || 0; + my $payoneret = ""; + my $payone_conf = $dbt->{operator}->{$varenv->{dbname}}->{payone_conf} || $dbt->{payone_conf}; + + if($ctt->{c_id} && (!$ctt->{state} || $ctt->{int14} || $ctt->{txt28})){ + my $amount = 0; + $amount = $ctt->{int01} * 100 if($ctt->{int01}); + my $preauth_request = { + request => 'capture', + amount => "$amount", + currency => 'EUR', + txid => "$ctt->{txt16}" + }; + my $request = { %$payone_conf, %$preauth_request}; + $payoneret = $self->rpc("captureCC",$varenv,$request,$ctadr,$ctt,$owner) if($request); + } + return $payoneret; +} + +#TODO +#with previous preauthorization/ authorization and clearingtype=”elv”: +#An “amount = 0” can be used to cancel a +#direct debit transaction. This is not possible if the parameter “due_time” has +#been used, if the portal has enabled a delayed settlement (setup by PAYONE) or +#the direct debit has already been processed (after midnight). +#./src/scripts/payone_post.pl $varenv{syshost} refund contenttrans "" 6799 4 +##Request "refund" (Rückerstattung) +#txt16=txid must be copied from last captured invoice. +#int01 sum must be set! +#sequenz = 2 +#sudo su www-data -c "./src/scripts/payone_post.pl tinkdms refund contenttrans '' 32332 2" +sub refund { + my $self = shift; + my $varenv = shift; + my $ctadr = shift; + my $ctt = shift; + my $owner = shift || 0; + my $sequenz = shift || 0; + my $payoneret = ""; + my $payone_conf = $dbt->{operator}->{$varenv->{dbname}}->{payone_conf} || $dbt->{payone_conf}; + + if($ctt->{c_id}){ + my $amount = 0; + $amount = $ctt->{int01} * 100 if($ctt->{int01}); + my $currency = "EUR"; + + my $preauth_request = { + request => 'refund', + sequencenumber => "$sequenz",#$sequenz= must be +1 of the last capture + amount => "$amount", + currency => "$currency", + txid => "$ctt->{txt16}" + }; + my $request = { %$payone_conf, %$preauth_request}; + $payoneret = $self->rpc("refund",$varenv,$request,$ctadr,$ctt,$owner) if($request); + } + return $payoneret; +} + + +#################################################################################### +#Create a request +sub rpc { + my $self = shift; + my $todo = shift; + my $varenv = shift; + my $request = shift; + my $ctadr = shift || { c_id => 0 }; + my $ctt = shift || { c_id => 0 }; + my $owner = shift || 0; + my $payoneret = ""; + my $dbh = ""; + + #payone API URL + my $payoneLive = 1; + my $httpReqServer = "https://api.pay1.de/post-gateway/"; + my $req = HTTP::Request->new(POST => "$httpReqServer"); + + my $post; + foreach (keys (%$request)){ + my $encoded_val = $uri_encode->encode($request->{$_}); + $post .= "$_=$encoded_val&"; + } + $post =~ s/\&$//; + $req->content_type('application/x-www-form-urlencoded'); + $req->content($post); + + #Pass request to the user agent and get a response back + my $res = $ua->request($req); + my $vde_on_fail = $ctadr->{int12} || 1;#keep last or set 1 + my $debug=0; + $debug=1; + + my $update_adr = { + table => "contentadr", + mtime => "now()", + owner => $owner + }; + + my $update_ctt = { + table => "contenttrans", + mtime => "now()", + owner => $owner + }; + + + open(FILE,">>$varenv->{logdir}/payone-return-post.log") if($debug); + print FILE "\n*** $now_dt (ctadr_id:$ctadr->{c_id}, ctt_id:$ctt->{c_id}) from payone_post.pl\n$httpReqServer \n" if($debug); + print FILE "---> request to payone $todo:\n$post\n"; + + #Payone CONFIGURATION TransactionStatus URL: + #https://tinkrpc.copri.eu/src/scripts/postread_server.pl + #Check the outcome of the response + if ($res->is_success) { + print FILE "<--- return from payone $todo:\n" . $res->content . "\n" if($debug); + #print FILE Dumper($res); + my @content = split(/\n/,$res->content); + + print FILE $res->status_line, "\n" if($debug); + if($res->content =~ /status=APPROVED|status=REDIRECT/){ + #SEPA + if($todo =~ /managemandate/){ + my $mival = ""; + $mival = $1 if($res->content =~ /mandate_identification=(.*)/); + $payoneret = $mival; + print FILE "mival: $mival && $ctadr->{c_id}\n" if($debug); + + if($mival && $ctadr->{c_id}){ + foreach(@content){ + my ($key,$val) = split(/=/,$_); + $val = $q->escapeHTML("$val"); + $update_adr->{txt22} = $val if($key eq "iban"); + $update_adr->{txt23} = $val if($key eq "bic"); + $update_adr->{ct_name} = $val if($key eq "mandate_identification"); + $update_adr->{txt27} = $val if($key eq "mandate_status"); + $update_adr->{txt28} = $val if($key eq "mandate_text" && ($val =~ /SEPA/ || !$val)); + } + $update_adr->{int12} = 0;#Vde + $dbt->update_record($dbh,$update_adr,$ctadr) if($ctadr->{c_id} > 0); + my $ret = $self->pdfmandat($varenv,$ctadr->{c_id}); + print FILE "pdfmandat call generates: $ret\n" if($debug); + }elsif($ctadr->{c_id}){ + $update_adr->{int12} = $vde_on_fail;#Vde + } + } + + my $txidval = ""; + + #CC and SEPA after preauthorization + if($todo =~ /preauthorization/){ + $txidval = $1 if($res->content =~ /txid=(\d+)/); + $payoneret = $txidval; + print FILE "$todo: $txidval && $ctt->{c_id} && $ctadr->{c_id}\n" if($debug); + my $useridval = $1 if($res->content =~ /userid=(\d+)/);#2020-02-11 preauthorization returns payone Debitorennr + $update_ctt->{ct_name} = $ctt->{ct_name} if($ctt->{ct_name}); + + if($txidval && $ctt->{c_id} && $ctadr->{c_id}){ + $update_ctt->{int03} = $ctadr->{int03}; + $update_ctt->{int17} = $useridval if($useridval); + $update_ctt->{txt16} = $txidval; + $update_ctt->{txt22} = $ctt->{renewed} if($ctt->{renewed}); + $update_ctt->{txt26} = $ctadr->{ct_name};#Mandat/pseudocp + $update_ctt->{txt28} = ""; + $update_adr->{int12} = 0; + $update_adr->{int17} = $useridval if($useridval); + $update_adr->{txt28} = ""; + }elsif($ctadr->{c_id}){ + $update_ctt->{int14} = 1;#OPOS + $update_ctt->{txt28} = $now_dt . $res->content; + $update_adr->{int12} = $vde_on_fail;#Vde + } + } + + #Capture + if($todo =~ /capture/){ + $txidval = $1 if($res->content =~ /txid=(\d+)/); + $payoneret = $txidval; + print FILE "$todo: ($txidval && $ctt->{c_id} && $ctadr->{c_id})\n" if($debug); + + if($txidval && $ctt->{c_id} && $ctadr->{c_id} && $res->content =~ /settleaccount=/){ + #int01 and state will be set by "buchen" via Prelogic + $update_ctt->{int14} = "null"; + $update_ctt->{txt28} = ""; + $update_adr->{int12} = 0; + $update_adr->{txt28} = ""; + }else{#because of Prelogic logic set it empty if no capture + $update_ctt->{int14} = 1;#OPOS + $update_ctt->{txt28} = $now_dt . $res->content; + $update_adr->{int12} = $vde_on_fail;#Vde + #system(`$varenv->{basedir}/src/Mod/newsletter_tink.pl "$varenv->{basedir}" "$varenv->{wwwhost}" "send_capture_fail" "$ctadr->{c_id}" "$ctt->{ct_name}"`); + } + } + + }else{#not APPROVED + print FILE "not APPROVED: ($ctt->{c_id} && $res->content)\n" if($debug); + $update_ctt->{int14} = 1 if($ctt->{state} && $ctt->{state} !~ /Zahlungseingang/);;#OPOS + + #errormessage=Reference number already exists --> disabled + #errormessage=Amount no longer available --> disabled + if($res->content !~ /errorcode=911/){ + + my $payone_message = "$now_dt\n" . $res->content . "\nAufgrund der payone Ablehnung wurde der Verleih gesperrt. Die Bankdaten müssen überarbeitet werden\n"; + if($payoneLive == 1 && $ctadr->{c_id}){ + $update_ctt->{txt28} = $payone_message; + $update_adr->{txt28} = $payone_message; + #never delete on state=occupied, in this case ist must delete it on available + if($res->content !~ /errorcode=80/){ + $update_adr->{int12} = $vde_on_fail;#Vde + } + } + if($payoneLive == 1 && $ctt->{c_id}){ + $update_adr->{txt28} = $payone_message; + } + + }else{ + if($payoneLive == 1 && $ctt->{c_id}){ + my $payone_message = "$now_dt\n" . $res->content . "\n"; + $update_ctt->{txt28} = $payone_message; + $update_adr->{txt28} = $payone_message; + } + } + } + }else { + print FILE $res->status_line, "\n" if($debug); + } + + close(FILE) if($debug); + $dbt->update_record($dbh,$update_adr,$ctadr) if($ctadr->{c_id} > 0); + $dbt->update_record($dbh,$update_ctt,$ctt) if($ctt->{c_id} > 0); + return $payoneret; +} + +#SEPA PDFGenerator +sub pdfmandat { + my $self = shift; + my $varenv = shift; + my $c_id = shift || 0; + + my $dbh = ""; + my $authref = { + table => "contentadr", + fetch => "one", + template_id => "202", + c_id => "$c_id", + }; + my $ctadr = $dbt->fetch_record($dbh,$authref); + + open(EMA, ">> $varenv->{logdir}/SEPA-PDFprint.log"); + print EMA "*** $now_dt trying pdf --> $varenv->{basedir}/pdfinvoice/SEPA-Lastschriftmandat-$varenv->{dbname}-$ctadr->{ct_name}.pdf && $ctadr->{txt27}\n"; + if((! -f "$varenv->{basedir}/pdfinvoice/SEPA-Lastschriftmandat-$varenv->{dbname}-$ctadr->{ct_name}.pdf") && $ctadr->{txt27} && $ctadr->{txt27} =~ /active|pending/){ + my $topdf = "$varenv->{basedir}/src/wkhtmltopdf-amd64"; + my $print_return = `$topdf --page-size A4 "$varenv->{wwwhost}/PDFGenerator?printer_id=SEPA-Lastschriftmandat\&mandant_main_id=$dbt->{shareedms_conf}->{parent_id}\&id=$ctadr->{c_id}" $varenv->{basedir}/pdfinvoice/SEPA-Lastschriftmandat-$varenv->{dbname}-$ctadr->{ct_name}.pdf 2>&1`; + my $exit_code = $?; + my $filesize = -s "$varenv->{basedir}/pdfinvoice/SEPA-Lastschriftmandat-$varenv->{dbname}-$ctadr->{ct_name}.pdf"; + print EMA "$topdf --page-size A4 '$varenv->{wwwhost}/PDFGenerator?printer_id=SEPA-Lastschriftmandat\&mandant_main_id=$dbt->{shareedms_conf}->{parent_id}\&id=$ctadr->{c_id}' $varenv->{basedir}/pdfinvoice/SEPA-Lastschriftmandat-$varenv->{dbname}-$ctadr->{ct_name}.pdf\nreturn: $print_return\nfilesize: $filesize\nexit_code: $exit_code\n"; + } + close EMA; + return "$varenv->{logdir}/pdfinvoice/SEPA-Lastschriftmandat-$varenv->{dbname}-$ctadr->{ct_name}.pdf"; +} +#end ported from payone_post.pl +# + +#jused by payone_cron.pl +sub payone_capture(){ + my $self = shift; + my $varenv = shift; + my $ctf = shift; + my $ctadr = shift; + my $ctt = shift; + my $sum_paid = shift; + my $owner = shift; + + my $lang = "de"; + my $mandant_id = 100002; + my $main_id = 300008;#Rechnung + my $today4db = strftime("%Y-%m-%d %H:%M:%S",localtime(time)); + my $retval = {}; + my $return_text = "\n"; + my $dbh = ""; + + #Node and HoleCkeck depended auto Rechnungs-Nummer + my $node = $db->get_node4multi($main_id,$lang);#Rechnung node + if($node->{int06} > 0){ + if($ctt->{ct_name} !~ /\d/){ + #HoleCheck if ReNr available before ReNr counter + my $ReNr_start = 40000; + my $freeNr = $lb->get_freeReNr("contenttrans","$ReNr_start","$node->{int06}","txt00","$node->{node_name}"); + my $nextNr = $node->{int06}; + $nextNr = $freeNr if($freeNr && $freeNr < $node->{int06}); + $db->update_content4change("contenttrans",$ctt->{c_id},$nextNr,$nextNr,"barcode"); + if(!$freeNr){ + my $int06 = $node->{int06} + 1; + $db->updater("nodes","main_id",$main_id,"int06",$int06,"","","","","no_time"); + } + } + }else{ + $return_text = "---> payone_cron Payment.pm exit, $node->{int06} | $ctt->{ct_name} can not generate invoice number\n"; + return $return_text; + } + + #We do it only if txt80 end_time in Firma is defined + my $max_timestamp; + if($ctf->{txt80} && $ctt->{txt20}){ + if($ctt->{txt20} =~ /(\d{2})\.(\d{2})\.(\d{4})$/){ + $max_timestamp = "$1.$2.$3 23:59"; + }else{ + $return_text = "---> Payment.pm max_timestamp: $max_timestamp fails and exit\n"; + return $return_text; + } + } + + + my $state = $ctt->{state}; + if($varenv->{Zahlungsweise}){ + my @_paymentstate = split(/\|/,$varenv->{Zahlungsweise}); + if($ctadr->{int03} && $ctadr->{int03} == 1 && $ctadr->{ct_name} =~ /\w{2}-\d+/){ + $state = "$_paymentstate[0]"; + }else{ + undef $_paymentstate[0]; + } + if($ctadr->{int03} && $ctadr->{int03} == 2 && length($ctadr->{ct_name}) >= 19){ + $state = "$_paymentstate[1]"; + }else{ + undef $_paymentstate[1]; + } + } + + $db->update_content4change("contenttrans",$ctt->{c_id},"","$sum_paid","int01"); + $db->update_content4change("contenttrans",$ctt->{c_id},"",$state,"state"); + $db->update_content4change("contenttrans",$ctt->{c_id},"",$owner,"owner"); + $db->updater("contenttrans","c_id",$ctt->{c_id},"int14","2","","","","","");#must be to capture + #in cron we set OPOS anyway. If payone captured, it will be set int14=null + if(!$state || $state !~ /payone/){ + $db->updater("contenttrans","c_id",$ctt->{c_id},"txt22","cronjob fail","","","","",""); + $return_text = "---> Payment.pm can not preauthorization because of absent payment-data in ctadr.c_id:$ctadr->{c_id}, SEPA/CC:$ctadr->{int03}, $ctadr->{ct_name}, we exit\n"; + return $return_text; + } + + #preauth + if($ctadr->{int03} && $ctadr->{int03} == 1 && $ctadr->{ct_name} && $ctadr->{ct_name} =~ /\w{2}-\d+/ && (!$ctt->{txt16} || $ctt->{int03} ne "1")){ + $return_text .= "---> trying payone preauthorizationSEPA\n"; + $self->preauthorizationSEPA_main($varenv,$ctadr,$ctt,$owner); + + sleep 2; + }elsif($ctadr->{int03} && $ctadr->{int03} == 2 && $ctadr->{ct_name} && length($ctadr->{ct_name}) >= 19 && (!$ctt->{txt16} || $ctt->{int03} ne "2")){ + $return_text .= "---> trying payone preauthorizationCC\n"; + $self->preauthorizationCC_main($varenv,$ctadr,$ctt,$owner); + sleep 2; + } + + #check if preauth txid is done by payone + $ctt = $db->get_content1("contenttrans",$ctt->{c_id}); + + #SEPA capture + if($ctt->{int03} == 1 && $ctt->{txt16} && $ctt->{state} =~ /SEPA/){#SEPA + $return_text .= "---> trying payone captureSEPA\n"; + $self->captureSEPA_main($varenv,$ctadr,$ctt,$owner); + } + #CC capture + if($ctt->{int03} == 2 && $ctt->{txt16} && $ctt->{state} =~ /Kreditkarte/){#CC + $return_text .= "---> trying payone captureCC\n"; + $self->captureCC_main($varenv,$ctadr,$ctt,$owner); + } + + #Rechnungspositionen itime > end Abrechnunsgdatum --> results in generating new Invoice + if($max_timestamp && $varenv->{wwwhost} =~ /tink/){ + my $ctpos_ck = $db->get_content7("contenttranspos","ct_id",$ctt->{c_id},"itime",">","$max_timestamp"); + if($ctpos_ck->{c_id}){ + my $ctadr = $db->get_content7("contentadr","c_id",$ctadr->{c_id}); + my $ct_id = $dbt->insert_contenttrans($dbh,$ctadr,"300008","218","----",$owner); + $db->updater("contenttrans","c_id",$ct_id,"start_time","$ctt->{start_time}",$owner); + $db->updater("contenttrans","c_id",$ct_id,"end_time","$ctt->{end_time}",$owner); + + $db->updater("contenttranspos","ct_id",$ctt->{c_id},"ct_id",$ct_id,"","itime",">","$max_timestamp","no_time"); + } + } + + #wkhtml + #TODO to sharee + if(1==1){ + my $praefix = "$ctt->{txt00}-TINK"; + my $wc_line= $ctt->{int04};#Adresse.Tabelle + my $topdf = "$varenv->{basedir}/src/wkhtmltopdf-amd64"; + my $print_return = `$topdf --page-size A4 "$varenv->{wwwhost}/Printpreview?printer_id=PDF\&mandant_main_id=$mandant_id\&main_id=$main_id\&ct_name2print=$ctt->{ct_name}\&c_id4trans=$ctt->{c_id}\&u_id=$owner\&wc=$wc_line" $varenv->{pdf}/$praefix-$ctt->{ct_name}.pdf 2>&1`; + $return_text .= "$topdf --page-size A4 \"$varenv->{wwwhost}/Printpreview?printer_id=PDF\&mandant_main_id=$mandant_id\&main_id=$main_id\&ct_name2print=$ctt->{ct_name}\&c_id4trans=$ctt->{c_id}\&u_id=$owner\&wc=$wc_line\" $varenv->{pdf}/$praefix-$ctt->{ct_name}.pdf\n"; + + #send_invoice infomail + if(-f "$varenv->{pdf}/$praefix-$ctt->{ct_name}.pdf"){ + system(`$varenv->{basedir}/src/Mod/newsletter_tink.pl "$varenv->{basedir}" "$varenv->{wwwhost}" "send_invoice" "$ctadr->{c_id}" "$ctt->{ct_name}"`); + $return_text .= "---> Sent Invoice Info e-mail\n"; + } + + } + #TODO + #$retval = $db->get_content1("contenttrans",$ctt->{c_id}); + return ($retval,$return_text); +} + +1; + + diff --git a/copri4/main/src/Mod/Prelib.pm b/copri4/main/src/Mod/Prelib.pm new file mode 100644 index 0000000..9148500 --- /dev/null +++ b/copri4/main/src/Mod/Prelib.pm @@ -0,0 +1,354 @@ +package Prelib; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +#migrate some methodes form Prelogic and Premain to here +#defined methodes are available for web-app and backend + +use strict; +use warnings; +use POSIX; +use File::Path qw(make_path remove_tree); +use CGI ':standard'; +use CGI::Carp qw(fatalsToBrowser); +use Scalar::Util qw(looks_like_number); + +use Lib::Config; +use Mod::Libenzdb; +use Mod::Libenz; +use Mod::DBtank; +use Mod::Basework; +use Mod::APIfunc; +use Data::Dumper; + +my $cf = new Config; +my $db = new Libenzdb; +my $lb = new Libenz; +my $dbt = new DBtank; +my $bw = new Basework; +my $apif = new APIfunc; +my $q = new CGI; +my @keywords = $q->param; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +my $i_rows=0; +my $u_rows=0; +my $d_rows=0; +my $lang = "de"; + +my %varenv = $cf->envonline(); +my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; +my $debug=1; + + +#new node relation with option to create subnode for Servicelog +sub new_relation { + my $self = shift; + my $main_id = shift; + my $owner = shift; + my %varenv = $cf->envonline(); + my $ret = ""; + my $dbh = ""; + + #$ret = "failure::temporarily disabled"; + #return $ret; + open(FILE,">>$varenv{logdir}/new_relation.log") if($debug); + print FILE "\n*--> $now_dt| main_id: $main_id | owner: $owner\n" if($debug); + + my $prefix_id = "0"; + my $working_parent_id = $R::parent_id; + $prefix_id = $1 if($R::main_id =~ /^(\d)/ && $R::main_id >= "100000"); + $ret = $lb->checkinput($R::node_name); + return $ret if($ret =~ /failure/); + my $node_name = $q->escapeHTML($R::node_name); + + #check multiple node_name + my $subrelnode = $dbt->get_subrelnode($dbh,$working_parent_id,"",$node_name); + if($subrelnode->{node_name} eq "$R::node_name"){ + return "failure::Abbruch, der Menuename \"$subrelnode->{node_name}\" ist bereits vorhanden. Bitte eindeutige Menuenamen verwenden."; + } + + if($R::new_submenu){ + $working_parent_id = $R::main_id; + $prefix_id++; + } + my $new_main_id = $dbt->get_freenode($dbh,$prefix_id); + my $template_id = 0, + my $n_sort = 1; + $template_id = $R::template_id if(looks_like_number($R::template_id)); + $n_sort = $R::n_sort if(looks_like_number($R::n_sort)); + + + my $insert = { + main_id => $new_main_id, + parent_id => $working_parent_id, + template_id => $template_id, + content_id => 0, + node_name => $node_name, + n_sort => $n_sort, + lang => "de", + owner => $owner, + change => "now()", + }; + my $rel_id = $dbt->insert_nodeoid($dbh,$insert); + $i_rows = 1 if($rel_id > 0); + + print FILE "new_relation with" . Dumper($insert) . "\n" if($debug); + + #sub Servicelog for rental bikes + if($template_id == 205){ + $prefix_id++; + my $new_submain_id = $dbt->get_freenode($dbh,$prefix_id); + my $new_subtemplate_id = $dbt->get_freetpl($dbh,"400","499"); + + my $ret_tpl_id = $dbt->copy_template($dbh,"400",$new_subtemplate_id,$owner); + + my $insert_sub = { + main_id => $new_submain_id, + parent_id => $new_main_id, + template_id => $new_subtemplate_id, + content_id => 0, + node_name => "$node_name-Servicelog", + n_sort => $n_sort, + lang => "de", + owner => $owner, + change => "now()", + }; + my $subrel_id = $dbt->insert_nodeoid($dbh,$insert_sub); + $i_rows += 1 if($subrel_id > 0); + + print FILE "new_subrelation with" . Dumper($insert_sub) . "\nwith template_id=$ret_tpl_id" if($debug); + } + + close(FILE) if($debug); + + my $uri_path = $dbt->recurse_node("",$new_main_id); + print "$varenv{wwwhost}/$uri_path?return=$i_rows-$u_rows-$d_rows\n"; + print redirect("$varenv{wwwhost}/$uri_path?return=$i_rows-$u_rows-$d_rows"); + exit 0; +} +#end new_relation + + +#save node relation +sub save_relation { + my $self = shift; + my $main_id = shift; + my $owner = shift; + my %varenv = $cf->envonline(); + + my $dbh = ""; + my $update_node = { + table => "nodes", + main_id => "$main_id", + }; + my $update_relation = { + table => "relation", + main_id => "$main_id", + }; + my $subrelnode = $dbt->get_subrelnode($dbh,$main_id,"",""); + + foreach(@keywords){ + my $val = $q->param($_); + my $valxx = $q->escapeHTML("$val"); + $valxx =~ s/^\s+//; $valxx =~ s/\s+$//; + if(($_ eq "node_name") && $valxx){ + #if defined another path + my $node_name = $valxx; + my $node_path = $node_name; + #internal for splitting node_name node_path + ($node_name,$node_path) = split(/\|/,$node_name) if($node_name =~ /\|/); + my $return; + $return = $lb->checkinput($node_name); + $return = $lb->checkinput($node_path); + return $return if($return =~ /failure/); + + $u_rows = $dbt->update_one($dbh,$update_node,"node_name='$node_name'"); + $u_rows = $dbt->update_one($dbh,$update_node,"node_path='$node_path'"); + if($subrelnode->{main_id} && $subrelnode->{template_id} >= 400 && $subrelnode->{template_id} <= 499){ + my $update_subnode = { + table => "nodes", + main_id => "$subrelnode->{main_id}", + }; + $u_rows = $dbt->update_one($dbh,$update_subnode,"node_name='$node_name-Servicelog'"); + $u_rows = $dbt->update_one($dbh,$update_subnode,"node_path='$node_path-Servicelog'"); + } + } + if($_ =~ /template_id/ && $valxx){ + $u_rows = $dbt->update_one($dbh,$update_relation,"template_id=$valxx"); + } + if($_ =~ /int|n_sort|owner|node_public/){ + $valxx =~ s/,/./; + $valxx = "null" if(!$valxx && $valxx ne "0");#for empty + $valxx = "0" if($valxx eq "0"); + $u_rows = $dbt->update_one($dbh,$update_node,"$_=$valxx") if($valxx =~ /^\d+$|null|0/); + } + if($_ =~ /txt01/){ + $u_rows = $dbt->update_one($dbh,$update_node,"$_='$valxx'"); + } + if(! -d "$varenv{data}/$main_id"){ + mkdir("$varenv{data}/$main_id",0777); + mkdir("$varenv{data}/$main_id-thumb",0777); + mkdir("$varenv{data}/$main_id-resize",0777); + } + } + my $uri_path = $dbt->recurse_node("",$main_id); + print "$varenv{wwwhost}/$uri_path?return=$i_rows-$u_rows-$d_rows\n"; + print redirect("$varenv{wwwhost}/$uri_path?return=$i_rows-$u_rows-$d_rows"); + exit 0; +} + +#delete node relation with some ki deleting sub content +sub delete_relation { + my $self = shift; + my $main_id = shift; + my $owner = shift; + my %varenv = $cf->envonline(); + my $dbh = ""; + my $ret = ""; + my $debug=1; + open(FILE,">>$varenv{logdir}/delete_relation.log") if($debug); + print FILE "\n*--> $now_dt| main_id: $main_id \n" if($debug); + + #get all node para + my $noderef = { + main_id => $main_id, + fetch => "one", + }; + my $noderel = $dbt->fetch_rel4tpl4nd($dbh,$noderef); + my $ctref = { + table => "$noderel->{ct_table}", + main_id => $main_id, + fetch => "one", + c_id => ">::0", + }; + my $ct_record = $dbt->fetch_record($dbh,$ctref); + + + my $collect_rows=0; + if($R::template_id eq "205"){ + (my $collect_node,$collect_rows) = $dbt->collect_noderel($dbh,$noderel->{parent_id},$R::template_id); + } + my $subrelnode = $dbt->get_subrelnode($dbh,$main_id,"",""); + + #if 1 then deleteable + my $deleteable_subnode = 1; + my $deleteable_node = 1; + my $deleteable_last_node = 1; + if($subrelnode->{template_id} >= 400 && $subrelnode->{template_id} <= 499){ + $deleteable_subnode = 1; + if($collect_rows <= 1){ + $deleteable_last_node = 0; + } + }elsif($subrelnode->{template_id}){ + $deleteable_subnode = 0; + } + + if($ct_record->{c_id} > 0){ + $deleteable_node = 0; + } + print FILE "$deleteable_subnode == 0 || $deleteable_node == 0 --> collect_rows: $collect_rows|c_id: $ct_record->{c_id}\n" if($debug); + + if($deleteable_last_node == 0){ + $ret = "failure::Abbruch, es muss mindestens eine Mietrad Flotte definiert sein. ($collect_rows on $noderel->{parent_id})"; + }elsif($deleteable_subnode == 0 || $deleteable_node == 0){ + $ret = "failure::Abbruch, der Ordner enthält Daten. Für die referentielle Integrität ist es notwendig die Ordner Inhalte (content) und/oder Relationen des Ordners zu löschen. ($deleteable_subnode == 0 || $deleteable_node == 0 , $subrelnode->{template_id}, $main_id, $ct_record->{c_id}, $noderel->{ct_table})"; + }else{ + print FILE "delete_relation with $subrelnode->{main_id}, $subrelnode->{template_id}\n" if($debug); + if($deleteable_subnode && $subrelnode->{main_id}){ + $dbt->delete_content($dbh,"contentpos","all",$subrelnode->{template_id}) if($subrelnode->{template_id} >= 400 && $subrelnode->{template_id} <= 499); + $d_rows += $dbt->delete_noderel($dbh,$subrelnode->{main_id}); + $d_rows += $dbt->delete_template($dbh,$subrelnode->{template_id}); + } + $d_rows += $dbt->delete_noderel($dbh,$main_id); + + remove_tree("$varenv{data}/$main_id"); + remove_tree("$varenv{data}/$main_id-thumb"); + remove_tree("$varenv{data}/$main_id-resize"); + my $uri_path = $dbt->recurse_node($dbh,$noderel->{parent_id}); + $uri_path =~ s/\/\w+$//; + print redirect("$varenv{wwwhost}/$uri_path?return=$i_rows-$u_rows-$d_rows"); + exit 0; + } + + close(FILE) if($debug); + return $ret; +} + +#sharee Bonusnummer with Tarif automatic +sub set_usertarif { + my $self = shift; + my $dbh = shift; + my $dbname = shift; + my $adr_bonus = shift; + + open(FILE,">>$varenv{logdir}/save_account.log") if($debug); + print FILE "\n*Prelib--> $now_dt| c_id: $adr_bonus->{c_id} \n" if($debug); + + my $ret = $adr_bonus->{ret}; + my $i = 0; + my $dbh_operator = $dbt->dbconnect_extern($dbname);#operator connect + if($adr_bonus->{txt15} =~ /\w+/){ + if(1==1){ + my $pref_cc = { + table => "content", + keyfield => "c_id", + fetch => "all", + template_id => "228", + int03 => ">::0", + ct_name => $adr_bonus->{txt15}, + }; + my $record_op = $dbt->fetch_record($dbh_operator,$pref_cc); + my @new_txt30 = (); + foreach my $id (keys (%$record_op)){ + print FILE "-1-> txt15: $adr_bonus->{txt15}\n" if($debug); + $i++; + foreach my $sourcetarif (@{$adr_bonus->{txt30_array}}){ + print FILE "-1.2-> activeTarif-source:$sourcetarif | Bonus-source:$record_op->{$id}->{int21} | Bonus-target:$record_op->{$id}->{int22}\n" if($debug); + if($sourcetarif eq $record_op->{$id}->{int22}){ + print FILE "-2.1-> still activ Bonusnr ct_name: $record_op->{$id}->{ct_name}\n" if($debug); + $ret = "success::txt15"; + push(@new_txt30,$sourcetarif); + }elsif($record_op->{$id}->{int21} eq $sourcetarif && $record_op->{$id}->{int22}){ + $dbt->update_content4comp($dbh_operator,$record_op->{$id}->{c_id},"-","1"); + $u_rows = $dbt->update_one($dbh_operator,$adr_bonus,"txt15='$adr_bonus->{txt15}'"); + print FILE "-2.2-> match-update Bonusnr ct_name: $record_op->{$id}->{ct_name}\n" if($debug); + $ret = "success::txt15"; + push(@new_txt30,$record_op->{$id}->{int22}); + }else{ + print FILE "-2.3-> No matching Bonusnr ct_name: $record_op->{$id}->{ct_name}, keeping sourcetarif\n" if($debug); + push(@new_txt30,$sourcetarif); + #$ret = "failure::txt15#top1"; + } + } + } + if(@new_txt30){ + print FILE "-3-> txt30: @new_txt30\n" if($debug); + $u_rows = $dbt->update_one($dbh_operator,$adr_bonus,"txt30='@new_txt30'"); + } + $ret = "failure::txt30#top2" if(!$adr_bonus->{txt30_array} || $adr_bonus->{txt30_array} !~ /\d/); + } + }else{ + print FILE "-4-> update Tarif txt30: @{$adr_bonus->{txt30_array}}\n" if($debug); + $u_rows = $dbt->update_one($dbh_operator,$adr_bonus,"txt30='@{$adr_bonus->{txt30_array}}'"); + $u_rows = $dbt->update_one($dbh_operator,$adr_bonus,"txt15=''"); + $ret = "failure::txt30#top3" if(!$adr_bonus->{txt30_array} || $adr_bonus->{txt30_array} !~ /\d/); + } + + #if bonus value doesn't match + if($adr_bonus->{txt15} && $i == 0){ + print FILE "-5-> failure txt15: ''\n" if($debug); + $ret = "failure::txt15#top4"; + } + close(FILE) if($debug); + return $ret; +} + +1; diff --git a/copri4/main/src/Mod/Prelogic.pm b/copri4/main/src/Mod/Prelogic.pm new file mode 100644 index 0000000..82b521b --- /dev/null +++ b/copri4/main/src/Mod/Prelogic.pm @@ -0,0 +1,1126 @@ +package Prelogic; +# +#Deprecated module, please use Prelib.pm +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +#should be refactored +# +use strict; +use warnings; +use POSIX; +use CGI; +use CGI::Carp qw(fatalsToBrowser); +use CGI ':standard'; +use Date::Calc qw(:all); +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Libenzdb; +use Mod::DBtank; +use Mod::Callib; +use Mod::Payment; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub preinit(){ + my $self = shift; + my $users_dms = shift; + + my $q = new CGI; + $q->import_names('R'); + my @keywords = $q->param; + my $cf = new Config; + my $lb = new Libenz; + my $db = new Libenzdb; + my $dbt = new DBtank; + my $cb = new Callib; + my $but = new Buttons; + my $payone = new Payment; + my %ib = $but->ibuttons(); + my %varenv = $cf->envonline(); + my $script = $q->script_name(); + my $path_info = $q->path_info(); + my $path = $path_info; + #with meta_host, + if("$varenv{metahost}"){ + $path = "$script" . "$path_info"; + $script=""; + } + my $lang = "de"; + my $c_id = $R::c_id || "0";#c_id aus content + my $time = time(); + my $now_date = strftime "%Y-%m-%d", localtime; + my $today = strftime("%d.%m.%Y",localtime(time)); + my $today4db = strftime("%Y-%m-%d %H:%M",localtime(time)); + my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; + my $day = strftime "%d", localtime; + my $mon = strftime "%m", localtime; + my $year = strftime "%Y", localtime; + my $i_rows=0; + my $u_rows=0; + my $d_rows=0; + my $dbh = ""; + + if(!$users_dms->{u_id}){ + return "failure::Fehler
    Die Anwender Authentifikation wurde unterbrochen."; + } + + #Mindestmengenanzeige #ist in Liste.pm implementiert + #if(!$R::detail_search && $path =~ /root$/ && "$R::redirected" ne "1"){ + # my $repath = $lb->shortcut2("$path","$users_dms->{u_id}"); + #print redirect("$varenv{wwwhost}$script$repath?redirected=1&detail_search=1&s_int03=<=0"); + #exit 0; + #}els + #topmenu shortcut handling + #if(!$R::no_redirect && !$R::detail_search && $path =~ /^\/([\w-\s]+)\/([\w-\s]+)$|root$/ && "$R::redirected" ne "1"){ + # my $repath = $lb->shortcut2("$path","$users_dms->{u_id}"); + # if("$repath" ne "$path"){ + # print redirect("$varenv{wwwhost}$script$repath?redirected=1\&return=0-0-0|$i_rows-$u_rows-$d_rows"); + # exit 0; + # } + #} + + + + #international buttons + my ($key,$val,$ib_key); + while (($key,$val) = each(%ib)) { + $ib_key = $key if($R::ct_trans eq $val); + } + $ib_key = $R::ct_trans if(!$ib_key); + my ($ct_last,$c_idnew); + + my $table = "contenttrans"; + $table = "contenttver" if($users_dms->{kind_of_trans} =~ /Veranstaltung|Proje/); + my $ctt = $db->get_content1($table,$users_dms->{c_id4trans}); + my $buchen_mtime = $lb->time4de($ctt->{mtime}); + + #actual-path an get right mandant for verkauf + $R::kind_of_trans = $R::kind_of_trans || $users_dms->{kind_of_trans}; + my $node_mandant = $db->get_node2($users_dms->{fullurl},"$R::kind_of_trans",$lang); + my $mandant_main_id = $R::mandant_main_id || $node_mandant->{parent_id}; + my $parent_trans = $db->get_node3("$mandant_main_id","$R::kind_of_trans","$lang") if($mandant_main_id); + my $ctf = $db->get_content1("contentuser","$node_mandant->{parent_id}"); + my $ctb = $db->get_content1("contentuser","$users_dms->{u_id}"); + + if($node_mandant->{parent_id} && !$parent_trans->{main_id}){ + return "failure::Fehler
    keine eindeutige Modulzuweisung vorhanden."; + } + my $rel = $db->get_rel4tpl4nd($parent_trans->{main_id},$lang,$users_dms->{c_id4trans}); + $rel = $db->get_rel4tpl4nd("",$lang,$users_dms->{c_id4trans},$rel->{template_id}) if($users_dms->{c_id4trans} > "0"); + + my $ct_name = $q->escapeHTML("$R::ct_name"); + my $barcode=0; + + #Kassen-Abschluss Logik + my $s_owner_id=0; + if(($ctf->{txt06} eq "Benutzer") && ($R::kind_of_trans =~ /Verkauf|Verleih|Faktur/)){ + $s_owner_id = $users_dms->{u_id}; + } + + if($R::cash_sort){ + $db->users_up("cash_sort",$R::cash_sort,$users_dms->{u_id}); + } + if($R::ctpos_close){ + $db->users_up("ctpos_activ","0",$users_dms->{u_id}); + }elsif($R::ctpos_activ){ + $db->users_up("ctpos_activ",$R::ctpos_activ,$users_dms->{u_id}); + } + + if($R::s_start_date_time && $varenv{dataflow} =~ /wiki/){ + $db->users_up("cal_start","$R::s_start_date_time",$users_dms->{u_id}); + } + if($R::s_end_date_time && $varenv{dataflow} =~ /wiki/){ + $db->users_up("cal_end","$R::s_end_date_time",$users_dms->{u_id}); + } + if($R::view_list && $varenv{dataflow} =~ /wiki/){ + $db->users_up("view_list","$R::view_list",$users_dms->{u_id}); + } + + + + #OPEN/CLOSE + if(($R::ct_trans eq "open") && ("$R::kind_of_trans" !~ /Kalender|Mietjournal/)){ + $db->update_users4trans($R::c_id4trans,$R::tpl_id4trans,$R::kind_of_trans,$users_dms->{u_id}); + $users_dms = $db->select_users($users_dms->{u_id}); + }elsif(($R::ct_trans eq "close") && ("$R::kind_of_trans" !~ /Kalender|Mietjournal/)){ + $db->update_users4trans("0","0","",$users_dms->{u_id}); + $users_dms = $db->select_users($users_dms->{u_id}); + } + + + #NEW contenttrans + if($ib_key =~ /^new_/){ + $ct_name = "----" if(!$ct_name); + my $foreign_key; + my $sort; + my $main_id = $R::main_id; + if($ib_key =~ /new_trans/){ + $table = "contenttrans"; + $foreign_key="ct_id"; + $main_id = $parent_trans->{main_id} if(!$R::main_id); + }elsif($ib_key =~ /new_tver/){ + $table = "contenttver"; + $foreign_key="cv_id"; + $main_id = $parent_trans->{main_id} if(!$R::main_id); + } + my $node = $db->get_node4multi($main_id,$lang); + + #new content for all sub_nodes + if($varenv{dataflow} =~ /wiki/ && $table && $main_id){ + my $main_id2 = $main_id; + $main_id2 = $node->{parent_id} if($main_id >= 300000); + my ($dd1,$mo1,$yy1) = split(/\./,$R::s_start_date_time); + my $dt1 = $yy1 . $mo1 . $dd1; + my ($dd2,$mo2,$yy2) = split(/\./,$today); + my $dt2 = $yy2 . $mo2 . $dd2; + if($R::s_start_date_time && ($dt1 > $dt2)){ + return "failure::Der Vorgang wurde abgebrochen. Das anlegen von Datensätzen in die Zukunft ist nicht vorgesehen da problematisch Aufgrund der Übernahme der Inhalte aus \"Vereinbarungen\". ($R::s_start_date_time > $today alias $dt1 > $dt2)"; + } + my $start_time = $R::s_start_date_time || $today; + my $sub_nodes = $db->collect_node($main_id2,$lang,$users_dms->{u_id}); + #only sub-nodes 300000 + foreach my $id (sort { lc($sub_nodes->{$a}->{node_name}) cmp lc($sub_nodes->{$b}->{node_name}) } (keys (%$sub_nodes))){ + #print "$sub_nodes->{$id}->{main_id}|"; + my $ctrel; + $ctrel = $db->get_ctrel2($table,"",$sub_nodes->{$id}->{main_id},$lang,"","",$R::template_id,"start_time","$start_time","="); + if(!$ctrel->{c_id} && $sub_nodes->{$id}->{main_id} > 300000){ + $c_idnew = $db->insert_content($table,$ct_name,$users_dms->{u_id},$sort); + $i_rows += 1 if($c_idnew > 0); + $db->updater("$table","c_id",$c_idnew,"ct_name","$c_idnew"); + $db->updater("$table","c_id",$c_idnew,"start_time","$start_time"); + my $ctrel_desc = $db->get_ctrel2($table,"",$sub_nodes->{$id}->{main_id},$lang,"","",$R::template_id,"","","","start_time","DESC");#copy Vereinbarung und Wissenswertes + $db->updater("$table","c_id",$c_idnew,"txt00","$ctrel_desc->{txt00}"); + #$db->updater("$table","c_id",$c_idnew,"txt01","$ctrel_desc->{txt01}");#don't copy + my $rel_id = $db->insert_relationlist($table,$sub_nodes->{$id}->{main_id},$lang,$c_idnew,$R::template_id,$foreign_key); + } + } + print redirect("$varenv{wwwhost}$script$path?detail_search=1\&s_start_date_time=$start_time\&s_end_date_time=$start_time\&return=$i_rows-$u_rows-$d_rows"); + exit 0; + }elsif($table && $main_id && $R::kind_of_trans){ + my $rel = $db->get_rel4tpl($main_id,$lang); + $c_idnew = $db->insert_content2($table,$ct_name,$users_dms->{u_id},""); + $i_rows += 1 if($c_idnew > 0); + my $rel_id = $db->insert_relationlist($table,$rel->{main_id},$lang,$c_idnew,$rel->{tpl_id},$foreign_key); + $rel->{content_id} = $c_idnew; #notwendig bei prozeduralem $R::select_part + $db->update_content4change($table,$c_idnew,"",$parent_trans->{parent_id},"int09");#mandant_main_id + $db->update_content4change($table,$c_idnew,"",$node->{main_id},"int12");#zusätzl. Formtyp + $db->update_content4change($table,$c_idnew,"",$node->{node_name},"txt00");#node_name + $db->update_content4change($table,$c_idnew,"",$today4db,"start_time") if($R::kind_of_trans =~ /Faktur|Verleih/); + $db->update_content4change($table,$c_idnew,"",$today4db,"end_time") if($R::kind_of_trans =~ /Faktur|Verleih/); + $db->update_users4trans($c_idnew,$R::tpl_id4trans,$R::kind_of_trans,$users_dms->{u_id}) if("$R::kind_of_trans" !~ /Kalender|Mietjournal/); + if($ib_key eq "new_trans"){ + $db->update_content4change($table,$c_idnew,"","txt63","txt21");#Text-1 + $db->update_content4change($table,$c_idnew,"","Barkunde","txt01") if($varenv{wwwhost} =~ /lx-rad/); + $db->update_content4change($table,$c_idnew,"","txt61,txt63","txt21") if($R::kind_of_trans =~ /Faktur|Verleih/);#Text-3 + } + }else{ + return "failure::Fehler, Datensatz kann nicht angelegt werden weil folgende Informationen fehlen: ($main_id && $R::kind_of_trans)"; + } + } + + + ###ADD PARTS/DATE TO Transactions + if((($ib_key =~ /add_transpos|add_transdate/) || ($R::select_part && ($R::spart_ct_name || $R::json_select))) && (!$ctt->{close_time})){ + $table = "contenttranspos"; + my $menge="1"; + + #Leihrad-logik + my ($zcolumn,$zcontent,$ct_node); + $zcolumn = "barcode"; + $zcontent = "$R::spart_ct_name" || "$R::json_select"; + + #get part for adding and get from_main_id + my $ct_name = "$R::spart_ct_name" || "$R::json_select" || "";#turn-around!§$ + my $c_id = "$R::c_id" || ""; + my ($ct,$waren,$pre_lager,$lager); + + #my $warentpl_ids = $ctf->{txt37}; + my $warentpl_ids = "205,224,225,210,226,227,228,229"; + $ct = $db->get_ctrel2("content","$ct_name","","$lang","","$c_id","$warentpl_ids","$zcolumn","$zcontent",""); + + $ct_name = $ct->{ct_name} if($ct->{ct_name}); + $lager = $ct->{txt12} if($ct->{txt12}); + $lager = $mandant_main_id if(($ib_key =~ /new_transdate/) || ($R::spart_ct_name == $varenv{termin_id})); + + + if($ct->{main_id}){ + $ct_node = $db->get_node4multi($ct->{main_id},$lang); + #check if part linked to mandant + my $mandant_check; + $waren = $db->get_node2($users_dms->{fullurl},"Waren",$lang); + $mandant_check = $db->collect_noderec($waren->{main_id},$lang,"nothing") if($waren->{main_id}); + $mandant_check =~ s/,/|/g; + $users_dms = $db->select_users($users_dms->{u_id}) if($ib_key =~ /new_/);#nur bei new_ mit save_ + if(!$users_dms->{c_id4trans} && $ib_key !~ /new_transdate/){ + return "failure::Zu welchem Vorgang soll die Aktion verknüpft werden? Bitte erst den entsprechenden Vorgang öffnen."; + }elsif($ct->{main_id} && ($ct_node->{main_id} !~ /$mandant_check/)){ + return "failure::Der Artikel \"$R::spart_ct_name\" ist in der Datenbank vorhanden, aber nicht in \"$ctf->{ct_name}\" verlinkt
    Kläre bitte ob eine Faktura hier in Zukunft gewollt ist. Falls ja, informiere den Admin damit dieser die Verknüpfung herstellt."; + } + } + + if(($ct_name || $ct->{barcode}) && $rel->{content_id} && $ct_node->{main_id}){ + my $partnr = "$ct_name / $ct->{barcode}"; + $partnr = "$ct_name" if("$ct_name" eq "$ct->{barcode}" || !$ct->{barcode}); + my $bezeichnung = "$ct->{txt01}"; + $ct->{int02} = $ct->{int02} * -1 if($ct->{main_id} == 300012);#Gutscheine + my $einzel_preis = $ct->{int02}; + my $einzel_rabatt = $ct->{int07}; + $einzel_rabatt = $ctt->{int06} if($ctt->{int06} > 0); + my $unit = $ct->{txt03}; + if($ctf->{int02} != 0 && $ct->{int09} != 0){ + $einzel_preis = $ctf->{int02}; + $menge = $ct->{int09}; + $unit = "AW"; + } + + + #umst + my $umst=0; + $umst = $ct_node->{int03}; + $umst = $1 if($ctf->{txt13} =~ /(\d+)/ && $ct_node->{int03} !~ /\d/);#Standard VK Umst + + #Add Parts from content to contenttranspos################# + my $pos_id; + #Sort counter + my $ctpos = $db->get_content2sort("contenttranspos","1",">=","ct_id","$rel->{content_id}","",""); + + my $ctt = $db->get_content1("contenttrans",$users_dms->{c_id4trans}); + + #INSERT pos + $pos_id = $db->insert_contenttranspos($table,$partnr,$users_dms->{u_id},$ct->{barcode},$ct->{c_id},$ctt->{c_id},$ct->{main_id},$bezeichnung,$ct_node->{node_name},$unit,$einzel_preis,$menge,$umst,$einzel_rabatt,$lager,"","$ct->{txt05}","$ct->{txt06}","$ct->{txt07}","$ctt->{txt08}","$ctt->{int10}"); + $i_rows += 1 if($pos_id > 0); + + #append Rahmennummer + if($ct->{txt11}){ + my $rahmennr = "$ct->{txt11}"; + $rahmennr = "$ctt->{txt11} | $ct->{txt11}" if($ctt->{txt11});#add nr. + $db->updater("contenttrans","c_id",$rel->{content_id},"txt11",$rahmennr,$users_dms->{u_id}); + } + + #} + ################################################################# + + #negate if not rental-bike + if(($ct->{template_id} ne "205") && ($ctt->{txt00} !~ /Angebot|Kostenvoranschlag|Auftrag|Storno/) && !$R::c_idpos){ + $db->update_content4comp("content",$ct_name,"$ct->{c_id}","-","1","$R::kind_of_trans","$lager"); + } + return "pos_id=$pos_id";#new return-code to get opened Part-Position in Transposition + }elsif($ct_name && !$rel->{content_id}){ + return "failure::Für die Terminzuordnung bitte zuerst einen Verkauf Vorgang öffnen oder neu erzeugen.
    ::$script/$users_dms->{fullurl}/Verkauf::Zum Verkauf"; + }else{ + return "failure::Die Artikelnummer ist in der Waren Datenbank nicht angelegt oder einem anderen Lagerort zugeordnet.
    ::$script/$users_dms->{fullurl}/Waren::Waren verwalten"; + } + } + ##### + + #UPDATE CONTENT + #print "@keywords "; + if($ib_key =~ /save/){ + $c_id = $R::c_id if($ib_key eq "save");#only in journal edit + $db->users_up("c_id4edit","0","$users_dms->{u_id}");#delete edit marker + my $table = "contenttrans"; + #Maybe obsolete, because of ajax autosave --> for now back to old + #print "$ib_key|$R::ct_trans2c_idadr|$R::c_idadr"; + if($ib_key eq "save_adr" && $R::ct_trans2c_idadr eq "save_contentadr" && $R::c_idadr =~ /^\d+$/){ + $table = "contentadr"; + $c_id = "$R::c_idadr"; + }elsif($ib_key eq "save_adr" && $R::ct_trans2c_idadr eq "save_contentadr"){ + # #like new_adr in Premain.pm + $table = "contentadr"; + my $foreign_key="ca_id"; + my $p_main_id = $ctf->{txt32}; + my $barcode_last = $db->get_barcode("users","$table");#hier gilt: $table=column in users + my $freenr = $lb->get_freenr($table,$barcode_last->{$table}); + ($ct_name,$barcode) = $lb->barcodeable($table,$freenr);#new nr routine + if($barcode){ + $db->users_up("$table","$barcode",$users_dms->{u_id}); + }else{ + return "failure::Fehler, neue Nummer kann nicht generiert werden"; + } + if($p_main_id && $users_dms->{kind_of_trans}){ + #if($address->{main_id} && $users_dms->{kind_of_trans}){ + $rel = $db->get_rel4tpl($p_main_id,$lang); + $c_idnew = $db->insert_content2($table,$ct_name,$users_dms->{u_id},""); + $i_rows += 1 if($c_idnew > 0); + $db->update_barcode($table,$c_idnew,$ct_name,$barcode); + my $rel_id = $db->insert_relationlist($table,$rel->{main_id},$lang,$c_idnew,$rel->{tpl_id},$foreign_key); + $c_id = $c_idnew; #for contenadr update + $R::c_idadr = $c_idnew; #for copy contentadr to contenttrans + } + #Freitext oder nur in contentrans speichern + }elsif($ib_key eq "save_adr" || $ib_key =~ /save_text/){ + $table = "contenttrans"; + $c_id = "$R::c_id4trans"; + }elsif($ib_key =~ /save_tver/){ + $table = "contenttver"; + $c_id = "$users_dms->{c_id4trans}"; + $c_id = $R::c_id if($R::cell_key && $R::c_id); + }elsif($ib_key eq "save_pos"){ + $table = "contenttranspos"; + $c_id = $R::c_idpos || $R::pos_id; + }elsif($ib_key eq "save_verpos"){ + $table = "contenttverpos"; + $c_id = $R::c_idpos || $R::pos_id; + } + + #Miet- bzw. BaseVA- Zeitraum + if($R::start_date =~ /\d{1,2}\.\d{1,2}\.\d{4}/ && $R::end_date =~ /\d{1,2}\.\d{1,2}\.\d{4}/){ + my $start_date = $q->escapeHTML("$R::start_date"); + my $end_date = $q->escapeHTML("$R::end_date"); + my $s_hh = $q->escapeHTML("$R::s_hh") || "0"; + my $s_mi = $q->escapeHTML("$R::s_mi") || "0"; + my $e_hh = $q->escapeHTML("$R::e_hh") || "0"; + my $e_mi = $q->escapeHTML("$R::e_mi") || "0"; + $s_hh = "24" if($s_hh > "24"); + $e_hh = "24" if($e_hh > "24"); + $s_mi = "59" if($s_mi > "59"); + $e_mi = "59" if($e_mi > "59"); + my $start_time="null"; + my $end_time="null"; + $start_time = "$start_date $s_hh:$s_mi" if("$start_date $s_hh:$s_mi" =~ /\d{1,2}\.\d{1,2}\.\d{4}\s\d{1,2}:\d{1,2}/); + $end_time = "$end_date $e_hh:$e_mi" if("$end_date $e_hh:$e_mi" =~ /\d{1,2}\.\d{1,2}\.\d{4}\s\d{1,2}:\d{1,2}/); + + + if($ib_key =~ /save_pos/){ + my $pos_id = $R::c_idpos; + my ($start_datetime,$end_datetime,$s_up,$e_up,$menge) = $cb->contenttranspos_dating($pos_id,$start_time,$end_time,$today4db,""); + my ($s_yy,$s_mo,$s_dd,$s_hh,$s_mi) = $cb->split_date($start_datetime); + my $s_time = Mktime($s_yy,$s_mo,$s_dd,$s_hh,$s_mi,0); + my ($e_yy,$e_mo,$e_dd,$e_hh,$e_mi) = $cb->split_date($end_datetime); + my $e_time = Mktime($e_yy,$e_mo,$e_dd,$e_hh,$e_mi,0); + + my $ctpos_id=0; + my $cvpos_id=0; + $ctpos_id = $pos_id if($table eq "contenttranspos"); + $cvpos_id = $pos_id if($table eq "contenttverpos"); + $db->updater($table,"c_id",$pos_id,"start_time","$start_datetime",$users_dms->{u_id}); + $db->updater($table,"c_id",$pos_id,"end_time","$end_datetime",$users_dms->{u_id}); + #print "($s_time <= $time && $e_time >= $time) xxxx"; + #set contentpos status + if($s_time <= $time && $e_time >= $time){ + $db->updater($table,"c_id",$pos_id,"int10","3",$users_dms->{u_id}); + }else{ + $db->updater($table,"c_id",$pos_id,"int10","1",$users_dms->{u_id}); + #2021-08-04 set also bike available + $db->updater("content","c_id",$R::cc_id,"int10","1",$users_dms->{u_id}) if($R::cc_id); + } + #TINK $menge counting + #we believe setting by manually insert of int03=$menge via Transposition + #$db->updater($table,"c_id",$pos_id,"int03","$menge",$users_dms->{u_id}); + #set GPS + if($R::txt06 && $R::txt06 =~ /^(\d{1,2}\.\d+),\s?(\d{1,2}\.\d+)$/){ + $db->updater($table,"c_id",$pos_id,"txt06","$R::txt06",$users_dms->{u_id}); + } + #set StationID + if($R::int04 =~ /^\d+$/){ + $db->updater($table,"c_id",$pos_id,"int04","$R::int04",$users_dms->{u_id}); + #require "Mod/KMLout.pm"; + #my $kmlfile = Mod::KMLout::kmlGenerator("",""); + } + + $db->updater("contenttrans","c_id",$ctt->{c_id},"start_time","$start_datetime",$users_dms->{u_id}); + $db->updater("contenttrans","c_id",$ctt->{c_id},"end_time","$end_datetime",$users_dms->{u_id}); + + }elsif($ib_key =~ /save_tver|save_verpos/){ + $u_rows += $db->updater("contenttver","c_id",$c_id,"start_time","$start_time"); + $u_rows += $db->updater("contenttver","c_id",$c_id,"end_time","$end_time"); + $db->users_up("cal_start","$start_time",$users_dms->{u_id}) if($varenv{dataflow} =~ /wiki/); + } + } + + #hidden select keys to delete first, marked with off_ (Project.pm) + foreach(@keywords){ + if($_ =~ /off_(txt\d+)/){ + $db->updater("$table","c_id",$c_id,"$1",""); + } + } + + my $ct_exist2; + $ct_exist2 = $db->get_content2($table,$ct_name) if($ct_name); + $ct_exist2 = $db->get_content1($table,$c_id) if($c_id); + if($ct_exist2->{ct_name} && ($ct_exist2->{c_id} ne $c_id)){ + return "failure::$ct_exist2->{ct_name} - $ct_exist2->{c_id} - $c_id
    content name exists"; + }elsif($c_id){ + $users_dms = $db->select_users($users_dms->{u_id});#to get new cal_start + my $j=0; + foreach(@keywords){ + $j++; + my $val = $q->param($_); + my $valxx = $q->escapeHTML("$val"); + my @val = $q->param($_); + $valxx = $q->escapeHTML("@val"); + $_ =~ s/col_//; + $ct_exist2->{$_} =~ s/^\s+//; $ct_exist2->{$_} =~ s/\s+$//; + $valxx =~ s/^\s+//; $valxx =~ s/\s+$//; + $valxx .= ".00" if($valxx =~ /^\d+$/ && $_ =~ /int\d+/); + #print "|$_:$ct_exist2->{$_} -- $valxx|
    "; + if($_ =~ /sort4pos_\d+/ && $valxx =~ /^\d+$/){ + $db->updater("contenttverpos","c_id",$1,"sort","$valxx") if($_ =~ /sort4pos_(\d+)/); + }elsif(("$ct_exist2->{$_}" ne "$valxx") || $R::ckid_main || $_ =~ /txt10|txt11/ || $R::edit_main){ + if($_ eq "ct_name" && $valxx && $table){ + $u_rows +=$db->updater("$table","c_id",$c_id,"$_","$valxx"); + } + if($_ =~ /txt21|txt6/ && $table){ + $db->update_content4change2($table,$c_id,"$R::txt61,$R::txt62,$R::txt63,$R::txt64,$R::txt65,$R::txt66,$R::txt67,$R::txt68,$R::txt69","txt21") + }elsif($_ =~ /txt(\d+)$/ && $table){ + $valxx = "null" if(!$valxx);#for empty + my $txtxx = $valxx; + $u_rows +=$db->updater("$table","c_id",$c_id,"$_","$valxx"); + } + + if($_ =~ /mtime/ && $table){ + my $timexx = $valxx; + $u_rows += $db->update_content4change($table,$c_id,$ct_name,$timexx,$_,$users_dms->{u_id}) if($timexx =~ /\d{1,2}\.\d{1,2}\.\d{2,4}\s\d{1,2}:\d{1,2}/ || $timexx =~ /\d{1,2}\.\d{1,2}\.\d{2,4}$/); + } + if($_ =~ /state/ && $table){ + my $state = $valxx; + $u_rows += $db->update_content4change($table,$c_id,$ct_name,$state,$_,$users_dms->{u_id}); + } + if($_ =~ /(xml_export)/ && $table){#boolean + my $key = $1; + my $value = $valxx || "f"; + $u_rows += $db->update_content4change($table,$c_id,$ct_name,$value,$key,$users_dms->{u_id}); + } + if($_ =~ /int(\d+)/ && $table){ + $valxx =~ s/,/./; + $valxx =~ s/\.00//; + $valxx = "null" if(!$valxx);#for empty + my $intxx = $valxx; + #Ausgaben trigger + if($ib_key eq "save_pos" && $_ eq "int02" && $intxx =~ /-\d/){ + $u_rows += $db->update_content4change($table,$c_id,$ct_name,$intxx,"int02",$users_dms->{u_id}); + }elsif($ib_key eq "save_pos" && $_ eq "int03"){ + #Warenbestands trigger + my $op="+"; + $op = $1 if($intxx =~ s/(-|\+)//); + if($op =~ /-/){ + return "failure::Bitte einen fiktiven Artikel unter \"Ausgaben\" verwenden."; + } + my $add_menge="0"; + #differenz, es wird nur der zuwachs verwendet + $ct_exist2->{$_} = 0 if(!$ct_exist2->{$_}); + $add_menge = - $ct_exist2->{$_} + $intxx if($op eq "+"); + my $rows = $db->update_content4comp("contenttranspos",$R::ct_name,$R::c_idpos,"$op","$add_menge","$R::kind_of_trans"); + if($rows){ + $u_rows += $db->update_content4comp("content",$R::ct_name,"$R::cc_id","-","$add_menge","$R::kind_of_trans","$ct_exist2->{txt12}") if(($R::kind_of_trans =~ /Faktur|Verleih/) && ($ctt->{txt00} !~ /Angebot|Kostenvoranschlag|Auftrag/) && ("$ctb->{txt02}" ne "aus")); + } + }else{ + $u_rows +=$db->updater("$table","c_id",$c_id,"$_","$valxx"); + } + } + } + } + } + } + + + ###SET workflow (like copy doc-type) + #follows address copy + #1. counter for WaWi and ReNr + my $c_id4trans = $R::c_id4trans;#It needs hidden posts. Only implemented in Address and Transact + if($R::set_workflow && $R::set_main_id4workflow && $R::ct_name4workflow =~ /\d/){ + return "failure::Bitte erst einen Formular-Typ wählen" if($R::set_main_id4workflow <= "300000"); + $table = "contenttrans"; + my $foreign_key="ct_id"; + my $j="1"; + $rel = $db->get_rel4tpl("",$lang,$c_id4trans,$R::tpl_id4trans); + my $set_tpl = $db->get_rel4tpl($R::set_main_id4workflow,$lang,"","","ASC"); + my $backlink = $R::ct_name4workflow; + my $ct_name = $R::ct_name4workflow; + my $subname= 1; + ($ct_name,$subname) = split(/-/,$R::ct_name4workflow) if($R::ct_name4workflow =~ /\d+-\d+/); + my $lastct_name = $db->get_like2sort($table,"ct_name","$ct_name-"); + if($lastct_name->{ct_name}){ + ($ct_name,$subname) = split(/-/,$lastct_name->{ct_name}); + $subname++; + } + my $ct_name_new = "$ct_name-$subname"; + my $barcode = "$ct_name$subname"; + + ###Vorsicht, redundanter code-abschnitt = set_main_id + my ($node,$ct_exist); + $node = $db->get_node4multi($R::set_main_id4workflow,$lang); + if($node->{main_id} > 300000){ + my $rows = $node->{int10} + 1; + $db->updater("nodes","main_id",$node->{main_id},"int10",$rows); + } + + #Node abhängige auto Beleg-Nummer + my $journal_nodes = "$ctf->{txt23}"; + $journal_nodes .= "|$ctf->{txt24}" if($ctf->{txt24}); + $journal_nodes .= "|$ctf->{txt25}" if($ctf->{txt25}); + if(($node->{int06} > 0) && ("$R::set_main_id4workflow" != "$rel->{main_id}") && ("$rel->{main_id}" !~ /$journal_nodes/) && ($node->{node_name} !~ /steuerfrei/)){ + $ct_exist = $db->get_ctrel2($table,$node->{int06},$R::set_main_id4workflow,$lang); + if($ct_exist->{rel_id}){ + return "failure::Konflikt, die Nummer \"$ct_exist->{ct_name}\" ist bereits vergeben."; + } + #$ct_name_new = "$node->{int06}" . "-$ct_name";#neue subNummer + #$barcode = "$node->{int06}" . "$ct_name"; + $ct_name_new = "$node->{int06}"; + $barcode = "$node->{int06}"; + my $int06 = $node->{int06} + 1; + $u_rows += $db->updater("nodes","main_id",$R::set_main_id4workflow,"int06",$int06,"","","","","no_time"); + } + ### + + $ct_exist = $db->get_ctrel2($table,$ct_name_new,"",$lang,"","",$set_tpl->{tpl_id}); + if($ct_exist->{ct_name} && $node->{node_name} !~ /Storno/){ + return "failure::Der Vorgang mit der Nummer \"$ct_exist->{ct_name}\" ist bereits vorhanden"; + } + $c_idnew = $db->insert_content2($table,$ct_name_new,$users_dms->{u_id},""); + $i_rows += 1 if($c_idnew > 0); + my $rel_id = $db->insert_relationlist($table,$R::set_main_id4workflow,$lang,$c_idnew,$set_tpl->{tpl_id},$foreign_key); + $node = $db->get_node4multi($R::set_main_id4workflow,$lang); + $db->updater($table,"c_id",$c_idnew,"close_time","null"); + + #2017-08-10 adapted from lx-rad, set backlink for workflow documentation + $db->updater($table,"c_id",$c_idnew,"txt04","$backlink"); + $db->update_content4change($table,$c_idnew,"",$barcode,"barcode"); + $db->update_content4change($table,$c_idnew,"",$parent_trans->{parent_id},"int09");#mandant_id + $db->update_content4change($table,$c_idnew,"",$R::set_main_id4workflow,"int12");#zusätzl. Formtyp + $db->update_content4change($table,$c_idnew,"",$node->{node_name},"txt00");#node_name + $db->update_content4change($table,$c_idnew,"","txt61,txt63","txt21") if($node->{node_name} =~ /Mietvertrag/);#Text-3 + $db->update_content4change($table,$c_idnew,"","txt64","txt21") if($node->{node_name} =~ /Rückgabe/);#Text-4 + $db->update_content4change($table,$c_idnew,"","txt65","txt21") if($node->{node_name} =~ /steuerfrei/);#Text-5 + $db->update_users4trans($c_idnew,$set_tpl->{tpl_id},$R::kind_of_trans,$R::owner); + + $node = $db->get_node4multi($R::set_main_id4workflow,$lang); + my $old_node = $db->get_node4multi($rel->{main_id},$lang); + + #workflow + #print "$old_node->{node_name} ---> $node->{node_name}"; + + #position copy + my ($cttpos,$rows) = $db->collect_contentpos("$table",$c_id4trans); + foreach my $id (sort { lc($cttpos->{$a}->{sort}) cmp lc($cttpos->{$b}->{sort}) } keys(%$cttpos)){ + #2019-05-24, adding Storno (300009) to Rechnung + if(($node->{node_name} =~ /Storno/) || ($R::set_main_id eq "300009" && $node->{node_name} =~ /Rechnung/)){ + $cttpos->{$id}->{int02} = $cttpos->{$id}->{int02} * -1 if($cttpos->{$id}->{int02} != 0); + $cttpos->{$id}->{int07} = $cttpos->{$id}->{int07} * -1 if($cttpos->{$id}->{int07} != 0 && $cttpos->{$id}->{int08} == 1);#if Rabatt int08 != 1 alias €; + if($R::kind_of_trans =~ /Faktur/){ + $db->update_content4comp("content",$cttpos->{$id}->{ct_name},"$cttpos->{$id}->{cc_id}","+","$cttpos->{$id}->{int03}","$R::kind_of_trans","$cttpos->{$id}->{txt12}"); + } + } + + delete $cttpos->{$id}->{c_id}; + delete $cttpos->{$id}->{ct_id}; + delete $cttpos->{$id}->{itime}; + delete $cttpos->{$id}->{mtime}; + my $insert_pos = { + %{$cttpos->{$id}}, + table => "contenttranspos", + ct_id => $c_idnew, + itime => 'now()', + mtime => 'now()', + }; + my $ctpos_id = $dbt->insert_contentoid($dbh,$insert_pos,""); + $i_rows += 1 if($ctpos_id > 0); + + } + + $db->update_users4trans($c_idnew,$set_tpl->{tpl_id},$R::kind_of_trans,$R::owner); + $users_dms = $db->select_users($users_dms->{u_id}); + $c_id4trans = $users_dms->{c_id4trans}; + } + #### + + + #copy ADD ADDRESS from contentadr to contenttrans + #Attention, doupled saved over Terminal AND over set_workflow + #All Verkauf-Terminal submits without Print PDF! + # + if(($R::ct_trans !~ /print_pdf|print/i) && (($ib_key eq "add_transadr") || $R::ct_trans2c_idadr || $R::set_main_id || $R::set_main_id4workflow)){ + $c_id4trans = $users_dms->{c_id4trans} if($ib_key eq "add_transadr" && $users_dms->{c_id4trans}); + if(!$c_id4trans){ + return "failure::Wohin damit? Für die Zuweisung bitte erst ein Ziel öffnen."; + } + $table = "contenttrans"; + my $ctt; + #202=Adressenliste + if(($ib_key eq "add_transadr") || ($R::ct_trans2c_idadr eq "save_contentadr")){ + $ctt = $db->get_ctrel("contentadr","",$lang,"",$R::c_idadr,"202"); + }else{ + my $c_id4copy = $R::c_id4copy || $c_id4trans; + $ctt = $db->get_content1("contenttrans",$c_id4copy); + } + #214=Adressendefinition + my $tpl = $db->get_tpl("214"); + my @ct4tpl = split (/,/,$tpl->{tpl_order}); + foreach(@ct4tpl){#copy + my ($key,$val) = split /=/,$_; + $ctt->{$key} = "no" if(!$ctt->{$key} && $key =~ /txt/); + $ctt->{$key} = "0" if(!$ctt->{$key} && $key =~ /int/); + if($R::c_idadr > 0){#from contentadr + #print "---> $key"; + if($key =~ /int10/){ + $u_rows += $db->update_content4change($table,$c_id4trans,"",$R::c_idadr,"int10"); + }elsif(($ib_key eq "add_transadr") && ($key =~ /txt09|txt10|txt11|txt12/)){ + my $advanced_fields = "no"; + }elsif(($R::ct_trans2c_idadr eq "save_contentadr") && ($key =~ /txt10|txt11|txt12/)){#wg.Reparaturobjekt|Rahmen|Freitext + my $advanced_fields = "no"; + }else{ + $u_rows += $db->update_content4change($table,$c_id4trans,"",$ctt->{$key},$key); + } + }else{ + $u_rows += $db->update_content4change($table,$c_id4trans,"",$ctt->{$key},$key); + } + } + $db->update_content4change($table,$c_id4trans,"",$users_dms->{u_id},"owner"); + } + ### + + #delete ask + if("$ib_key" eq "remove_chk4rel" && $R::main_id && $R::c_id && $R::template_id && $R::rel_id){ + my $rel4nd = $db->collect_rel4nodes("",$R::c_id,$R::template_id); + my $rel4tpl = $db->get_rel4tpl($R::main_id,$lang,"","","",$R::rel_id); + my $node_names; my $i=0; + my $delete_key = ""; + $delete_key = "delete_trans" if($rel4tpl->{ct_table} eq "contenttrans"); + $delete_key = "delete_tver" if($rel4tpl->{ct_table} eq "contenttver"); + foreach my $rid (sort { lc($rel4nd->{$a}->{node_name}) cmp lc($rel4nd->{$b}->{node_name}) } keys (%$rel4nd)){ + $i++; + $node_names .= "• $rel4nd->{$rid}->{node_name}
    " if($rel4nd->{$rid}->{node_name}); + } + if($i == 1){ + return "failure::Datensatz wirklich löschen. ::?ct_trans=$delete_key\&exit_box2=1\&xml_export=$R::xml_export\&c_id=$R::c_id\&rel_id=$R::rel_id ::löschen" + }else{ + return "failure::Es gibt hier zwei Möglichkeiten. Nur die Relation löschen oder den Content komplett löschen. ::?ct_trans=delete_rel4ct\&exit_box2=1\&main_id=$R::main_id\&rel_id=$R::rel_id ::Relation löschen ::?rel_edit=$delete_key\&exit_box2=1\&xml_export=$R::xml_export\&c_id=$R::c_id\&rel_id=$R::rel_id ::Content löschen" + } + } + + #delete Only relation ... without content + if("$ib_key" eq "delete_rel4ct" && $R::main_id && $R::rel_id){ + $d_rows += $db->delete_relation($R::main_id,$lang,$R::rel_id); + $db->cleanup_users($users_dms->{u_id}) if($users_dms->{u_id}); + } + + #DELETE abschluss + if($ib_key eq "delete" || $ib_key =~ /delete_tver/){ + $table = "contenttrans"; + $table = "contenttver" if($ib_key =~ /delete_tver/); + $d_rows += $db->delete_content("$table","$R::c_id"); + $db->update_users4trans("0","0","",$users_dms->{u_id}); + } + + #DELETE + if($ib_key =~ /delete_trans/){ + my $c_id4del = $R::c_id4trans || $R::c_id; + $table = "contenttrans" if($ib_key =~ /delete_trans/); + my $ctt = $db->get_content1("$table","$c_id4del"); + + if(($R::kind_of_trans =~ /Faktur|Verleih/) && ($ctt->{txt00} !~ /Angebot|Kostenvoranschlag|Auftrag|Storno/) && ("$ctb->{txt02}" ne "aus")){ + my ($cttpos,$rows) = $db->collect_contentpos("$table","$c_id4del"); + foreach my $id (sort { lc($cttpos->{$a}->{sort}) cmp lc($cttpos->{$b}->{sort}) } keys(%$cttpos)){ + $db->update_content4comp("content",$cttpos->{$id}->{ct_name},"$cttpos->{$id}->{cc_id}","+","$cttpos->{$id}->{int03}","$users_dms->{kind_of_trans}","$cttpos->{$id}->{txt12}"); + #my @packc_ids = split(/,/,$cttpos->{$id}->{txt05}); + #foreach(@packc_ids){ + # $db->update_content4comp("content","","$_","+","$cttpos->{$id}->{int03}","$R::kind_of_trans","$cttpos->{$id}->{txt12}"); + #} + } + } + + $d_rows += $db->delete_content("$table","$c_id4del"); + $db->update_users4trans("0","0","",$users_dms->{u_id}); + print $q->div({-class=>'elementwhite'},"2... redirecting to ... or CLICK ", $q->a({href=>"$varenv{wwwhost}$script$path"},"$varenv{wwwhost}$script$path")); + print redirect("$varenv{wwwhost}$script$path?redirected=1\&return=0-0-0|$i_rows-$u_rows-$d_rows"); + exit 0; + } + + my $pos_id = $R::c_idpos || $R::pos_id; + #DELETE verpos + if($ib_key eq "remove_verpos" && $pos_id){ + $table = "contenttverpos"; + $d_rows += $db->delete_content("$table","$pos_id"); + } + + #DELETE pos + if($ib_key =~ /delete_pos|delete_verpos/ && $pos_id){ + $table = "contenttranspos"; + $table = "contenttverpos" if($ib_key =~ /delete_verpos/); + my $cttpos = $db->get_content1($table,$pos_id); + + my $ctpos_sort; + if($pos_id == $users_dms->{ctpos_activ}){ + my $ctt_subpos = $db->collect_content2($table,"ctpos_id","$pos_id"); + foreach my $id (keys(%$ctt_subpos)){ + $d_rows += $db->delete_content("$table","$ctt_subpos->{$id}->{c_id}"); + } + } + $d_rows += $db->delete_content("$table","$pos_id"); + $db->users_up("ctpos_activ","0",$users_dms->{u_id}) if("$pos_id" eq "$users_dms->{ctpos_activ}"); + $ct_name = $1 if($R::ct_name =~ /^(\d+)/); + if(($R::kind_of_trans =~ /Faktur|Verleih/) && ($ctt->{txt00} !~ /Angebot|Kostenvoranschlag|Auftrag/) && ("$ctb->{txt02}" ne "aus")){ + $u_rows += $db->update_content4comp("content",$ct_name,"$cttpos->{cc_id}","+","$cttpos->{int03}","$R::kind_of_trans","$cttpos->{txt12}"); + #my @packc_ids = split(/,/,$cttpos->{txt05}); + # foreach(@packc_ids){ + # $db->update_content4comp("content","","$_","+","$cttpos->{int03}","$R::kind_of_trans","$cttpos->{txt12}"); + # } + } + } + ### + + #Auftragsstatus + if($R::order_state && $R::c_id4trans){ + my $table = "contenttrans"; + $u_rows += $db->updater($table,"c_id",$R::c_id4trans,"txt22","$R::txt22",$users_dms->{u_id}); + } + + ###SET Relation (like move doc-type) + #executed by Terminal submit-buttons + #2. counter for WaWi and ReNr + if((!$R::close_time && $R::set_main_id) && ($R::set_relation || $R::set_state || $R::open_set_main_id > 300000 || $R::ct_trans =~ /print_pdf|print/i)){ + if($R::open_set_main_id){ + $R::set_main_id = $R::open_set_main_id; + $users_dms = $db->select_users($users_dms->{u_id}); + } + my $c_id = $users_dms->{c_id4trans} || "";#Document id + return "failure::Abbruch, die Aktion konnte keinem Dokument zugeordnet werden. Arbeiten Sie mit mehreren Browser-Tabs? Bitte multiple COPRI Tabs schließen und anschließend das Verkauf-Terminal neu öffnen." if(!$c_id); + + my $table = "contenttrans"; my $ctt; + my $rel = $db->get_rel4tpl("",$lang,$users_dms->{c_id4trans},$users_dms->{tpl_id4trans}); + $ctt = $db->get_content1("contenttrans",$rel->{content_id}); + my ($node,$ct_exist); + return "failure::Bitte erst einen Formular-Typ wählen" if($R::set_main_id <= "300000"); + $u_rows += $db->update_relation2("",$lang,$R::set_main_id,"",$rel->{rel_id}) if(!$R::close_time && $rel->{rel_id}); + $node = $db->get_node4multi($R::set_main_id,$lang); + if($node->{main_id} > 300000){ + my $rows = $node->{int10} + 1; + $db->updater("nodes","main_id",$node->{main_id},"int10",$rows); + } + + #Node and HoleCkeck depended auto Rechnungs-Nummer + if(($node->{int06} > 0) && ("$ctt->{ct_name}" !~ /\d/ || "$R::set_main_id" != "$rel->{main_id}")){ + + #HoleCheck if ReNr available before ReNr counter + my $ReNr_start = 40000; + my $freeNr = $lb->get_freeReNr("$table","$ReNr_start","$node->{int06}","txt00","$node->{node_name}"); + my $nextNr = $node->{int06}; + $nextNr = $freeNr if($freeNr && $freeNr < $node->{int06}); + + $u_rows += $db->update_content4change($table,$c_id,$nextNr,$nextNr,"barcode"); + if(!$freeNr){ + my $int06 = $node->{int06} + 1; + $u_rows += $db->updater("nodes","main_id",$R::set_main_id,"int06",$int06,"","","","","no_time"); + } + + + }elsif($ctt->{ct_name} !~ /\d/){ + $db->update_content4change($table,$c_id,$c_id,$c_id,"barcode") ; + } + + #Payone managemandate (txt16=txid means payment process ID) + my $subset_state = $R::set_state || $ctt->{state}; + if($R::c_idadr && $subset_state =~ /payone/){ + my $ctadr = $db->get_content1("contentadr",$R::c_idadr); + + #SEPA + if($ctadr->{int03} == 1 && (!$ctt->{txt16} || $ctt->{int03} != 1 || $ctadr->{ct_name} !~ /\w{2}-\d+/ || $ctt->{txt28} =~ /errorcode=/)){ + if($ctadr->{ct_name} !~ /\w{2}-\d+/){ + $payone->managemandate_main(\%varenv,$ctadr,"",$users_dms->{u_id}); + sleep 3; + $ctadr = $db->get_content1("contentadr",$R::c_idadr); + } + #preauthorizationSEPA sets new Rechnungsnummer + if($ctadr->{txt27} =~ /active|pending/ || !$ctt->{txt16} || $ctt->{txt28} =~ /errorcode=80|errorcode=907|errorcode=911|errorcode=950|errorcode=902|errorcode=1077/){ + + my $renewed=""; + $renewed = "txid auto renewd" if($ctt->{txt28} =~ /errorcode=80|errorcode=907|errorcode=911|errorcode=950|errorcode=902|errorcode=1077/); + $ctt->{renewed} = $renewed; + $payone->preauthorizationSEPA_main(\%varenv,$ctadr,$ctt,$users_dms->{u_id}); + } + } + + #CC + #preauthorizationCC sets new Rechnungsnummer + if($ctadr->{int03} == 2 && (!$ctt->{txt16} || $ctt->{txt28} =~ /errorcode=80|errorcode=907|errorcode=911|errorcode=950|errorcode=902|errorcode=33|errorcode=908|errorcode=4|errorcode=5|errorcode=1077/ || $ctt->{int03} != 2 || length($ctadr->{ct_name}) < 19)){#CC + + my $renewed=""; + $renewed = "txid auto renewd" if($ctt->{txt28} =~ /errorcode=80|errorcode=907|errorcode=911|errorcode=950|errorcode=902|errorcode=33|errorcode=908|errorcode=4|errorcode=5|errorcode=1077/); + $ctt->{renewed} = $renewed; + $payone->preauthorizationCC_main(\%varenv,$ctadr,$ctt,$users_dms->{u_id}); + } + } + + #Change Formular Type ----------------------------------------------- + #if("$R::set_main_id" != "$rel->{main_id}"){ + if(($R::ct_trans =~ /print_pdf|print/i) || ("$R::set_main_id" != "$rel->{main_id}")){ + my $table = "contenttrans"; + + #zum Angebot den Warenbestand hochsetzen! + if(($ctt->{txt00} !~ /Angebot|Kostenvoranschlag|Auftrag|Storno/) && ($node->{node_name} =~ /Angebot|Kostenvoranschlag|Auftrag/) && ("$ctb->{txt02}" ne "aus")){ + my ($cttpos,$rows) = $db->collect_contentpos("$table",$users_dms->{c_id4trans}); + foreach my $id (sort { lc($cttpos->{$a}->{sort}) cmp lc($cttpos->{$b}->{sort}) } keys(%$cttpos)){ + $u_rows += $db->update_content4comp("content",$cttpos->{$id}->{ct_name},"$cttpos->{$id}->{cc_id}","+","$cttpos->{$id}->{int03}","$users_dms->{kind_of_trans}","$cttpos->{$id}->{txt12}"); + } + } + #vom Angebot zur Rechnung usw. den Warenbestand runtersetzen! + if(($ctt->{txt00} =~ /Angebot|Kostenvoranschlag|Auftrag/) && ($node->{node_name} !~ /Angebot|Kostenvoranschlag|Auftrag/) && ("$ctb->{txt02}" ne "aus")){ + my ($cttpos,$rows) = $db->collect_contentpos("$table",$users_dms->{c_id4trans}); + foreach my $id (sort { lc($cttpos->{$a}->{sort}) cmp lc($cttpos->{$b}->{sort}) } keys(%$cttpos)){ + $u_rows += $db->update_content4comp("content",$cttpos->{$id}->{ct_name},"$cttpos->{$id}->{cc_id}","-","$cttpos->{$id}->{int03}","$users_dms->{kind_of_trans}","$cttpos->{$id}->{txt12}"); + } + } + + $u_rows += $db->update_content4change($table,$c_id,"",$R::set_main_id,"int12");#zusätzl. Formtyp + $db->update_content4change($table,$c_id,"",$node->{node_name},"txt00");#node_name + $db->update_content4change($table,$c_id,"",$ctb->{txt06},"txt13") if($ctb->{txt06});#vendor name + $db->update_content4change($table,$c_id,"","txt61,txt63","txt21") if($node->{node_name} =~ /Mietvertrag/);#Text-3 + $db->update_content4change($table,$c_id,"","txt64","txt21") if($node->{node_name} =~ /Rückgabe/);#Text-4 + $db->update_content4change($table,$c_id,"","$R::mtime_changed","mtime") if($today !~ /$R::mtime_changed/);#invoice date + } + + #SET state alias Zahlung buchen + if($R::set_state && !$R::close_time){ + my $state = "no"; + $state = $R::state if($R::state); + my $sum_paid = "null"; + my $sum_kaution = "null"; + if($state ne "no"){ + $sum_paid = $R::sum_paid; + $sum_kaution = $R::sum_kaution; + $sum_paid =~ s/,/\./; + $sum_kaution =~ s/,/\./; + } + + #We do it only if txt80 end_time in Firma is defined + my $max_timestamp; + if($ctf->{txt80} && $ctt->{txt20}){ + if($ctt->{txt20} =~ /(\d{2})\.(\d{2})\.(\d{4})$/){ + $max_timestamp = "$1.$2.$3 23:59"; + }else{ + return "failure::Abbruch, das Leistungsdatum muss als einfaches Datum (Bsp: 31.08.2016) oder als Zeitraum wie im folgenden Beispiel definiert sein: 01.08.2016 - 31.08.2016\n"; + } + } + + $u_rows += $db->update_content4change($table,$c_id,"","$sum_paid","int01"); + $db->update_content4change($table,$c_id,"",$state,"state"); + $db->update_content4change($table,$c_id,"","now()","mtime"); + $db->update_content4change($table,$c_id,"",$users_dms->{u_id},"owner"); + + #2020-02-05, do it only if payone (without payone Zahlunseingang) + if($state =~ /payone/){ + $db->updater($table,"c_id","$c_id","int14","1","","","","",""); + + #preauth + my $ctadr = $db->get_content1("contentadr",$ctt->{int10}); + if($ctadr->{int03} == 1 && $ctadr->{ct_name} =~ /\w{2}-\d+/ && ($ctt->{txt16} !~ /\d+/ || $ctt->{int03} != 1)){ + my $payoneret = $payone->preauthorizationSEPA_main(\%varenv,$ctadr,$ctt,$users_dms->{u_id}); + sleep 2; + }elsif($ctadr->{int03} == 2 && length($ctadr->{ct_name}) >= 19 && ($ctt->{txt16} !~ /\d+/ || $ctt->{int03} != 2)){ + my $payoneret = $payone->preauthorizationCC_main(\%varenv,$ctadr,$ctt,$users_dms->{u_id}); + sleep 2; + } + #2018-10-18, check if preauth is done with txid (txt16) + $ctt = $db->get_content1("contenttrans",$c_id); + + #SEPA capture + if($ctt->{int03} == 1 && $ctt->{txt16} && $R::state =~ /SEPA/ && $state !~ /Zahlungseingang/){#SEPA + my $payoneret = $payone->captureSEPA_main(\%varenv,$ctadr,$ctt,$users_dms->{u_id}); + } + #CC capture + if($ctt->{int03} == 2 && $ctt->{txt16} && $R::state =~ /Kreditkarte/ && $state !~ /Zahlungseingang/){#CC + my $payoneret = $payone->captureCC_main(\%varenv,$ctadr,$ctt,$users_dms->{u_id}); + } + }else{ + $db->updater($table,"c_id","$c_id","int14","null","","","","",""); + } + + #Rechnungspositionen itime > end Abrechnunsgdatum + if($max_timestamp){ + my $ctpos_ck = $db->get_content7("contenttranspos","ct_id","$c_id","itime",">","$max_timestamp"); + if($ctpos_ck->{c_id}){ + my $ctadr = $db->get_content7("contentadr","c_id",$ctt->{int10}); + my $ct_id = $dbt->insert_contenttrans($dbh,$ctadr,"300008","218","----",$users_dms->{u_id}); + $db->updater($table,"c_id",$ct_id,"start_time","$ctt->{start_time}",$users_dms->{u_id}); + $db->updater($table,"c_id",$ct_id,"end_time","$ctt->{end_time}",$users_dms->{u_id}); + + $i_rows = $db->updater("contenttranspos","ct_id","$c_id","ct_id","$ct_id","","itime",">","$max_timestamp","no_time"); + } + } + } + + } + ###end SET Relation or state (V Terminal submit's) + + my $c_id4print = $users_dms->{c_id4trans}; + $c_id4print= $R::c_id if($R::printer_id =~ /Adresse|Kunde/); + if($c_id4print){ + my $print_return; + my $exit_code = 1; + my $table = "contenttrans"; + $table = "contenttver" if($rel->{ct_table} eq "contenttver"); + $table = "contentadr" if($R::printer_id =~ /Adresse|Kunde/);#jbw + my $ctt = $db->get_content1($table,$c_id4print); + my $praefix = "$ctt->{txt00}-$varenv{praefix}"; + #$praefix = "$ctt->{txt00}-TINK" if($varenv{wwwhost} =~ /tink|konrad/); + #$praefix = "$ctt->{txt00}-sharee" if($varenv{wwwhost} =~ /sharee/); + + + ###PRINT + if($R::ct_trans =~ /print_pdf|print/i){ + my $main_id = $R::set_main_id || $R::main_id; + my $node = $db->get_node4multi($main_id,$lang); + my $psize="A4"; + if("$ctt->{txt00}" =~ /Quittung/){ + $psize="A5"; + #-B 0 -T 0 -L 0 -R 0 # testing paper-margin=0 + } + my $wc_line=0; + $wc_line= $ctt->{int04};#Adresse.Tabelle + my ($sysname, $nodename, $release, $version, $machine) = uname(); + my $topdf = "$varenv{basedir}/src/wkhtmltopdf-amd64"; + + if("$R::printer_id" =~ /PDF/){ + #without system() because we have to wait until PDF is ready + $print_return = `$topdf --page-size $psize "$varenv{wwwhost}$script/Printpreview?printer_id=$R::printer_id\&mandant_main_id=$mandant_main_id\&main_id=$node->{main_id}\&ct_name2print=$ctt->{ct_name}\&c_id4trans=$c_id4print\&u_id=$users_dms->{u_id}\&wc=$wc_line" $varenv{pdf}/$praefix-$ctt->{ct_name}.pdf 2>&1`; + $exit_code = $?; + + if(1==1){#debugging + my $filesize = -s "$varenv{pdf}/$praefix-$ctt->{ct_name}.pdf"; + open(EMA, ">> $varenv{logdir}/copri-print.log"); + print EMA "$today4db\n$topdf --page-size $psize $varenv{wwwhost}$script/Printpreview?printer_id=$R::printer_id\&mandant_main_id=$mandant_main_id\&main_id=$node->{main_id}\&ct_name2print=$ctt->{ct_name}\&c_id4trans=$c_id4print\&u_id=$users_dms->{u_id}\&wc=$wc_line $varenv{pdf}/$praefix-$ctt->{ct_name}.pdf\nreturn: $print_return\nfilesize: $filesize\nexit_code: $exit_code\n"; + close EMA; + #exit 0; + } + + if($R::set_state ne "buchen"){#no redirect if buchen incl. print_pdf + if( -f "$varenv{pdf}/$praefix-$ctt->{ct_name}.pdf" && $varenv{metahost}){ + #print redirect("$varenv{metahost}$script/pdf/$praefix-$ctt->{ct_name}.pdf"); + #exit 0; + print ""; + }elsif( -f "$varenv{pdf}/$praefix-$ctt->{ct_name}.pdf"){ + #print redirect("$varenv{wwwhost}/pdf/$praefix-$ctt->{ct_name}.pdf"); + #exit 0; + print ""; + }else{ + return "failure::PDF konnte nicht generiert werden, bitte Info an: info\@gnu-systems.de\n $varenv{wwwhost}/pdf/$praefix-$ctt->{ct_name}.pdf"; + } + } + + } + } + + ## ./src/Mod/newsletter_tink.pl '/var/www/copri3/tinkdms' 'https://tinkdms.copri.eu' 'send_invoice' '1842' '2866' + #2018-01-12 + #if(($R::send_invoice && $print_return =~ /Done/ && $exit_code == 0) || ($ib_key eq "send_invoice_again")){ + if(-f "$varenv{pdf}/$praefix-$ctt->{ct_name}.pdf" && (($R::set_state eq "buchen" && $R::send_invoice) || ($ib_key eq "send_invoice_again"))){ + #sleep 3;#PDF invoice sending disabled because of partly empty invoices + # + #print "$varenv{basedir}/src/Mod/newsletter_tink.pl '$varenv{basedir}' '$varenv{wwwhost}' 'send_invoice' '$ctt->{int10}' '$ctt->{ct_name}'"; + #Last check!!!!! + #my $key_pdf; + #$key_pdf = `/usr/bin/pdftotext $varenv{pdf}/$praefix-$ctt->{ct_name}.pdf - | grep "Seite:"`; + system(`$varenv{basedir}/src/Mod/newsletter_tink.pl "$varenv{basedir}" "$varenv{wwwhost}" "send_invoice" "$ctt->{int10}" "$ctt->{ct_name}"`);# if($key_pdf =~ /Seite:/); + + } + # + }#end c_id4print + + #SET Tagesabschluss + if($R::v_abschluss){ + my $journal_tpl="999999"; + my $journal_id="999999"; + my $Xjournal_id="999999"; + if("$R::kind_of_trans" eq "Verkauf"){ + $journal_id=$ctf->{txt23} if($ctf->{txt23}); + $Xjournal_id=$ctf->{txt70} if($ctf->{txt70}); + $journal_tpl=$ctf->{txt26} if($ctf->{txt26}); + } + if($R::kind_of_trans =~ /Faktur|Verleih/){ + $journal_id=$ctf->{txt25} if($ctf->{txt25}); + $Xjournal_id=$ctf->{txt70} if($ctf->{txt70}); + $journal_tpl=$ctf->{txt28} if($ctf->{txt28}); + } + + #test node + my $n_exist = $db->get_node4multi($journal_id,$lang); + my $t_exist = $db->get_tpl($journal_tpl); + if(!$n_exist->{n_id} || !$t_exist->{tpl_id}){ + return "failure::Die Journal Konfiguration ist fehlerhaft."; + } + + #collect sub-nodes + my $main_ids = "$parent_trans->{main_id},"; + $main_ids .= $db->collect_noderec($parent_trans->{main_id},$lang,"nothing") if($parent_trans->{main_id}); + $main_ids =~ s/,$//; + + my $tpl_vk="$R::tpl_id"; + my $table = "contenttrans"; + my $sum_start = $R::sum_start || "0"; + my $sum_kasse = $R::sum_kasse || "0"; + $sum_start = $lb->checkint($sum_start); + $sum_kasse = $lb->checkint($sum_kasse); + my $c_id4kasse; + #my $journal_node = $db->get_node3("$parent_trans->{main_id}","Verkaufsjournal","$lang"); + my $c_id4abschluss = $db->get_content6("$table","close_time","null","state","Kassenbestand","int09","$parent_trans->{parent_id}","","","$s_owner_id"); + if($journal_id){ + if($c_id4abschluss->{c_id} && $c_id4abschluss->{c_id} > 0){ + $c_id4kasse = $c_id4abschluss->{c_id}; + }else{ + $ct_name = "--- auto ct_name = c_id ---"; + $c_id4kasse = $db->insert_content2($table,$ct_name,$users_dms->{u_id},"Kassenbestand"); + $i_rows += 1 if($c_id4kasse > 0); + $db->update_content4change("contenttrans",$c_id4kasse,"$c_id4kasse"); + $db->update_content4change("contenttrans",$c_id4kasse,"",$parent_trans->{parent_id},"int09");#mandant_main_id + $db->update_content4change("contenttrans",$c_id4kasse,"",$c_id4kasse,"int11");#last_ab + $db->update_content4change("contenttrans",$c_id4kasse,"",$journal_id,"int12");#main_id + + #2021-04-30, check close_time if fails. 300011 not in main_ids #TODO $db->collect_noderec + #$db->update_content4change("contenttrans",$c_id4kasse,"","now()","close_time"); + $db->update_content4change("contenttrans",$c_id4kasse,"",$n_exist->{node_name},"txt00");#node_name + #my $rel_id = $db->insert_relationlist($table,$journal_id,$lang,$c_id4kasse,$journal_tpl,"ct_id"); + my $rel_id = $db->insert_relationlist($table,$journal_id,$lang,$c_id4kasse,$tpl_vk,"ct_id"); + } + $u_rows += $db->update_kasse($table,$c_id4kasse,$sum_kasse,$sum_start); + + if($journal_id && $journal_tpl && $R::close_trans){ + my $opos="null"; + $u_rows += $db->update_tagesabschluss($table,$c_id4kasse,$journal_id,$journal_tpl,$tpl_vk,$parent_trans->{parent_id},"$main_ids","$s_owner_id","$opos"); + + #Move thinks which are in context to closed transactions + if(1==1){ + my $Xlast = $db->collect_Xlast($c_id4kasse,$journal_id,$journal_tpl,$parent_trans->{parent_id}); + foreach my $c_id (keys (%$Xlast)){ + my @Xct_name = split(/-/,$Xlast->{$c_id}->{ct_name}); + foreach(@Xct_name){ + $u_rows += $db->update_Xabschluss($table,$c_id4kasse,$Xjournal_id,$journal_tpl,$tpl_vk,$parent_trans->{parent_id},"$main_ids","$s_owner_id","$_") if($_ > 10); #because of max workflow counter + } + } + } + + if("$R::kind_of_trans" eq "Verkauf"){ + $path =~ s/$R::kind_of_trans.*/$R::kind_of_trans\/Verkaufsjournal/; + } + if("$R::kind_of_trans" eq "Einkauf"){ + $path =~ s/$R::kind_of_trans.*/$R::kind_of_trans\/Einkaufsjournal/; + } + if($R::kind_of_trans =~ /Faktur|Verleih/){ + $path =~ s/$R::kind_of_trans.*/$R::kind_of_trans\/Verleihjournal/; + } + + #calculate and set counts + my @mainis = split(/,/,$main_ids); + foreach(@mainis){ + my $rows = $db->count_content($table,"$_","$tpl_vk"); + $db->updater("nodes","main_id",$_,"int10",$rows) if($_ > 300000 && $rows =~ /\d/); + } + print $q->div({-class=>'elementwhite'},"1... redirecting to ... or CLICK ", $q->a({href=>"$varenv{wwwhost}$script$path"},"$varenv{wwwhost}$script$path")); + print redirect("$varenv{wwwhost}$script$path?redirected=1\&return=0-0-0|$i_rows-$u_rows-$d_rows"); + exit 0; + } + } + $db->cleanup_users($users_dms->{u_id}); + } + ### + return "$i_rows-$u_rows-$d_rows"; +} +1; diff --git a/copri4/main/src/Mod/Premain.pm b/copri4/main/src/Mod/Premain.pm new file mode 100644 index 0000000..e0aaef7 --- /dev/null +++ b/copri4/main/src/Mod/Premain.pm @@ -0,0 +1,1294 @@ +package Premain; +# +#Deprecated module, please use Prelib.pm +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; +use POSIX; +use File::Path qw(make_path remove_tree); +use File::Copy; +use File::Copy::Recursive qw(fcopy rcopy dircopy fmove rmove dirmove); +use CGI::Carp qw(fatalsToBrowser); +use CGI ':standard'; +use Scalar::Util qw(looks_like_number); +use Image::Magick; +use LWP::UserAgent; +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Libenzdb; +use Mod::DBtank; +use Mod::Prelib; +use Data::Dumper; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +sub maininit(){ + my $self = shift; + my $users_dms = shift; + + my $q = new CGI; + my $pi = new Image::Magick; + my @keywords = $q->param; + my $cf = new Config; + my $lb = new Libenz; + my $db = new Libenzdb; + my $but = new Buttons; + my $ua = LWP::UserAgent->new; + my $dbt = new DBtank; + my $pl = new Prelib; + my %ib = $but->ibuttons(); + my %varenv = $cf->envonline(); + my $script = $q->script_name(); + my $path_info = $q->path_info(); + my $path = $path_info; + if("$varenv{metahost}"){ + $path = "$script" . "$path_info"; + $script=""; + } + my $lang = "de"; + my $dbh = ""; + + ###users global + if($R::col_sort){ + $db->users_up("col_sort",$R::col_sort,$users_dms->{u_id}); + } + if($R::sort_updown){ + $db->users_up("sort_updown",$R::sort_updown,$users_dms->{u_id}); + } + if($R::cal_sort_updown){ + $db->users_up("cal_sort_updown",$R::cal_sort_updown,$users_dms->{u_id}); + } + if($R::col_sort eq "off"){ + $db->users_up("col_sort","0",$users_dms->{u_id}); + } + if("$R::rel_edit" =~ /_dnd/){ + $db->users_up("rel_edit","$R::rel_edit",$users_dms->{u_id}); + } + if($R::cms_public =~ /^t$|^f$/){ + $db->users_up("cms_public","$R::cms_public",$users_dms->{u_id}); + } + + if($R::view_sort){ + $db->users_up("view_sort",$R::view_sort,$users_dms->{u_id}); + } + + ### + my $time = time; + my $now_time = strftime "%Y-%m-%d %H:%M", localtime; + my $now_date = strftime "%Y-%m-%d", localtime; + my $i_rows=0; + my $u_rows=0; + my $d_rows=0; + + #international buttons + my ($key,$val,$ib_key); + while (($key,$val) = each(%ib)) { + $ib_key = $key if($R::rel_edit eq $val); + } + $ib_key = $R::rel_edit if(!$ib_key); + + my $ct_name = $q->escapeHTML("$R::ct_name"); + my $barcode = $q->escapeHTML("$R::barcode"); + my $txt11 = $q->escapeHTML("$R::txt11"); + my $teaserd_ct = $q->escapeHTML("$R::teaserd_ct"); + + my $sort = $R::sort; + $sort =~ s/,/./; + #$sort = $R::sort4edit if($R::sort4edit eq "new$users_dms->{u_id}"); + $barcode=0 if($barcode !~ /^\d+$/); + + my ($c_idnew,$rel_idnew,$ct_last,$tt_last,$table,$tpl); + $tpl = $db->get_tpl($R::template_id) if($R::template_id); + + #service_done (submit data via API) + if($R::rel_edit eq "service_done"){ + my $httpReqServer = $varenv{api_server}; + my $request = { + request => "service_done", + authcookie => $users_dms->{cookie}, + }; + if(looks_like_number($q->param('s_barcode'))){ + $request = { %$request, bike => $q->param('s_barcode') }; + } + my $station = ""; + if(looks_like_number($q->param('s_int04'))){ + $station = 1000 + $q->param('s_int04'); + $request = { %$request, station => $station }; + } + + my $req = HTTP::Request->new(POST => "$httpReqServer"); + $req->content_type('application/x-www-form-urlencoded'); + + my $post; + foreach (keys (%$request)){ + $post .= "$_=$request->{$_}&"; + } + #keep in mind, SubList Editor-button sends on submit also search-fields (s_) + foreach(@keywords){ + my $val = $q->param($_); + $post .= "$_=" . $q->escapeHTML($val) . "&" if($_ =~ /^txt\d+|^int\d+|^service_id/); + } + $req->content($post); + $ua->agent("COPRI APIclient"); + my $res = $ua->request($req); + + # Check the outcome of the response + if ($res->is_success) { + #print $res->content; + return $res->content;#JSON in $return + #print $res->status_line, "\n"; + #}else { + #print $res->status_line, "\n"; + } + }#end service_done + + #new content + if($ib_key =~ /new_user|new_pers|new_nel|new_time|new_adr|new_content/ && $R::main_id && $R::template_id){ + my $foreign_key = ""; + $ct_name = $q->escapeHTML("$R::s_ct_name") if($R::s_ct_name);#new over search + $barcode = $q->escapeHTML("$R::s_barcode") if($R::s_barcode =~ /^\d+$/);#new over search + $txt11 = $q->escapeHTML("$R::s_txt11") if($R::s_txt11);#new over search + $ct_name = "$ct_name" || $barcode || ""; + + if($ib_key eq "new_user"){ + $table = "contentuser"; + $foreign_key = "cu_id"; + $ct_last = $db->get_content2($table,$ct_name,$users_dms->{u_id}); + }elsif($ib_key eq "new_nel"){ + $table = "contentnel"; + $foreign_key = "cn_id"; + $ct_last = $db->get_content1($table,$R::c_id,$users_dms->{u_id}); + }elsif($ib_key eq "new_time"){ + $table = "timetable"; + $foreign_key = "ct_id"; + }elsif($ib_key eq "new_adr"){ + $table = "contentadr"; + $foreign_key = "ca_id"; + #if($ct_name && $ct_name ne "new$users_dms->{u_id}"){ + if($ct_name){ + $ct_last = $db->get_content2($table,$ct_name); + #}else{ + # $ct_last = $db->get_content2multi($table,"","","","sort","new$users_dms->{u_id}"); + # if($ct_last->{c_id}){ + #$d_rows += $db->delete_content("$table","","","new$users_dms->{u_id}"); + #$ct_last->{c_id} = ""; + #} + } + }elsif($ib_key =~ /new_content/){ + $table = "content"; + $foreign_key = "cc_id"; + #new Nr. check + $ct_last = $db->get_content4new($table,"$ct_name","$ct_name","$ct_name") if(!$ct_last->{c_id} && $ct_name =~ /^\d+$/); + $ct_last = $db->get_content4new($table,"$barcode","$barcode","$barcode") if(!$ct_last->{c_id} && $barcode); + $ct_last = $db->get_content4new($table,"$txt11","$txt11","$txt11") if(!$ct_last->{c_id} && $txt11); + + #if($ct_last->{c_id} && ("$ct_last->{sort}" eq "new$users_dms->{u_id}")){ + #$d_rows += $db->delete_content("$table","$ct_last->{c_id}"); + #$ct_last->{c_id} = ""; + #} + my $ct_sort = $db->get_content3sort($table,$R::main_id); + $sort = $ct_sort->{sort} + 1;# if(!$R::sort4edit); + } + + #if(("$ct_last->{ct_name}" eq "$ct_name") && ("$ct_last->{ct_name}" ne "new$users_dms->{u_id}")){ + # $ct_name = "new$users_dms->{u_id}"; + # $ct_last->{c_id} = ""; + #} + #print "$ib_key, $ct_last->{c_id}, $ct_name, && ($ct_last->{ct_name} !~ /new\d+/)"; + #exit 0; + + if($ct_last->{c_id} && !$ct_last->{ct_name}){ + return "failure::Abbruch, der Datensatz \"$ct_last->{ct_name} | $ct_last->{barcode} | $ct_last->{txt11}\" ist bereits vorhanden"; + } + + #Barcode + #hier sollen auch frei vom Anwedner definierte Nummern moeglich sein. + my $leer; my $next_barcode; + my $barcode_last; + $barcode_last = $db->get_barcode("users","$table") if($users_dms->{$table});#hier gilt: $table=column in users + $barcode_last->{$table} = 1000 if(!$barcode_last->{$table}); + #my $freenr = $lb->get_freenr($table,$barcode_last->{$table}); + my $lastnr = $db->get_content2($table);#get just last c_id + my $freenr = $lastnr->{c_id}; + $freenr++; + + if(!$ct_name && !$barcode && $varenv{barcode}){ + ($ct_name,$next_barcode) = $lb->barcodeable($table,$freenr);#new nr routine + }elsif(($ct_name =~ /^\d+$/) && !$barcode && $varenv{barcode}){ + ($leer,$next_barcode) = $lb->barcodeable($table,$freenr); + } + + if($barcode > "999999"){ + return "failure::Abbruch, die interne Barcode-Nummer muss kleiner als \"1000000\" sein.
    Hier bitte keine EAN's verwenden"; + } + + #if($next_barcode =~ /^\d+$/ && $freenr eq $next_barcode){ + if($freenr > 0){ + #$barcode = $next_barcode; + $barcode = $next_barcode || $freenr; + $db->users_up("$table","$barcode","$users_dms->{u_id}"); + } + + my ($rel4e,$ctrel); + $c_idnew = $db->insert_content($table,$ct_name,$users_dms->{u_id},$sort); + $db->updater("$table","c_id",$c_idnew,"txt01","$now_date") if($varenv{dataflow} =~ /wiki/); + $i_rows += 1 if($c_idnew > 0); + $db->update_barcode($table,$c_idnew,$ct_name,$barcode); + $rel4e = $db->get_rel4empty($R::main_id,$lang,$c_idnew,$R::template_id); + $rel_idnew = $db->insert_relationlist($table,$R::main_id,$lang,$c_idnew,$R::template_id,$foreign_key); + if((! -d "$varenv{data}/$R::main_id-resize/$c_idnew") && ($varenv{orga} eq "dms")){ + mkdir("$varenv{data}/$R::main_id/$c_idnew",0777); + mkdir("$varenv{data}/$R::main_id-thumb/$c_idnew",0777); + mkdir("$varenv{data}/$R::main_id-resize/$c_idnew",0777); + } + + #nice alco for special table-columns + my $tinfo = $db->table_info("relation"); + foreach my $rid (%$tinfo){ + if($tinfo->{$rid}->{attname} eq "template_right_id"){ + $db->updater("relation","main_id",$R::main_id,"template_right_id",$rel4e->{template_right_id}); + } + } + $db->users_up("rel_id4edit","0",$users_dms->{u_id}); + if(!$R::search_pattern){ + print redirect("$varenv{wwwhost}$script$path?node2edit=editpart\&rel_id=$rel_idnew\&return=$i_rows-$u_rows-$d_rows"); + exit 0; + } + } + ### + + #new Attribute for template as tpl_order + if($ib_key =~ /new_attrtpl_(\w+)/){ + my $key = $1; + my $debug=1; + open(ATTR,">>$varenv{logdir}/attr.log") if($debug); + print ATTR "\n----- $now_time -------\n" if($debug); + foreach(@keywords){ + $val = $q->param($_); + print ATTR "$_: $val\n" if($debug); + } + + my $table = "template"; + my $tpl_id = "400";#Master template + my $tpl_master = $db->get_tpl($tpl_id); + my @tpl_masterorder = split /,/,$tpl_master->{tpl_order}; + + my $num=1; + my $next=1; + my $size=15; + foreach (@tpl_masterorder){ + my ($m_key,$m_des,$m_size) = split /=/,$_; + if($m_key =~ /$key(\d+)/){ + $num = $1; + $size = $m_size if($m_size); + $next = $num if($next < $num); +print ATTR "$next = $num if($next < $num)\n" if($debug); + } + } + $next++; +print ATTR "next: $next\n" if($debug); + + if($key && $next > 20){ + return "failure:: Abbruch, die maximale Menge der Datenfelder wurde erreicht."; + } + + $next = sprintf("%.2d", $next); + $tpl_master->{tpl_order} .= ",$key$next=new$users_dms->{u_id}=$size"; + $i_rows += $db->updater("$table","tpl_id",$tpl_id,"tpl_order","$tpl_master->{tpl_order}",$users_dms->{u_id}); + + $path =~ s/\/\//\//; + $path .= "/supervisor" if($path !~ /supervisor/); + print ATTR "$varenv{wwwhost}$script$path?node2edit=edit_template\&tpl_id=$tpl_id\&key=$key$next\n" if($debug); + close(ATTR) if($debug); + + print redirect("$varenv{wwwhost}$script$path?node2edit=edit_template\&tpl_id=$tpl_id\&key=$key$next"); + exit; + } + ### + + #save Attribute for template as tpl_order + if($ib_key =~ /save_attrtpl/ && $R::key && $R::key_typ && $R::des && $R::asort){ + my $debug=1; + open(ATTR,">>$varenv{logdir}/attr.log") if($debug); + print ATTR "\n----- $now_time -------\n" if($debug); + foreach(@keywords){ + $val = $q->param($_); + print ATTR "$_: $val\n" if($debug); + } + + + my $template; + if($users_dms->{mandant_id} && $users_dms->{mandant_id} < "200000"){ + my $ctf = $db->get_content1("contentuser","$users_dms->{mandant_id}"); + $template = $db->collect_tpl("$ctf->{txt35}","$R::key") if($ctf->{txt35});#TINK master template_id=400 + } + + #change all templates if $R::key + foreach my $id (keys(%$template)){ + + my $asort = $R::asort; + my @new_order; + my @tpl_order = split /,/,$template->{$id}->{tpl_order}; + + #1. extract array-skalar without $R::key + #print "1. @tpl_order
    "; + foreach (@tpl_order){ + my ($m_key,$m_des,$m_size) = split /=/,$_; + if($m_key !~ /$R::key/){ + push @new_order,$_; + } + } + + #3. put in new key=des=size value at asort + my $new_tpl_order; + my $size=15; + my $new_key = $R::key_typ; + ($new_key,$size) = split(/_/,$R::key_typ) if($R::key_typ =~ /_/); + + + my $i=0; + my $ok=0; + foreach (@new_order){ + $i++; + if($i == $asort){ + $ok++; + $new_tpl_order .= "$R::key=$R::des=$size,"; + } + $new_tpl_order .= "$_,"; + } + $new_tpl_order .= "$R::key=$R::des=$size," if(!$ok);#last chance + $new_tpl_order =~ s/,$//; + + + $i_rows += $db->updater("template","tpl_id",$template->{$id}->{tpl_id},"tpl_order","$new_tpl_order",$users_dms->{u_id}); + } + close(ATTR) if($debug); + } + ### + + #remove and delete attribute with check + if($ib_key =~ /remove_chk4attr/ && $R::key){ + return "failure::Wenn Sie die Eigenschaft-Definition loeschen, wird die Eigenschaft in allen Objekten geloescht. ::?rel_edit=delete_attrtpl\&exit_box2=1\&key=$R::key ::loeschen" + } + if($ib_key =~ /delete_attrtpl/ && $R::key){ + my $template; + if($users_dms->{mandant_id} && $users_dms->{mandant_id} < "200000"){ + my $ctf = $db->get_content1("contentuser","$users_dms->{mandant_id}"); + $template = $db->collect_tpl("$ctf->{txt35}","$R::key") if($ctf->{txt35});#TINK master template_id=400 + } + + foreach my $id (keys(%$template)){ + my $new_tpl_order; + my @tpl_order = split /,/,$template->{$id}->{tpl_order}; + foreach (@tpl_order){ + my ($m_key,$m_des,$m_size) = split /=/,$_; + if($m_key !~ /$R::key/){ + $new_tpl_order .= "$_,"; + } + } + $new_tpl_order =~ s/,$//; + $i_rows += $db->updater("template","tpl_id",$template->{$id}->{tpl_id},"tpl_order","$new_tpl_order",$users_dms->{u_id}); + $i_rows += $db->updater($template->{$id}->{ct_table},"1","1","$R::key","null","","","","","no_time");#delete key-value in All content without mtime and user stamp + } + } + + #packpos Packaging + if($R::rel_edit eq "add_packpos" && $R::c_id && $R::c_idpackpos){ + my $ct = $db->get_content1("content",$R::c_id); + my $cp_ids = "$ct->{txt05}"; + if($cp_ids !~ /^\d/){ + $cp_ids = "$R::c_idpackpos"; + }else{ + $cp_ids .= ",$R::c_idpackpos"; + } + $u_rows += $db->updater("content","c_id",$R::c_id,"txt05","$cp_ids",$users_dms->{u_id}); + } + if($R::rel_edit eq "remove_packpos" && $R::c_id && $R::c_idpackpos){ + my $ct = $db->get_content1("content",$R::c_id); + my $cp_ids = "$ct->{txt05}"; + $cp_ids =~ s/[,]?$R::c_idpackpos//; + $u_rows += $db->updater("content","c_id",$R::c_id,"txt05","$cp_ids",$users_dms->{u_id}); + } + + + #save content + #if($ib_key =~ /save/ && $R::c_id && $R::rel_id){ + my $c_id = $R::c_id || $c_idnew;#also over new + my $rel_id = $R::rel_id || $rel_idnew;#also over new + if(($ib_key =~ /save_content|save_user|save_adr|save_nel|newsletter_mailman/) || ($ib_key =~ /new_content/ && $R::search_pattern) && $c_id){ + + if($ib_key eq "save_user"){ + $table = "contentuser"; + }elsif($ib_key eq "save_nel" || $ib_key eq "newsletter_mailman"){ + $table = "contentnel"; + }elsif($ib_key eq "save_adr"){ + $table = "contentadr"; + }elsif($ib_key =~ /save_content|new_content/){ + $table = "content"; + } + + my $freenr; + if((!$ct_name && !$barcode) && ("$table" eq "contentadr" || "$table" eq "content")){ + my $barcode_last; + + $barcode_last = $db->get_barcode("users","$table") if($users_dms->{$table});#hier gilt: $table=column in users + $barcode_last->{$table} = 1000 if(!$barcode_last->{$table}); + #$freenr = $lb->get_freenr($table,$barcode_last->{$table}); + my $lastnr = $db->get_content2($table);#get just last c_id + $freenr = $lastnr->{c_id}; + $freenr++; + + $db->users_up("$table","$freenr","$users_dms->{u_id}") if($freenr); + $ct_name = $freenr; + } + + my $ct_exist1 = $db->get_content1($table,$c_id); + my $IBAN_last = $ct_exist1->{txt22} || ""; + my $BIC_last = $ct_exist1->{txt23} || ""; + my $ct_exist2 = $db->get_content5($table,$ct_name,$c_id,"","not"); + if($table ne "contentadr" && ($ct_name && $ct_exist1->{c_id} && $ct_exist2->{c_id}) && ($ct_exist1->{c_id} ne $ct_exist2->{c_id}) && (("$ct_name" eq "$ct_exist2->{ct_name}") || ("$ct_name" eq "$ct_exist2->{barcode}"))){ + return "failure:: Konflikt, der Inhalt \"$ct_name ($ct_exist1->{c_id} ne $ct_exist2->{c_id})\" ist bereits vorhanden. Das speichern wurde verweigert"; + } + #Mandatsreferenz / IBAN Konflikt + if(($tpl->{tpl_order} =~ /Mandatsreferenz|Referenz/) && $ct_exist2->{txt22} && ($ct_name eq $ct_exist2->{ct_name}) && ($ct_exist1->{c_id} ne $ct_exist2->{c_id}) && ("$R::txt22" ne "$ct_exist2->{txt22}") && ("$table" eq "contentadr")){ + return "failure:: Konflikt, die Mandatsreferenz \"$ct_name\" existiert bereits mit der IBAN \"$ct_exist2->{txt22}\" (Code: $ct_exist1->{c_id} ne $ct_exist2->{c_id} && $R::txt22 ne $ct_exist2->{txt22}). Das speichern wurde verweigert"; + } + + #eMail txt08 + if($tpl->{tpl_id} =~ /202/ && $R::txt08){ + $ct_exist2 = $db->get_content7($table,"txt08",$R::txt08,"c_id","!=",$c_id); + if($ct_exist2->{c_id} && ($c_id != $ct_exist2->{c_id}) && ("$R::txt08" eq "$ct_exist2->{txt08}")){ + return "failure:: Konflikt, die eMail Adresse \"$R::txt08\" existiert bereits (Code: $c_id != $ct_exist2->{c_id}) && $R::txt08 eq $ct_exist2->{txt08}). Das speichern wurde verweigert"; + } + } + + #hidden select keys to delete first, marked with off_ (Project.pm) + foreach(@keywords){ + if($_ =~ /off_(int\d+)/){ + $db->updater("$table","c_id",$c_id,"$1","null"); + } + } + + + my $img02; + my $img03; + my $img04; + foreach(@keywords){ + my $val = $q->param($_); + my $valxx = $q->escapeHTML("$val"); + #print "$_:$valxx
    "; + $valxx =~ s/^\s+//; $valxx =~ s/\s+$//; + if($_ =~ /^int|barcode/){ + $valxx =~ s/,/./g; + $valxx = "null" if(!looks_like_number($valxx));#empty + } + + if($_ =~ /^txt[\d+]|^int[\d+]|uri[\d+]|byte[\d+]/){ + if(1==1){ + #on IBAN/BIC change set override Mandantsreferenz to c_id to trigger payone + if($table eq "contentadr" && (($_ eq "txt22" && $valxx ne "null" && $valxx ne $ct_exist1->{txt22}) || ($_ eq "txt23" && $valxx ne "null" && $valxx ne $ct_exist1->{txt23}))){ + $u_rows += $db->updater("$table","c_id",$c_id,"ct_name","$c_id",$users_dms->{u_id}); + } + if($table eq "contentadr" && $_ eq "txt22" && $valxx){ + my $currency = "EUR"; + $currency = "CHF" if($valxx =~ /^(CH)/i); + $u_rows += $db->updater("$table","c_id",$c_id,"txt22","$valxx",$users_dms->{u_id}); + $u_rows += $db->updater("$table","c_id",$c_id,"txt24","$currency",$users_dms->{u_id}); + } + elsif($table eq "contentadr" && $_ eq "txt15"){ + $valxx = "" if($valxx eq "null"); + my $swk_code=""; + $swk_code = $lb->grep_filecontent("$varenv{basedir}/$varenv{ftp_getfile}","$valxx") if($valxx =~ /\d+/); + if(looks_like_number($swk_code) && "$swk_code" eq "$valxx"){ + my $ct = $db->get_content6("contentadr","txt15","$swk_code","","","","","","",""); + if($ct->{c_id} && $ct->{c_id} != $c_id){ + return "failure::Abbruch, die SWK Bonusnummer ist bereits vergeben."; + }else{ + $u_rows = $db->updater("$table","c_id",$c_id,$_,$swk_code); + my $konrad_tarif = 3430;#swk konrad tarif + $u_rows = $db->updater("$table","c_id",$c_id,"int15","$konrad_tarif") if($ct_exist1->{int15}); + my $tink_tarif = 3432;#swk TINK tarif + $u_rows = $db->updater("$table","c_id",$c_id,"int14","$tink_tarif") if($ct_exist1->{int14}); + } + }elsif($valxx){ + $u_rows = $db->updater("$table","c_id",$c_id,$_,""); + return "failure::Abbruch, die SWK Bonusnummer ($valxx) existiert nicht."; + }else{ + $u_rows = $db->updater("$table","c_id",$c_id,$_,""); + } + } + #txt23 = Service Farbcode multiple select + elsif($tpl->{tpl_id} == 205 && $_ eq "txt23"){ + my @val = $q->param($_); + $valxx = $q->escapeHTML("@val"); + $u_rows += $db->updater("$table","c_id",$c_id,$_,$valxx,$users_dms->{u_id}); + } + #txt24 bike_group/station_group multiple select + elsif($tpl->{tpl_id} == 225 && $_ eq "txt24"){ + my @val = $q->param($_); + $valxx = $q->escapeHTML("@val"); + $u_rows += $db->updater("$table","c_id",$c_id,$_,$valxx,$users_dms->{u_id}); + } + elsif($table eq "content" && $_ eq "txt06"){#GPS + if($valxx =~ /^(\d{1,2}\.\d+),\s?(\d{1,2}\.\d+)$/ || !$valxx || $valxx eq "null"){ + $u_rows += $db->updater("$table","c_id",$c_id,$_,$valxx,$users_dms->{u_id}); + } + } + elsif($table eq "content" && $_ eq "txt10"){#Verleih content Status + if($valxx){ + $u_rows += $db->updater("$table","c_id",$c_id,$_,$valxx,$users_dms->{u_id}); + } + } + elsif($table eq "content" && $_ =~ /byte/){ + $u_rows += $db->updater("$table","c_id",$c_id,$_,"\\x$valxx",$users_dms->{u_id}); + } + else{ + $u_rows += $db->updater("$table","c_id",$c_id,$_,$valxx,$users_dms->{u_id}); + } + } + else{ + $u_rows += $db->updater("$table","c_id",$c_id,$_,$valxx,$users_dms->{u_id}); + } + } + + if($_ =~ /^img[\d+]/ && $table eq "contentuser"){ + #other img saved over save_media and imageresize! + $u_rows += $db->updater("$table","c_id",$c_id,$_,$valxx,$users_dms->{u_id}); + } + + if($_ eq "sort"){ + $valxx = 0 if($valxx =~ /new/); + $u_rows += $db->updater("$table","c_id",$c_id,$_,$valxx,$users_dms->{u_id}); + } + if($_ =~ /date_time[\d+]/){ + my ($date_time,$chck) = $lb->checkdate($valxx); + $u_rows += $db->updater("$table","c_id",$c_id,$_,$date_time,$users_dms->{u_id}) if(!$chck); + } + if($_ =~ /^ct_name|barcode/){ + $u_rows += $db->updater("$table","c_id",$c_id,$_,$valxx,$users_dms->{u_id}); + if($table eq "contentadr" && $varenv{syshost} eq "tinkdms" && $ct_exist1->{int03}){ + my $nothing;#never change mandat/pseudocardpan + }elsif($freenr && $freenr ne $valxx){ + $u_rows += $db->updater("$table","c_id",$c_id,$_,$freenr,$users_dms->{u_id}); + $u_rows += $db->update_barcode($table,$c_id,$freenr,$freenr) if($table eq "contentadr"); + } + } + if($_ eq "barcode" && $varenv{barcode}){ + ($valxx,$barcode) = $lb->barcodeable($table,$valxx); + $barcode = "null" if(!$barcode);#for empty + $u_rows += $db->update_barcode($table,$c_id,$valxx,$barcode); + my $price = $R::int02; + $price =~ s/\./,/; + $price = $price . ",00" if($price !~ /,\d/); + } + }#end foreach(@keywords) + + my $ct_info = $db->table_info("$table"); + foreach my $nid (%$ct_info){ + if(($ct_info->{$nid}->{attname} eq "content_public")){ + my $ct_public = $R::content_public || 0; + $u_rows += $db->updater("$table","c_id",$c_id,"content_public",$ct_public); + } + } + + #falls keine Teilenummer alias ct_name, s.o. + $u_rows += $db->updater("$table","c_id",$c_id,"ct_name",$barcode,$users_dms->{u_id}) if(!$ct_name && $barcode); + + + #Bild xx Auswahl|Select + if($ib_key =~ /save_content_/){ + #print redirect("$varenv{wwwhost}$script$path?$ib_key=1\&rel_id=$R::rel_id\&xpos=$R::xpos\&ypos=$R::ypos\&return=$i_rows-$u_rows-$d_rows"); + }elsif($varenv{orga} eq "dms" && $R::search_pattern){ + print redirect("$varenv{wwwhost}$script$path?node2edit=editpart\&rel_id=$rel_id\&return=$i_rows-$u_rows-$d_rows"); + exit 0; + } + + if(1==1){ + if($ib_key =~ /save_adr/ && $c_id){ + $ct_exist1 = $db->get_content1($table,$c_id); + $db->updater("$table","c_id",$c_id,"int01","1",$users_dms->{u_id}) if($varenv{PI});#sync reset + + #2021-11-26 disabled because only users have to request mandate + #if($ct_exist1->{int03} && $ct_exist1->{int03} == 1 && ($IBAN_last ne "$R::txt22" || $BIC_last ne "$R::txt23")){ + # use Mod::Payment; + # my $pay = new Payment; + # $pay->managemandate_main(\%varenv,$ct_exist1,""); + #} + + if((!$ct_exist1->{int14} && !$ct_exist1->{int15}) || !$ct_exist1->{int03} || !$ct_exist1->{int04} || $ct_exist1->{int12}){ + my $deaktivated = "null"; + $deaktivated = 2 if($ct_exist1->{owner} >= 1000 && $ct_exist1->{int12} >= 1); + $db->updater("contentadr","c_id","$c_id","int12","$deaktivated"); + }else{ + $db->updater("contentadr","c_id","$c_id","int12","null"); + } + + }elsif($ib_key =~ /save_content/){ + #require "Mod/KMLout.pm"; + #my $kmlfile = Mod::KMLout::kmlGenerator("",""); + + #copy sharee document for web CMS + if($tpl->{tpl_id} =~ /227/ && $R::txt02 && $R::txt03){ + copy("$varenv{data}/$R::main_id/$c_id/$R::txt02","$varenv{basedir}/site/$R::txt03"); + } + } + } + + }#end save_ + ### + + #new_relation + if("$ib_key" =~ /new_relation/ && $R::parent_id && $R::main_id){ + my $prefix_id = "0"; + my $working_parent_id = $R::parent_id; + $prefix_id = $1 if($R::main_id =~ /^(\d)/ && $R::main_id >= "100000"); + my $node_name = $R::node_name || "new$users_dms->{u_id}"; + $node_name = $q->escapeHTML("$node_name"); + my $return; + $return = $lb->checkinput($node_name); + return $return if($return =~ /failure/); + + #check multiple node_name + my $check_name; + $check_name = $db->get_node3($R::parent_id,$node_name,$lang); + $check_name = $db->get_node3($R::main_id,$node_name,$lang) if(!$check_name->{node_name}); + + if($check_name->{node_name} eq "$node_name"){ + return "failure::Abbruch, der Menuename \"$check_name->{node_name}\" ist bereits vorhanden. Bitte eindeutige Menuenamen verwenden."; + } + + if("$ib_key" =~ /new_relation4sub/ || $R::new_submenu){ + $working_parent_id = $R::main_id; + $prefix_id++; + } + + my $tpl_id = $R::template_id; + my $new_main_id = $db->get_freenode($prefix_id); + my $rc = $db->insert_node($working_parent_id,$new_main_id,$node_name,$lang,$R::n_sort,$tpl_id,$R::c_id,$users_dms->{u_id}); + + $i_rows += 1 if($rc > 0); + $u_rows += $db->updater("nodes","main_id",$new_main_id,"node_public","$R::node_public") if($R::node_public); + $u_rows += $db->updater("nodes","main_id",$new_main_id,"footer","$R::footer") if($R::footer); + $db->updater("relation","main_id",$new_main_id,"template_id","$tpl_id") if($tpl_id); + + if($varenv{orga} eq "dms"){ + mkdir("$varenv{data}/$new_main_id",0777); + mkdir("$varenv{data}/$new_main_id-thumb",0777); + mkdir("$varenv{data}/$new_main_id-resize",0777); + } + #nice alco for special table-columns + my $tinfo = $db->table_info("relation"); + foreach my $rid (%$tinfo){ + $u_rows += $db->updater("relation","main_id",$R::main_id,"template_right_id",$R::template_right_id) if($tinfo->{$rid}->{attname} eq "template_right_id"); + } + + my $new_path; + if("$ib_key" =~ /new_relation4sub/ || $R::new_submenu){ + $path =~ s/\/maintainer//; + $new_path = "$path"; + #$new_path = "$path/$node_name"; + }else{ + my @pathseq = split(/\//,$path); + pop @pathseq if($path =~ /\/maintainer/); + pop @pathseq; + foreach(@pathseq){ + $new_path .= "/$_" if($_ =~ /\w/); + print "$new_path
    "; + } + $new_path .= "/$node_name"; + } + $new_path =~ s/\/\//\//g; + print "$new_path
    "; + print redirect("$varenv{wwwhost}$script$new_path?node2edit=edit_relation\&main_id=$new_main_id\&tpl_id=$tpl_id\&return=$i_rows-$u_rows-$d_rows"); + exit 0; + } + + #save_relation + #TODO save bike relation with service contentpos tree + if("$ib_key" eq "save_relation" && $R::main_id){ + my $working_parent_id = $R::parent_id; + my $prefix_id = "0"; + $prefix_id = $1 if($R::main_id =~ /^(\d)/ && $R::main_id >= "100000"); + + foreach(@keywords){ + my $val = $q->param($_); + my $valxx = $q->escapeHTML("$val"); + #$_ =~ s/col_//; + $valxx =~ s/^\s+//; $valxx =~ s/\s+$//; + if(($_ eq "node_name") && $valxx){ + #for sub-menue hack + my $node_name = $valxx; + my $node_path = $node_name; + #for splitting node_name?node_path + ($node_name,$node_path) = split(/\|/,$node_name) if($node_name =~ /\|/); + my $return; + $return = $lb->checkinput($node_name); + $return = $lb->checkinput($node_path); + return $return if($return =~ /failure/); + + $u_rows += $db->updater("nodes","main_id",$R::main_id,"node_name",$node_name,"","parent_id"); + $u_rows += $db->updater("nodes","main_id",$R::main_id,"node_path",$node_path,"","parent_id"); + } + if($_ =~ /(template_id)/ && $valxx){ + my $rc = $db->update_relation3($R::main_id,$lang,$R::main_id,$valxx); + + } + + if($_ =~ /int|n_sort|owner/){ + $valxx =~ s/,/./; + $valxx = "null" if(!$valxx && $valxx ne "0");#for empty + $valxx = "0" if($valxx eq "0"); + #print "xxxxxxx $_ : $valxx |"; + $u_rows += $db->updater("nodes","main_id",$R::main_id,$_,$valxx) if($valxx =~ /^\d+$|null|0/); + } + if($_ =~ /txt01/){ + $u_rows += $db->updater("nodes","main_id",$R::main_id,$_,$valxx); + } + if((! -d "$varenv{data}/$R::main_id") && ($varenv{orga} eq "dms")){ + mkdir("$varenv{data}/$R::main_id",0777); + mkdir("$varenv{data}/$R::main_id-thumb",0777); + mkdir("$varenv{data}/$R::main_id-resize",0777); + } + } + + my $node_info = $db->table_info("nodes"); + foreach my $nid (%$node_info){ + if(($node_info->{$nid}->{attname} eq "node_public")){ + my $node_public = $R::node_public || 0; + $u_rows += $db->updater("nodes","main_id",$R::main_id,"node_public",$node_public); + } + if(($node_info->{$nid}->{attname} eq "footer")){ + my $footer = $R::footer || 0; + $u_rows += $db->updater("nodes","main_id",$R::main_id,"footer",$footer); + } + } + + my $uri_path = $dbt->recurse_node($dbh,$R::main_id); + print "$varenv{wwwhost}/$uri_path?return=$i_rows-$u_rows-$d_rows\n"; + print redirect("$varenv{wwwhost}/$uri_path?return=$i_rows-$u_rows-$d_rows"); + exit 0; + } + + #relate or move content, multiple node-content relation + #init from RelationEdit.pm (for _dnd look at Libenz.pm) + if("$R::rel_edit" =~ /relate_content|move_content/ && $R::set_main_id && ($R::rel_id || ($R::main_id && $R::set_content_id && $R::template_id))){ + my $table = "content"; + my $foreign_key = "cc_id"; + if($ib_key =~ /relate_contentadr|move_contentadr/){ + $table = "contentadr"; + $foreign_key = "ca_id"; + } + if($ib_key =~ /relate_contenttrans|move_contenttrans/){ + $table = "contenttrans"; + $foreign_key = "ct_id"; + } + if($ib_key =~ /relate_contenttver|move_contenttver/){ + $table = "contenttver"; + $foreign_key = "cv_id"; + } + if($ib_key =~ /relate_contentnel|move_contentnel/){ + $table = "contentnel"; + $foreign_key = "cn_id"; + } + + my $ctrel; + if($R::rel_id){ + $ctrel = $db->get_ctrel($table,"",$lang,$R::rel_id); + $R::main_id = $ctrel->{main_id}; + $R::set_content_id = $ctrel->{content_id}; + $R::template_id = $ctrel->{template_id}; + } + + my $return_rel_id=0; + my $ctrel_ck; + $ctrel_ck = $db->get_ctrel($table,$R::set_main_id,$lang,"",$R::set_content_id,$R::template_id); + + if($varenv{orga} eq "dms" && $varenv{wwwhost} =~ /wogedms|fsdm/){ + my @set_main_ids = (); + my $set_main_ids = ""; + foreach(@keywords){ + if($_ =~ /set_main_id/){ + @set_main_ids = $q->param($_); + } + } + $set_main_ids = join(',',@set_main_ids); + + my $ct4rel_ck = $db->collect_ct4rel("$table","","$lang","","","","","$R::template_id","","","$R::set_content_id","main_id"); + my $ctrel; + foreach(@set_main_ids){ + if($_ != $ct4rel_ck->{$_}->{main_id}){ + #print "insert: $table,$_,$lang,$R::set_content_id,$R::template_id,$foreign_key
    "; + $return_rel_id = $db->insert_relationlist($table,$_,$lang,$R::set_content_id,$R::template_id,$foreign_key) if($R::rel_edit =~ /relate_/ && $_); + $ctrel_ck = $db->get_ctrel($table,$_,$lang,"",$R::set_content_id,$R::template_id); + + if($ctrel_ck->{int02} == 1 && $return_rel_id && $R::template_id eq "202"){ + `sudo $varenv{basedir}/src/scripts/mailman_member.pl add $return_rel_id $varenv{syshost}`; + } + if( -d "$varenv{data}/$R::main_id/$R::set_content_id" ){ + #print "$varenv{data}/$R::main_id/$R::set_content_id --> $varenv{data}/$_/$R::set_content_id"; + rcopy("$varenv{data}/$R::main_id/$R::set_content_id","$varenv{data}/$_/$R::set_content_id"); + rcopy("$varenv{data}/$R::main_id-thumb/$R::set_content_id","$varenv{data}/$_-thumb/$R::set_content_id"); + rcopy("$varenv{data}/$R::main_id-resize/$R::set_content_id","$varenv{data}/$_-resize/$R::set_content_id"); + } + } + } + foreach my $id (keys(%$ct4rel_ck)){ + if($ct4rel_ck->{$id}->{main_id} && $set_main_ids !~ /$ct4rel_ck->{$id}->{main_id}/){ + #print "delete: $ct4rel_ck->{$id}->{main_id},$lang,$ct4rel_ck->{$id}->{rel_id}
    "; + if($R::template_id eq "202"){ + `sudo $varenv{basedir}/src/scripts/mailman_member.pl remove $ct4rel_ck->{$id}->{rel_id} $varenv{syshost}`; + } + if($R::rel_edit =~ /relate_/ && $ct4rel_ck->{$id}->{c_id}){ + $db->delete_relation($ct4rel_ck->{$id}->{main_id},$lang,$ct4rel_ck->{$id}->{rel_id}); + if( -d "$varenv{data}/$ct4rel_ck->{$id}->{main_id}/$ct4rel_ck->{$id}->{c_id}" ){ + remove_tree("$varenv{data}/$ct4rel_ck->{$id}->{main_id}/$ct4rel_ck->{$id}->{c_id}"); + remove_tree("$varenv{data}/$ct4rel_ck->{$id}->{main_id}-thumb/$ct4rel_ck->{$id}->{c_id}"); + remove_tree("$varenv{data}/$ct4rel_ck->{$id}->{main_id}-resize/$ct4rel_ck->{$id}->{c_id}"); + } + } + } + } + if($users_dms->{mandant_id} && $users_dms->{mandant_id} < "200000"){ + my $uri_path = $dbt->recurse_node($dbh,$R::set_main_id); + print redirect("$varenv{wwwhost}/$uri_path?exit_box2=1\&rel_id=$return_rel_id\&return=$i_rows-$u_rows-$d_rows"); + exit 0; + } + + }elsif($varenv{orga} eq "dms"){ + my @ck_ids = $R::rel_id; + @ck_ids = split(/\s/,$R::ck_ids) if($R::ck_ids); + foreach(@ck_ids){ + #1.get ctrel + my $ctrel = $db->get_ctrel("$table","","$lang","$_","","",""); + #2.1. update relation for move + if($R::rel_edit =~ /move_/){ + $return_rel_id = $db->update_relation2("",$lang,$R::set_main_id,$R::set_template_id,$ctrel->{rel_id}); + #3.move medias + if($return_rel_id){ + move("$varenv{data}/$R::main_id/$ctrel->{c_id}","$varenv{data}/$R::set_main_id/$ctrel->{c_id}"); + move("$varenv{data}/$R::main_id-thumb/$ctrel->{c_id}","$varenv{data}/$R::set_main_id-thumb/$ctrel->{c_id}"); + move("$varenv{data}/$R::main_id-resize/$ctrel->{c_id}","$varenv{data}/$R::set_main_id-resize/$ctrel->{c_id}"); + } + } + #2.2. insert relation for linking + if($R::rel_edit =~ /relate_/){ + my $mastermain_id = $R::main_id; + $return_rel_id = $db->insert_relationlist($table,$R::set_main_id,$lang,$R::set_content_id,$R::template_id,$foreign_key,$mastermain_id) if($R::rel_edit =~ /relate_/); + } + } + }elsif($ctrel_ck->{rel_id} > 1){ + return "failure::Abbruch, die Content-Node Relation existiert bereits"; + }else{ + my $mastermain_id = $R::mastermain_id || $R::main_id; + $return_rel_id = $db->insert_relationlist($table,$R::set_main_id,$lang,$R::set_content_id,$R::template_id,$foreign_key,$mastermain_id); + } + $i_rows += 1 if($return_rel_id > 0); + + if($users_dms->{mandant_id} && $users_dms->{mandant_id} < "200000"){ + my $uri_path = $dbt->recurse_node($dbh,$R::set_main_id); + print redirect("$varenv{wwwhost}/$uri_path?return=$i_rows-$u_rows-$d_rows"); + exit 0; + } + } + + ###copy (released at jbw) + if($ib_key =~ /copy_tver|copy_nel|^copy_content|copy_adr/){ + if($R::main_id && $lang && $R::rel_id && $R::c_id && $R::template_id){ + my ($table,$foreign_key,$ctrel,$tpl); + my @split_lates; + if($ib_key eq "copy_content"){ + $table = "content"; + $foreign_key = "cc_id"; + $ctrel = $db->get_ctrel($table,$R::main_id,$lang,$R::rel_id,$R::c_id,$R::template_id); + $tpl = $db->get_tpl($ctrel->{template_id}); + @split_lates = ($tpl->{tpl_order}); + }elsif($ib_key eq "copy_adr"){ + $table = "contentadr"; + $foreign_key = "ca_id"; + $ctrel = $db->get_ctrel($table,$R::main_id,$lang,$R::rel_id,$R::c_id,$R::template_id); + my $edit_template = "$ctrel->{template_id}" . "000"; + $tpl = $db->get_tpl($edit_template); + @split_lates = ($tpl->{tpl_order}); + }elsif($ib_key eq "copy_nel"){ + $table = "contentnel"; + $foreign_key = "cn_id"; + $ctrel = $db->get_ctrel($table,$R::main_id,$lang,$R::rel_id,$R::c_id,$R::template_id); + my $edit_template01 = "$ctrel->{template_id}" . "001"; + $tpl = $db->get_tpl($edit_template01); + @split_lates = ($tpl->{tpl_order}); + }elsif($ib_key eq "copy_tver"){ + $table = "contenttver"; + $foreign_key = "cv_id"; + $ctrel = $db->get_ctrel($table,$R::main_id,$lang,$R::rel_id,$R::c_id,$R::template_id); + my $edit_template01 = "$ctrel->{template_id}" . "001"; + my $edit_template02 = "$ctrel->{template_id}" . "002"; + my $edit_template03 = "$ctrel->{template_id}" . "003"; + my $tpl01 = $db->get_tpl($edit_template01); + my $tpl02 = $db->get_tpl($edit_template02); + my $tpl03 = $db->get_tpl($edit_template03); + @split_lates = ("$tpl01->{tpl_order}","$tpl02->{tpl_order}","$tpl03->{tpl_order}"); + } + + my $c_idnew; + $c_idnew = $db->insert_content2($table,$ct_name,$users_dms->{u_id},""); + if($c_idnew > 0){ + $i_rows += 1; + my $rel_id = $db->insert_relationlist($table,$R::main_id,$lang,$c_idnew,$R::template_id,$foreign_key); + $db->update_content4change($table,$c_idnew,"",$ctrel->{barcode},"barcode") if($ctrel->{barcode}); + #$db->update_users4trans($c_idnew,$R::template_id,$R::kind_of_trans,$users_dms->{u_id}) if($ib_key eq "copy_tver"); + foreach(@split_lates){ + my @tpl_order = split /,/,$_; + foreach (@tpl_order){ + my ($key,$val) = split /=/,$_; + if($key eq "txt01"){ + $db->updater("$table","c_id",$c_idnew,"$key","$ctrel->{$key} (copy)"); + }elsif($ctrel->{$key} && $key !~ /owner|mtime|itime/){ + $u_rows += $db->updater("$table","c_id",$c_idnew,"$key","$ctrel->{$key}"); + } + } + } + if($ib_key =~ /copy_tver|copy_nel/){ + print redirect("$varenv{wwwhost}$script$path?ct_trans=open\&c_id4trans=$c_idnew\&tpl_id4trans=$R::template_id\&kind_of_trans=$users_dms->{kind_of_trans}\&owner=$users_dms->{u_id}\&xpos=$R::xpos\&ypos=$R::ypos\&return=$i_rows-$u_rows-$d_rows"); + exit 0; + }else{ + print redirect("$varenv{wwwhost}$script$path?node2edit=editpart\&rel_id=$rel_id\&xpos=$R::xpos\&ypos=$R::ypos\&return=$i_rows-$u_rows-$d_rows"); + exit 0; + } + } + }else{ + return "failure::Fehler, Datensatz kann nicht angelegt werden weil folgende Informationen fehlen: ($R::main_id && $lang && $R::rel_id && $R::c_id && $R::template_id)"; + } + } + # + #copy (released at jvbasel), dialogs with RelationEdit.pm + #3. fixed, cleaned for content + elsif($R::rel_edit eq "copy_content" && $R::main_id && $R::set_main_id){ + my $table = "content"; + my $foreign_key = "cc_id"; + + my @ck_ids = $R::rel_id; + @ck_ids = split(/\s/,$R::ck_ids) if($R::ck_ids); + foreach(@ck_ids){ + #1.get ctrel + my $ctrel = $db->get_ctrel($table,"",$lang,$_); + if($ctrel->{c_id}){ + my $columns; + my $tinfo = $db->table_info("content"); + foreach my $rid (%$tinfo){ + if($tinfo->{$rid}->{attname} =~ /ct_name|barcode|txt|int|img/){ + $columns .= "$tinfo->{$rid}->{attname},"; + #print "$tinfo->{$rid}->{attname}|"; + } + } + $columns =~ s/,$//; + my $ct_name = $ctrel->{ct_name}; + my $k=0; + ($ct_name,$k) = split(/-/,$ctrel->{ct_name}); + $k++; + my $ct_name_new = $ct_name . "-" . $k; + my $c_idnew = $db->copy_content($table,"c_id",$ctrel->{c_id},"$columns"); + $u_rows += $db->updater("$table","c_id",$c_idnew,"ct_name","$ct_name_new",$users_dms->{u_id}); + my $rel_id = $db->insert_relationlist($table,$R::set_main_id,$lang,$c_idnew,$ctrel->{template_id},$foreign_key); + $i_rows += 1 if($rel_id > 0); + #3.copy recursive medias + if($rel_id){ + rcopy("$varenv{data}/$R::main_id/$ctrel->{c_id}","$varenv{data}/$R::set_main_id/$c_idnew"); + rcopy("$varenv{data}/$R::main_id-thumb/$ctrel->{c_id}","$varenv{data}/$R::set_main_id-thumb/$c_idnew"); + rcopy("$varenv{data}/$R::main_id-resize/$ctrel->{c_id}","$varenv{data}/$R::set_main_id-resize/$c_idnew"); + } + } + + $db->users_up("rel_id4edit","0",$users_dms->{u_id}); + if($users_dms->{mandant_id} && $users_dms->{mandant_id} < "200000"){ + my $uri_path = $dbt->recurse_node($dbh,$R::set_main_id); + print redirect("$varenv{wwwhost}/$uri_path?return=$i_rows-$u_rows-$d_rows"); + exit 0; + } + } + ### + } + ### + + ###PDFout Generator + if("$ib_key" =~ /PDFout|Upload/){ + $db->users_up("time4csv","$time",$users_dms->{u_id}); + $users_dms = $db->select_users($users_dms->{u_id}); + my ($sysname, $nodename, $release, $version, $machine) = uname(); + #print "($sysname, $nodename, $release, $version, $machine)"; + my $topdf = "$varenv{basedir}/src/wkhtmltopdf-i386"; + $topdf = "$varenv{basedir}/src/wkhtmltopdf-amd64" if($machine =~ /_64/); + $topdf = "$varenv{basedir}/src/wkhtmltopdf.app/Contents/MacOS/wkhtmltopdf" if($sysname =~ /Darwin/); + + #my @ck_ids = $R::rel_id; + #foreach(@keywords){ + # @ck_ids = $q->param($_) if($_ =~ /ckid/);#because of $R::ckid_rel as array + #} + #my $ck4ex = join(',',@ck_ids); + my $ck4ex = "$users_dms->{checked4dragg}"; + if($ck4ex && $R::template_id && $R::main_id){ + my $psize="A4"; + my $wc_line=0; + my $node = $db->get_node4multi($R::main_id,$lang); + system(`$topdf --page-size $psize "$varenv{wwwhost}$script/Printpreview?printer_id=$R::printer_id\&main_id=$node->{main_id}\&template_id=$R::template_id\&ck4ex=$ck4ex\&ct_name2print=$node->{node_name}\&u_id=$users_dms->{u_id}\&wc=$wc_line" $varenv{pdf}/$users_dms->{u_id}-$users_dms->{time4csv}.pdf`); + + #print "$topdf --page-size $psize \"$varenv{wwwhost}$script/Printpreview?printer_id=$R::printer_id\&main_id=$node->{main_id}\&template_id=$R::template_id\&ck4ex=$ck4ex\&ct_name2print=$node->{node_name}\&u_id=$users_dms->{u_id}\&wc=$wc_line\" $varenv{pdf}/$users_dms->{u_id}-$users_dms->{time4csv}.pdf\n"; + if( -f "$varenv{pdf}/$users_dms->{u_id}-$users_dms->{time4csv}.pdf" && $varenv{metahost}){ + print redirect(-uri=>"$varenv{metahost}/pdf/$users_dms->{u_id}-$users_dms->{time4csv}.pdf", -target=>'_blank'); + exit 0; + } + } + } + ### + + ###CSV Generator + if("$ib_key" =~ /XLSout/ && $R::template_id){ + $db->users_up("time4csv","$time",$users_dms->{u_id}); + my $table = "content"; + my $tpl_id = $R::template_id; + if("$ib_key" =~ /XLSout_contentadr/ && "$R::ckid_rel"){ + $table = "contentadr"; + my $rel = $db->get_relation("","$lang","$R::ckid_rel"); + $tpl_id = $rel->{template_id}; + } + + my $scol = "txt01"; + $scol = $R::scol if($R::scol); + + my @ck_ids; + foreach(@keywords){ + @ck_ids = $q->param($_) if($_ =~ /ckid_rel/);#because of fetching array + } + my $ck4ex = join(',',@ck_ids); + + $ck4ex = "$users_dms->{checked4dragg}" if($ck4ex !~ /\d/); + if($ck4ex && $tpl_id){ + my $ct4rel = $db->collect_ct4rel4nd("$table","","de","$scol","","","","","","$ck4ex","rel_id"); + #print "$ib_key|$tpl_id $ck4ex"; exit 0; + my $tpl = $db->get_tpl($tpl_id); + my @tpl_order = split /,/,$tpl->{tpl_order}; + #unshift(@tpl_order, "img00=Ordner"); + + $users_dms = $db->select_users($users_dms->{u_id}); + open(CSV, "> $varenv{pdf}/$users_dms->{u_id}-$users_dms->{time4csv}.csv"); + #CSV Table Header + my $col_header=""; + foreach(@tpl_order){ + my ($key,$val) = split /=/,$_; + if($key eq "txt01" && $table eq "contentadr"){ + $col_header .= ";Name-01;Name-02;Name-03"; + }elsif($key !~ /mtime|owner/){ + $col_header .= ";$val"; + } + } + $col_header =~ s/^;//g; + print CSV "$col_header\n"; + + foreach my $id (sort { lc($ct4rel->{$a}->{$scol}) cmp lc($ct4rel->{$b}->{$scol}) } keys (%$ct4rel)){ + my $line=""; + foreach(@tpl_order){ + my ($key,$val) = split /=/,$_; + $ct4rel->{$id}->{$key} = $q->unescapeHTML("$ct4rel->{$id}->{$key}"); + $ct4rel->{$id}->{$key} =~ s/:\d{2}\..*$// if($key =~ /time/); + if($key eq "txt01" && $table eq "contentadr"){ + my ($n01,$n02,$n03) = split(/\n/,$ct4rel->{$id}->{$key}); + $n02 =~ s/^\s//;#jbw fix + $line .= ";$n01;$n02;$n03"; + }elsif($key eq "date_time"){ + $ct4rel->{$id}->{start_time} =~ s/\s.*// if($ct4rel->{$id}->{start_time}); + $ct4rel->{$id}->{end_time} =~ s/\s.*// if($ct4rel->{$id}->{end_time}); + $line .= ";$ct4rel->{$id}->{start_time} - $ct4rel->{$id}->{end_time}"; + }elsif($key !~ /mtime|owner/){ + $line .= ";$ct4rel->{$id}->{$key}"; + } + } + + $line =~ s/^;//g; + $line =~ s/\n//g; + $line =~ s/\r//g; + print CSV "$line\n"; + } + close CSV; + + $db->csv2xls($users_dms->{u_id},$users_dms->{time4csv}); + } + } + ### + + ###remove with question + #delete ask, if content with multiples + if("$ib_key" =~ /remove_chk4rel/){ + if($R::main_id && $R::c_id){ + my $rel4nd = $db->collect_rel4nodes("",$R::c_id,$R::template_id); + my $tpl = $db->get_tpl($R::template_id); + my $i=0; + my $delete_key = "delete_content"; + $delete_key = "delete_adr" if($tpl->{ct_table} eq "contentadr"); + $delete_key = "delete_nel" if($tpl->{ct_table} eq "contentnel"); + + foreach my $rid (sort { lc($rel4nd->{$a}->{node_name}) cmp lc($rel4nd->{$b}->{node_name}) } keys (%$rel4nd)){ + $i++; + } + + if($i == 1 && ($varenv{orga} =~ /dms/ || $varenv{wwwhost} =~ /k9/)){ + return "failure::really delete ::?rel_edit=$delete_key\&exit_box2=1\&main_id=$R::main_id\&c_id=$R::c_id\&rel_id=$R::rel_id ::delete" + }else{ + #until now, for copri3 we need it for k9 + return "failure::Es gibt hier zwei Moeglichkeiten. Nur die Relation loeschen oder den Content komplett loeschen. ::?rel_edit=delete_rel4ct\&exit_box2=1\&main_id=$R::main_id\&rel_id=$R::rel_id ::Relation loeschen ::?rel_edit=$delete_key\&exit_box2=1\&main_id=$R::main_id\&c_id=$R::c_id\&rel_id=$R::rel_id ::Content loeschen" + } + }elsif($R::ckid_rel || $R::rel_id){ + #delete ask for checkbox selected content + my @ck_ids = $R::rel_id; + foreach(@keywords){ + @ck_ids = $q->param($_) if($_ =~ /ckid/);#because of fetching array + } + return "failure::Wirklich loeschen. ::?rel_edit=delete_ckcontent\&exit_box2=1\&main_id=$R::main_id\&template_id=$R::template_id\&ck_ids=@ck_ids ::loeschen" + } + } + ### + + ###delete stack of content and check if more related automatic + if($R::rel_edit =~ /delete_ckcontent/ && $R::template_id && ($R::ck_ids || $R::rel_id)){ + my $table = "content"; + my $tpl = $db->get_tpl($R::template_id); + $table = "contentadr" if($tpl->{ct_table} eq "contentadr"); + $table = "contentnel" if($tpl->{ct_table} eq "contentnel"); + my @ck_ids = $R::rel_id; + @ck_ids = split(/\s/,$R::ck_ids); + foreach(@ck_ids){ + #1.get ctrel + my $ctrel; + $ctrel = $db->get_ctrel("$table","","$lang","$_","","",""); + #2.only! delete relation + $d_rows += $db->delete_relation($ctrel->{main_id},$lang,$ctrel->{rel_id}) if($ctrel->{c_id}); + $db->cleanup_users($users_dms->{u_id}) if($users_dms->{u_id}); + + #3.get ctrel_check to check if some other relations with c_id available + my $ctrel_check; + $ctrel_check = $db->get_ctrel("$table","","$lang","","$ctrel->{c_id}","$ctrel->{template_id}",""); + #4.delete media and content only if no further relation-content available + if($ctrel->{c_id} && !$ctrel_check->{c_id}){ + remove_tree("$varenv{data}/$ctrel->{main_id}/$ctrel->{c_id}"); + remove_tree("$varenv{data}/$ctrel->{main_id}-thumb/$ctrel->{c_id}"); + remove_tree("$varenv{data}/$ctrel->{main_id}-resize/$ctrel->{c_id}"); + $table = "contentnel" if($ib_key eq "delete_nel"); + #5.delete also content if no further relations with same c_id + $d_rows += $db->delete_content("$table","$ctrel->{c_id}") if(!$ctrel_check->{rel_id}); + my $tpl = $db->get_tpl($ctrel->{template_id}); + $db->delete_users("$ctrel->{c_id}","") if($tpl->{tpl_name} =~ /Mitarbeiter/); + } + } + } + ### + + #delete Only relation ... without content + if("$ib_key" eq "delete_rel4ct" && $R::main_id && $R::rel_id){ + if($varenv{wwwhost} =~ /wogedms|fsdm/){ + `sudo $varenv{basedir}/src/scripts/mailman_member.pl remove $R::rel_id $varenv{syshost}` if($R::rel_id); + } + $d_rows += $db->delete_relation($R::main_id,$lang,$R::rel_id); + + $db->cleanup_users($users_dms->{u_id}) if($users_dms->{u_id}); + } + + #delete node-relation + if("$ib_key" eq "delete_relation" && $R::main_id){ + my $subnode = $db->get_subnode($R::main_id,$lang); + my $ctrel; + $ctrel = $db->get_ctrel("content",$R::main_id,$lang); + if($subnode->{main_id} || ($ctrel->{c_id} > 0)){ + return "failure::Abbruch, der Ordner enthält Daten. Für die referentielle Integrität ist es notwendig die Ordner Inhalte (content) und/oder Relationen des Ordners zu löschen. (code: $subnode->{main_id} || $ctrel->{c_id})"; + }elsif($R::main_id > "100" && !$subnode->{main_id}){ + $d_rows += $db->delete_node($R::main_id,$lang); + $db->cleanup_users($users_dms->{u_id}) if($users_dms->{u_id}); + + remove_tree("$varenv{data}/$R::main_id"); + remove_tree("$varenv{data}/$R::main_id-thumb"); + remove_tree("$varenv{data}/$R::main_id-resize"); + my $uri_path = $dbt->recurse_node($dbh,$R::main_id); + $uri_path =~ s/\/\w+$//; + print redirect("$varenv{wwwhost}/$uri_path?return=$i_rows-$u_rows-$d_rows"); + exit 0; + }else{ + return "failure::Fehler, Relation kann nicht gelöscht werden ($R::main_id && $subnode->{main_id})"; + } + } + + #delete content + if($ib_key =~ /delete_user|delete_adr|delete_time|delete_content|delete_nel|delete_ttrans|delete_tver/ && $R::c_id && $R::rel_id){ + if($ib_key =~ /delete_user/){ + $table = "contentuser"; + $d_rows += $db->delete_content("$table","$R::c_id"); + $db->delete_users("$users_dms->{u_id}","$users_dms->{u_id}") if($users_dms->{u_id} > "100"); + }elsif($ib_key =~ /delete_adr/){ + $table = "contentadr"; + $d_rows += $db->delete_content("$table","$R::c_id"); + }elsif($ib_key =~ /delete_time/){ + $table = "timetable"; + $d_rows += $db->delete_time("$table","$R::t_id"); + }elsif($ib_key =~ /delete_content|delete_nel/){ + if($varenv{orga} eq "dms"){ + remove_tree("$varenv{data}/$R::main_id/$R::c_id"); + remove_tree("$varenv{data}/$R::main_id-thumb/$R::c_id"); + remove_tree("$varenv{data}/$R::main_id-resize/$R::c_id"); + } + $table = "content"; + $table = "contentnel" if($ib_key eq "delete_nel"); + $d_rows += $db->delete_content("$table","$R::c_id"); + }elsif($ib_key =~ /delete_ttrans/){ + $table = "contenttrans"; + $d_rows += $db->delete_content("$table","$R::c_id"); + $db->cleanup_users($users_dms->{u_id}) if($users_dms->{u_id}); + }elsif($ib_key =~ /delete_tver/){ + $table = "contenttver"; + $d_rows += $db->delete_content("$table","$R::c_id"); + $db->cleanup_users($users_dms->{u_id}) if($users_dms->{u_id}); + } + $db->users_up("rel_id4edit","0",$users_dms->{u_id}); + } + + if($ib_key eq "delete_media2" && $R::main_id && $R::c_id && $R::img_name){ + $R::img_name =~ s/\:.*//; + $R::img_name =~ s/\s/\\ /g; + #print "$varenv{data}/$R::main_id/$R::c_id/$R::img_name*"; + unlink glob "$varenv{data}/$R::main_id/$R::c_id/$R::img_name*"; + unlink glob "$varenv{data}/$R::main_id-thumb/$R::c_id/$R::img_name*"; + unlink glob "$varenv{data}/$R::main_id-resize/$R::c_id/$R::img_name*"; + $d_rows += 1; + } + + #delete image or pdf via Image-Pdf-browser + if($ib_key eq "delete_media" && $R::rel_id && $R::img_name){ + my $table = "content"; + my $ctrel = $db->get_ctrel($table,"",$lang,$R::rel_id); + my $tpl = $db->get_tpl($ctrel->{template_id}); + my @ct4tpl = split (/,/,$tpl->{tpl_order}); + #foreach(@ct4tpl){ + # my $cttest = $db->get_contentimage("$_","$R::img_name") if($_ =~ /img|pdf/); + # if($cttest->{c_id}){ + # print $q->div({-id=>'Inhalttxt'}, "
    Die Datei kann nicht geloescht werden, da es mit dem Content \"$cttest->{ct_name}\" referenziert ist", $q->p({-align=>'center'}, $q->a({-class=>"linknav",-href=>'javascript:history.back()'}, "[ back ]"))); + # exit 0; + # } + #} + unlink("$varenv{img4ct}/$R::img_name"); + unlink("$varenv{img4bg}/$R::img_name"); + unlink("$varenv{img4thumb}/$R::img_name"); + unlink("$varenv{img4bgthumb}/$R::img_name"); + unlink("$varenv{pdf4ct}/$R::img_name"); + $d_rows += 1; + } + +return "$i_rows-$u_rows-$d_rows"; +} +1; + + + diff --git a/copri4/main/src/Mod/Pricing.pm b/copri4/main/src/Mod/Pricing.pm new file mode 100644 index 0000000..b427408 --- /dev/null +++ b/copri4/main/src/Mod/Pricing.pm @@ -0,0 +1,272 @@ +package Pricing; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; +use POSIX; +use CGI; # only for debugging +use Scalar::Util qw(looks_like_number); + +use Lib::Config; +use Mod::Libenz; +use Mod::DBtank; +use Mod::Callib; +use Mod::Basework; +use Data::Dumper; + +my $cf = new Config; +my $lb = new Libenz; +my $dbt = new DBtank; +my $cal = new Callib; +my $bw = new Basework; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +my $dbh = ""; + +sub only_first_free(){ + my $self = shift; + my $ctpos = shift; + my %varenv = $cf->envonline(); + + my $pref = { + table => "contenttrans", + table_pos => "contenttranspos", + fetch => "one", + template_id => "218",#Faktura tpl_id + ca_id => "=::$ctpos->{ca_id}", + c_id => "!=::$ctpos->{c_id}", + #txt10 => "IN::('available','canceled')", + int10 => "IN::('1','6')", + "ct.close_time" => "is::null", + }; + $pref = { %$pref, time_range => "start_time >= '$ctpos->{start_time}' and start_time < '$ctpos->{end_time}' and start_time != end_time" }; + + my $record = $dbt->collect_post($dbh,$pref); + return $record; + +} + +sub sharee_pricing(){ + my $self = shift; + my $ctpos = shift; + my $todo = shift; + my %varenv = $cf->envonline(); + my $today4db = strftime("%Y-%m-%d %H:%M:%S",localtime(time)); + + my $return = {}; + my $logging = {}; + $logging->{ID} = "c_id:$ctpos->{c_id}/ct_id:$ctpos->{ct_id}/ca_id:$ctpos->{ca_id}"; + + my $computed_end_time = $ctpos->{end_time} || $today4db; + $computed_end_time = $today4db if($ctpos->{int10} && $ctpos->{int10} == 3); + + my ($start_datetime,$end_datetime,$s_up,$e_up,$hours) = $cal->contenttranspos_dating($ctpos->{c_id},$ctpos->{start_time},"$computed_end_time","$today4db",""); + $logging->{hours_input} = $hours; + $logging->{tariff} = "$ctpos->{txt04} - $ctpos->{int09}"; +; + my $bike_group = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}$ctpos->{int12}" || ""; + my $days_pricemax = $ctpos->{int17} || 9; + $logging->{days_pricemax} = $days_pricemax; + + my $price = 2; #FIXME to real val. must be not 0 + $price = sprintf('%.2f',$ctpos->{int02}) if($ctpos->{int02} && $ctpos->{int02} > 0); + my $total = 0; + + #my $days_pricemax = "4.5";#TINK max 9,- € bike/day depends on 2,- €/hour + #my $days_pricemax = 5; #KonRad max 15,- € bike/day depends on 3,- €/hour + my $days_hour4price = $days_pricemax / $price; + $logging->{days_hour4price} = $days_hour4price; + my $real_hours = $hours; + + if($ctpos->{int16} && $ctpos->{int16} > 0){#z.b. 30 Min/Gratis --> 0.5 + my $ctpos_freed = $self->only_first_free($ctpos); + #Bsp 1h = 60min , 60*0,02 = 1,2min + if(!$ctpos_freed->{c_id} || $real_hours <= 0.02){ + $hours -= $ctpos->{int16}; + $logging->{hours_freed} = $hours; + }else{ + $logging->{hours_freed} = "Not freed because of (!$ctpos_freed->{c_id} && $ctpos->{int16} || $real_hours <= 0.02)"; + } + } + + #If available then take saved hours + if($ctpos->{int10} && $ctpos->{int10} == 1 && $todo eq "readonly"){ + if($ctpos->{int03} && $ctpos->{int03} > 0){ + $hours = $ctpos->{int03}; + $total = $hours * $price if(looks_like_number($hours) && looks_like_number($price)); + }else{ + $hours = 0; + $total = 0; + } + } + #jede angebrochene Std. + elsif(looks_like_number($hours) && $hours > 0){ + if($days_hour4price > 0 && $hours >= $days_hour4price && $hours <= 24){ + $logging->{_hours_lower24} = "$days_hour4price > 0 && $hours >= $days_hour4price && $hours <= 24"; + $logging->{__hours_lower24} = $hours; + $hours = $days_hour4price; + $logging->{hours_lower24} = $hours; + } + elsif($days_hour4price > 0 && $hours >= 24){ + $logging->{hours_greate24} = "$days_hour4price > 0 && $hours >= 24"; + my $days = $hours / 24; + my $days_int = $days; + my $dez = 0; + ($days_int,$dez) = split(/\./, $days) if($days =~ /\.\d/); + my $days_hour = $days_int * 24; + my $rest = $hours - $days_hour; + $rest = $days_hour4price if($rest > $days_hour4price); + $hours = ($days_int * $days_hour4price) + $rest; + $logging->{hours_compute} = "$hours = ($days_int * $days_hour4price) + $rest"; + } + + $logging->{hours_preround} = $hours; + $hours = $lb->round_half($hours); + $logging->{hours_postround} = $hours; + $total = $hours * $price if(looks_like_number($hours) && looks_like_number($price)); + }else{ + $hours = 0; + } + $total = sprintf('%.2f', $total); + #Bsp 1h = 60min , 60*0,02 = 1,2min + $hours = "0" if($real_hours <= 0.02); + + $return->{real_hours} = "$real_hours"; + $return->{computed_hours} = "$hours"; + $return->{unit_price} = "$price"; + $return->{total_price} = "$total"; + $return->{bike_group} = ["$bike_group"]; + + + $return->{station} = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}$ctpos->{int04}";#TODO save with prefix + $return->{uri_operator} = "$varenv{wwwhost}";#TODO, should be DB select + $return->{bike} = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}$ctpos->{barcode}"; + $return->{state} = "$dbt->{copri_conf}->{bike_state}->{$ctpos->{int10}}" || ""; + $return->{bike_charge} = "$ctpos->{int19}" if($ctpos->{int19}); + $return->{description} = "$ctpos->{txt01}"; + $return->{request_time} = "$ctpos->{itime}"; + $return->{start_time} = "$ctpos->{start_time}"; + $return->{end_time} = "$computed_end_time"; + $return->{system} = "Ilockit" || "";#FIXME + + if($ctpos->{int11} eq "2"){ + #$return->{gps} = "$ctpos->{txt06}";#end_gps + ($return->{gps}->{latitude},$return->{gps}->{longitude}) = split(/,/,$ctpos->{txt06}); + + #if($ctpos->{txt10} =~ /requested|occupied/) + if($ctpos->{int10} == 2 || $ctpos->{int10} == 3){ + $return->{tariff_description}->{name} = "$ctpos->{txt04}"; + $return->{tariff_description}->{number} = "$ctpos->{int09}"; + $return->{tariff_description}->{eur_per_hour} = "$ctpos->{int02}" || "0"; + $return->{tariff_description}->{max_eur_per_day} = "$ctpos->{int17}" || "0"; + $return->{tariff_description}->{free_hours} = "$ctpos->{int16}" if($ctpos->{int16} && $ctpos->{int16} > 0); + $return->{tariff_description}->{abo_eur_per_month} = "$ctpos->{int15}" if($ctpos->{int15} && $ctpos->{int15} > 0); + $return->{tariff_description}->{track_info} = "Ich stimme der Speicherung (Tracking) meiner Fahrstrecke zwecks wissenschaftlicher Auswertung und Berechnung der CO2-Einsparung zu!" if($ctpos->{int25}); + $return->{tariff_description}->{operator_agb} = "Mit der Mietrad Anmietung wird folgender Betreiber AGB zugestimmt (als Demo sharee AGB)." if($ctpos->{ca_id} == 1842 || $ctpos->{ca_id} == 5781); + + $return->{Ilockit_GUID} = "$ctpos->{txt17}"; + $return->{Ilockit_ID} = "$ctpos->{txt18}"; + #$return->{gps} = "$ctpos->{txt06}";#start_gps + ($return->{gps}->{latitude},$return->{gps}->{longitude}) = split(/,/,$ctpos->{txt06}); + $return->{lock_state} = "locked" if($ctpos->{int20} == 1); + $return->{lock_state} = "unlocked" if($ctpos->{int20} == 2); + } + } + $bw->log("hour computed:",$logging,""); + return $return; +} + +#CO2 calculator +#Bsp Berechnungen: +# Pkw: +# Distanz * CO2-Emission Pkw / 100 km +# 8.760 km * 20 kg CO2 / 100 km = 1.752 kg CO2 +# Pedelec: +# Distanz * CO2-Emission Pedelec / 100 km +# 10.950 km * 0,546 kg CO2 / 100 km = 62 kg CO2 +# +# Aus der Differenz zwischen der CO2-Emission Pkw und der CO2-Emission Pedelec ergibt sich das Einsparpotenzial: +# 1.752 kg CO2 – 62 kg CO2 = 1.690 kg CO2, also rund 1,7 t CO2 pro Jahr +# +sub co2calc { + my $self = shift; + my $ctpos = shift; + my $co2diff = 0; + + my $co2pkw = $ctpos->{int26} * 20 / 100; + my $co2ped = $ctpos->{int26} * 0.546 / 100; + $co2diff = $co2pkw - $co2ped; + $co2diff = sprintf('%.2f',$co2diff); + $co2diff =~ s/\./,/; + + return $co2diff; +} + +#calculates sprit saving +sub sprit2calc { + my $self = shift; + my $ctpos = shift; + + my $einzel = $ctpos->{int02}; + my $menge = $ctpos->{int03}; + my $rabatt_val = $ctpos->{int07} || 0; + my $gesamt = 0; + if($rabatt_val != 0 && $einzel && $menge){ + my $rabatt_eur = $rabatt_val; + #if int08 != 1 alias € + $rabatt_eur = $einzel * $menge * $rabatt_val/100 if($ctpos->{int08} != 1); + $gesamt = $einzel * $menge - $rabatt_eur; + }elsif($einzel && $menge){ + $gesamt = $einzel * $menge; + } + + my $sprit_price = 0; + $sprit_price = $ctpos->{int26} * 0.3 if($ctpos->{int26} != 0); + $sprit_price -= $gesamt; + $sprit_price = sprintf('%.2f',$sprit_price); + $sprit_price =~ s/\./,/; + + return $sprit_price; +} + + +#computes position price and rabatt +sub price2calc { + my $self = shift; + my $ctpos = shift; + + my $gesamt = 0; + my $rabatt = ""; + my $einzel = $ctpos->{int02}; + my $menge = $ctpos->{int03}; + my $rabatt_val = $ctpos->{int07} || 0; + if($rabatt_val != 0 && $einzel && $menge){ + my $rabatt_eur = $rabatt_val; + #if int08 != 1 alias € + $rabatt_eur = $einzel * $menge * $rabatt_val/100 if($ctpos->{int08} != 1); + $gesamt = $einzel * $menge - $rabatt_eur; + }elsif($einzel && $menge){ + $gesamt = $einzel * $menge; + } + + if($ctpos->{int07} && $ctpos->{int07} > 0 && $menge > 0){ + $rabatt = "-" . $ctpos->{int07}; + if($ctpos->{int08} == 1){ + $rabatt .= " €"; + }else{ + $rabatt =~ s/\.00//; + $rabatt .= " %"; + } + } + + return ($gesamt,$rabatt); +} +1; diff --git a/copri4/main/src/Mod/Relation.pm b/copri4/main/src/Mod/Relation.pm new file mode 100644 index 0000000..6888c1e --- /dev/null +++ b/copri4/main/src/Mod/Relation.pm @@ -0,0 +1,78 @@ +package Relation; +# +## +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; +use CGI; +use CGI::Carp qw(fatalsToBrowser); +use CGI ':standard'; +use Mod::Buttons; +use Mod::Libenzdb; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my ($source,$main_id,$ct_name,$barcode,$u_id,$lang,$set_style,$colspan_left,$colspan_right) = @_; + + my $q = new CGI; + my $db = new Libenzdb; + my $but = new Buttons; + my $users = $db->select_users($u_id); + my %ib = $but->ibuttons(); + + #collect recursive waren + my $node_mandant = $db->get_node2($users->{fullurl},"$source",$lang); + my $main_ids = $db->collect_noderec($node_mandant->{main_id},$lang,"nothing"); + my $parent_nodes = $db->collect_node($node_mandant->{main_id},$lang); + my $nodes = $db->collect_node2("$main_ids"); + + + my $setpart_main_id=$main_id; + my @_waren_rel; + foreach my $pid (sort { lc($parent_nodes->{$a}->{node_name}) cmp lc($parent_nodes->{$b}->{node_name}) } keys (%$parent_nodes)){ + my $parent_name = "/"; + $parent_name .= $parent_nodes->{$pid}->{node_name} if($parent_nodes->{$pid}->{node_name}); + push (@_waren_rel, "$pid:$parent_name") if($parent_name && "$parent_name" !~ /root/); + foreach my $id (sort { lc($nodes->{$a}->{node_name}) cmp lc($nodes->{$b}->{node_name}) } keys (%$nodes)){ + if($nodes->{$id}->{parent_id} eq $parent_nodes->{$pid}->{main_id}){ + push (@_waren_rel, "$id:$parent_name/$nodes->{$id}->{node_name}") if($nodes->{$id}->{node_name}); + } + } + } + + print $q->hidden(-name=>'main_id', -value=>"$main_id"); + print $q->Tr(); + print "\n"; + print $q->start_table({-style=>'',-border=>'0',-align=>'left', -cellpadding=>'0', -cellspacing=>'0'}); + + print $q->Tr(); + print $q->td({-class=>'tdescr2',-colspan=>"$colspan_left",-style=>"$set_style"},"Kontext Kopie",$but->singlesubmit2("rel_edit","context_copy_content","$ib{context_copy_content}","$set_style")); + if($barcode){ + $ct_name = "" if($barcode == $ct_name); + print $q->hidden(-name=>'barcode', -value=>"$barcode"); + print $q->hidden(-name=>'empty_rel_id', -value=>"1"); + print $q->td({-class=>'tdval2',-colspan=>"$colspan_right",-style=>"$set_style"}, "Teilenummer:",$q->textfield(-class=>'etxt',-name=>"other_ct_name",-default=>"$ct_name",-size=>12,-maxlength=>15), "  Barcode (intern): $barcode\n"); + }else{ + print $q->td({-class=>'tdval2',-colspan=>"$colspan_right",-style=>"$set_style;color:red"}, "Der Barcode (intern) muss vorhanden sein\n"); + } + #print $q->Tr(); + #print $q->td({-class=>'tdescr2',-colspan=>"$colspan_left",-style=>"$set_style"},"Kopieren",$but->singlesubmit2("rel_edit","copy_content","$ib{copy_content}","$set_style")); + #print $q->hidden(-name=>'', -value=>""); + #print $q->td({-class=>'tdval2',-colspan=>"$colspan_right",-style=>"$set_style"}, "Barcode:",$q->textfield(-class=>'etxt',-name=>"new_barcode",-default=>"$barcode",-size=>12,-maxlength=>15), "\n"); + print $q->Tr(); + print $q->td({-class=>'tdescr2',-colspan=>"$colspan_left",-style=>"$set_style"},"Verschieben",$but->singlesubmit2("rel_edit","move_content","$ib{move_content}","$set_style")); + print $q->td({-class=>'tdval2',-colspan=>"$colspan_right",-style=>"$set_style"}, "Gruppen-Ordner:",$but->selector("setpart_main_id","250px",$setpart_main_id,@_waren_rel),"\n"); + print $q->end_table; + print ""; + +} +1; diff --git a/copri4/main/src/Mod/RelationEdit.pm b/copri4/main/src/Mod/RelationEdit.pm new file mode 100644 index 0000000..86cf0e8 --- /dev/null +++ b/copri4/main/src/Mod/RelationEdit.pm @@ -0,0 +1,216 @@ +package RelationEdit; +# +## +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; +use CGI; +use CGI::Carp qw(fatalsToBrowser); +use CGI ':standard'; +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Libenzdb; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my $node_meta = shift; + my $users_dms = shift; + my $u_group = shift; + my $return = shift; + + my $q = new CGI; + my @keywords = $q->param; + my $cf = new Config; + my $lb = new Libenz; + my $db = new Libenzdb; + my $but = new Buttons; + my %ib = $but->ibuttons(); + my $script = $q->script_name(); + my %varenv = $cf->envonline(); + my $path_info = $q->path_info(); + my $path = $path_info; + #with meta_host, + if("$varenv{metahost}"){ + $path = "$script" . "$path_info"; + $script=""; + } + my $lang = "de"; + my $ctn; + if($R::rel_id){ + $ctn = $db->collect_rel4nodes("",$node_meta->{content_id},$node_meta->{template_id}); + }else{ + return "failure::Fehler bei der Auswahluebergabe"; + } + my $bg_color = "gray"; + my $table = "content"; + my $relate_key; + $relate_key = "move_content" if($R::rel_edit =~ /move_/); + $relate_key = "relate_content" if($R::rel_edit =~ /relate_/); + $relate_key = "copy_content" if($R::rel_edit =~ /copy_/); + if($node_meta->{ct_table} eq "contentadr"){ + $table = "contentadr"; + $relate_key = "move_contentadr" if($R::rel_edit =~ /move_/); + $relate_key = "relate_contentadr" if($R::rel_edit =~ /relate_/); + } + if($node_meta->{ct_table} eq "contenttrans"){ + $table = "contenttrans"; + $relate_key = "move_conttrans" if($R::rel_edit =~ /move_/); + $relate_key = "relate_contenttrans" if($R::rel_edit =~ /relate_/); + } + if($node_meta->{ct_table} eq "contenttver"){ + $table = "contenttver"; + $relate_key = "move_contenttver" if($R::rel_edit =~ /move_/); + $relate_key = "relate_contenttver" if($R::rel_edit =~ /relate_/); + } + if($node_meta->{ct_table} eq "contentnel"){ + $table = "contentnel"; + $relate_key = "move_contentnel" if($R::rel_edit =~ /move_/); + $relate_key = "relate_contentnel" if($R::rel_edit =~ /relate_/); + } + + + #print "$table,$node_meta->{main_id},$lang,$R::rel_id, xxxxxxxxxxxxxx"; + my $ctrel = $db->get_ctrel($table,"",$lang,$R::rel_id); + my $node = $db->get_node4multi($node_meta->{main_id},$lang); + $ctrel->{mtime} = $lb->time4de($ctrel->{mtime},"1") if($ctrel->{mtime}); + $ctrel->{rel_id} = 0 if(!$ctrel->{rel_id}); + my $ct_users; + $ct_users = $db->collect_users("users") if($u_group eq "manager");#users map + + #we mean roots for sub-NodePath selection + my $module; + my @viewsel = split /\//,$1 if($path =~ /^\/(.*)/); + my $depth = scalar(@viewsel); + my $view_root = $viewsel[0] || "root"; + $module = $db->get_node("$view_root","$lang","<","200000"); + + if(!$module->{main_id} && ($path =~ /^\/([\w-\sßäöüÄÖÜ]+)\/([\w-\sßäöüÄÖÜ]+)/)){ + $module = $db->get_node2($1,$2,$lang); + } + my $module_id = "$module->{main_id}" || "100000"; + my $selector = "this_is_no_selection"; + $selector = $1 if($path =~ /\/(Waren|Kunden|Veranstaltung|Nachrichten)/); + + #collect recursive nodes + my $selsize="200px"; + #nodes with relation would be better + my $nodes = $db->collect_node4all("","","","100000"); + my @_menu_rel; + foreach my $id (sort { lc($nodes->{$a}->{node_name}) cmp lc($nodes->{$b}->{node_name}) } keys (%$nodes)){ + my @viewsel; + my $depth=0; + my $j=0; + my ($m_id,$uri) = $lb->make_uri5($nodes->{$id}->{main_id},$nodes); + #print "$module->{node_name}|$selector|$m_id:$uri
    "; + #if(($uri =~ /$module->{node_name}/) && ($uri !~ /000 root/)){ + if(($uri =~ /\w\/\w/) && ($uri !~ /000 root/)){ + @viewsel = split(/\//,$uri) if($uri =~ /^\/(.*)/); + $depth = scalar(@viewsel); + if($varenv{orga} ne "dms"){ + if($depth >= 3){ + my $ct4rel = $db->collect_ct4rel("$table",$nodes->{$id}->{main_id},$lang,"","","","",""); + foreach my $id (keys(%$ct4rel)){ + $j++ if($ct4rel->{$id}->{c_id}); + } + push (@_menu_rel, "$m_id:$uri"); + } + }elsif($varenv{orga} eq "dms"){ + #sharee-copri workaround to get only bike menue + if($selector && ($path =~ /\/$selector/) && ($uri =~ /$selector/) && ($node_meta->{template_id} == 205)){#Waren bikes + if($depth >= 2){ + my $rel = $db->get_relation($nodes->{$id}->{main_id},$lang,""); + push (@_menu_rel, "$m_id:$uri") if($rel->{template_id} == 205); + } + } + } + } + } + my $mcount = scalar(@_menu_rel); + # + + #collect content + my $content = $db->collect_content(); + my @_content; + foreach my $id (sort { lc($content->{$a}->{ct_name}) cmp lc($content->{$b}->{ct_name}) } keys (%$content)){ + push (@_content, "$id:$content->{$id}->{ct_name}") if($content->{$id}->{ct_name}); + } + # + + print "
    "; + + my $u_name; + foreach my $ctu_id (keys (%$ct_users)){ + if($ctrel->{owner} eq $ct_users->{$ctu_id}->{owner}){ + $u_name = $ct_users->{$ctu_id}->{u_name}; + } + } + $db->users_up("rel_id4edit",$ctrel->{rel_id},$users_dms->{u_id}); + print $q->hidden(-name=>'main_id', -value=>"$ctrel->{main_id}"); + print $q->hidden(-name=>'rel_id', -value=>"$ctrel->{rel_id}") if($ctrel->{rel_id}); + print $q->hidden(-name=>'template_id', -value=>"$ctrel->{template_id}"); + + print $q->start_table({-class=>'list', -border=>'0', -width=>'100%', -align=>'left', -cellpadding=>'3', -cellspacing=>'3'}); + + #Buttons + print $q->Tr(); + print "\n"; + print $but->singlesubmit7("rel_edit","$relate_key","$ib{$relate_key}"); + print "\n"; + + print $q->Tr(); + print $q->td({-colspan=>'2'}," "); + + if("$R::relate_dialog" eq "menu" || $R::rel_edit =~ /dialog4menu/){ + print $q->hidden(-name=>'set_content_id', -value=>"$ctrel->{content_id}"); + print $q->Tr(); + print $q->td({-class=>'tdescr2'}, "Content"),"\n"; + print $q->td({-class=>'tdval2'},$q->b("$ctrel->{ct_name} ($ctrel->{txt01})"),"\n"); + print $q->Tr(); + print $q->td({-class=>'tdescr2'}, "Node"),"\n"; + if($mcount > 0 || $varenv{orga} eq "dms"){ + if($varenv{wwwhost} =~ /woge|fsd/){#with multiple select + my $height = scalar(@_menu_rel); + my $remain_id; + foreach my $in (keys(%$ctn)){ + $remain_id .= "$ctn->{$in}->{main_id},"; + } + $remain_id =~ s/,$//; + print $q->td({-class=>'tdval2'},$but->selector2("set_main_id","600px","$height",$remain_id,@_menu_rel)),"\n"; + }else{ + print $q->td({-class=>'tdval2'},$but->selector("set_main_id","250px",$node_meta->{main_id},@_menu_rel)),"\n"; + } + }else{ + print $q->td({-class=>'tdval2'},"Es ist kein leeres Menue fuer eine Verknuepfung vorhanden."),"\n"; + } + print $q->hidden(-name=>'mastermain_id', -value=>"$node_meta->{mastermain_id}") if($node_meta->{mastermain_id}); + }elsif("$R::relate_dialog" eq "content" || $R::rel_edit =~ /dialog4content/){ + print $q->hidden(-name=>'set_main_id', -value=>"$node_meta->{main_id}"); + print $q->Tr(); + print $q->td({-class=>'tdescr2'}, "Node"),"\n"; + print $q->td({-class=>'tdval2'},$q->b($node->{node_name}),"\n"); + print $q->Tr(); + print $q->td({-class=>'tdescr2'}, "Content"),"\n"; + print $q->td({-class=>'tdval2'},$but->selector("set_content_id","250px",$ctrel->{c_id},@_content),"\n"); + } + print $q->Tr(); + print $q->td({-colspan=>'2'}," "); + #print $q->Tr(); + #print ""; + #print $q->a({-class=>"linknav2",-href=>'javascript:history.back()'}, "zurück"); + #print "\n"; + + print $q->end_table; + print "
    \n"; + +} +1; diff --git a/copri4/main/src/Mod/SMSTransport.pm b/copri4/main/src/Mod/SMSTransport.pm new file mode 100644 index 0000000..f8b6d39 --- /dev/null +++ b/copri4/main/src/Mod/SMSTransport.pm @@ -0,0 +1,125 @@ +package SMSTransport; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +#SMS sender +# +#perl -cw do +#use lib "/var/www/copri4/shareeapp-primary/src"; + +use strict; +use warnings; +use POSIX; +use CGI; # only for debugging +use LWP::UserAgent; +use URI::Encode; +use JSON; + +use Scalar::Util qw(looks_like_number); +use Mod::DBtank; +use Mod::Basework; +use Data::Dumper; + +my $q = new CGI; +my $dbt = new DBtank; +my $bw = new Basework; + + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; + +my $ua = LWP::UserAgent->new; +$ua->agent("sharee smsclient"); + +my $uri_encode = URI::Encode->new( { encode_reserved => 1 } ); +my $json = JSON->new->allow_nonref; +my $response_in = {}; +my $dbh = ""; +my $owner = 181; + +sub sms_ack_digest { + my $self = shift; + my $ctadr = shift; + + #Ack digest + my $ack_digest = $q->unescapeHTML($ctadr->{txt34}) || ""; + my $email_ack_digest = $1 if($ack_digest =~ /^(.{5})/); + my $sms_ack_digest = $1 if($ack_digest =~ /(.{5})$/); + + my $sms_from = "Mietradsystem"; + my $sms_to = $ctadr->{txt07};# || "+491799xxxx72"; + my $sms_message = "Ihr Mietradsystem SMS-Bestätigungscode lautet: $sms_ack_digest"; + my $message = Encode::encode('iso-8859-1', Encode::decode('utf-8',"$sms_message")); + + open(FILE,">>$dbt->{copri_conf}->{logdir}/sms_gtx.log"); + print FILE "\n*** $now_dt 'sharee smsclient' \n"; + + my $request = { + from => $sms_from, + to => $sms_to, + text => $message, + }; + + print FILE "---> request:\n" . Dumper($request); + + my $ret_json = $self->get_sms_gtx($request); + + eval { + $response_in = decode_json($ret_json); + print FILE "<--- response_in:\n" . Dumper($response_in); + }; + if ($@){ + print FILE "<--- failure raw response_in:\n" . Dumper($ret_json) . "\n"; + warn $@; + } + + close(FILE); + + return $ret_json; +} + + +#sms gtx http request +sub get_sms_gtx { + my $self = shift; + my $request = shift || ""; + + my $api_file = "/var/www/copri4/shareeconf/apikeys.cfg"; + my $aconf = Config::General->new($api_file); + my %apikeyconf = $aconf->getall; + #print $apikeyconf{smsgtx}->{gtx_key}; + + my $endpoint = "https://rest.gtx-messaging.net/smsc/sendsms/$apikeyconf{smsgtx}->{gtx_key}/json"; + my $rest; + foreach (keys (%$request)){ + my $encoded_val = $uri_encode->encode($request->{$_}); + $rest .= "$_=$encoded_val&"; + } + $rest =~ s/\&$//; + + my $gtx_request = "$endpoint?$rest"; + + print FILE "===> GET2gtx >> " . $gtx_request . "\n"; + + my $req = HTTP::Request->new(GET => "$gtx_request"); + $req->content_type('application/x-www-form-urlencoded'); + + my $res = $ua->request($req); + if ($res->is_success) { + #print $res->content; + return $res->content; + print $res->status_line, "\n"; + }else { + print $res->status_line, "\n"; + } +} +# + +1; diff --git a/copri4/main/src/Mod/Shareework.pm b/copri4/main/src/Mod/Shareework.pm new file mode 100644 index 0000000..6b60c99 --- /dev/null +++ b/copri4/main/src/Mod/Shareework.pm @@ -0,0 +1,990 @@ +package Shareework; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +#disable for syntax check +#use lib qw(/var/www/copri4/shareeapp-primary/src); + +use strict; +use warnings; +use POSIX; +use CGI; # only for debugging +use Mod::Libenzdb; +use Mod::Libenz; +use Mod::DBtank; +use Mod::Buttons; +use Lib::Config; +use Mod::APIfunc; +use Digest::MD5 qw(md5 md5_hex); +use Digest::SHA qw(sha1_base64); +use Scalar::Util qw(looks_like_number); +use Mod::Prelib; +use Mod::Basework; +use Mod::Payment; +#use Mod::MailTransport; +use Mod::SMSTransport; +use Data::Dumper; + +my $cf = new Config; +my $but = new Buttons; +my $db = new Libenzdb; +my $lb = new Libenz; +my $dbt = new DBtank; +my $apif = new APIfunc; +my $pl = new Prelib; +my $bw = new Basework; +my $payone = new Payment; +#my $mailtrans = new MailTransport; +my $smstrans = new SMSTransport; + +my $q = new CGI; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +my $i_rows=0; +my $u_rows=0; +my $d_rows=0; + +# +#also done in src/Tpl/Anmelden.pm!? +sub delete_account { + my $self = shift; + my $c_id = shift; + my $owner = shift; + + my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; + my %varenv = $cf->envonline(); + my $debug=1; + my $dbh = ""; + + $bw->log("delete_account",$c_id,""); + open(FILE,">>$varenv{logdir}/delete_account.log") if($debug); + + my $dbh_primary = $dbt->dbconnect_extern("sharee_primary"); + my $authref = { + table => "contentadr", + fetch => "one", + template_id => "202", + c_id => "$c_id", + }; + my $ctadr = $dbt->fetch_record($dbh_primary,$authref); + + print FILE "\n*-->DB $varenv{dbname} $now_dt| owner: $owner | c_id: $c_id \n" if($debug); + + #First on operator DMS delete and then second on primary delete txt17 operator DB + if($varenv{dbname} ne "sharee_primary"){ + $d_rows += $dbt->delete_content($dbh,"contentadr",$c_id); + + my $update_primary = { + table => "contentadr", + mtime => "now()", + owner => "$owner", + c_id => "$c_id", + }; + + my @operators = ("$ctadr->{txt17}"); + @operators = split(/\s+/,$ctadr->{txt17}) if($ctadr->{txt17} =~ /\w\s\w/); + my @new_operators = (); + foreach(@operators){ + push(@new_operators,$_) if($_ =~ /sharee_\w+/ && $_ !~ /$varenv{dbname}/); + } + + print FILE "delete operator dbname: $varenv{dbname} | update_primary txt17='@new_operators'\n"; + $u_rows = $dbt->update_one($dbh_primary,$update_primary,"txt17='@new_operators'"); + $u_rows = $dbt->update_one($dbh_primary,$update_primary,"txt19=null"); + }else{ + print FILE "delete on all by operatorsloop by primary\n"; + $dbt->update_operatorsloop($varenv{dbname},$ctadr->{c_id},"delete"); + $d_rows += $dbt->delete_content($dbh,"contentadr",$c_id); + } + + close(FILE) if($debug); + + return "$i_rows-$u_rows-$d_rows"; +} + + +sub check_account(){ + my $self = shift; + my ($column2,$op2,$content2,$column3,$op3,$content3) = @_; + my $table = "contentadr"; + $content2 = $q->escapeHTML("$content2"); + my $account_check = $db->get_like2sort("contentadr","","","$column2","$op2","$content2","$column3","$op3","$content3"); + return $account_check; +} + +#create_account is alwas done on primary first +sub create_account(){ + my $self = shift; + my $owner = shift; + my $table = "contentadr"; + + my $c_idnew = $db->insert_content($table); + $db->updater("$table","c_id",$c_idnew,"ct_name","$c_idnew","$owner"); + $db->updater("$table","c_id",$c_idnew,"barcode","$c_idnew","$owner"); + $db->updater("$table","c_id",$c_idnew,"int20","$owner","$owner"); + my $rel_idnew = $db->insert_relationlist($table,"200011","de",$c_idnew,"202","ca_id"); + return $c_idnew; +} + + +#sharee save_account is always done on primary first +sub save_account(){ + my $self = shift; + my $c_id = shift; + my $coo = shift || ""; + my $owner = shift || 0; + + my $table = "contentadr"; + $q = new CGI; + $q->import_names('R'); + my @keywords = $q->param; + + my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; + my %varenv = $cf->envonline(); + $bw->log("save_account",$q,""); + + my $debug=1; + my $dbh = "";#keep in mind, empty dbh defaults to local copri-instance dbname + + open(FILE,">>$varenv{logdir}/save_account.log") if($debug); + + #Always on sharee_primary + if($varenv{dbname} ne "sharee_primary"){ + $dbh = $dbt->dbconnect_extern("sharee_primary"); + print FILE "\n*-->If no-primary connect DB sharee_primary $now_dt| c_id: $c_id \n" if($debug); + }else{ + #keep in mind, should be only done by web-app user Formular (primary) + print FILE "\n*-->Else take local copri-Instance DB $varenv{dbname} $now_dt| c_id: $c_id \n" if($debug); + } + + my $authref = { + table => "contentadr", + fetch => "one", + template_id => "202", + c_id => "$c_id", + }; + my $ctadr = $dbt->fetch_record($dbh,$authref); + + my $update_primary = { + table => "contentadr", + mtime => "now()", + owner => "$owner", + c_id => "$c_id", + }; + + + my $ret = ""; + my $ret_conflict = ""; + my $fkeys = ""; + my $pw_dummy = ""; + @keywords = grep {!/txt31/} @keywords; + print FILE Dumper($q) if($debug); + foreach(@keywords){ + $fkeys .= "$_,"; + my $val = $q->param("$_"); + my $valxx = $q->escapeHTML("$val"); + $valxx =~ s/^\s+//; + $valxx =~ s/\s+$//; + print FILE "$_:$valxx \n" if($debug); + if($_ =~ /^int|barcode/){ + $valxx =~ s/,/./g; + if(looks_like_number($valxx)){ + $valxx = $valxx; + }else{ + $valxx = "null" + } + } + if($_ =~ /^txt[\d+]|^int[\d+]|^uri[\d+]|ct_name/){ + #PW + if($_ =~ /^txt04/){ + if($valxx eq "xxxxxxxx"){ + $pw_dummy = "1"; + }elsif($valxx){ + my $pwmd5 = md5_hex($valxx); + $u_rows = $dbt->update_one($dbh,$update_primary,"txt11='$pwmd5'"); + } + } + #operators, only if saved by operator DMS + elsif($_ eq "txt17"){ + #2021-07-29 post input disabled, because it fails + #my @txt17 = $q->param('txt17'); + #@txt17 = grep {!/null/g} @txt17; + #push(@txt17,$varenv{dbname}) if($varenv{dbname} ne "sharee_primary"); + #my %txt17 = map {$_ => 1} @txt17; + my %txt17 = (); + if($ctadr->{txt17} =~ /\w\s\w/){ + %txt17 = map { $_ => 1 } split(/\s+/,$ctadr->{txt17}); + }else{ + $txt17{$ctadr->{txt17}} = 1; + } + my $txt19 = $q->escapeHTML($q->param('txt19')) || ""; + if($txt19 && $dbt->{operator}{$txt19}->{database}->{dbname}){ + $txt17{$dbt->{operator}{$txt19}->{database}->{dbname}} = 1; + } + my @operators = (); + foreach my $keys (keys %txt17) { + push(@operators,$keys); + } + $u_rows = $dbt->update_one($dbh,$update_primary,"txt17='@operators'"); + } + #Web-Login|Rabatt|Vde|payone cron-intervall|Ilockit-Admin + #elsif($_ =~ /int05|int07|int12|int16|int19/){ + elsif($_ =~ /int05|int07|int16|int19/){ + #if($varenv{dbname} ne "sharee_primary"){ + #on all $keys which on delete on loop sync + $u_rows = $dbt->update_one("",$update_primary,"$_=$valxx"); + # } + } + #user_tour + elsif($_ =~ /txt18/){ + #if($varenv{dbname} ne "sharee_primary"){ + #on all $keys which on delete on loop sync + my @txt18 = $q->param('txt18'); + @txt18 = grep {!/null/} @txt18; + $u_rows = $dbt->update_one("",$update_primary,"$_='@txt18'"); + # } + } + #Text Sonstiges + elsif($_ =~ /txt29/){ + # if($varenv{dbname} ne "sharee_primary"){ + #on all $keys which on delete on loop sync + $u_rows = $dbt->update_one("",$update_primary,"$_='$valxx'"); + # } + } + + #txt15=Bonus- oder Antragsnummer (falls vorhanden)=15 + #only check bonusnr and add operators dbname. + #bonustarif will be set after operator insert + elsif($_ eq "txt15"){ + #only done by App web iframe Anmelde-Registration formular + print FILE "Bonusnr request $_: $valxx\n" if($debug); + + if($varenv{dbname} eq "sharee_primary"){ + my %txt17 = (); + if($ctadr->{txt17} =~ /\w\s\w/){ + %txt17 = map { $_ => 1 } split(/\s+/,$ctadr->{txt17}); + }else{ + $txt17{$ctadr->{txt17}} = 1; + } + + if($valxx && ($valxx =~ /^(\w{2,3})-(\w+)/ || $valxx =~ /^(\w{2,3})(\d+)/)){ + $valxx =~ s/\s//g; + my $bonus_prefix = uc($1), + my $bonusnr = $2; + my $operator_conf = $dbt->get_operator_conf($bonus_prefix); + + if(ref($operator_conf) eq "HASH" && $operator_conf->{oprefix} && $operator_conf->{database}->{dbname}){ + print FILE "Bonus- oder Antragsnummer $valxx : " . $operator_conf->{oprefix} . " " . $operator_conf->{database}->{dbname} . "\n" if($debug); + my $dbh_operator = $dbt->dbconnect_extern($operator_conf->{database}->{dbname}); + #to get operator bonusnr + my $pref_bo = { + table => "content", + fetch => "one", + template_id => "228", + int03 => ">::0", + ct_name => "$bonusnr", + }; + my $bonus_record = $dbt->fetch_record($dbh_operator,$pref_bo); + + #add operators dbname only if Bonusnr matches + print FILE "txt15=$bonusnr requested on web Bonustarif on: $operator_conf->{database}->{dbname} --> barcode:$bonus_record->{barcode} --> txt21:$bonus_record->{int21} --> txt22:$bonus_record->{int22}\n" if($debug); + if($bonus_record->{c_id}){ + $txt17{$operator_conf->{database}->{dbname}} = 1; + my @operators = (); + foreach my $keys (keys %txt17) { + push(@operators,$keys) if($keys =~/sharee_/); + } + print FILE "txt17 saving operators on primary: @operators\n" if($debug); + $u_rows = $dbt->update_one($dbh,$update_primary,"txt17='@operators'"); + + #insert adr to operator if it doesn't exist before set operator bonustarif + my $ctadr_operator = $dbt->fetch_record($dbh_operator,$authref); + my @txt30_op = (); + #multiple select sharee Tarif + @txt30_op = ("$ctadr_operator->{txt30}") if($ctadr_operator->{txt30}); + @txt30_op = split(/\s+/,$ctadr_operator->{txt30}) if($ctadr_operator->{txt30} =~ /\w\s+\w/); + if(!$ctadr_operator->{c_id}){ + print FILE "Bonus oprefix address INSERT adr from record_primary to operator $operator_conf->{database}->{dbname} , c_id:$ctadr->{c_id}\n"; + my $insert_op = { + %$ctadr, + table => "contentadr", + mtime => 'now()', + owner => "198", + }; + my $c_id_op = $dbt->insert_contentoid($dbh_operator,$insert_op,"reset_adropkeys"); + $dbt->update_content4comp($dbh_operator,$bonus_record->{c_id},"-","1"); + + @txt30_op = ("$bonus_record->{int22}") if($bonus_record->{int22}); + } + my $adr_bonus = { + table => "contentadr", + mtime => "now()", + c_id => $c_id, + txt15 => $bonusnr, + txt30_array => \@txt30_op, + owner => $owner, + ret => $ret, + }; + print FILE "adr_bonus" . Dumper($adr_bonus) . "\n"; + $ret = $pl->set_usertarif($dbh,$operator_conf->{database}->{dbname},$adr_bonus); + } + }else{ + $ret = "failure::txt15#top5"; + } + }elsif($valxx && $valxx =~ /\w+/){ + $ret = "failure::txt15#top6"; + } + + } + } + #sharee txt30=Tarif (multible) and Bonusnummer txt15 automatic + elsif($_ eq "txt30"){ + #only done by Operator DMS + if($varenv{dbname} ne "sharee_primary"){ + my @txt30 = $q->param('txt30');#multiple select sharee Tarif + @txt30 = grep {!/null/} @txt30; + my $bonusnr = $q->escapeHTML("$R::txt15");#on Operator DMS without oprefix- + + my $bonushash = { + table => "contentadr", + mtime => "now()", + c_id => $c_id, + txt15 => $bonusnr, + txt30_array => \@txt30, + owner => $owner, + ret => $ret, + }; + $ret = $pl->set_usertarif($dbh,$varenv{dbname},$bonushash); + } + #phonenr + }elsif($_ eq "txt07"){ + $valxx =~ s/[\s\-\/]//g; + if($valxx !~ /\d{9}/ || length($valxx) > 16 || $valxx !~ /\+[1-9]{3}/){ + $ret = "failure::$_#top"; + }else{ + my $lastnum = $valxx; + $lastnum = $1 if($valxx =~ /(\d{9})$/); + my $phone_check = &check_account("","txt07","~",$lastnum,"c_id","!=",$c_id); + if($phone_check->{c_id} && $phone_check->{c_id} != $c_id){ + $ret_conflict = "failure::conflict_$_=$valxx#top"; + } + #smsAck reset + if($valxx ne $ctadr->{txt07}){ + $u_rows = $dbt->update_one($dbh,$update_primary,"int13=0"); + } + $u_rows = $dbt->update_one($dbh,$update_primary,"$_='$valxx'"); + my $email = $R::txt08; + $email =~ s/\s//g; + my $confirm_digest = sha1_base64($email . $valxx); + $u_rows = $dbt->update_one($dbh,$update_primary,"txt34='$confirm_digest'"); + } + #user alias email + }elsif($_ eq "txt08"){ + $valxx =~ s/\s//g; + if($valxx !~ /\w\@\w/){ + $ret = "failure::$_#top"; + }else{ + my $account_check = &check_account("","txt08","ilike",$valxx,"c_id","!=",$c_id); + print FILE "$account_check->{c_id} && $account_check->{c_id} != $c_id\n" if($debug); + if($account_check->{c_id} && $account_check->{c_id} != $c_id){ + $ret_conflict = "failure::conflict_$_=$valxx#top"; + } + #mailAck reset + if($valxx ne $ctadr->{txt08}){ + $u_rows = $dbt->update_one($dbh,$update_primary,"int04=0"); + } + $u_rows = $dbt->update_one($dbh,$update_primary,"$_='$valxx'"); + } + }elsif($_ eq "int12"){ + if($varenv{dbname} eq "sharee_primary" && $ctadr->{int12} == 2){ + $u_rows = $dbt->update_one($dbh,$update_primary,"$_=2"); + }else{ + $u_rows = $dbt->update_one($dbh,$update_primary,"$_=$valxx"); + } + }elsif($_ =~ /^int|barcode/){ + $u_rows = $dbt->update_one($dbh,$update_primary,"$_=$valxx"); + }elsif($_ eq "ct_name" && $R::base_edit){ + $u_rows = $dbt->update_one($dbh,$update_primary,"$_='$valxx'"); + #}elsif($_ !~ /ct_name|txt22|txt23|txt15/){ + }elsif($_ !~ /ct_name|txt15/){ + $u_rows = $dbt->update_one($dbh,$update_primary,"$_='$valxx'"); + } + + #Additionals after default updater + #on IBAN/BIC change set override Mandantsreferenz to c_id to trigger payone + if(($_ eq "txt22" && $valxx ne $ctadr->{txt22}) || ($_ eq "txt23" && $valxx ne $ctadr->{txt23})){ + $u_rows += $dbt->update_one($dbh,$update_primary,"ct_name='$c_id'"); + } + if($_ =~ /txt22/ && $valxx){ + my $currency = "EUR"; + $currency = "CHF" if($valxx =~ /^(CH)/i); + $u_rows = $dbt->update_one($dbh,$update_primary,"txt24='$currency'"); + } + + print FILE "-----> $_: $valxx\n" if($debug); + + $ret = "failure::$_#top" if(($_ =~ /int14/) && ($valxx eq "null" || !$valxx));#sharee AGB + + #Zahlungsart + $ret = "failure::$_#top" if(($_ =~ /int03/) && ($valxx eq "null" || !$valxx)); + + $ret = "failure::$_#top" if($_ =~ /txt01/ && $valxx !~ /[a-zäöü]+\s+[a-zäöü]+/i); + $ret = "failure::$_#top" if($_ =~ /txt03/ && ($valxx !~ /[\w|\.]+\s+\d+/ && $valxx !~ /\d+\s+[\w|\.]+/)); + + if($_ =~ /txt04/ && !$pw_dummy){ + my $alphacount = 0; + my $alphafail = 0; + $alphacount = () = $valxx =~ /[a-z]/gi; + $alphafail = length($valxx) - $alphacount; + if(!$valxx || length($valxx) < 8 || $alphafail < 2){ + #$ret = "failure::pwlazy_txt04#top"; + $ret = "failure::$_#top"; + } + } + + $ret = "failure::$_#top" if($_ =~ /txt06/ && $valxx !~ /\d+\s+[a-zäöü]+/i); + $ret = "failure::$_#top" if($_ =~ /txt08/ && $valxx !~ /\w\@\w/); + $ret = "failure::$_#top" if($R::sharee_edit && $_ =~ /txt22/ && $valxx !~ /\w/); + $ret = "failure::$_#top" if($R::sharee_edit && $_ =~ /txt23/ && $valxx !~ /\w/); + + } + print FILE "ret: $ret | ret_conflict: $ret_conflict\n" if($debug && ($ret || $ret_conflict)); + }#end foreach keyword + + #payone only if SEPA Mandat checked + #Testbuchhung mit 1 € preauthorization and 0 € capture + $ctadr = $dbt->fetch_record($dbh,$authref); + print FILE "+++ $R::request && $ctadr->{int03} == 1 && $ctadr->{ct_name} eq $ctadr->{c_id} \n" if($debug); + if($R::request eq "managemandate" && $ctadr->{int03} == 1 && $ctadr->{ct_name} eq $ctadr->{c_id}){ + my $vde_on_fail = $ctadr->{int12} || 3;#keep last or set 3 + + my $payone_mival = $payone->managemandate_main(\%varenv,$ctadr,"",$owner); + if($payone_mival && $payone_mival =~ /\w{2}-\d+/){ + #define fictiv invoice to get 1 € test + my $epoche = time(); + my $ctt = { + c_id => 1, + int01 => 0, + int15 => 1, + txt16 => "", + reference => "$ctadr->{c_id}_$epoche", + renewed => '' + }; + my $payone_txid = ""; + $payone_txid = $payone->preauthorizationSEPA_main(\%varenv,$ctadr,$ctt,$owner); + if($payone_txid){ + $ctt->{txt16} = "$payone_txid"; + $payone_txid = $payone->captureSEPA_main(\%varenv,$ctadr,$ctt,$owner); + }else{ + $u_rows = $dbt->update_one($dbh,$update_primary,"int12=$vde_on_fail");#Vde + } + }else{ + $u_rows = $dbt->update_one($dbh,$update_primary,"int12=$vde_on_fail");#Vde + } + #$u_rows = $dbt->update_one($dbh,$update_primary,"int12=3");#Vde test fail + } + + if($R::txt04 && $R::confirm_txt04 && $R::txt04 ne $R::confirm_txt04){ + $ret = "failure::confirm_txt04#top"; + } + + if($ret =~ /failure::(\w+)/ && $ret !~ /txt15|txt16/){#persistent failure without Bonus or Gutschein + my $rval = $1; + #$rval =~ s/pwlazy_//g;#obsolet, all done in pw template description + $rval =~ s/confirm_//g;#PW confirm + $rval =~ s/conflict_//g;#conflict + print FILE "ret: $ret | rval: $rval\n" if($debug); + $dbt->update_one($dbh,$update_primary,"txt31='$rval'"); + }elsif($fkeys =~ /$ctadr->{txt31}/){ + print FILE " No failure and empty txt31 (fkeys: $fkeys =~ /$ctadr->{txt31}/) \n" if($debug); + $u_rows = $dbt->update_one($dbh,$update_primary,"txt31=''"); + } + + $ret = $ret_conflict if($ret_conflict); + print FILE "final ret: $ret \n" if($debug); + + close(FILE) if($debug); + + #if(!$ret){#we do it also on failures to get sync + #update operator with primary data after COPRI address edit + $dbt->update_operatorsloop($varenv{dbname},$ctadr->{c_id},"update"); + + return ($ret,"$i_rows-$u_rows-$d_rows"); +} + +#insert/save/delete DMS users +sub manage_dmsusers { + my $self = shift; + my $base_edit = shift; + my $u_id = shift; + my $users_dms = shift || {}; + my $owner = $users_dms->{u_id} || 0; + my $table = "users"; + $q = new CGI; + $q->import_names('R'); + my @keywords = $q->param; + + my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; + my %varenv = $cf->envonline(); + $bw->log("manage_dmsusers",$q,""); + + my $dbh = ""; + my $authref = { + table => "contentadr", + fetch => "one", + template_id => "202", + c_id => "$u_id", + }; + my $ctadr = $dbt->fetch_record($dbh,$authref); + + #users have to be exist only if DMS activated + my $uref = { + table => "users", + fetch => "one", + u_id => "$u_id", + }; + my $users = $dbt->fetch_tablerecord($dbh,$uref); + + #datahash on update + my $dmsusers = { + table => "users", + mtime => "now()", + owner => "$owner", + u_id => "$u_id", + }; + + if(ref($users) eq "HASH" && $users->{u_id} && (!$ctadr->{c_id} || $base_edit eq "delete_dmsusers")){ + $bw->log("delete DMS user from $varenv{dbname}",$ctadr->{c_id},""); + $d_rows += $dbt->delete_content($dbh,"users",$u_id); + }elsif(ref($users) eq "HASH" && $users->{u_id} && $ctadr->{c_id} && $ctadr->{c_id} == $users->{u_id} && $base_edit eq "save_dmsusers"){ + $bw->log("update DMS user to $varenv{dbname}",$ctadr->{c_id},""); + foreach(@keywords){ + my $val = $q->param($_); + my $valxx = $q->escapeHTML("$val"); + $valxx =~ s/^\s+//; $valxx =~ s/\s+$//; + if($_ =~ /^int\d+/){ + $valxx =~ s/,/./g; + #$valxx = "null" if(!looks_like_number($valxx));#empty + $valxx = 0 if(!looks_like_number($valxx));# set to 0 for using == operator + $u_rows = $dbt->update_one($dbh,$dmsusers,"$_=$valxx"); + } + } + + }elsif($ctadr->{c_id} && !$users->{u_id} && $base_edit eq "new_dmsusers"){ + $bw->log("insert DMS user to $varenv{dbname}",$ctadr->{c_id},""); + $i_rows = $dbt->insert_users($dbh,$ctadr->{c_id},$owner); + } + + return "$i_rows-$u_rows-$d_rows"; +} + + +#coupon alias Gutschein +sub save_transact(){ + my $self = shift; + my ($c_id,$coo,$owner) = @_; + + $q = new CGI; + $q->import_names('R'); + my @keywords = $q->param; + + my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; + my %varenv = $cf->envonline(); + $bw->log("save_transact",$q,""); + my $debug=1; + my $dbh = "";#keep in mind, empty dbh defaults to local copri-instance dbname + + open(FILE,">>$varenv{logdir}/save_account.log") if($debug); + print FILE "\n*-->local copri-Instance DB $varenv{dbname} $now_dt| c_id: $c_id \n" if($debug); + + my $authref = { + table => "contentadr", + fetch => "one", + template_id => "202", + c_id => "$c_id", + }; + my $ctadr = $dbt->fetch_record($dbh,$authref); + + my $update_primary = { + table => "contentadr", + mtime => "now()", + owner => "$owner", + c_id => "$c_id", + }; + + + my $pos_id=""; + my $ret; + my $fkeys; + foreach(@keywords){ + $fkeys .= "$_,"; + my $val = $q->param($_); + my $valxx = $q->escapeHTML("$val"); + #print "|$_: $valxx"; + $valxx =~ s/^\s+//; + $valxx =~ s/\s+$//; + #Gutschein + if($_ eq "txt16"){ + print FILE "Gutschein request $_: $valxx\n" if($debug); + if($valxx && ($valxx =~ /^(\w{2,3})-(\w+)/ || $valxx =~ /^(\w{2,3})(\d+)/)){ + $valxx =~ s/\s//g; + my $coupon_prefix = uc($1), + my $coupon_nr = $2; + my $operator_conf = $dbt->get_operator_conf($coupon_prefix); + + if(ref($operator_conf) eq "HASH" && $operator_conf->{oprefix} && $operator_conf->{database}->{dbname}){ + print FILE "Gutschein $valxx : " . $operator_conf->{oprefix} . " " . $operator_conf->{database}->{dbname} . "\n" if($debug); + my $dbh_operator = $dbt->dbconnect_extern($operator_conf->{database}->{dbname}); + + #to get operator coupon_nr + my $pref_co = { + table => "content", + fetch => "one", + template_id => "224", + int03 => ">::0", + ct_name => "$coupon_nr", + }; + my $ct = { c_id => 0 }; + $ct = $dbt->fetch_record($dbh_operator,$pref_co); + $ct->{int02} *= -1 if($ct->{int02} > 0);#coupon price must be negate + + print FILE "txt16=$coupon_nr, unit_price $ct->{int02} --> requested on web on: $operator_conf->{database}->{dbname} --> barcode:$ct->{barcode}\n" if($debug); + + if($ct->{c_id}){ + my $ctadr_operator = { c_id => 0 }; + $ctadr_operator = $dbt->fetch_record($dbh_operator,$authref); + + if(!$ctadr_operator->{c_id}){ + print FILE "Gutschein oprefix address INSERT adr from record_primary to operator $operator_conf->{database}->{dbname} , c_id:$ctadr->{c_id}\n"; + my $insert_op = { + %$ctadr, + table => "contentadr", + mtime => 'now()', + owner => "198", + }; + my $c_id_op = $dbt->insert_contentoid($dbh_operator,$insert_op,"reset_adropkeys"); + } + + $ctadr_operator = $dbt->fetch_record($dbh_operator,$authref); + if($ctadr_operator->{c_id} > 0){ + + my $pref = { + table => "contenttrans", + fetch => "one", + main_id => 300008,#must be Rechnung (and not Storno) + template_id => 218, + #ca_id => "$ctadr->{c_id}", + int10 => "$ctadr_operator->{c_id}", + state => "is::null", + close_time => "is::null", + }; + + my $ctt = { c_id => 0 }; + $ctt = $dbt->fetch_record($dbh_operator,$pref); + if($ctt->{c_id} > 0){ + $pos_id = $dbt->insert_pos($dbh_operator,$ctt->{c_id},$ct,$ctadr_operator,"",$now_dt,$ct->{ct_name},"0",$owner); + }else{ + my $ct_id = $dbt->insert_contenttrans($dbh_operator,$ctadr_operator,"300008","218","----",$owner); + $pos_id = $dbt->insert_pos($dbh_operator,$ct_id,$ct,$ctadr_operator,"",$now_dt,$ct->{ct_name},"0",$owner); + } + + if($pos_id){ + $ret = "success::txt16"; + $dbt->update_content4comp($dbh_operator,$ct->{c_id},"-","1"); + } + }else{ + $ret = "failure::txt16#top"; + } + }else{ + $ret = "failure::txt16#top"; + } + } + }elsif($valxx && $valxx =~ /\w+/){ + $ret = "failure::txt16#top"; + } + } + } + + print FILE "save_transact ret: $ret \n" if($debug); + close(FILE) if($debug); + + return $ret; +}#end save_transact + + +#online net bike booking +#Used by APP API +sub net_booking(){ + my $self = shift; + my $auth = shift;#API auth + my $bikeIDin = shift;#API request + my $owner = shift; + my $gps = shift || ""; + + my $c_id = $auth->{c_id}; + $bikeIDin =~ s/\s//g; + my $bikeID = $q->escapeHTML($bikeIDin) if($bikeIDin =~ /\d+$/); + my $db_bike = $bikeID; + $db_bike = $1 if($db_bike =~ /(\d+)/); + + my %varenv = $cf->envonline(); + my $ctf = $db->get_content1("contentuser",$dbt->{shareedms_conf}->{parent_id}); + + my $pos_id=""; + my $return=0; + my $now_dt = strftime "%Y-%m-%d %H:%M", localtime; + my $dbh = ""; + my $response_state = "OK"; + my $response_text = ""; + + $bw->log("net_booking booking_request bikeIDin $bikeIDin, authID $auth->{c_id}","",""); + + my $ctadr = $db->get_contentrow("contentadr",$auth->{c_id}); + + my $pref = { + table => "contenttrans", + fetch => "one", + main_id => 300008, + template_id => 218, + #ca_id => "$ctadr->{c_id}",#TODO + int10 => "$ctadr->{c_id}", + state => "null", + close_time => "is::null", + }; + + + my $main_ids; + my ($bike_group,$user_group,$tariff_content,$user_tour) = $apif->fetch_tariff($ctadr,""); + $main_ids = join(",",@{$bike_group}); + $main_ids =~ s/[a-z_]+//ig; + my $ct = {}; + my $pref_cc = { + table => "content", + fetch => "one", + main_id => "IN::($main_ids)", + barcode => $db_bike, + int10 => 1, + }; + + $ct = $dbt->fetch_record($dbh,$pref_cc) if($main_ids); + + + + #$tariff_nr in contentadr are saved by COPRI OR user Tarif-Select!!! + #This is the automatic user tariff setter + my $tariff_nr = ""; + my @adr_tariff = (); + @adr_tariff = ("$ctadr->{txt30}"); + @adr_tariff = split(/\s+/,$ctadr->{txt30}) if($ctadr->{txt30} =~ /\w\s+\w/); + + if(ref($ct) eq "HASH" && $ct->{main_id}){ + foreach my $id (keys (%$tariff_content)){ + foreach(@adr_tariff){ + if($tariff_content->{$id}->{int12} && $tariff_content->{$id}->{int12} == $ct->{main_id} && $tariff_content->{$id}->{barcode} && $_ == $tariff_content->{$id}->{barcode}){ + $tariff_nr = $tariff_content->{$id}->{barcode}; + } + } + } + #2021-07-10, if no tarif then update user account to fallback default public or private or hidden tarif + #if(!$tariff_nr && !$ctadr->{txt30}) + if(!$tariff_nr){ + foreach my $id (keys (%$tariff_content)){ + # #int18 + # + # 2 = "public" + # 3 = "private" + # 4 = "hidden-lv" + # + if($tariff_content->{$id}->{int18} && ($tariff_content->{$id}->{int18} == 2 || $tariff_content->{$id}->{int18} == 3 || $tariff_content->{$id}->{int18} == 4)){ + if($tariff_content->{$id}->{int12} && $tariff_content->{$id}->{int12} == $ct->{main_id} && $tariff_content->{$id}->{barcode}){ + $tariff_nr = $tariff_content->{$id}->{barcode}; + } + } + } + $bw->log("--> NO user tariff defined, update user account to fallback default public or private or hidden",$tariff_nr,""); + $db->updater("contentadr","c_id",$ctadr->{c_id},"txt30","$tariff_nr",$owner); + }else{ + $bw->log("--> user tariff selected",$tariff_nr,""); + } + } + + $bw->log("---> bike $ct->{barcode} matching by bike_group: @{$bike_group} main_ids:$main_ids | user_group:@{$user_group} | Tarif selected: $tariff_nr",$tariff_content->{$tariff_nr},""); + + if($ct->{c_id} && $tariff_nr){ + my $ctt; + my $payoneable_check=0; + if(($ctadr->{int03} == 1 && $ctadr->{ct_name} =~ /\w{2}-\d+/ && $ctadr->{ct_name} !~ /LV-\d+/) || ($ctadr->{int03} == 2 && length($ctadr->{ct_name}) >= 19) || ($ctadr->{int03} == 1 && $varenv{dbname} eq "sharee_lv" && $ctadr->{ct_name} =~ /LV-\d+/)){ + $payoneable_check=1; + }else{ + $response_state="Failure 1006: There is no valid payment methode"; + $response_text="Bitte überprüfen Sie Ihre Profildaten auf Vollständigkeit, nur dann können wir das Fahrradmietsystem für Sie freischalten"; + } + + $bw->log("--->0. payable_check=$payoneable_check for $ctadr->{txt08} int01=$ctadr->{int01}|int03=$ctadr->{int03}|int04=$ctadr->{int04}|int13=$ctadr->{int13}|int12=$ctadr->{int12}|$ctadr->{ct_name}|length($ctadr->{ct_name}) >= 19\n","",""); + + #int04==1 if email Ack + #int13==1 if sms Ack + #int12!=1|2|3 if Vde + #int14==1 if AGB + if($ctadr->{txt08} && $ctadr->{int04} == 1 && $ctadr->{int13} == 1 && !$ctadr->{int12} && $ctadr->{int14} && $payoneable_check){ + + $bw->log("---> net_booking select Tarif ct->{main_id}:$ct->{main_id}| tariff_nr:$tariff_nr| ct_tariff --> Tarif-Nr:$tariff_content->{$tariff_nr}->{barcode}|Tarif desc:$tariff_content->{$tariff_nr}->{ct_name}|unit_price:$tariff_content->{$tariff_nr}->{int02}|max EUR/Tag:$tariff_content->{$tariff_nr}->{int17}|Abo EUR:$tariff_content->{$tariff_nr}->{int15}|Gratis Std/Rad:$tariff_content->{$tariff_nr}->{int16}\n","",""); + + $ctt = $dbt->fetch_record($dbh,$pref); + #if invoice exist + if($ctt->{c_id}){ + my $ctpos = {}; + if($bikeID && $ctadr->{c_id}){ + my $booking_pos = { + table => "contenttranspos", + fetch => "one", + barcode => "$db_bike", + int10 => "IN::('2','3')", + ca_id => "$ctadr->{c_id}", + }; + $ctpos = $dbt->fetch_tablerecord($dbh,$booking_pos); + } + if(!$ctpos->{c_id}){ + #2 = "requested" + $pos_id = $dbt->insert_pos($dbh,$ctt->{c_id},$ct,$ctadr,$tariff_content->{$tariff_nr},$now_dt,"$bikeID","2","$owner"); + if($pos_id){ + $response_state = "OK, bike " . $bikeID . " succesfully requested"; + $response_text = "Fahrrad Nr. $bikeID wurde erfolgreich für 15 Min. reserviert"; + $bw->log("--->2. (insert contenttranspos pos_id: $pos_id\n","",""); + #require "Mod/KMLout.pm"; + #my $kmlfile = Mod::KMLout::kmlGenerator($ctadr,""); + + $db->updater("contenttrans","c_id",$ctt->{c_id},"start_time","$now_dt",$owner); + $db->updater("contenttrans","c_id",$ctt->{c_id},"end_time","$now_dt",$owner); + }else{ + $response_state="Failure 1007: booking request fails"; + $response_text="Entschuldigung, es ist ein Fehler aufgetreten. Bitte kontaktieren Sie unsere Hotline damit wir das Problem lösen können"; + } + } + #else if invoice does not exist, generate one + }else{ + my $ct_id; + if($ctt->{c_id}){ + $ct_id = $ctt->{c_id}; + }else{ + $ct_id = $dbt->insert_contenttrans($dbh,$ctadr,"300008","218","----","$owner"); + $ctt = $dbt->fetch_record($dbh,$pref); + } + $ctt = $dbt->fetch_record($dbh,$pref); + + #TODO refactory, routines douple definend + if($ctt->{c_id}){ + my $ctpos = {}; + if($bikeID && $ctadr->{c_id}){ + my $booking_pos = { + table => "contenttranspos", + fetch => "one", + barcode => "$db_bike", + int10 => "IN::('2','3')", + ca_id => "$ctadr->{c_id}", + }; + $ctpos = $dbt->fetch_tablerecord($dbh,$booking_pos); + } + if(!$ctpos->{c_id}){ + #2 = "requested" + $pos_id = $dbt->insert_pos($dbh,$ctt->{c_id},$ct,$ctadr,$tariff_content->{$tariff_nr},$now_dt,"$bikeID","2","$owner"); + if($pos_id){ + $response_state = "OK, bike " . $bikeID . " succesfully requested"; + $response_text = "Fahrrad Nr. $bikeID wurde erfolgreich für 15 Min. reserviert"; + $bw->log("--->3. (insert contenttranspos pos_id: $pos_id\n","",""); + #require "Mod/KMLout.pm"; + #my $kmlfile = Mod::KMLout::kmlGenerator($ctadr,""); + + $db->updater("contenttrans","c_id",$ctt->{c_id},"start_time","$now_dt",$owner); + $db->updater("contenttrans","c_id",$ctt->{c_id},"end_time","$now_dt",$owner); + }else{ + $response_state="Failure 1008: booking request fails"; + $response_text="Entschuldigung, es ist ein Fehler aufgetreten. Bitte kontaktieren Sie unsere Hotline damit wir das Problem lösen können"; + } + } + } + } + }else{#end Vde AGB and payable_check + $response_state="Failure 1005: user-account deactivated because of failing data"; + $response_text="Bitte überprüfen Sie Ihre Profildaten auf Vollständigkeit, nur dann können wir das Fahrradmietsystem für Sie freischalten"; + } + + }else{ + my $ctpos = {}; + my $booking_pos = { + table => "contenttranspos", + fetch => "one", + barcode => "$db_bike", + int10 => "IN::('2','3')", + ca_id => "$ctadr->{c_id}", + }; + $ctpos = $dbt->fetch_tablerecord($dbh,$booking_pos) if($bikeID && $ctadr->{c_id}); + if($ctpos->{c_id}){ + $response_state = "OK, bike " . $bikeID . " already requested or occupied"; + $response_text = "Fahrrad Nr. " . $bikeID . " ist bereits reserviert"; + }elsif($ct->{c_id} && !$tariff_nr){ + $response_state="Failure 2089: booking bike $bikeID fails, no user tariff available"; + $response_text="Reservierungsfehler Fahrrad Nr. $bikeID. Es konnte kein Mietrad Tarif gefunden werden."; + }else{ + $response_state="Failure 2001: booking bike $bikeID fails, bike not available"; + $response_text="Fahrrad Nr. $bikeID ist leider nicht verfügbar. U.U. ist die Fahrrad Flotte für Sie nicht freigeschaltet. Bitte überprüfen Sie Ihre Profildaten auf Vollständigkeit"; + } + } + $bw->log("response_state:$response_state\n","",""); + + if(ref($auth) eq "HASH"){ + $return = { + bike => "$bikeID", + state => "requested", + response_state => "$response_state", + response_text => "$response_text" + }; + }else{ + if($response_state =~ /Failure/){ + $return = "failure::int01 $response_state"; + } + } + + return $return; +} + +#Send sms after payable check and !int13 +sub smsack(){ + my $self = shift; + my $ctadr = shift; + $smstrans->sms_ack_digest($ctadr); +} + +#Send email after payable check and !int04 +sub emailack(){ + my $self = shift; + my $c_id = shift; + my %varenv = $cf->envonline(); + system(`$varenv{basedir}/src/Mod/newsletter_tink.pl "$varenv{basedir}" "$varenv{wwwhost}" "emailack" "$c_id" ""`); +} + +#Password forgotten send email +sub send_password(){ + my $self = shift; + my ($email,$coo,$owner) = @_; + my %varenv = $cf->envonline(); + + $email = $q->escapeHTML($email); + $email =~ s/\s//g; + + my $pwmd5 = md5_hex($coo); + $db->updater("contentadr","1","1","txt11","$pwmd5","$owner","txt08","ilike","$email"); + + system(`$varenv{basedir}/src/Mod/newsletter_tink.pl "$varenv{basedir}" "$varenv{wwwhost}" "send_password" "$email" "$coo"`); +} + + +1; + diff --git a/copri4/main/src/Mod/ajax_json.pm b/copri4/main/src/Mod/ajax_json.pm new file mode 100644 index 0000000..09ead15 --- /dev/null +++ b/copri4/main/src/Mod/ajax_json.pm @@ -0,0 +1,68 @@ +package Mod::ajax_json; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use warnings; +use strict; +use POSIX; +use CGI; +use Apache2::Const -compile => qw(OK ); +use DBI; +use JSON; +use Mod::Libenzdb; +use Lib::Config; +use Data::Dumper; + +sub handler { + my ($r) = @_; + my $q = new CGI; + $q->import_names('R'); + my $db = new Libenzdb; + my $cf = new Config; + my %varenv = $cf->envonline(); + my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; + my $lang="de"; + my $main_id = $q->param('main_id'); + my $table = $q->param('table'); + my $search = $q->param('term'); + my @keywords = $q->param; + my @query_output = (); + my $debug=1; + + print $q->header(-type => "application/json", -charset => "utf-8"); + + open(FILE,">>/var/log/copri4/ajax_json.log") if($debug); + print FILE "$now_dt|$main_id\n" if($debug); + + foreach(@keywords){ + my @val = $q->param($_); + my $valxx = $q->escapeHTML("@val"); + if($_ eq "c_idadr"){ + $search = $valxx; + } + print FILE "$_: $valxx\n" if($debug); + } + + + if($table eq "content"){ + my $sth = $db->search_json("$table","$lang","$search","$main_id"); + while ( my $row = $sth->fetchrow_hashref ){ + push @query_output, $row; + } + print FILE Dumper(\@query_output) if($debug); + print JSON::to_json(\@query_output); + }elsif($table eq "contentadr"){ + my $sth = $db->search_jsonadr("$table","$lang","$search","$main_id",""); + while ( my $row = $sth->fetchrow_hashref ){ + push @query_output, $row; + } + print FILE Dumper(\@query_output) if($debug); + print JSON::to_json(\@query_output); + } + close(FILE) if($debug); + + return Apache2::Const::OK; +} +1; + diff --git a/copri4/main/src/Mod/ajax_post.pm b/copri4/main/src/Mod/ajax_post.pm new file mode 100644 index 0000000..9b4796e --- /dev/null +++ b/copri4/main/src/Mod/ajax_post.pm @@ -0,0 +1,96 @@ +package Mod::ajax_post; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# + +use strict; +use warnings; +use POSIX; +use CGI ':standard'; +use Apache2::Const -compile => qw(OK ); +use Scalar::Util qw(looks_like_number); +use Lib::Config; +use Mod::Libenzdb; +use Mod::Libenz; + +sub handler { + my ($r) = @_; + my $q = new CGI(); + $q->import_names('R'); + my @keywords = $q->param; + my $cf = new Config; + my $db = new Libenzdb; + my $lb = new Libenz; + my %varenv = $cf->envonline(); + my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; + my $lang = "de"; + print $q->header(-charset=>'utf-8'); + + open(FILE,">>$varenv{logdir}/ajax_post.log"); + print FILE "\n\nPost-start: $now_dt\n"; + foreach my $xkey (@keywords){ + my @val; + my $matrix_val; + my $tpl_id; + my $xval; + if($xkey =~ /^matrix_/){ + @val = $q->param($xkey); + foreach(@val){ + my ($key,$des,$size,$interval,$service_type) = split /=/,$_; + #print FILE "$key,$des,$size,$interval,$service_type\n"; + + my $interval = 0; + $interval = $q->param("interval_$key") if(looks_like_number($q->param("interval_$key"))); + my $service_type = 0; + $service_type = $q->param("servicetype_$key") if(looks_like_number($q->param("servicetype_$key"))); + print FILE "\n$key --> interval: $interval | service_type: $service_type\n"; + $matrix_val .= "$_=$interval=$service_type,";# if($interval =~ /(\d+)/); + } + $matrix_val =~ s/,$//; + #print FILE "$xkey: @val\n"; + #print FILE "matrix_val: $matrix_val\n"; + #}elsif($_ =~ /^ckid_rel|ckid_main|edit_main|post_request/){ + }else{ + my @xval = $q->param($xkey); + foreach(@xval){ + $xval .= "$_," if($_); + } + $xval =~ s/,$//; + print FILE "$xkey: $xval (owner: $R::owner)\n"; + } + + if($xkey =~ /c_id4trans/ && looks_like_number($R::owner) && looks_like_number($xval)){ + $db->update_ajaxes("users","","","","c_id4trans","$xval","$R::owner"); + } + + if($xkey =~ /matrix_users/ && $R::owner){ + $matrix_val = "" if($R::u_group =~ /supervisor/); + $db->update_ajaxes("users","","","","checkboxes","$matrix_val","$R::owner"); + } + if($xkey =~ /matrix_template/ && $R::template_id){ + $db->update_ajaxes("template","tpl_id","=","$R::template_id","tpl_order","$matrix_val",""); + print FILE "update_ajaxes(\"template\",\"tpl_id\",\"=\",\"$R::template_id\",\"tpl_order\",\"$matrix_val\")\n"; + } + if($xkey =~ /k9itemList_(\d+)/){ + $db->update_ajaxes("template","tpl_id","=","$1","tpl_order","$xval",""); + } + + #because of downward compatibility + if($xkey =~ /^ckid_rel/ && $R::owner){ + $db->update_ajaxes("users","","","","checked4dragg","$xval","$R::owner"); + } + if($xkey =~ /^ckid_main/ && $R::owner){ + $db->update_ajaxes("users","","","","view_list","$xval","$R::owner"); + } + if($xkey =~ /^edit_main/ && $R::owner){ + $db->update_ajaxes("users","","","","edit_list","$xval","$R::owner"); + } + + + } + close(FILE); + + return Apache2::Const::OK; +} +1; diff --git a/copri4/main/src/Mod/newsletter_tink.pl b/copri4/main/src/Mod/newsletter_tink.pl new file mode 100644 index 0000000..2415e25 --- /dev/null +++ b/copri4/main/src/Mod/newsletter_tink.pl @@ -0,0 +1,564 @@ +#!/usr/bin/perl -w +# +## SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +#TODO, migrate to MailTransport.pm +# +#su www-data -c "./src/Mod/newsletter_tink.pl '/var/www/copri4/shareeapp-operator' 'https://shareeapp-operator.copri-bike.de' 'emailack' '1842'" + +#on command +#sudo su www-data -c "./src/Mod/newsletter_tink.pl '/var/www/copri3/konrad' 'https://konrad.tink-konstanz.de' 'send_password' 'ragu@gnu-systems.de' '59e5c7bce6'" + +#su www-data -c "./src/Mod/newsletter_tink.pl '/var/www/copri3/tinkdms' 'https://tinkdms.copri.eu' 'send_invoice' '1842' '2866'" + + +use strict; +use warnings; +use utf8; +use Encode; +use CGI ':standard'; +use DBI; +use POSIX; +use Email::MIME; +use IO::All; +use Email::MIME::CreateHTML; +use Email::Sender::Simple qw(sendmail); +#use Email::Sender::Transport::SMTPS; +use Net::SMTP; +use Try::Tiny; +use Config::General; +use URI::Encode; +my $uri_encode = URI::Encode->new( { encode_reserved => 1 } ); +use Data::Dumper; + +use Sys::Hostname; +my $hostname = hostname; + +my $q = new CGI; +my $basedir = $ARGV[0]; +my $wwwhost = $ARGV[1]; +my $todo = $ARGV[2]; +my $c_id=""; +my $ct_name=""; +my $emailpw=""; +my $coopw=""; +if($todo =~ /emailack|send_invoice|send_capture_fail/){ + $c_id = $ARGV[3] || "";#contentadr.c_id + $ct_name = $ARGV[4] || "";#contenttrans.c_id +}elsif($todo eq "send_password"){ + $emailpw = $ARGV[3] || ""; + $emailpw =~ s/\s//g; + $coopw = $ARGV[4] || ""; +} + +my $today = strftime("%d.%m.%Y %H:%M:%S",localtime(time)); + +my $globalconf_file = "/var/www/copri4/shareeconf/global.cfg"; +my $gconf = Config::General->new($globalconf_file); +my %globalconf = $gconf->getall; + +my $mailx_file = "/var/www/copri4/shareeconf/mailx.cfg"; +my $mconf = Config::General->new($mailx_file); +my %mailxconf = $mconf->getall; + +require "$basedir/src/Lib/Config.pm"; +my %varenv = &Config::envonline("","$wwwhost"); +#print Dumper(%varenv); + +open(EMA, ">> $varenv{logdir}/newsletter_tink.log"); + print EMA "\n$today, start mailing\n"; + print EMA "'$today' '$basedir' '$wwwhost' '$todo' 'c_id:$c_id' 'invoice ct_name:$ct_name' 'emailpw:$emailpw' 'coopw:$coopw'\n"; +close EMA; + + +my $dbh = &dbconnect(); +sub dbconnect { + my $options =""; + my $dbh = DBI->connect("dbi:Pg:dbname=$varenv{dbname};host=$varenv{dbhost};port=5432;options='$options'", "$varenv{dbuser}", "$varenv{dbpassw}",{ RaiseError => 1, AutoCommit => 1 }) or die "Can't connect to $varenv{dbname}: $DBI::errstr"; + return $dbh; +} + +sub get_contentadr(){ + my ($c_id,$emailpw) = @_; + my $where="where ct.c_id=rel.content_id"; + $where .= " and ct.c_id=$c_id" if($c_id =~ /^\d+$/); + $where .= " and ct.txt08 ilike '$emailpw'" if($emailpw =~ /\w+/); + $where .= " and rel.template_id = 202";#tpl_id Adressen + my $sth = $dbh->prepare("SELECT * FROM contentadr ct, relation rel $where"); + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + return $ct; +} + +sub get_content(){ + my ($table,$c_id,$tpl_id) = @_; + my $where="where ct.c_id=rel.content_id"; + $where .= " and ct.c_id=$c_id" if($c_id =~ /^\d+$/); + $where .= " and rel.template_id = $tpl_id" if($tpl_id =~ /^\d+$/); + my $sth = $dbh->prepare("SELECT * FROM $table ct, relation rel $where"); + my $rc = $sth->execute(); + my $ct = $sth->fetchrow_hashref(); + return $ct; +} + +#update trivial, matchs anything +sub updater(){ + my ($table,$w_col,$w_val,$column,$content,$owner,$w_col2,$w_op2,$w_val2,$set_time) = @_; + my $ct_set = "mtime='now()'"; + if($set_time eq "no_time"){ + $ct_set = ""; + }elsif($table !~ /content/){ + $ct_set = "change='now()'"; + } + + if("$content" eq "null" || (!$content && $content !~ /^0$/)){ + $ct_set .= ",$column=null"; + }elsif($content || $content == 0){ + $ct_set .= ",$column='$content'"; + } + $ct_set .= ",owner='$owner'" if($owner); + $ct_set =~ s/^,/ /; + my $where = "$w_col='$w_val'"; + $where .= " and $w_col2 $w_op2 ($w_val2)" if("$w_col2" && "$w_op2" && "$w_val2"); + my $sth = $dbh->prepare("UPDATE $table SET $ct_set where $where"); + my $rows = $sth->execute(); + return $rows; +} + + +my $ctadr = &get_contentadr($c_id,$emailpw) if($c_id =~ /^\d+$/ || $emailpw =~ /\w+\@\w+/); + + my $smtp = Net::SMTP->new($mailxconf{mailx}->{mail_gateway}, + Port => 465, + Hello => 'fahrradspezialitaeten.com', + Timeout => 30, + Debug => 0, + SSL => 1, + ); + + + #$varenv{sasl_password} = Encode::encode('iso-8859-1', Encode::decode('utf-8', $varenv{sasl_password})); + $smtp->auth($mailxconf{mailx}->{sasl_username},$mailxconf{mailx}->{sasl_password}); + $smtp->mail($mailxconf{mailx}->{mail_from}); + +my $smtp_return = ""; +if($todo eq "emailack"){ + $smtp_return = &esender_success($smtp,$ctadr,$wwwhost); +}elsif($todo eq "send_password" && $ctadr->{txt08} =~ /\w+\@\w+/){ + $smtp_return = &esender_password($smtp,$ctadr,$coopw,$wwwhost); +}elsif($todo eq "send_invoice"){ + my $send_invoice; + $smtp_return = &esender_invoice($smtp,$todo,$ctadr,$ct_name,$wwwhost); + # if sendmail true then null. For us we need text + #if(!$smtp_return && $ct_name =~ /\d+/){ + if($ct_name =~ /\d+/){ + $today =~ s/:\d+$//; + $send_invoice = "$today, Rechnungsinfo per eMail versandt (debug: $smtp_return)"; + &updater("contenttrans","ct_name","$ct_name","txt30","$send_invoice","","","","","no_time"); + } +}elsif($todo eq "send_capture_fail"){ + $smtp_return = &esender_invoice($smtp,$todo,$ctadr,$ct_name,$wwwhost); +} +open(EMA, ">> $varenv{logdir}/newsletter_tink.log"); + print EMA "smtp_return: $smtp_return\n"; +close EMA; + + + +#Registration acknowledgement +sub esender_success { + my $smtp = shift; + my $ctadr = shift; + my $wwwhost = shift; + my %varenv = &Config::envonline("","$wwwhost"); + + my $ct = {}; + if($varenv{syshost} =~ /konrad|tink/i){ + $ct = &get_content("content","3435","1"); + $ct->{txt01} = $q->unescapeHTML($ct->{txt01}); + $ct->{txt01} =~ s/\r\n/
    /g; + $ct->{txt01} = Encode::encode('iso-8859-1', Encode::decode('utf-8', $ct->{txt01})); + }else{ + $ct = &get_content("contentuser",$globalconf{shareedms_conf}->{parent_node},"201"); + } + + + my $email = $q->unescapeHTML($ctadr->{txt08}); + my $anrede = $q->unescapeHTML($ctadr->{txt02}); + my $name = $q->unescapeHTML($ctadr->{txt01}); + $name = Encode::encode('iso-8859-1', Encode::decode('utf-8', $name)); + + my $strasse = $q->unescapeHTML($ctadr->{txt03}); + $strasse = Encode::encode('iso-8859-1', Encode::decode('utf-8', $strasse)); + + my $ort = $q->unescapeHTML($ctadr->{txt06}); + my $telefon = $q->unescapeHTML($ctadr->{txt07}); + + #Ack digest + my $ack_digest = $q->unescapeHTML($ctadr->{txt34}) || ""; + my $email_ack_digest = $1 if($ack_digest =~ /^(\w{5})/); + my $sms_ack_digest = $1 if($ack_digest =~ /(\w{5})$/); + + #disabled because of payone payment + #my $iban = $q->unescapeHTML($ctadr->{txt22}); + #$iban =~ s/.{3}$/XXX/; + #IBAN: $iban (letzte drei Ziffern maskiert) + + +#email html body--------------------------------------------------- +my $body; + +if($varenv{syshost} =~ /konrad|tink/i){ +my $encoded_email = $uri_encode->encode($ctadr->{txt08}); +$body = <www.konrad-konstanz.net?confirm_email=$encoded_email&confirm_code=$ctadr->{c_id} +Der Link führt Sie zur Website der Stadtwerke Konstanz. Damit sind Sie freigeschaltet. + +Falls Sie zur Eingabe eines Bestätigungscode aufgefordert werden, lautet dieser: $ctadr->{c_id} + +Die hinterlegten Zugangsdaten dienen zum Anmelden im Fahrradmietsystem der APP und im Browser www.konrad-konstanz.de + +Viel Spaß beim Radeln. + +EOF +; + +}else{#sharee + +my $encoded_email = $uri_encode->encode($ctadr->{txt08}); +$body = <$email_ack_digest
    + +Viel Spaß beim Radeln. +
    +$ct->{txt09} +$ct->{txt04} +$ct->{txt05} + +$ct->{txt08} +$ct->{txt11} +
    + + +EOF +; +} + + $body =~ s/\n/
    /g; + my $html = "$varenv{title}\n"; + $html .= "
    $body
    "; + #if($mandant eq "TINK"){ + # $html .= "
    "; + #} + if($varenv{syshost} =~ /konrad|tink/i){ + $html .= "
    $ct->{txt01}
    \n"; + } + $html .= ""; + + +#----------------------------------------------------------------- + + + my $subject = "$varenv{title} Anmeldebestätigung"; + if($hostname ne "$varenv{live_hostname}"){ + $email = $mailxconf{mailx}->{mail_testto}; + $subject .= "* offline Test *"; + } + + if ($smtp->to($email)) { + $smtp->data(); + $smtp->datasend("To: $email\n"); + $smtp->datasend("Subject: $subject\nMIME-Version: 1.0\nContent-Type: text/html; charset=UTF-8 \n\n"); + $smtp->datasend($html); + $smtp->dataend(); + } else { + print "Error: ", $smtp->message(); + } + + return "1. okay"; +} + +#Password forgotten +sub esender_password { + my ($smtp,$ctadr,$coopw,$wwwhost) = @_; + + my %varenv = &Config::envonline("","$wwwhost"); + + my $ct = {}; + if($varenv{syshost} =~ /konrad|tink/i){ + $ct = &get_content("content","3435","1"); + $ct->{txt01} = $q->unescapeHTML($ct->{txt01}); + $ct->{txt01} =~ s/\r\n/
    /g; + $ct->{txt01} = Encode::encode('iso-8859-1', Encode::decode('utf-8', $ct->{txt01})); + }else{ + $ct = &get_content("contentuser",$globalconf{shareedms_conf}->{parent_node},"201"); + } + + + my $email = $q->unescapeHTML($ctadr->{txt08}); + my $anrede = $q->unescapeHTML($ctadr->{txt02}); + my $name = $q->unescapeHTML($ctadr->{txt01}); + $name = Encode::encode('iso-8859-1', Encode::decode('utf-8', $name)); + + +#email html body--------------------------------------------------- +my $body; +if($varenv{syshost} =~ /konrad|tink/i){ +$body = <$coopw
    + +Nach Ihrem Login www.konrad-konstanz.de können Sie das Passwort in Ihrem Profil unter Kundendaten auch gerne wieder ändern. + +Viel Spaß beim Radeln. + +EOF +; + +}else{#sharee + +$body = <$coopw + +Nach Ihrem Login können Sie das Passwort in Ihrem NutzerInnen Konto unter 1.Kundendaten auch gerne wieder ändern. + +
    +Freundliche Grüße, +-- +$ct->{txt09} +$ct->{txt04} +$ct->{txt05} + +$ct->{txt08} +$ct->{txt11} +
    + +sharee.bike ist ein Angebot der TeilRad GmbH + +EOF +; +} + + $body =~ s/\n/
    /g; + my $html = "$varenv{title}\n"; + $html .= "
    $body
    "; + #if($mandant eq "TINK"){ + # $html .= "
    "; + #} + if($varenv{syshost} =~ /konrad|tink/i){ + $html .= "
    $ct->{txt01}
    \n"; + } + $html .= ""; + + +#----------------------------------------------------------------- + + + my $subject = "$varenv{title} Passwort vergessen"; + if($hostname ne "$varenv{live_hostname}"){ + $email = $mailxconf{mailx}->{mail_testto}; + $subject .= "* offline Test *"; + } + + if ($smtp->to($email)) { + $smtp->data(); + $smtp->datasend("To: $email\n"); + $smtp->datasend("Subject: $subject\nMIME-Version: 1.0\nContent-Type: text/html; charset=UTF-8 \n\n"); + $smtp->datasend($html); + $smtp->dataend(); + } else { + print "Error: ", $smtp->message(); + } + + return "2. okay"; +} + +#Send Invoice and capture_fails +sub esender_invoice { + my ($smtp,$todo,$ctadr,$ct_name,$wwwhost) = @_; + + my %varenv = &Config::envonline("","$wwwhost"); + my $ct = {}; + $ct = &get_content("contentuser",$globalconf{shareedms_conf}->{parent_node},"201"); + + #generate html for email-body + my $email = $q->unescapeHTML($ctadr->{txt08}); + my $anrede = $q->unescapeHTML($ctadr->{txt02}); + my $name = $q->unescapeHTML($ctadr->{txt01}); + $name = Encode::encode('iso-8859-1', Encode::decode('utf-8', $name)); + + +#email html body--------------------------------------------------- +my $subject; +my $body; +my $signature; + +if($varenv{syshost} =~ /konrad|tink/i){ +$signature = <Für Hinweise auf herumstehende Räder (gerne mit Radnummer, genauer Position und Fotos) aber auch Personen, die unsere Räder unrechtmäßig fahren oder beschädigen sind wir sehr dankbar. Sie erreichen uns über E-Mail (konrad\@fahrradspezialitaeten.com) und telefonisch über unsere Hotline: +49 761 45370099 (7 Tage/ 24 Stunden erreichbar). +Wenn Sie beobachten, wie jemand eines unserer Räder beschädigt, rufen Sie bitte unmittelbar die Polizei (Tel.:07531 995 2222) hinzu! + +Vielen Dank für Ihre Unterstützung! + +EOF +; +$signature =~ s/\n/
    /g; +} + +if($todo eq "send_invoice"){ + +#$subject = "TINK Rechnung"; +$subject = "Fahrradmietsystem Rechnung"; + +if($varenv{syshost} =~ /konrad|tink/i){ + +$body = <https://www.stadtwerke-konstanz.de/mobilitaet/rad-mietsystem für Sie bereit. +Nach dem Anmelden ist in Ihrem Nutzer Profil unter Verleihdaten die Rechnung als PDF hinterlegt. + +EOF +; +$body =~ s/\n/
    /g; + +}else{#sharee + +$body = < +Freundliche Grüße, +-- +$ct->{txt09} +$ct->{txt04} +$ct->{txt05} + +$ct->{txt08} +$ct->{txt11} + + +sharee.bike ist ein Angebot der TeilRad GmbH + +EOF +; +$body =~ s/\n/
    /g; +} + +}elsif($todo eq "send_capture_fail"){ + + +$subject = "Fahrradmietsystem Account"; + +if($varenv{syshost} =~ /konrad|tink/i){ + +$body = <https://www.stadtwerke-konstanz.de/mobilitaet/rad-mietsystem ) haben Sie die Möglichkeit Ihre Daten zu überprüfen und ggf. zu erneuern. +Kontaktieren Sie uns bitte falls Ihr Account für den Verleih nicht automatisch freigeschaltet wurde. + +Für weitere Fragen wenden Sie sich bitte an unsere Buchhaltung unter: buchhaltung\@fahrradspezialitaeten.com oder telefonisch 0761/5158912 (Mo, Mi, Fr 9-12 Uhr) + +EOF +; +$body =~ s/\n/
    /g; + +}else{#sharee + +$body = < +Freundliche Grüße, +-- +$ct->{txt09} +$ct->{txt04} +$ct->{txt05} + +$ct->{txt08} +$ct->{txt11} + + +sharee.bike ist ein Angebot der TeilRad GmbH + +EOF +; +$body =~ s/\n/
    /g; + +} + +} + + my $html = "\n"; + $html .= "
    $body
    \n"; + #$html .= "
    "; + $html .= "
    $signature
    \n"; + $html .= ""; + + +#----------------------------------------------------------------- + + + if($hostname ne "$varenv{live_hostname}"){ + $email = $mailxconf{mailx}->{mail_testto}; + $subject .= "* offline Test *"; + } + my $message; + + + if ($smtp->to($email)) { + $smtp->data(); + $smtp->datasend("To: $email\n"); + $smtp->datasend("Subject: $subject\nMIME-Version: 1.0\nContent-Type: text/html; charset=UTF-8 \n\n"); + $smtp->datasend($html); + $smtp->dataend(); + } else { + print "Error: ", $smtp->message(); + } + + return "3. okay"; +} + + + +open(EMA, ">> $varenv{logdir}/newsletter_tink.log"); + print EMA "\n$today, done mailing\n"; + print EMA "'$today' '$basedir' '$wwwhost' '$todo' '$ctadr->{txt08}'\n"; + print EMA "\n\n"; +close EMA; + +$smtp->quit; + +1; diff --git a/copri4/main/src/Tpl/APIdialog.pm b/copri4/main/src/Tpl/APIdialog.pm new file mode 100644 index 0000000..0bbd987 --- /dev/null +++ b/copri4/main/src/Tpl/APIdialog.pm @@ -0,0 +1,159 @@ +package APIdialog; +# +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; +use POSIX; +use CGI::Carp qw(fatalsToBrowser); +use CGI ':standard'; +use JSON; +#use Test::JSON; +use Scalar::Util qw(looks_like_number); +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::DBtank; +use Mod::APIfunc; +use Data::Dumper; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + + +#Template +sub tpl(){ + my $node_meta = shift; + my $users_dms = shift; + my $u_group = shift; + my $return = shift; + + my $q = new CGI; + my $json = JSON->new->allow_nonref; + my $cf = new Config; + my $lb = new Libenz; + my $dbt = new DBtank; + my $apif = new APIfunc; + my $but = new Buttons; + my $dbh = "";#$dbt->dbconnect(); + + my %varenv = $cf->envonline(); + my %ib = $but->ibuttons(); + my $tpl = $dbt->get_tpl($dbh,$node_meta->{template_id}); + my $tpl_order = $tpl->{tpl_order}; + #$tpl_order =~ s/barcode=Rad/barcode=Rad,txt09=Wartungsarbeiten=area/; + #$tpl_order =~ s/int04=Station/int04=Station,txt09=Wartungsarbeiten=area/ if($tpl->{tpl_id} == 403); + $tpl_order = "barcode=Rad,txt09=Wartungsprotokoll=area"; + $tpl_order = "int04=Station,txt09=Wartungsprotokoll=area" if($tpl->{tpl_id} == 403); + + my @tpl_order = split /,/,$tpl_order; + + my $edit="rel_edit"; + my $save_key = "service_done"; + my $ctrel = {}; + if(ref($return) ne "SCALAR" && $return =~ /shareejson/){ + my $tj = $json->pretty->decode($return); + foreach my $obj (keys (%{$tj->{shareejson}})){ + if($obj eq "service_id_done" && looks_like_number($tj->{shareejson}->{$obj})){ + my $c_id = $tj->{shareejson}->{$obj}; + my $fetch = { + table => "contentpos", + fetch => "one", + c_id => "$c_id", + }; + $ctrel = $dbt->fetch_tablerecord($dbh,$fetch); + + } + } + }else{ + print $q->div($return),"\n"; + return; + } + + my $u_name; + my $channel_map = $dbt->channel_map(); + my $mapref = {}; + my $ct_users = $dbt->users_map($dbh,$mapref);#get serviceAPP and DMS users from contentadr + + foreach my $id (sort { $channel_map->{$a} cmp $channel_map->{$b} } keys (%$channel_map)){ + if($id == $ctrel->{owner}){ + $u_name = $channel_map->{$id}; + } + } + if(!$u_name){ + foreach my $ctu_id (keys (%$ct_users)){ + if($ct_users->{$ctu_id}->{c_id} == $ctrel->{owner}){ + $u_name = $ct_users->{$ctu_id}->{txt01}; + } + } + } + $ctrel->{mtime} = $lb->time4de($ctrel->{mtime},"1") if($ctrel->{mtime}); + + print $q->hidden(-name=>'mode', -value=>"manager",-override=>1),"\n"; + print $q->hidden(-name=>'detail_search', -value=>"1",-override=>1),"\n"; + print $q->hidden(-name=>'owner', -value=>"$users_dms->{u_id}",-override=>1),"\n"; + print $q->hidden(-name=>'s_barcode', -value=>"$ctrel->{barcode}",-override=>1),"\n" if($ctrel->{barcode}); + print $q->hidden(-name=>'s_int04', -value=>"$ctrel->{int04}",-override=>1),"\n" if($ctrel->{int04}); + print $q->hidden(-name=>'service_id', -value=>"$ctrel->{c_id}",-override=>1),"\n"; + print $q->hidden(-name=>'main_id', -value=>"$node_meta->{main_id}",-override=>1),"\n"; + print $q->hidden(-name=>'template_id', -value=>"$node_meta->{template_id}",-override=>1),"\n"; + + + print "
    "; + + #1. table submit + print $q->start_table({-class=>'list', -border=>'0', -width=>'100%',-align=>'center', -cellpadding=>'3', -cellspacing=>'0'}); + print $q->Tr(); + print ""; + print $but->singlesubmit7("$edit","$save_key","$ib{$save_key}","margin:0 5px;"); + print $q->span({-style=>'margin-left:200px; font-size:1em;'}, "$u_name / $ctrel->{mtime} ID $ctrel->{c_id}"); + print "\n"; + print $q->end_table; + + print $q->start_table({-border=>'0', -width=>'100%',-align=>'center', -cellpadding=>'3', -cellspacing=>'0'}); + my $required=""; + my $autofocus=""; + foreach (@tpl_order){ + my ($key,$des,$size) = split /=/,$_; + #$des .= " ($key)" if($users_dms->{u_id} eq $varenv{superu_id}); + my $label_des = $des; + $ctrel->{$key} = $q->unescapeHTML("$ctrel->{$key}"); + $ctrel->{$key} = $lb->newline($ctrel->{$key},"","1"); + + if($key =~ /barcode|int04/){ + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + if(!$ctrel->{$key}){ + print $q->td({-class=>'content1_cms'},$q->textfield(-class=>'etxt', -style=>"",-name=>"s_$key", -default=>"$ctrel->{$key}", -autofocus=>1, -required=>1)),"\n"; + }else{ + print $q->td({-class=>'content1_cms'},"$ctrel->{$key}"),"\n"; + } + }elsif($key =~ /int/ && $size eq "checkbox"){ + my $ck_style = $but->checkbox_style($key,"cbox"); + print "$ck_style"; + my $checked = ""; + $checked = "checked" if($ctrel->{$key}); + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},""),"\n"; + print $q->td({-class=>'content1_cms'},$q->div("")),"\n"; + + }elsif($key =~ /txt/){ + my $h= 20;# if($size =~ /area(\d+)/); + print $q->Tr(); + print $q->td({-class=>'left_italic_cms',-style=>'vertical-align: top;', -colspan=>1},"$des"),"\n"; + print $q->td({-class=>'content1_cms'},$q->textarea(-class=>"autos", -style=>'border: 1px solid silver;',-rows=>"$h",-cols=>'60;', -name=>"$key", -override=>'1',-default=>"$ctrel->{$key}")),"\n"; + } + } + print $q->end_table,"\n"; + print $q->div($but->singlesubmit7("$edit","$save_key","$ib{$save_key}","margin:10px 20px;")),"\n"; + + print "
    "; + +} +1; diff --git a/copri4/main/src/Tpl/Address3.pm b/copri4/main/src/Tpl/Address3.pm new file mode 100644 index 0000000..66ee46d --- /dev/null +++ b/copri4/main/src/Tpl/Address3.pm @@ -0,0 +1,485 @@ +package Address3; +# +## +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; +use CGI; +use CGI::Carp qw(fatalsToBrowser); +use CGI ':standard'; +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Libenzdb; +use Mod::DBtank; +use Tpl::TransPositionen; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my ($node_meta,$users_dms,$return) = @_; + my $q = new CGI; + my $cf = new Config; + my $lb = new Libenz; + my $db = new Libenzdb; + my $dbt = new DBtank; + my $but = new Buttons; + my $transp = new TransPositionen; + my %varenv = $cf->envonline(); + my $script = $q->script_name(); + my $path_info = $q->path_info(); + my $path = $path_info; + #with meta_host, + if("$varenv{metahost}"){ + $path = "$script" . "$path_info"; + $script=""; + } + my $u_id = $users_dms->{u_id}; + my $lang = "de"; + + my $users = $db->select_users($u_id); + my $user_agent = $q->user_agent(); + my %ib = $but->ibuttons(); + my $line_count1; + + #get Firma + my $ctf = $db->get_content1("contentuser",$dbt->{shareedms_conf}->{parent_id}); + + my $rel4tpl = $db->get_rel4tpl("",$lang,$users_dms->{c_id4trans},$users_dms->{tpl_id4trans}); + my @tpl_order = split /,/,$rel4tpl->{tpl_order}; + my $node = $db->get_node4multi($rel4tpl->{main_id},$lang) if($rel4tpl->{main_id}); + if(!$node->{main_id} && $users->{owner}){ + $db->update_users4trans("0","0",$users_dms->{kind_of_trans},$users_dms->{u_id}); + $users = $db->select_users($u_id); + } + #edit marker for "question save" dialog + if($u_id && $R::trans2edit && $R::c_id4trans){ + $db->users_up("c_id4edit","$R::c_id4trans","$users->{owner}"); + } + my $ctx = $db->get_content1("contenttrans",$users_dms->{c_id4trans}); + my $c_idadr = $ctx->{int10};#c_id orig from contentadr + my $ctadr = $db->get_content1("contentadr",$c_idadr); + my $rel_adr = $db->get_rel4tpl("","$lang","$c_idadr","202"); + + #print "\nc_idadr Got it from contenttrans.int10: $c_idadr\n"; + # + #my $c_kdnr = $ctx->{txt14}; + #my $mandat; + #$mandat = " | Mandat $ctx->{txt26}" if($ctx->{txt26}); + + my $ctt = $ctx; + if(("$R::trans2edit" eq "client" && $R::c_idadr) || ($R::ct_trans eq "add_transadr")){ + $ctt = $db->get_content1("contentadr",$R::c_idadr); + $c_idadr = $ctt->{c_id}; + #print "c_idadr Got it from contentadr.c_id: $c_idadr\n"; + #$mandat = " | Mandat $ctt->{ct_name}" if($ctt->{ct_name}); + #$c_kdnr = $ctt->{ct_name}; + } + +print< + .ui-autocomplete { + text-align:left; + background:#eeeeee; + border:1px solid silver; + } + + + +EOF +; + + my $main_id = $rel4tpl->{main_id} || $ctx->{int12}; + my $set_main_id = $ctf->{txt22}; + + my @formular_relations=("$set_main_id:Typ auswählen ..."); + my @workflow_relations=("$set_main_id:Typ auswählen ..."); + my $nodes = $db->collect_node($dbt->{shareedms_conf}->{faktura}, "$lang"); + my $depends = "irgendeinzeichen"; + #$depends = "Storno" if(!$ctx->{close_time}); + foreach my $id (sort { $nodes->{$a}->{node_name} cmp $nodes->{$b}->{node_name} } keys (%$nodes)){ + push (@formular_relations, "$id:$nodes->{$id}->{node_path}") if(($main_id eq $id) || ($nodes->{$id}->{node_path} !~ /journal|bericht|offen|Storno|Vorauszahlungsrechnung|letzte|langzeit|OPOS|$depends/)); + push (@workflow_relations, "$id:$nodes->{$id}->{node_path}") if($nodes->{$id}->{node_path} !~ /journal|bericht|offen|Schlussrechnung|letzte|langzeit|OPOS|$node->{node_name}$|$ctx->{txt00}|$depends/); + } + + print "\n
    \n"; + if(!$users_dms->{c_id4trans} || !$users_dms->{tpl_id4trans}){ + $lb->failure3("Das Formular wurde gelöscht bzw. ist nicht vorhanden"); + } + + #######Verkauf Header + print $q->start_form(),"\n"; + print "\n
    \n"; + #submit Header + + my $invoice_time = ""; + if($ctt->{invoice_time}){#since 2020-03-16 will be set on Printpreview + $invoice_time = $lb->time4de($ctt->{invoice_time},1); + }else{ + $invoice_time = $lb->time4de($ctt->{mtime},1); + } + + my $channel_map = $dbt->channel_map(); + my $buchen_users = { txt01 => "" }; + if($channel_map->{$ctt->{owner}}){ + $buchen_users = { txt01 => "$channel_map->{$ctt->{owner}}" }; + }else{ + $buchen_users = $db->get_content1("contentadr",$ctt->{owner}); + } + + $set_main_id=$main_id if($rel4tpl->{main_id} > "300000"); + if(!$ctx->{close_time} && ($ctx->{txt00} !~ /Storno/)){ + my $ebutton = "ebutton"; + $ebutton = "ebutton4" if($ctx->{ct_name} !~ /\d+/ && $R::trans2edit ne "client"); + print $but->singlesubmit1("set_relation","set_relation","$ebutton","","Generiert RechnungNr. incl. payone Vorautorisierung (txid)"); + print $but->selector("set_main_id","11em",$set_main_id,@formular_relations); + }else{ + print $q->hidden(-name=>'set_main_id', -override=>'1', -value=>"$set_main_id"); + print $q->span({-style=>'padding:0.05em 3em;background-color:white;border:solid thin gray;'}, "$ctx->{txt00}"); + } + + print $q->b("\# $ctx->{ct_name}"); + print $q->span({-style=>'margin:0 0.2em;'}," | "); + if($ctx->{ct_name} =~ /\d+/){ + print $but->singlesubmit1("set_workflow","set_workflow"); + print $but->selector("set_main_id4workflow","11em","",@workflow_relations); + print $q->span({-style=>'margin:0 0.2em;'}," | "); + } + print $but->singlesubmit1("ct_trans","print_pdf"); + print $q->hidden(-name=>'printer_id', -override=>'1', -value=>"PDF"); + + if(!$ctt->{int01} || $ctt->{ct_name} =~ /-/){ + print $q->span({-style=>'margin:0 0.2em;position:absolute;right:3px;'}," $buchen_users->{txt01} / $invoice_time ", $but->singlesubmit7("ct_trans","remove_chk4rel","$ib{remove_chk4rel}","")),"\n"; + print $q->hidden(-name=>'c_id', -override=>'1', -value=>"$rel4tpl->{content_id}"); + print $q->hidden(-name=>'template_id', -override=>'1', -value=>"$rel4tpl->{template_id}"); + print $q->hidden(-name=>'main_id', -override=>'1', -value=>"$rel4tpl->{main_id}"); + print $q->hidden(-name=>'rel_id', -override=>'1', -value=>"$rel4tpl->{rel_id}"); + }else{ + print $q->span({-style=>'margin:0 0.2em;position:absolute;right:3px;'}," $buchen_users->{txt01} / $invoice_time "),"\n"; + } + print "
    \n"; + + print $q->hidden(-name=>'owner', -override=>'1', -value=>"$users->{owner}"); + print $q->hidden(-name=>'c_idadr', -override=>'1', -value=>"$c_idadr"); + print $q->hidden(-name=>'offset', -override=>'1', -value=>"$R::offset"); + print $q->hidden(-name=>'limit', -override=>'1', -value=>"$R::limit"); + print $q->hidden(-name=>'relids', -override=>'1', -value=>"$R::relids"); + print $q->hidden(-name=>'ct_name4workflow', -override=>1, -value=>"$ctx->{ct_name}"); + print $q->hidden(-name=>'p_template', -override=>'1', -value=>"$node->{node_path}"); + print $q->hidden(-name=>'c_id4trans', -override=>'1', -value=>"$ctx->{c_id}"); + print $q->hidden(-name=>'c_id4copy', -override=>'1', -value=>"$ctx->{c_id}"); + print $q->hidden(-name=>'close_time', -override=>'1', -value=>"$ctx->{close_time}"); + + print $q->end_form,"\n"; + print $q->div({-style=>'position:fixed;bottom:2%;right:1%;z-index:10;font-size:13px;'}," (c_id: $ctx->{c_id} | rel_id: $rel4tpl->{rel_id} | tpl_id: $rel4tpl->{tpl_id})"),"\n" if($u_id eq $varenv{superu_id}); + ########## + + + #Form for AdressData + print $q->start_form(-name=>'addressform'),"\n"; + #Big table + print $q->start_table({-class=>'list', -border=>'0', -width=>'100%',-align=>'left', -cellpadding=>'3', -cellspacing=>'0'}),"\n"; + + + print "\n"; + print $q->start_table({-class=>'list', -height=>'10em',-border=>'0', -width=>'100%',-align=>'left', -cellpadding=>'0', -cellspacing=>'0'}),"\n"; + ###Content #Edit Address --> template=Adressenliste + $ctt->{txt01} = $q->unescapeHTML("$ctt->{txt01}"); + if($u_id && ($R::trans2edit eq "client" || $R::ct_trans eq "add_transadr")){ + my @_anrede = ("","Frau","Herr","Firma"); + print $q->hidden(-name=>'c_id4trans', -override=>'1', -value=>"$ctx->{c_id}"),"\n";#c_id from contenttrans + print $q->hidden(-name=>'int10', -override=>'1', -value=>"$c_idadr"),"\n"; + #print $q->hidden(-name=>'txt26', -override=>'1', -value=>"$mandat"),"\n"; + print $q->hidden(-name=>'c_idadr', -override=>'1', -value=>"$c_idadr"),"\n"; + print $q->hidden(-name=>'rel_id', -override=>'1', -value=>"$rel4tpl->{rel_id}"),"\n"; + print $q->hidden(-name=>'u_id', -override=>'1', -value=>"$u_id"),"\n"; + print $q->Tr(),"\n"; + print ""; + print $but->singlesubmit7("ct_trans","save_adr","$ib{save_adr}","","","ebutton4"),"\n"; + #print $q->span($q->a({-class=>"ebutton3",-href=>'javascript:history.back()'}, " back ")); + print "\n"; + print $q->td({-class=>'tdval',-nowrap=>1}, $but->selector("txt02","60px",$ctt->{txt02},@_anrede)),"\n"; + #print $q->td({-class=>'tdval'}," ID $c_idadr $mandat"),"\n"; + print $q->td({-class=>'tdval'},"Kunden ID $c_idadr"),"\n"; + $ctt->{txt01} = $lb->newline($ctt->{txt01},"","1"); + print $q->Tr(),"\n"; + print $q->td({-class=>'tdescr'},"Vorname Name
    Zusatz"),"\n"; + print $q->td({-class=>'tdval',-colspan=>'2'},$q->textarea(-class=>'autos',-style=>'border:1px solid #ededed;background-color: #ededed;', -name=>'txt01', -default=>"$ctt->{txt01}", -rows=>1, -columns=>38)),"\n"; + print $q->Tr(),"\n"; + print $q->td({-class=>'tdescr'},"Straße Nr."),"\n"; + print $q->td({-class=>'tdval',-colspan=>'2',-nowrap=>1}, $q->textfield(-class=>'etxt',-name=>'txt03', -default=>"$ctt->{txt03}", -size=>'34', maxlength=>'45')),"\n"; + print $q->Tr(),"\n"; + print $q->td({-class=>'tdescr'},"PLZ Ort"),"\n"; + print $q->td({-class=>'tdval',-colspan=>'2'}, $q->textfield(-class=>'etxt',-name=>'txt06', -default=>"$ctt->{txt06}", -size=>'34', maxlength=>'45')),"\n"; + print $q->Tr(),"\n"; + print $q->td({-class=>'tdescr'},"eMail"),"\n"; + print $q->td({-class=>'tdval',-colspan=>'2'}, $q->textfield(-class=>'etxt',-name=>'txt08', -default=>"$ctt->{txt08}", -size=>'34', maxlength=>'45')),"\n"; + }elsif($u_id){ + print $q->Tr(),"\n"; + if(!$ctx->{close_time}){ + print ""; + print $but->singlesubmit2glyph("trans2edit","client","Kunden bearbeiten","background-color:white;"),"\n"; + print $q->hidden(-name=>'c_id4trans', -override=>'1', -value=>"$ctx->{c_id}"),"\n"; + #from json_selectadr + print $q->hidden(-id=>'c_idadr', -name=>"c_idadr", -override=>'1'),"\n"; + print $q->hidden(-id=>'vorname_name', -name=>"vorname_name", -override=>'1'),"\n"; + print $q->textfield(-style=>'border:1px solid silver;vertical-align: top;',-id=>"json_selectadr",-name=>"json_selectadr", -value=>""),"\n"; + print "\n"; + }else{ + print $q->td({-class=>'tdtxt'}," "),"\n"; + } + + print $q->td({-class=>'tdval'},"$ctt->{txt02}"),"\n"; + if($c_idadr && $rel_adr->{rel_id}){ + print $q->td({-class=>'tdval'},$q->span({-style=>"background-color:#dcd77f;"},$q->a({-class=>"linknav",-href=>"/$users->{fullurl}/Kunden?node2edit=editpart\&mode=manager\&rel_id=$rel_adr->{rel_id}\&tpl_id=202",-title=>"Kunden Stammdaten öffnen"}," Kunden ID $c_idadr ")), $q->span({-style=>"color:red;"}," $ctadr->{int12}")),"\n"; + } + if($ctt->{txt01} || $ctt->{txt02} || $ctt->{txt07} || $ctt->{txt08}){ + $ctt->{txt01} = $lb->newline($ctt->{txt01},"",""); + print $q->Tr(),"\n"; $line_count1++; + print $q->td({-class=>'tdtxt'}," "),"\n"; + print $q->td({-class=>'tdval',-colspan=>2},"$ctt->{txt01}"),"\n"; + print $q->Tr(),"\n"; $line_count1++; + print $q->td({-class=>'tdtxt'}," "),"\n"; + print $q->td({-class=>'tdval',-colspan=>2},"$ctt->{txt03}"),"\n"; + print $q->Tr(),"\n"; $line_count1++; + print $q->td({-class=>'tdtxt'}," "),"\n"; + print $q->td({-class=>'tdval',-colspan=>2},"$ctt->{txt06}"),"\n"; + print $q->Tr(),"\n"; $line_count1++; + print $q->td({-class=>'tdtxt'}," "),"\n"; + print $q->td({-class=>'tdval',-colspan=>2},"$ctt->{txt08}"),"\n"; + } + } + print $q->end_table; + print "\n"; + + my $txt20 = $ctt->{txt20} || $ctf->{txt80}; + my $int05 = ""; + $int05 = "(manuell)" if($ctt->{int05}); + + print "\n"; + print $q->start_table({-class=>'list', -border=>'0', -width=>'100%',-align=>'left', -cellpadding=>'0', -cellspacing=>'0'}),"\n"; + if($u_id && ($R::trans2edit eq "client" || $R::ct_trans eq "add_transadr")){ + print $q->Tr(),"\n"; + print $q->td({-class=>'tdescr'},"RFID"),"\n"; + print $q->td({-class=>'tdval'}, $q->textfield(-class=>'etxt',-name=>'txt09', -default=>"$ctt->{txt09}", -size=>'25', maxlength=>'40')),"\n"; + print $q->Tr(),"\n"; + print $q->td({-class=>'tdescr'},"Telefon"),"\n"; + print $q->td({-class=>'tdval'}, $q->textfield(-class=>'etxt',-name=>'txt07', -default=>"$ctt->{txt07}", -size=>'25', maxlength=>'40')),"\n"; + print $q->Tr(),"\n"; + print $q->td({-class=>'tdescr'},"Leistungsdatum"),"\n"; + print $q->td({-class=>'tdval'}, $q->textfield(-class=>'etxt',-name=>'txt20', -default=>"$txt20", -size=>'25', maxlength=>'60'),$but->checkbox("1","int05","$ctt->{int05}"),"manuell"),"\n"; + print $q->hidden(-name=>"int05",-override=>1,-value=>""); + }else{ + if($ctt->{txt09}){ + print $q->Tr(),"\n"; + print $q->td({-class=>'tdescr'},"RFID"),"\n"; + print $q->td({-class=>'tdval'},"$ctt->{txt09}"),"\n"; + } + if($ctt->{txt07}){ + print $q->Tr(),"\n"; + print $q->td({-class=>'tdescr'},"Telefon"),"\n"; + print $q->td({-class=>'tdval',-style=>'min-width:20em;'},"$ctt->{txt07}"),"\n"; + } + if($txt20){ + print $q->Tr(),"\n";$line_count1++; + print $q->td({-class=>'tdescr'},"Leistungsdatum"),"\n"; + if($ctt->{txt20}){ + print $q->td({-class=>'tdval'},"$ctt->{txt20} $int05"),"\n"; + }else{ + print $q->td({-class=>'tdval'},"Zur Info: Anhand der Einstellung werden nur Positionen bis Buchungsdatum \"$ctf->{txt80}\" erfasst. Für Buchungen neueren Datums wird nach dem \"buchen\" eine weitere Rechnung generiert."),"\n"; + } + } + } + + #payone is working? + #keep in mind + #$ctx is primarly contenttrans + #$ctt = $ctx + #$ctt will partly overwritten by contentadr if address changes + my $pay_sequence = " | sequencenr: $ctt->{int18}" if($ctt->{int18}); + if($ctt->{int03} && $ctt->{txt16}){ + my @_paymentstate = split(/\|/,$varenv{Zahlungsweise}); + my $kind_of_payment = "fehlt"; + $kind_of_payment = "$_paymentstate[0]" if($ctt->{int03} == 1); + $kind_of_payment = "$_paymentstate[1]" if($ctt->{int03} == 2); + print $q->Tr(),"\n"; + print $q->td({-class=>'tdescr'},"Payone Zahlungsart"),"\n"; + print $q->td({-class=>'tdval'},"$kind_of_payment"),"\n"; + print $q->Tr(),"\n"; + print $q->td({-class=>'tdescr'},"Payone TXID"),"\n"; + print $q->td({-class=>'tdval'},"$ctt->{txt16}"),"\n"; + print $q->Tr(),"\n"; + print $q->td({-class=>'tdescr'},"Payone Saldo"),"\n"; + print $q->td({-class=>'tdval'},"$ctt->{int16} $pay_sequence"),"\n"; + if($ctt->{txt28} =~ /error/i){ + print $q->Tr(),"\n"; + print $q->td({-class=>'tdescr'},"payone error"),"\n"; + print $q->td({-class=>'tdval'},"(transaction) $ctt->{txt28}"),"\n"; + } + }else{ + #check payone status + if($ctt->{txt28} =~ /error/i){ + print $q->Tr(),"\n"; + print $q->td({-class=>'tdescr'},"payone error"),"\n"; + print $q->td({-class=>'tdval'},"(transaction) $ctt->{txt28}"),"\n"; + }elsif($ctadr->{txt28} =~ /error/i){ + print $q->Tr(),"\n"; + print $q->td({-class=>'tdescr'},"payone error"),"\n"; + print $q->td({-class=>'tdval'},"(address) $ctadr->{txt28}"),"\n"; + } + + } + + + print $q->end_table; + print "\n"; + + ###end + print $q->end_form,"\n"; + + + ###Content #Edit Parts + print "\n"; + + #require "Tpl/TransPositionen.pm"; + my $line_count2 = $transp->tpl($node_meta,$users_dms,$set_main_id,$rel4tpl->{main_id},$rel4tpl->{rel_id},$ctx->{c_id},$u_id,$lang,"$return","$node->{node_name}"); + + print "\n"; + ###end Edit Parts + + #Text & Vorbelegungen + my $tplf = $db->get_tpl("201");#Firma tpl + my @tplf_order = split /,/,$tplf->{tpl_order}; + + + print $q->start_form(),"\n"; + print "\n"; + print $q->start_table({-class=>'list', -border=>'0', -width=>'100%',-align=>'left', -cellpadding=>'0', -cellspacing=>'0'}),"\n"; + + + print $q->Tr(),"\n"; + print $q->td({-class=>'tdval4',-colspan=>"2"},$q->span({-style=>'font-weight:bold;'},"Internas und Bearbeitungstatus")),"\n"; + if($varenv{order_state}){ + print $q->Tr(),"\n"; + my @_orderstate = split(/\|/,$varenv{order_state}); + print $q->td({-class=>'tdval4',-colspan=>2},$but->selector("txt22","180px",$ctt->{txt22},@_orderstate)),"\n"; + } + $ctt->{txt23} = $q->unescapeHTML("$ctt->{txt23}") if($ctt->{txt23}); + print $q->Tr(),"\n"; + print $q->td({-class=>'tdval4',-colspan=>'2'},$q->textarea(-class=>'etxt',-name=>'txt23', -default=>"$ctt->{txt23}", -rows=>4, -columns=>90)),"\n"; + + print $q->hidden(-name=>'c_id4trans', -override=>'1', -value=>"$ctx->{c_id}"); + print $q->hidden(-name=>'set_main_id', -override=>'1', -value=>"$set_main_id"),"\n"; + my $ebutton = "ebutton"; + $ebutton = "ebutton4" if($ctx->{ct_name} && $ctx->{ct_name} =~ /\d+/ && !$R::trans2edit && !$ctt->{txt12} && $ctt->{txt21} && $ctt->{txt21} !~ /\,/); + print $q->Tr(),"\n"; + print $q->td({-class=>'tdval',-colspan=>2}, $but->singlesubmit7("ct_trans","save_text_internas","$ib{save_text}","","","$ebutton")),"\n" if($ctx->{close_time}); + + + if($ctx->{close_time}){ + print $q->end_form,"\n"; + print $q->start_form(),"\n"; + } + + print $q->Tr(),"\n"; + print $q->td({-class=>'tdval4',-colspan=>"2"},$q->span({-style=>'font-weight:bold;'},"PDF Formular Texte "),$q->span({-style=>'color:silver;font-weight:normal;'}," ( z.T. Definitionen aus Einstellung/Firma )")),"\n"; + + #Zahlungstexte + foreach(@tplf_order){ + my ($key,$des,$size) = split /=/,$_; + if($key =~ /txt5/ && $ctf->{$key}){ + my @line_txt = split(/\n/,$ctf->{$key}); + $line_count1 += scalar(@line_txt); + $ctf->{$key} = $q->unescapeHTML("$ctf->{$key}"); + $ctf->{$key} = $lb->newline($ctf->{$key},"",""); + if("$des" =~ /$ctt->{state}/){ + print $q->Tr(),"\n"; $line_count1++; + if($ctt->{int01} < 0){ + #print $q->td({-class=>'tdval4',-style=>'width:8em;'},"Gutschrift Text"),"\n"; + print $q->td({-class=>'tdval4',-colspan=>2},"$ctf->{txt58}"),"\n"; + }else{ + #print $q->td({-class=>'tdval4',-style=>'width:8em;'},"$des"),"\n"; + print $q->td({-class=>'tdval4',-colspan=>2},"$ctf->{$key}"),"\n"; + } + } + } + } + + + $ctt->{txt12} = $q->unescapeHTML($ctt->{txt12}) || ""; + print $q->Tr(),"\n"; + print $q->td({-class=>'tdval4',-colspan=>'2'},$q->textarea(-class=>'etxt',-name=>'txt12', -default=>"$ctt->{txt12}", -rows=>4, -columns=>90)),"\n"; + + print $q->Tr(),"\n"; $line_count1++; + my @line_txt12 = split(/\n/,$ctt->{txt12}); + $line_count1 += scalar(@line_txt12); + + #Vorbelegung-Text + my $formular_text = ""; + my $set_text_id; + #at first empty checkbox definition (txt21='txt61,txt62,...') + print $q->hidden(-name=>"off_txt21",-override=>1,-value=>""); + foreach(@tplf_order){ + my ($key,$des,$size) = split /=/,$_; + if($key =~ /txt6/ && $ctf->{$key}){ + $ctf->{$key} = $q->unescapeHTML("$ctf->{$key}"); + my $substrtxt = $lb->sub4txt($ctf->{$key},"0","14"); + my $check=""; + $check=1 if($ctt->{txt21} && $ctt->{txt21} =~ /$key/); + $formular_text .= " [ $key $substrtxt..." . $but->checkbox("$key","$key","$check","$ctf->{$key}") . " ] "; + if($ctt->{txt21} && $ctt->{txt21} =~ /$key/){ + my @line_key = split(/\n/,$ctf->{$key}); + $line_count1 += scalar(@line_key); + $ctf->{$key} = $lb->newline($ctf->{$key},"",""); + print $q->Tr(); $line_count1++; + print $q->td({-class=>'tdval4',-colspan=>2},"$ctf->{$key}"),"\n"; + } + } + } + ### + + print $q->hidden(-name=>'c_id4trans', -override=>'1', -value=>"$ctx->{c_id}"),"\n"; + print $q->hidden(-name=>'set_main_id', -override=>'1', -value=>"$set_main_id"),"\n"; + my $ebutton = "ebutton"; + $ebutton = "ebutton4" if($ctx->{ct_name} && $ctx->{ct_name} =~ /\d+/ && !$R::trans2edit && !$ctt->{txt12} && $ctt->{txt21} !~ /\,/); + print $q->Tr(),"\n"; + print $q->td({-class=>'tdval',-colspan=>2}, $but->singlesubmit7("ct_trans","save_text","$ib{save_text}","","","$ebutton"),"$formular_text"),"\n" if(!$ctx->{close_time}); + + print $q->end_table,"\n"; + print "\n"; + + print $q->end_form,"\n"; + + print $q->end_table,"\n"; + ###end Big + + + $line_count2 = "0" . "$line_count2" if($line_count2 < 10); + my $line_count = "$line_count1.$line_count2"; + #print $q->div({style=>'font-size:0.81em;'},"line to print -> address+text: $line_count1 | table: $line_count2"),"\n"; + print "
    \n"; + $db->update_content4change2("contenttrans",$ctx->{c_id},"$line_count","int04") if($ctx->{c_id}); + return $line_count; +} +1; diff --git a/copri4/main/src/Tpl/AttributEdit.pm b/copri4/main/src/Tpl/AttributEdit.pm new file mode 100644 index 0000000..5e273f3 --- /dev/null +++ b/copri4/main/src/Tpl/AttributEdit.pm @@ -0,0 +1,146 @@ +package AttributEdit; +# +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; +use CGI::Carp qw(fatalsToBrowser); +use CGI ':standard'; +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Libenzdb; +use Mod::DBtank; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my $node_meta = shift; + my $users_dms = shift; + my $mode = shift; + my $return = shift; + + my $q = new CGI; + my $cf = new Config; + my $lb = new Libenz; + my $db = new Libenzdb; + my $dbt = new DBtank; + my $but = new Buttons; + + my %varenv = $cf->envonline(); + my $script = $q->script_name(); + my $path = $q->path_info(); + my %ib = $but->ibuttons(); + my $dbh = ""; + my $tpl = $db->get_tpl($R::tpl_id);#Master template + my @tpl_order = split /,/,$tpl->{tpl_order}; + + my @_attr; + my $asort=0; + my $des_name; + my $key_txt; + my $checked_txt; + my $key_txtarea; + my $checked_txtarea; + my $key_int; + my $checked_int; + my $key_intcheck; + my $checked_intcheck; + my ($key,$des,$size); + foreach (@tpl_order){ + $asort++; + ($key,$des,$size) = split /=/,$_; + #push (@_attr, "$key") if($key); + if("$key" eq "$R::key"){ + $des_name = $des; + if($key =~ /ct_name/){ + last; + } + elsif($key =~ /txt(\d+)/ && $size =~ /area/){ + $key_txtarea = $1; + $checked_txtarea = "checked"; + last; + } + elsif($key =~ /txt(\d+)/){ + $key_txt = $1; + $checked_txt = "checked"; + last; + } + elsif($key =~ /int(\d+)/ && $size =~ /checkbox/){ + $key_intcheck = $1; + $checked_intcheck = "checked"; + last; + } + elsif($key =~ /int(\d+)/){ + $key_int = $1; + $checked_int = "checked"; + last; + } + } + } + + $tpl->{change} = $lb->time4de($tpl->{change},"1") if($tpl->{change}); + my $u_name = $tpl->{owner}; + + $u_name = $dbt->sys_username($dbh,$tpl->{owner}); + + print "
    "; + print $q->hidden(-name=>'key', -value=>"$R::key",-override=>'1'); + + print $q->start_table({-class=>'list', -border=>'0', -width=>'100%', -align=>'left', -cellpadding=>'3', -cellspacing=>'3'}); + #Buttons + print $q->Tr(); + print "\n"; + print $but->singlesubmit7("rel_edit","save_attrtpl","",""); + print $but->singlesubmit7("rel_edit","remove_chk4attr","","margin-left:10px;"); + #print $but->singlesubmit9("dummy","zurück","","ebutton","",""); + print $q->span({-style=>'margin-left:5em; font-size:0.91em;'}, "$u_name / $tpl->{change}"); + print "\n"; + + print $q->Tr(); + print $q->td({-colspan=>'2'}," "); + print $q->Tr(); + print $q->td({-class=>'tdescr'}, "Service Datenfeldname"),"\n"; + print $q->td({-class=>'tdval'},$q->textfield(-class=>'etxt',-name=>"des", -override=>'1',-default=>"$des_name")),"\n"; + if($key =~ /txt|int/){ + print $q->Tr(); + print $q->td({-class=>'tdescr'}, "Datentyp"),"\n"; + print "\n"; + if($R::key =~ /txt/){ + print $but->radiobox("txt","key_typ","$checked_txt"),"Textzeile\n"; + print $but->radiobox("txt_area","key_typ","$checked_txtarea"),"Textarea\n"; + }elsif($R::key =~ /int/){ + print $but->radiobox("int","key_typ","$checked_int"),"Dezimalzahl\n"; + print $but->radiobox("int_checkbox","key_typ","$checked_intcheck"),"Checkbox\n"; + } + print "\n"; + } + print $q->Tr(); + print $q->td({-class=>'tdescr'},"Sortierung"),"\n"; + print $q->td({-class=>'tdval'},$q->textfield(-class=>'etxt', -name=>"asort", -default=>"$asort")),"\n"; + #print $q->Tr(); + #print $q->td({-class=>'tdescr'},"Text Vorauswahl"),"\n"; + #my $pre_values = $q->unescapeHTML("$ctf->{$R::key}"); + #print $q->td({-class=>'tdval'},$q->textarea(-id=>"prev", -class=>'etxt',-style=>"width:300px;",-rows=>"1", -name=>"pre_values",-default=>"$pre_values", -override=>'1')),"\n"; + #print ""; + #print $q->hidden(-name=>'cuid_glob', -value=>"$cuid_glob",-override=>'1'); + + #print $q->Tr(); + #print $q->td({-class=>'tdescr',-colspan=>'2'},""),"\n"; + #print $q->Tr(); + #print $q->td({-class=>'tdescr',-colspan=>'2'},"Achtung, das löschen oder ändern verursacht Datenverlust."),"\n"; + + print $q->end_table; + + print "
    "; +} +1; + diff --git a/copri4/main/src/Tpl/AttributMatrix.pm b/copri4/main/src/Tpl/AttributMatrix.pm new file mode 100644 index 0000000..aa08c1c --- /dev/null +++ b/copri4/main/src/Tpl/AttributMatrix.pm @@ -0,0 +1,205 @@ +package AttributMatrix; +# +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; +use CGI::Carp qw(fatalsToBrowser); +use CGI ':standard'; +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Libenzdb; +use Mod::DBtank; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my $node_meta = shift; + my $users_dms = shift; + my $mode = shift; + my $return = shift; + + my $q = new CGI; + my $cf = new Config; + my $lb = new Libenz; + my $db = new Libenzdb; + my $but = new Buttons; + my $dbt = new DBtank; + + my %varenv = $cf->envonline(); + my $script = $q->script_name(); + my $path_info = $q->path_info(); + my $path = $path_info; + if("$varenv{metahost}"){ + $path = "$script" . "$path_info"; + $script=""; + } + my $dbh = ""; + my $lang = "de"; + my %ib = $but->ibuttons_arch(); + + my @viewsel = split /\//,$1 if($path =~ /^\/(.*)/); + + my $tpl_master = $db->get_tpl("400"); + my @tpl_masterorder = (); + my $node = {}; + + if($users_dms->{int08} == 2){ +print< + + \$(function() { + function postValues() { + var data = \$("input[type='checkbox'], input[type='text'], input[type='hidden']").serialize(); + \$.ajax({ + url: '$varenv{wwwhost}/ajax_post', + type: 'POST', + async: true, + cache: false, + data: data, + }); + } + \$("input[type='checkbox']").on( "click", postValues ); + \$("input[type='text']").on( "change", postValues ); + + }); + +EOF +; + } + + if($users_dms->{int08} >= 1){ + @tpl_masterorder = split /,/,$tpl_master->{tpl_order}; + my $pref = { template_id1 => 401, + template_id2 => 499, + fetch => "all", + keyfield => "main_id", + }; + $node = $dbt->fetch_rel4tpl4nd($dbh,$pref); + }else{ + $return = "failure::Abbruch. Keine Zugriffsberechtigung"; + } + + + sub checkbox_style2() { + my ($sid_key,$dialog) = @_; + my $ck_style = "\n"; + return $ck_style; + } + + print "
    \n"; + + print $q->div({-class=>"copri_header",-style=>"background-color:#cccccc;"},"$path",$q->span("(shareetool Datenfeld Matrix)")); + + print $q->start_form(); + print $q->hidden(-name=>'mode', -override=>1, -value=>"supervisor"); + + #table header + print $q->start_table({-border=>'0', -width=>'100%',-align=>'center', -cellpadding=>'0', -cellspacing=>'0'}); + print $q->Tr(); + if($users_dms->{int08} == 2){ + #print $q->th({-style=>'text-align:right;padding:1px 3px;font-size:1em;'},"Datenfeld", $but->singlesubmit2("rel_edit","new_attrtpl_int","$ib{new_attrtpl_int}","background-color:silver;"), $but->singlesubmit2("rel_edit","new_attrtpl_txt","$ib{new_attrtpl_txt}","background-color:silver;")),"\n"; + print $q->th({-style=>'text-align:right;padding:1px 3px;font-size:1em;'},"Datenfeld", $but->singlesubmit2glyph("rel_edit","new_attrtpl_int","$ib{new_attrtpl_int}","background-color:silver;")),"\n"; + }else{ + print $q->th({-style=>'text-align:right;padding:1px 3px;font-size:1em;'},""),"\n"; + } + #foreach my $id (sort {$node->{$a}->{n_sort} <=> $node->{$b}->{n_sort}} keys (%$node)){ + foreach my $id (sort {$node->{$a}->{node_name} cmp $node->{$b}->{node_name}} keys (%$node)){ + if($node->{$id}->{template_id}){ + if($node->{$id}->{main_id} == $node_meta->{main_id}){ + print $q->hidden(-name=>'template_id',-override=>'1', -value=>"$node->{$id}->{template_id}"); + print $q->th({-class=>'thmatrix',-nowrap=>1,-colspan=>2}, $q->b("$node->{$id}->{node_name}")),"\n"; + }else{ + if($users_dms->{int08} == 2){ + my $uri_path = $dbt->recurse_node($dbh,$node->{$id}->{main_id}); + print $q->th({-class=>'thmatrix',-nowrap=>1,-colspan=>2}, $q->a({-class=>"sortnav",-href=>"/$uri_path/supervisor",-title=>'aktivieren'}, "$node->{$id}->{node_name}")),"\n"; + }else{ + print $q->th({-class=>'thmatrix',-nowrap=>1,-colspan=>2},"$node->{$id}->{node_name}"),"\n"; + } + } + } + } + + #table content + my $j=0; + my $set_style; + my $checked=""; + #tpl_id=400 + foreach (@tpl_masterorder){ + $j++; + $set_style = "background-color:#fcfdfb;"; + $set_style = "background-color:#f4f1ee;" if($j %= 2); + print $q->Tr(); + my ($m_key,$m_des,$m_size) = split /=/,$_; + if($m_key !~ /img|time|c_id|barcode|int04|owner/){#static + print $q->td({-class=>'tdtxtw', -style=>"$set_style"},$q->a({-class=>'sortnav',-href=>"/$viewsel[0]/$viewsel[1]/$viewsel[2]/supervisor?node2edit=edit_template\&tpl_id=$tpl_master->{tpl_id}\&key=$m_key", -title=>"edit ($j)"},"$m_des")),"\n"; + }else{ + print $q->td({-class=>'tdtxtw', -style=>"$set_style"},$q->a({-class=>'sortnav',-href=>"#", -title=>"static"},"$m_des")),"\n"; + } + foreach my $id (sort {$node->{$a}->{node_name} cmp $node->{$b}->{node_name}} keys (%$node)){ + my $cat_off=""; + my $m_style="margin:auto;width:16px;height:16px;background-color:#cccccc;"; + my $interval=""; + #tpl_id > 400 and depends on node + if($node->{$id}->{tpl_order} =~ /$m_key=[a-z0-9-_ ]+=[a-z0-9-_]+=(\d+)/i){ + $interval = $1; + } + my $service_type=""; + if($node->{$id}->{tpl_order} =~ /$m_key=[a-z0-9-_ ]+=[a-z0-9-_]+=\d+=(\d+)/i){ + $service_type = $1; + } + + if($node->{$id}->{main_id} == $node_meta->{main_id}){ + my $ck_style = &checkbox_style2($m_key,"attr"); + print "$ck_style"; + $checked=""; + $checked="checked" if($node->{$id}->{tpl_order} =~ /$m_key/); + }else{ + $cat_off=1; + $m_style="margin:auto;width:16px;height:16px;background-color:#717171;" if($node->{$id}->{tpl_order} =~ /$m_key/); + } + #my @tpl_node = split /,/,$node->{$id}->{tpl_order}; + foreach (@tpl_masterorder){ + my ($key,$des,$size) = split /=/,$_; + if($m_key eq $key){ + if($cat_off){ + my $itext = ""; + my $ytext = ""; + if($interval){ + $itext = "$interval Tage Intervall"; + $ytext = ""; + $ytext = " | weich=1" if($service_type eq 1); + } + $ytext = " | hart=2" if($service_type eq 2); + print $q->td({-class=>'tdtxtc', -style=>"$set_style"},$q->div({-style=>"$m_style"},"")),"\n"; + print $q->td({-class=>'tdtxtc', -style=>"$set_style text-align:left"},$q->div({-style=>""},"$itext $ytext")),"\n"; + }else{ + #print $q->td({-class=>'tdtxtc', -style=>"$set_style"},$q->div({ -class => "sq_attr$key" },"")),"\n"; + print $q->td({-class=>'tdtxtc', -style=>"$set_style"},$q->div({ -class => "sq_attr$key" },"")),"\n"; + print $q->td({-class=>'tdtxtc', -style=>"$set_style text-align:left;"}, $q->textfield(-class=>'etxt',-size=>'1',-name=>"interval_$key", -override=>'1',-default=>"$interval"), "Tage Intervall | Typ ", $q->textfield(-class=>'etxt',-size=>'1',-name=>"servicetype_$key", -override=>'1',-default=>"$service_type")),"\n"; + } + } + } + } + } + + print $q->end_table; + print $q->end_form; + + print "
    \n"; + return $return; +} +1; diff --git a/copri4/main/src/Tpl/BaseEdit.pm b/copri4/main/src/Tpl/BaseEdit.pm new file mode 100644 index 0000000..bad5018 --- /dev/null +++ b/copri4/main/src/Tpl/BaseEdit.pm @@ -0,0 +1,608 @@ +package BaseEdit; +# +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +#use lib "/var/www/copri4/shareedms-primary/src"; +# +use strict; +use warnings; +use POSIX; +use CGI::Carp qw(fatalsToBrowser); +use CGI ':standard'; +use Lib::Config; +use Mod::Buttons; +use Date::Calc qw(:all); +use Mod::Libenz; +use Mod::Libenzdb; +use Mod::Basework; +use Mod::DBtank; +use Mod::APIfunc; +use Data::Dumper; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my $node_meta = shift; + my $users_dms = shift; + my $u_group = shift; + my $return = shift; + + my $q = new CGI; + my $cf = new Config; + my $lb = new Libenz; + my $db = new Libenzdb; + my $bw = new Basework; + my $dbt = new DBtank; + my $apif = new APIfunc; + my $but = new Buttons; + my %ib = $but->ibuttons(); + + my %varenv = $cf->envonline(); + my $lang = "de"; + my $dbh = ""; + #print $dbt->{operator}->{$varenv{dbname}}->{oprefix}; + + my $rel_id = $1 if($R::rel_id && $R::rel_id =~ /(\d+)/); + my $u_id = $1 if($R::u_id && $R::u_id =~ /(\d+)/); + $u_id = $1 if($R::c_idadr && $R::c_idadr =~ /(\d+)/ && $R::base_edit eq "new_dmsusers"); + my ($edit,$copy_key,$save_key,$relate_key,$move_key,$delete_key,$package_key); + my $tpl; + my @tpl_order; + my $edit_template; + my $bg_color = "grey"; + my $ctrel = {}; + if($node_meta->{ct_table} eq "content" && $node_meta->{tpl_id}){ + my $ref = { + table => "$node_meta->{ct_table}", + fetch => "one", + template_id => "$node_meta->{tpl_id}", + rel_id => "$rel_id", + }; + $ctrel = $dbt->fetch_record($dbh,$ref); + print $q->hidden(-name=>'c_id',-override=>'1', -value=>"$ctrel->{c_id}"); + print $q->hidden(-name=>'rel_id',-override=>'1', -value=>"$ctrel->{rel_id}"); + + $bg_color = $varenv{background_color2}; + $edit = "rel_edit"; + #$relate_key = "relate_dialog4menu"; + $move_key = "move_dialog4menu" if($node_meta->{tpl_id} == 205);#only Waren + #$copy_key = "copy_content"; + $save_key = "save_content"; + $edit_template = "$ctrel->{template_id}"; + $tpl = $db->get_tpl($edit_template); + }elsif($node_meta->{ct_table} eq "contentadr" && $node_meta->{tpl_id}){ + my $ref = { + table => "$node_meta->{ct_table}", + fetch => "one", + template_id => "$node_meta->{tpl_id}", + rel_id => "$rel_id", + }; + $ctrel = $dbt->fetch_record($dbh,$ref); + print $q->hidden(-name=>'c_id',-override=>'1', -value=>"$ctrel->{c_id}"); + print $q->hidden(-name=>'rel_id',-override=>'1', -value=>"$ctrel->{rel_id}"); + + $bg_color = $varenv{background_color2}; + $edit = "base_edit"; + $save_key = "save_adr"; + $edit_template = "$ctrel->{template_id}" . "000"; + $tpl = $db->get_tpl($edit_template); + }elsif($node_meta->{ct_table} eq "users" && $u_id){ + my $ref = { + table => "$node_meta->{ct_table}", + fetch => "one", + u_id => "$u_id", + }; + $ctrel = $dbt->fetch_tablerecord($dbh,$ref); + print $q->hidden(-name=>'u_id',-override=>'1', -value=>"$ctrel->{u_id}"); + + $bg_color = $varenv{background_color2}; + $edit = "base_edit"; + $save_key = "save_dmsusers"; + $tpl = $db->get_tpl($node_meta->{tpl_id}); + #print Dumper($node_meta->{tpl_id}) . "\n u_id:" . $u_id; + }else{ + print $q->div("Es konnten keine Daten gefunden werden"),"\n"; + return "failure::Error, no table selected"; + } + + my $u_name = $dbt->sys_username($dbh,$ctrel->{owner}); + + if(ref($ctrel) ne "HASH" && !$ctrel->{c_id} && !$ctrel->{u_id}){ + print $q->div("error: no content available"); + } + + $ctrel->{mtime} = $lb->time4de($ctrel->{mtime},"1") if($ctrel->{mtime}); + my $selsize="200px"; + #$db->users_up("rel_id4edit",$ctrel->{rel_id},$users_dms->{u_id}); + + print $q->hidden(-name=>'parent_id',-override=>'1', -value=>"$node_meta->{parent_id}"); + print $q->hidden(-name=>'main_id',-override=>'1', -value=>"$node_meta->{main_id}"); + print $q->hidden(-name=>'template_id',-override=>'1', -value=>"$node_meta->{template_id}"); + print $q->hidden(-name=>'offset',-override=>'1', -value=>"$R::offset"); + print $q->hidden(-name=>'limit', -override=>'1', -value=>"$R::limit"); + print $q->hidden(-name=>'relids', -override=>'1', -value=>"$R::relids"); + + my ($start_date,$start_time,$s_dd,$s_mo,$s_yy,$s_hh,$s_mi,$end_date,$end_time,$e_yy,$e_mo,$e_dd,$e_hh,$e_mi); + my $today = strftime("%d.%m.%Y",localtime(time)); + my $start_datetime = $ctrel->{start_time}; + my $end_datetime = $ctrel->{end_time}; + + if($start_datetime){ + ($start_date,$start_time) = split(/ /,$start_datetime); + ($s_yy,$s_mo,$s_dd) = split(/-/,$start_date); + $start_date = "$s_dd-$s_mo-$s_yy"; + ($s_hh,$s_mi) = split(/\:/,$start_time); + } + if($end_datetime){ + ($end_date,$end_time) = split(/ /,$end_datetime); + ($e_yy,$e_mo,$e_dd) = split(/-/,$end_date); + $end_date = "$e_dd-$e_mo-$e_yy"; + ($e_hh,$e_mi) = split(/\:/,$end_time); + } + ### + + my $bike_nodes = {}; + my $tariff_all = {}; + if($varenv{systype} eq "sharee"){ + my $node = { template_id => 205,#Leihrad_liste + parent_id => 200013,#Waren + fetch => "all", + keyfield => "main_id", + }; + $bike_nodes = $dbt->fetch_rel4tpl4nd($dbh,$node); + $tariff_all = $db->collect_ct4rel("content","300026",$lang,"","","","","210"); + } + + print "
    \n"; + #1. table submit + print $q->start_table({-class=>'list', -border=>'0', -width=>'100%',-align=>'center', -cellpadding=>'3', -cellspacing=>'0'}); + print $q->Tr(); + print ""; + print $but->singlesubmit7("$edit","$save_key","$ib{$save_key}","margin:0 5px;"); + print $but->singlesubmit7("rel_edit","$relate_key","$ib{$relate_key}","margin:0 5px;"); + print $but->singlesubmit7("rel_edit","$move_key","$ib{$move_key}","margin:0 5px;"); + print $but->singlesubmit7("rel_edit","$copy_key","$ib{$copy_key}","margin:0 5px;"); + print $but->singlesubmit7("$edit","remove_chk4rel","$ib{remove_chk4rel}","margin:0 5px;"); + + #print $q->div({-style=>'position:fixed;bottom:2%;right:1%;z-index:10;font-size:13px;'}," (c_id: $ctrel->{c_id} | rel_id: $ctrel->{rel_id} | tpl_id: $ctrel->{template_id} / $edit_template)"),"\n" if($users_dms->{u_id} eq $varenv{superu_id}); + print "\n"; + print $q->td({-style=>"background-color:$bg_color;padding-right:10px;border-bottom: 1px solid silver;text-align:right;font-size:11px;"}, "$u_name / $ctrel->{mtime}"); + print $q->end_table; + + + ###Terminal target + my $c_key = "c_id"; + my $add_trans = "add_transpos"; + if("$node_meta->{ct_table}" =~ /contentadr/){ + $add_trans = "add_transadr"; + $c_key = "c_idadr"; + } + + my $tpath = ""; + my $top = 70; + if($node_meta->{tpl_id} == 202){ + my $cttrans = $db->collect_ct4rel4nd("contenttrans","","$lang","","","","ct.int10","$ctrel->{c_id}","209,218","","rel_id",""); + foreach my $id (sort { $cttrans->{$b}->{c_id} <=> $cttrans->{$a}->{c_id} } keys (%$cttrans)){ + my $toppx = $top . "px"; + print $q->div({-style=>"position:absolute;top:$toppx;right:20px;"}, " TXID $cttrans->{$id}->{txt16} ",$q->span({-style=>"background-color:$varenv{term_active_color}"},$q->a({-class=>"linknav",-href=>"/$dbt->{shareedms_conf}->{parent_node}/Faktura/$cttrans->{$id}->{node_name}?ct_trans=open\&c_id4trans=$cttrans->{$id}->{c_id}\&tpl_id4trans=$cttrans->{$id}->{template_id}\&kind_of_trans=$users_dms->{kind_of_trans}&owner=$users_dms->{u_id}",-title=>"Faktura Terminal öffnen"},"[ $cttrans->{$id}->{node_name} #$cttrans->{$id}->{ct_name} ]"))),"\n"; + $top += 22; + } + }elsif($node_meta->{tpl_id} == 205){ + my $day = strftime "%d", localtime; + my $month = strftime "%m", localtime; + my $year = strftime "%Y", localtime; + my ($nyear,$nmonth,$nday) = Add_Delta_YMD($year,$month,$day, 0,0,-28); + my $toppx = $top . "px"; + print $q->div({-style=>"position:absolute;top:$toppx;right:20px;"}, $q->span({-style=>"background-color:$varenv{calendar_active_color}"},$q->a({-class=>"linknav",-href=>"/$dbt->{shareedms_conf}->{parent_node}/Mietjournal/?detail_search=1&barcode=$ctrel->{barcode}&start_date_time=$nday.$nmonth.$nyear",-title=>"Mietjournal der letzten 4 Wochen"},"[ Mietjournal zu Rad $dbt->{operator}->{$varenv{dbname}}->{oprefix}$ctrel->{barcode} ]"))),"\n"; + $top += 22; + #}else{ + #print $q->div({-style=>"position:absolute;top:$top;right:20px;"},"no valid users path definition: $tpath"),"\n"; + } + ### + +#just for checking if ct_name or barcode still available +if($varenv{orga} eq "dms"){ +print< + .ui-autocomplete { + text-align:left; + font-size:14px; + background:#eeeeee; + border:1px solid silver; + } + + + +EOF +; +} + + #2. table content + print $q->start_table({-border=>'0', -width=>'100%',-align=>'center', -cellpadding=>'3', -cellspacing=>'0'}); + print "\n"; + + my $j=0; + @tpl_order = split /,/,$tpl->{tpl_order}; + + #2.1 sub-table + print "\n"; + print $q->start_table({-border=>'0', -width=>'100%',-align=>'center', -cellpadding=>'3', -cellspacing=>'0'}); + $j++; + my @_service_valxx = ("","1","2","3","4"); + + foreach (@tpl_order){ + my ($key,$des,$size,$postdes) = split /=/,$_; + my $seldes = $des; + $des .= " ($key)" if($users_dms->{u_id} eq $varenv{superu_id}); + + $ctrel->{$key} = $q->unescapeHTML("$ctrel->{$key}"); + $ctrel->{$key} = $lb->newline($ctrel->{$key},"",1); + if($key =~ /c_id|ct_name|barcode|txt/ && $size eq "readonly"){ + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>2},$q->textfield(-class=>'etxt', -style=>"width:15em;",-name=>"$key", -default=>"$ctrel->{$key}", -readonly=>1)),"\n"; + }elsif($key eq "u_id" && $size eq "readonly"){ + my $adref = { + table => "contentadr", + fetch => "one", + template_id => "202", + c_id => "$ctrel->{$key}", + }; + my $ctadr = $dbt->fetch_record($dbh,$adref); + + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"ID"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>2},$q->textfield(-class=>'etxt', -style=>"width:15em;",-name=>"$key", -default=>"$ctrel->{$key}", -readonly=>1)),"\n"; + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"Vorname Name"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>2},$q->textfield(-class=>'etxt', -style=>"width:15em;",-name=>"", -default=>"$ctadr->{txt01}", -readonly=>1)),"\n"; + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"eMail (Login)"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>2},$q->textfield(-class=>'etxt', -style=>"width:15em;",-name=>"", -default=>"$ctadr->{txt08}", -readonly=>1)),"\n"; + + }elsif($key eq "ct_name"){ + #blank Teilenummer + my $ct_name = $ctrel->{$key}; + if(($node_meta->{ct_table} eq "content") && ($tpl->{tpl_order} =~ /barcode/) && ("$ct_name" eq "$ctrel->{barcode}")){ + $ct_name = ""; + } + my $w = $size . "em"; + my $oprefix = ""; + $oprefix = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}-" if($node_meta->{tpl_id} == 224 || $node_meta->{tpl_id} == 228); + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>2}, "$oprefix", $q->textfield(-class=>'etxt', -style=>"width:$w;",-name=>"$key", -override=>'1',-default=>"$ct_name")),"\n"; + } + elsif($key eq "barcode"){ + my $w = $size . "em"; + my $oprefix = ""; + $oprefix = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}" if($node_meta->{tpl_id} == 205); + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>1}, "$oprefix", $q->textfield(-class=>'etxt',-style=>"width:$w;",-id=>"json_select",-name=>"$key",-value=>"$ctrel->{$key}", -override=>'1',-size=>"25",-maxlength=>50),""); + print $q->td({-class=>'content1_cms',-id=>'log'},""),"\n"; + } + elsif($key =~ /int/ && $size =~ /\w\+\w/ && $postdes eq "reverse"){ + my ($a,$b) = split /\+/,$size; + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>1},$but->radiobox2reverse("$key","$ctrel->{$key}","$a","$b")),"\n"; + } + elsif($key =~ /int/ && $size =~ /\w\+\w/){ + #if($users_dms->{u_id} eq $varenv{superu_id} || $des !~ /DMS/){#only superu_id can acivate DMS-Admin + if($users_dms->{u_id}){ + my ($a,$b,$c) = split /\+/,$size; + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>1},$but->radiobox2("$key","$ctrel->{$key}","$a","$b","$c")),"\n"; + } + } + elsif($key =~ /int/ && $size =~ /checkbox/){ + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms', -colspan=>'1'}, $but->checkbox("1","$key","$ctrel->{$key}"), $postdes),"\n"; + print $q->hidden(-name=>"$key",-override=>1,-value=>"null"); + } + elsif($key eq "int04"){ + my $w = $size . "em"; + my $oprefix = ""; + $oprefix = "$dbt->{operator}->{$varenv{dbname}}->{oprefix}" if($node_meta->{tpl_id} == 225 || $node_meta->{tpl_id} == 205); + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>1}, "$oprefix", $q->textfield(-class=>'etxt',-style=>"width:$w;",-name=>"$key",-value=>"$ctrel->{$key}", -override=>'1',-size=>"25",-maxlength=>50),""); + } + elsif($key =~ /int12/ && "$size" eq "select" && $node_meta->{tpl_id} == 210){#Flotte bike_group (bikenode.main_id) + my @_valxx = (""); + foreach my $rid (sort { $bike_nodes->{$a}->{node_name} cmp $bike_nodes->{$b}->{node_name} } keys (%$bike_nodes)){ + push (@_valxx, "$bike_nodes->{$rid}->{main_id}:$bike_nodes->{$rid}->{node_name} - $bike_nodes->{$rid}->{main_id}"); + } + print $q->Tr(); + print $q->td({-class=>'left_italic_cms',-colspan=>'1'},"$des"); + print $q->td({-class=>'content1_cms',-colspan=>'1'},$but->selector_class("$key","eselect","width:250px;",$ctrel->{$key},@_valxx)); + } + + elsif($key =~ /int21|int22/ && "$size" eq "select" && $node_meta->{tpl_id} == 228){#Bonus Tarif + my @_valxx = (""); + foreach my $rid (sort { $tariff_all->{$a}->{barcode} <=> $tariff_all->{$b}->{barcode} } keys (%$tariff_all)){ + push (@_valxx, "$tariff_all->{$rid}->{barcode}:$tariff_all->{$rid}->{barcode} - $tariff_all->{$rid}->{txt01}"); + } + print $q->Tr(); + print $q->td({-class=>'left_italic_cms',-colspan=>'1'},"$des"); + print $q->td({-class=>'content1_cms',-colspan=>'1'},$but->selector_class("$key","eselect","width:350px;",$ctrel->{$key},@_valxx)); + } + elsif($key =~ /int07/ && "$size" eq "select" && $node_meta->{tpl_id} == 225){#Station Service Tour + my $selsize="50px"; + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>'2'},$but->selector("$key","$selsize",$ctrel->{$key},@_service_valxx)); + } + elsif($key =~ /int10/ && "$size" eq "select" && ($node_meta->{tpl_id} == 205 || $node_meta->{tpl_id} == 225)){#bike_state + my @_lock_valxx = (); + while (my ($key, $value) = each %{ $dbt->{copri_conf}->{bike_state} }) { + push @_lock_valxx, "$key:$value";#[1:available] ... + } + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>'2'},$but->selector_class("$key","eselect","",$ctrel->{$key},@_lock_valxx)); + } + elsif($key =~ /int18/ && "$size" eq "select" && $node_meta->{tpl_id} == 210){#sharing_type + my @_lock_valxx = (); + while (my ($key, $value) = each %{ $dbt->{copri_conf}->{sharing_type} }) { + push @_lock_valxx, "$key:$value";#[0:private] ... + } + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>'2'},$but->selector_class("$key","eselect","",$ctrel->{$key},@_lock_valxx)); + } + elsif($key =~ /int20/ && "$size" eq "select" && $node_meta->{tpl_id} == 205){#lock_state locked/unlocked + my @_lock_valxx = (); + while (my ($key, $value) = each %{ $dbt->{copri_conf}->{lock_state} }) { + push @_lock_valxx, "$key:$value";#[2:unlocked] + } + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>'2'},$but->selector_class("$key","eselect","",$ctrel->{$key},@_lock_valxx)); + } + elsif($key =~ /int11/ && "$size" eq "select" && $node_meta->{tpl_id} == 205){#lock_system BC Ilockit usw + my @_lock_valxx = (); + while (my ($key, $value) = each %{ $dbt->{copri_conf}->{lock_system} }) { + push @_lock_valxx, "$key:$value";#[2:Ilockit] + } + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>'2'},$but->selector_class("$key","eselect","",$ctrel->{$key},@_lock_valxx)); + } + elsif($key =~ /int/ && "$size" eq "select"){ + my @_valxx; + my $selsize="50px"; + + @_valxx = split(/\|/,$varenv{$seldes}); + $ctrel->{$key} =~ s/\.00//; + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>'2'},$but->selector("$key","$selsize",$ctrel->{$key},@_valxx)); + } + elsif($key =~ /int/){ + my $w = $size . "em"; + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>2},$q->textfield(-class=>'etxt', -style=>"width:$w;",-name=>"$key", -override=>'1', -default=>"$ctrel->{$key}"), $postdes),"\n"; + } + elsif($key =~ /txt/ && "$size" eq "select" && "$des" =~ /Status|PiQuest|Zahlungsweise/){ + my @_valxx; + my $selsize="150px"; + @_valxx = split(/\|/,$varenv{$seldes}) if($varenv{$seldes}); + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + if($des eq "PiQuest"){ + print $q->td({-class=>'content1_cms',-colspan=>'2'},$but->selector("$key","$selsize","",@_valxx)," $ctrel->{$key}"); + }else{ + print $q->td({-class=>'content1_cms',-colspan=>'2'},$but->selector("$key","$selsize",$ctrel->{$key},@_valxx)); + } + } + elsif($key =~ /txt/ && "$size" eq "select" && "$des" =~ /System|Ziel Datei/){ + my @_valxx; + my $selsize="150px"; + @_valxx = split(/\|/,$varenv{$seldes}) if($varenv{$seldes}); + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>'2'},$but->selector("$key","$selsize",$ctrel->{$key},@_valxx)); + } + elsif($key =~ /txt/ && "$size" eq "select" && "$des" =~ /Land/){ + my @_valxx; + my $selsize="150px"; + my $country = $lb->country_code(); + $ctrel->{$key} = "DE" if(!$ctrel->{$key}); + foreach (sort { $country->{$a} cmp $country->{$b} } keys (%$country)){ + push @_valxx, "$_:$country->{$_}"; + } + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>'2'},$but->selector("$key","$selsize",$ctrel->{$key},@_valxx)); + } + elsif($node_meta->{tpl_id} == 205 && $key =~ /txt23/ && "$size" =~ /select/){#Service-Farbcode + my @_valxx = ("red","blue","green"); + my @service_code = ("red","red","red","red","red","red"); + @service_code = split(/\s/,$ctrel->{$key}) if($ctrel->{$key} =~ /\w+\s\w+\s\w+\s\w+\s\w+\s\w+/g); + print $q->Tr(); + print $q->td({-class=>'left_italic_cms',-style=>'vertical-align:top;',-colspan=>'1'},"$des"); + print "\n"; + foreach(@service_code){ + print $but->selector_color("$key","color:white;background-color:$_;width:60px;",$_,@_valxx); + } + print "\n"; + } + elsif($key =~ /txt/ && "$size" =~ /select/){ + if($size =~ /_multiple/){ + if($key =~ /txt18/ && $node_meta->{tpl_id} eq "202"){ #service_tour alias user_tour + my $height = scalar(@_service_valxx); + print $q->Tr(); + print $q->td({-class=>'left_italic_cms',-style=>'vertical-align:top;',-colspan=>'1'},"$des"); + print $q->td({-class=>'content1_cms',-colspan=>'1'},$but->selector2("$key","50px;","$height",$ctrel->{$key},@_service_valxx)); + } + elsif($key =~ /txt24/ && $node_meta->{tpl_id} == 225){ #sharee station_group (bikenode.main_ids) + my @_valxx = (""); + foreach my $rid (sort { $bike_nodes->{$a}->{node_name} cmp $bike_nodes->{$b}->{node_name} } keys (%$bike_nodes)){ + push (@_valxx, "$bike_nodes->{$rid}->{main_id}:$bike_nodes->{$rid}->{node_name} - $bike_nodes->{$rid}->{main_id}"); + } + my $height = scalar(@_valxx); + print $q->Tr(); + print $q->td({-class=>'left_italic_cms',-style=>'vertical-align:top;',-colspan=>'1'},"$des"); + print $q->td({-class=>'content1_cms',-colspan=>'1'},$but->selector2("$key","250px;","$height",$ctrel->{$key},@_valxx)); + } + #sharee user_group Tarif-2.0 (tarif.c_ids) + elsif($key =~ /txt30/ && $varenv{dbname} ne "sharee_primary"){ + my @_valxx = (""); + foreach my $rid (sort { $tariff_all->{$a}->{barcode} <=> $tariff_all->{$b}->{barcode} } keys (%$tariff_all)){ + if($tariff_all->{$rid}->{ct_name}){ + push (@_valxx, "$tariff_all->{$rid}->{barcode}:$tariff_all->{$rid}->{barcode} - $tariff_all->{$rid}->{txt01} - $tariff_all->{$rid}->{int12}"); + } + } + my $height = scalar(@_valxx); + print $q->Tr(); + print $q->td({-class=>'left_italic_cms',-style=>'vertical-align:top;',-colspan=>'1'},"$des"); + print $q->td({-class=>'content1_cms',-colspan=>'1'},$but->selector2("$key","350px;","$height",$ctrel->{$key},@_valxx)); + } + }else{ + my @_valxx = (""); + @_valxx = split(/,/,$varenv{$seldes}) if($varenv{$seldes}); + my $selsize = "80px"; + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>'2'},$but->selector("$key","$selsize",$ctrel->{$key},@_valxx)); + } + #print $q->hidden(-name=>"$key",-override=>1,-value=>"null");#2021-06-02 select works without empty null + } + elsif($key =~ /txt/ && $size =~ /area$/){ + my $h= 1;# if($size =~ /area(\d+)/); + print $q->Tr(); + print $q->td({-class=>'left_italic_cms',-colspan=>1},"$des"),"\n"; + print $q->td({-class=>'content1_cms', -colspan=>'3'},$q->textarea(-class=>"autos", -style=>'border: 1px solid silver;background-color:#ededed;',-rows=>"$h",-cols=>'35em;', -name=>"$key", -override=>'1',-default=>"$ctrel->{$key}")),"\n"; + } + elsif($key =~ /txt/ && $size =~ /area(\d+)/){ + #my $h= $1 if($size =~ /area(\d+)/); + my $h= "height:" . $1 . "em;"; + my $w = "width:25em;"; + $w= "width:" . $2 . "em;" if($size =~ /area(\d+)-(\d+)/); + print $q->Tr(); + print $q->td({-style=>'padding:4px 0 0 0px;',-colspan=>1},""),"\n"; + print $q->td({-style=>'padding:4px 0 0 0px;',-colspan=>3},"$des"),"\n"; + print $q->Tr(); + print $q->td({-style=>'padding:4px 0 0 0px;',-colspan=>1},""),"\n"; + if($key eq "txt28" && $ctrel->{$key} =~ /SEPA-Lastschriftmandat/){ + use URI::Encode qw(uri_encode uri_decode); + $ctrel->{txt28} = uri_decode($ctrel->{txt28}); + $ctrel->{txt28} =~ s/\+/ /g; + print $q->td({-style=>'border:1px solid silver;'},$ctrel->{txt28}),"\n"; + }else{ + print $q->td({-class=>'content1_cms', -colspan=>'3'},$q->textarea(-id=>"$key", -class=>"autos", -style=>"border: 1px solid silver;background-color:#ededed;$h $w", -name=>"$key", -override=>'1',-default=>"$ctrel->{$key}")),"\n"; + } + } + elsif($key =~ /txt02/ && $varenv{syshost} =~ /sharee/){ + #nothing txt02=Datei aktiv=10=sharee-APP aktivierte Dokument + } + elsif($key =~ /txt15/ && $varenv{syshost} =~ /sharee/ && $node_meta->{tpl_id} == 202){ + my $w = $size . "em"; + my $record_bonus = {c_id => 0}; + my $pref_cc = { + table => "content", + fetch => "one", + template_id => "228", + ct_name => "$ctrel->{txt15}", + }; + $record_bonus = $dbt->fetch_record($dbh,$pref_cc); + + my @tariff = ("$ctrel->{txt30}"); + @tariff = split(/\s/,$ctrel->{txt30}) if($ctrel->{txt30} =~ /\s/); + foreach my $tf_id (@tariff){ + $tf_id =~ s/\s//g; + #print "$record_bonus->{int22} == $tf_id
    "; + if($record_bonus->{int22} == $tf_id){ + $postdes = "Tarif: $record_bonus->{int21} - $record_bonus->{int22} (public - bonus)"; + $postdes .= $q->span({-style=>'color:red;padding-left:10px;'},"Fehler: Bonusnummer") if(!$ctrel->{$key}); + } + } + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>'2'},$q->textfield(-class=>'etxt', -style=>"width:$w;",-name=>"$key", -override=>'1', -default=>"$ctrel->{$key}"), $postdes),"\n"; + } + #Operators or Operators Antrag + elsif($key =~ /txt17|txt19/){ + if($varenv{dbname} eq "sharee_primary"){ + my $w = $size . "em"; + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>'2'},$q->textfield(-class=>'etxt', -style=>"width:$w;",-name=>"$key", -override=>'1', -default=>"$ctrel->{$key}"), $postdes),"\n"; + } + } + elsif($key =~ /txt/){ + my $w = $size . "em"; + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"$des"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>'2'},$q->textfield(-class=>'etxt', -style=>"width:$w;",-name=>"$key", -override=>'1', -default=>"$ctrel->{$key}"), $postdes),"\n"; + } + elsif($key =~ /byte/){ + my $K_int = unpack "H*", $ctrel->{$key}; + #$K_int =~ s/(.)/sprintf( "%x", ord($1))/eg; + my $w = $size . "em"; + print $q->Tr(); + print $q->td({-class=>'left_italic_cms',-colspan=>1},"$des"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>'2'},$q->textfield(-class=>'etxt', -style=>"width:$w;",-name=>"$key", -override=>'1', -default=>"$K_int"), $postdes),"\n"; + + } + + if($key =~ /date_time/){ + #print $q->hidden(-name=>'t_id', -override=>'1',-value=>"$times_id"); + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"Datum Start"),"\n"; + print $q->td({-class=>'content1_cms', -colspan=>'1'},$q->textfield(-id=>'datepicker1',-class=>'etxt',-name=>"start_date",-default=>"$start_date",-override=>'1',-size=>"10",-maxlength=>10)),"\n"; + print $q->td({-class=>'content1_cms', -colspan=>'1'},"Ende", $q->textfield(-id=>'datepicker2',-class=>'etxt',-name=>"end_date",-default=>"$end_date",-override=>'1',-size=>"10",-maxlength=>10)),"\n"; + print $q->Tr(); + print $q->td({-class=>'left_italic_cms'},"Uhrzeit Start"),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>'1'}, + $q->textfield(-class=>'etxt',-name=>"s_hh", -override=>'1',-default=>"$s_hh",-size=>"2",-maxlength=>2),":", + $q->textfield(-class=>'etxt',-name=>"s_mi", -override=>'1',-default=>"$s_mi",-size=>"2",-maxlength=>2)),"\n"; + print $q->td({-class=>'content1_cms',-colspan=>'1'},"Ende", + $q->textfield(-class=>'etxt',-name=>"e_hh", -override=>'1',-default=>"$e_hh",-size=>"2",-maxlength=>2),":", + $q->textfield(-class=>'etxt',-name=>"e_mi", -override=>'1',-default=>"$e_mi",-size=>"2",-maxlength=>2)),"\n"; + } + } + print $q->end_table; + print "\n"; + print "\n"; + + print $q->end_table; + #2.table ende + + print $q->div($but->singlesubmit7("$edit","$save_key","$ib{$save_key}","margin:10px 20px;")),"\n"; + my $debug = ""; + #$debug = "(ct_table: $node_meta->{ct_table} | main_id: $node_meta->{main_id} | c_id: $ctrel->{c_id} | tpl_id: $tpl->{tpl_id} | rel_id: $ctrel->{rel_id})"; + print $q->div({-style=>'z-index:10;font-size:13px;'},"$debug"),"\n" if($users_dms->{u_id} eq $varenv{superu_id}); + + print "
    "; +} +1; diff --git a/copri4/main/src/Tpl/Calorin.pm b/copri4/main/src/Tpl/Calorin.pm new file mode 100644 index 0000000..85142d9 --- /dev/null +++ b/copri4/main/src/Tpl/Calorin.pm @@ -0,0 +1,467 @@ +package Calorin; +# +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; +use POSIX; +use CGI; +use CGI::Carp qw(fatalsToBrowser); +use CGI ':standard'; +use Calendar::Simple; +use Date::Calc qw(:all); +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Callib; +use Mod::Libenzdb; +use Mod::DBtank; +use Mod::APIfunc; +use Mod::Pricing; +use Data::Dumper; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my ($node_meta,$users_dms,$u_group,$return) = @_; + my $q = new CGI; + my $cf = new Config; + my $lb = new Libenz; + my $but = new Buttons; + my $cb = new Callib; + my $db = new Libenzdb; + my $apif = new APIfunc; + my $dbt = new DBtank; + my $pri = new Pricing; + + my $lang = "de"; + #my $rel = $db->get_relation($main_id,$lang); + my $tpl = $db->get_tpl($node_meta->{template_id}); + my @tpl_order = split /,/,$tpl->{tpl_order}; + my %varenv = $cf->envonline(); + my %ib = $but->ibuttons(); + my $script = $q->script_name(); + my $path_info = $q->path_info(); + my $path = $path_info; + #with meta_host, + if("$varenv{metahost}"){ + $path = "$script" . "$path_info"; + $script=""; + } + + $path =~ s/\/user|\/manager|\/admin//; + my $now_time = strftime "%Y-%m-%d %H:%M", localtime; + + my $table = "contenttrans"; + my $u_name = $q->escapeHTML("$R::u_name"); + my $ctf = $db->get_content1("contentuser",$dbt->{shareedms_conf}->{parent_id}); + my $dbh = ""; + + my $channel_map = $dbt->channel_map(); + my $mapref = {}; + my $ct_users = $dbt->users_map($dbh,$mapref);#get serviceAPP and DMS users from contentadr + + my @_users = (":user"); + foreach my $id (sort { $channel_map->{$a} cmp $channel_map->{$b} } keys (%$channel_map)){ + push (@_users, "$id:$channel_map->{$id}"); + if($channel_map->{$id} eq $R::s_owner){ + #$searchref->{owner} = $id; + #$s_u_name = $channel_map->{$id}; + } + } + + if(1==1){ + foreach my $ctu_id (sort { $ct_users->{$a}->{txt01} cmp $ct_users->{$b}->{txt01} } keys (%$ct_users)){ + push (@_users, "$ct_users->{$ctu_id}->{c_id}:$ct_users->{$ctu_id}->{txt01}"); + if($ct_users->{$ctu_id}->{ct_name} && ($ct_users->{$ctu_id}->{txt01} =~ /$R::s_owner/i)){ + #$searchref->{owner} = $ct_users->{$ctu_id}->{c_id}; + #$s_u_name = $ct_users->{$ctu_id}->{txt01}; + } + } + } + + my $bnode = { template_id => 205,#Leihrad_liste + parent_id => 200013,#Waren + fetch => "all", + keyfield => "main_id", + }; + my $bike_nodes = $dbt->fetch_rel4tpl4nd($dbh,$bnode); + + my $root_id = 100; + #alle nicht abgeschlossene mandanten-einträge .... + my $x_main_ids = "$root_id,"; + my $tplids = "$node_meta->{template_id},"; + $tplids .= "$ctf->{txt34}," if($ctf->{txt34}); + $tplids .= "$ctf->{txt35}," if($ctf->{txt35}); + $tplids .= "$ctf->{txt36}," if($ctf->{txt36}); + + #sollte ins ctf-System. Verkaufliste,Verleihliste + #incl. Verkauf/Verleih journal + $tplids .= "204,207,218,209"; + $tplids =~ s/,$//; + + $x_main_ids .= $db->collect_noderec($root_id,$lang,"nothing"); + $x_main_ids =~ s/,$//; + my $ct4rel = $db->collect_ct4rel4nd($table,"$x_main_ids","$lang","","","","","","$tplids","","c_id",""); + my @months = $cb->monthmap(); + + my $hh;my $mm; + my $day = strftime "%d", localtime; + my $day_today = $day; + my $mon = strftime "%m", localtime; + my $mon_today = $mon; + my $year = strftime "%Y", localtime; + my $year_today = $year; + ($year,$mon,$day,$hh,$mm) = $lb->split_date($users_dms->{cal_start}) if($users_dms->{cal_start}); + + print $q->end_form; + print $q->start_form(); + + print "
    \n"; + + my $start_date_time = $R::start_date_time; + my $end_date_time = $R::end_date_time; + + $start_date_time = "01.$mon.$year" if(!$start_date_time); + + + my $c_date; my $start_chck=0;my $end_chck=0;my $message; + if($start_date_time){ + ($start_date_time,$start_chck) = $lb->checkdate($start_date_time) if($start_date_time ne "%"); + print $q->div({-style=>'background-color:white;color:red;'},"→ Datum Eingabefehler: $start_date_time <<<") if($end_chck); + } + if($end_date_time){ + ($end_date_time,$end_chck) = $lb->checkdate($end_date_time) if($end_date_time ne "%"); + print $q->div({-style=>'background-color:white;color:red;'},"→ Datum Eingabefehler: $end_date_time <<<") if($end_chck); + } + + if(!$end_date_time){ + my $days4month = Days_in_Month($year,$mon); + $end_date_time = "$days4month.$mon.$year"; + $end_date_time = $cb->datetime_defaults($end_date_time,"dummy",$lang); + } + + + my $limit = $R::limit || $varenv{limit} * 2;#max. 160 * 2 + my $offset = $R::offset || "0"; + if($R::detail_search){ + $limit = 10000; + $offset = 0; + } + #backward | forward + if($R::go eq "backward_list"){ + $offset -= $limit if($offset >= $limit); + }elsif($R::go eq "forward_list"){ + $offset += $limit; + } + + my $cttpos; + $R::ct_ct_name =~ s/\#//; + my $search = { + #table => "contenttranspos", + table => "$node_meta->{ct_table}", + cttpos_id => $q->escapeHTML("$R::cttpos_id"), + txt06 => $q->escapeHTML("$R::txt06"), + txt08 => $q->escapeHTML("$R::txt08"), + int04 => $q->escapeHTML("$R::int04"), + int06 => $q->escapeHTML("$R::int06"), + int12 => $q->escapeHTML("$R::int12"), + int13 => $q->escapeHTML("$R::int13"), + cp_ct_name => $q->escapeHTML("$R::cp_ct_name"), + int10 => $q->escapeHTML("$R::int10"), + int20 => $q->escapeHTML("$R::int20"), + barcode => $q->escapeHTML("$R::barcode"), + ct_txt06 => $q->escapeHTML("$R::ct_txt06"),#PLZ + ct_ct_name => $q->escapeHTML("$R::ct_ct_name"), + owner => $q->escapeHTML("$R::owner"), + limit => $q->escapeHTML($limit), + offset => $q->escapeHTML($offset), + cal_sort_updown => $users_dms->{cal_sort_updown}, + }; + $search = { %$search, + start_date_time => "$start_date_time", + end_date_time => "$end_date_time", + } if(!$R::cttpos_id); + + if(!$start_chck && !$end_chck){ + if($node_meta->{ct_table} eq "contenttranspos"){ + $cttpos = $dbt->collect_transpos($dbh,$search); + }elsif($node_meta->{ct_table} eq "contenttheftpos"){ + $cttpos = $dbt->collect_theftpos($dbh,$search); + } + } + + #2019-05-09 collect content to get content.txt10 for Räder Status + my $tpl_id_ware = "205"; + my $ct4rel_ware = {}; + $ct4rel_ware = $db->collect_cid("content",$lang,$tpl_id_ware,"","","",""); + + my $header_style = ""; + $header_style = "border:2px solid #9f1f0e;" if($message); + print $q->div({-class=>"copri_header",-style=>"background-color:$tpl->{bg_color};"},"$path", $q->span({-style=>"padding:4px 10px;color:white;"}, + " $months[$mon -1] $year", + $q->a({-class=>"linknav",-style=>"padding:0 0.5em;",-title=>"Monat zurück",-href=>"?cal_delta_start=0:-1:0"}," ← "), + $q->a({-class=>"linknav",-style=>"padding:0 0.5em;",-title=>"Monat aktuell",-href=>"?cal_today=1"}," • "), + $q->a({-class=>"linknav",-style=>"padding:0 0.5em;",-title=>"Monat vorwärts",-href=>"?cal_delta_start=0:1:0"}," → "), + "$message" + )),"\n"; + + my $sort_up = "up"; + my $sort_down = "down"; + $sort_up = "$sort_up" if($users_dms->{cal_sort_updown} eq "up"); + $sort_down = "$sort_down" if($users_dms->{cal_sort_updown} eq "down"); + + print $q->div({-style=>'background-color:silver;height:10px;'},""),"\n"; + + my $hstyle = "border-right: solid thin gray;border-bottom: solid thin gray;"; + my $search = "search"; + my $edit="ct_trans"; + my $new_key="new_transdate"; + + print $q->start_table({ -style=>"width:100%;", -border=>'0',-align=>'left', -cellpadding=>'1', -cellspacing=>'0'}); + print $q->Tr(); + print $q->td({-style=>"background-color:silver;$hstyle;width:30px;padding:1px 10px;"},$but->singlesubmit1("detail_search","$search")),"\n"; + + + #1. Search-fields + my $h=3; + print "\n"; + print $q->a({-class=>"sortnav",-href=>"?cal_sort_updown=up\&offset=$offset\&limit=$limit",-title=>'Aufsteigend sortieren'},"$sort_up"),"|",$q->a({-class=>"sortnav",-href=>"?cal_sort_updown=down\&offset=$offset\&limit=$limit",-title=>'Absteigend sortieren'},"$sort_down"),"\n"; + foreach(@tpl_order){ + #$h++; + my ($key,$des,$size) = split /=/,$_; + if($key =~ /time/){ + $size="10px"; + print $q->textfield(-id=>'datepicker1',-class=>'etxt',-name=>"start_$key",-default=>"$start_date_time",-size=>"$size",-maxlength=>20), "-", $q->textfield(-id=>'datepicker2',-class=>'etxt',-name=>"end_$key",-default=>"$end_date_time",-size=>"$size",-maxlength=>20),"\n"; + } + elsif($key =~ /owner/){ + print $but->selector_class("$key","eselect","width:80px;",$R::owner,@_users),"\n"; + } + elsif($key =~ /int10/ && "$size" eq "select"){# && $node_meta->{tpl_id} == 205){#bike_state + my @_lock_valxx = (":$des"); + while (my ($key, $value) = each %{ $dbt->{copri_conf}->{bike_state} }) { + push @_lock_valxx, "$key:$value";#[1:available] ... + } + print $but->selector_class("$key","eselect","",$R::int10,@_lock_valxx),"\n"; + } + elsif($key =~ /int12/ && "$size" eq "select"){# && $node_meta->{tpl_id} == 210){#Flotte bike_group (bikenode.main_id) + my @_valxx = (":$des"); + foreach my $rid (sort { $bike_nodes->{$a}->{node_name} cmp $bike_nodes->{$b}->{node_name} } keys (%$bike_nodes)){ + push (@_valxx, "$bike_nodes->{$rid}->{main_id}:$bike_nodes->{$rid}->{node_name} ($bike_nodes->{$rid}->{main_id})"); + } + print $but->selector_class("$key","eselect","width:100px;",$R::int12,@_valxx),"\n"; + } + elsif($key =~ /int20/ && "$size" eq "select"){# && $node_meta->{tpl_id} == 205){#lock_state locked/unlocked + my @_lock_valxx = (":$des"); + while (my ($key, $value) = each %{ $dbt->{copri_conf}->{lock_state} }) { + push @_lock_valxx, "$key:$value";#[2:unlocked] + } + print $but->selector_class("$key","eselect","width:100px;",$R::int20,@_lock_valxx),"\n"; + } + else{ + $size="9px" if($key =~ /int/); + if($key =~ /ct_name/){ + print $q->textfield(-class=>'stxt2',-name=>"$key",-default=>"",-size=>"$size",-maxlength=>40, -placeholder=>"$des",-autofocus=>1),"\n"; + }else{ + print $q->textfield(-class=>'stxt2',-name=>"$key",-default=>"",-size=>"$size",-maxlength=>40, -placeholder=>"$des"),"\n"; + } + } + } + print "\n"; + + + my ($daymarker,$raster_mmpx,$day4month) = $lb->month_line($users_dms); + + print $q->Tr(); + print $q->td({-class=>'element',-style=>"height:1.5em;padding:0;border:0px solid green;",-colspan=>"$h",-nowrap=>"1"},"$day4month"),"\n"; + ### + + ###Calendar Content + my $nx;my $set_style="";my $kind; + my $scale_color = $node_meta->{bg_color}; + my $edit="ct_trans"; + my $save_key="save"; + my $delete_key="delete"; + my $itime; + my $start_time; + my $end_time; + my ($year_st,$mon_st,$day_st,$hh_st,$mm_st); + my ($year_en,$mon_en,$day_en,$hh_en,$mm_en); + + my $nr=0; + my $i= $offset || 0; + $users_dms->{cal_sort_updown} = "down" if(!$users_dms->{cal_sort_updown}); + foreach my $pid (sort { + if($users_dms->{cal_sort_updown} eq "down"){ + $cttpos->{$b}->{end_time} cmp $cttpos->{$a}->{end_time} + }else{ + $cttpos->{$a}->{end_time} cmp $cttpos->{$b}->{end_time} + } + } keys(%$cttpos)){ + + $nr++; + $i++; + $nx++; + $set_style = "background-color:#fcfdfb;"; + $set_style = "background-color:#f4f1ee;" if($nx %= 2); + #$set_style = "background-color:$varenv{calendar_active_color}" if("$R::c_idpos" == "$cttpos->{$pid}->{c_id}"); + + my $trans_style = "padding:0 5px;border: 2px solid #f7ae37;"; + my $stamm_style = "padding:0 5px;border: 2px solid #98c13b;"; + my $ware_style = "padding:0 5px;border: 2px solid #dcd77f;"; + + my ($ct_name,$ct_txt00,$ct_txt01,$ct_phone,$c_id4trans,$tpl_id4trans,$u_name,$order_state22); + my $id = $cttpos->{$pid}->{ct_id}; + if($ct4rel->{$id}->{c_id} == $cttpos->{$pid}->{ct_id}){ + $ct_name = $ct4rel->{$id}->{ct_name}; + $ct_txt00 = $ct4rel->{$id}->{txt00}; + $ct_txt01 = $ct4rel->{$id}->{txt01}; + $ct_phone = $ct4rel->{$id}->{txt07}; + $order_state22 = $ct4rel->{$id}->{txt22}; + $c_id4trans = $ct4rel->{$id}->{c_id}; + $tpl_id4trans = $ct4rel->{$id}->{template_id}; + $trans_style .= "background-color:#f7ae37;" if($ct4rel->{$id}->{c_id} == $users_dms->{c_id4trans}); + } + ($year_st,$mon_st,$day_st,$hh_st,$mm_st) = $lb->split_date($cttpos->{$pid}->{start_time}) if($cttpos->{$pid}->{start_time}); + ($year_en,$mon_en,$day_en,$hh_en,$mm_en) = $lb->split_date($cttpos->{$pid}->{end_time}) if($cttpos->{$pid}->{end_time}); + + if($year_st && $mon_st && $day_st && $hh_st && $mm_st && $year_en && $mon_en && $day_en && $hh_en && $mm_en){ + + #generate px for rent scale + my $start_nr = $year_st . $mon_st . $day_st . $hh_st . $mm_st; + my $end_nr = $year_en . $mon_en . $day_en . $hh_en . $mm_en; + my $day_stpx = 0; + my $rent_day_px = 0; + my $time_style; + if($start_nr <= $end_nr){ + ($day_stpx,$rent_day_px) = $lb->rent_scale($users_dms,$year_st,$mon_st,$day_st,$hh_st,$mm_st,$year_en,$mon_en,$day_en,$hh_en,$mm_en); + }else{ + $time_style="color:red;"; + } + + if($cttpos->{$pid}->{start_time}){ + $itime = $lb->time4de($cttpos->{$pid}->{itime},1); + $start_time = $lb->time4de($cttpos->{$pid}->{start_time},1); + $end_time = $lb->time4de($cttpos->{$pid}->{end_time},1); + } + + my $u_name = $cttpos->{$pid}->{owner}; + my $u_name_end = $cttpos->{$pid}->{owner_end}; + foreach my $ctu_id (keys (%$ct_users)){ + if($channel_map->{$u_name}){ + $u_name = $channel_map->{$u_name}; + }elsif($cttpos->{$pid}->{owner} eq $ct_users->{$ctu_id}->{c_id}){ + $u_name = $ct_users->{$ctu_id}->{txt01}; + } + if($channel_map->{$u_name_end}){ + $u_name_end = $channel_map->{$u_name_end}; + }elsif($cttpos->{$pid}->{owner_end} eq $ct_users->{$ctu_id}->{c_id}){ + $u_name_end = $ct_users->{$ctu_id}->{txt01}; + } + } + + + #if($ct_name){ + if(1==1){ + print "\n"; + + my $pos_hash = $cttpos->{$pid}; + my $pos_details = ""; + foreach my $did (sort keys (%{$pos_hash})){ + $pos_details .= $did . " = " . $pos_hash->{$did} . "
    " if($pos_hash->{$did}); + } + my $pos_id = ""; + my $user_device = ""; + #if($users_dms->{u_id} == $dbt->{copri_conf}->{bike_state}->{superu_id}){ + if($users_dms->{u_id} && $users_dms->{u_id} =~ /1842|5781|11765/){ + $pos_id = $q->div({-class=>"popup",-onclick=>"toggle_box('$pid')"},"$cttpos->{$pid}->{c_id}", $q->span({-class=>"popuptext",-id=>"$pid"},"$pos_details")); + my $txt26 = $cttpos->{$pid}->{txt26}; + my $txt21 = $cttpos->{$pid}->{txt21}; + $txt26 = substr($cttpos->{$pid}->{txt26},0,20) . " ..." if(length($cttpos->{$pid}->{txt26}) > 20); + $txt21 = substr($cttpos->{$pid}->{txt21},0,50) . " ..." if(length($cttpos->{$pid}->{txt21}) > 50); + $user_device = ""; + $user_device .= " → lock charge $cttpos->{$pid}->{int14} %" if($cttpos->{$pid}->{int14}); + $user_device .= " → agent $txt26" if($txt26); + $user_device .= " → device $txt21" if($txt21); + } + + my $bikenr = "$cttpos->{$pid}->{barcode}"; + $bikenr = $q->a({-class=>"linknav3",-style=>"$stamm_style",-href=>"$script/$users_dms->{fullurl}/Waren/?detail_search=1&s_barcode=$cttpos->{$pid}->{barcode}",-title=>"Rad im Warenstamm"},"$cttpos->{$pid}->{barcode}") if($cttpos->{$pid}->{cc_id}); + # (Flotte $cttpos->{$pid}->{int12}) + # + + my $status = "$dbt->{copri_conf}->{bike_state}->{$cttpos->{$pid}->{int10}}" || "state failure"; + $status = "$dbt->{copri_conf}->{bike_state}->{$cttpos->{$pid}->{int10}}" if($cttpos->{$pid}->{int10} == 2 || $cttpos->{$pid}->{int10} == 3); + if($cttpos->{$pid}->{int10} ne $ct4rel_ware->{$cttpos->{$pid}->{cc_id}}->{int10}){ + $status = "$dbt->{copri_conf}->{bike_state}->{$cttpos->{$pid}->{int10}}"; + } + my $lock_state = "lock failure" if(!$cttpos->{$pid}->{int20}); + $lock_state = "locked" if($cttpos->{$pid}->{int20} == 1); + $lock_state = "unlocked" if($cttpos->{$pid}->{int20} == 2); + $lock_state = "locking in progress" if($cttpos->{$pid}->{int20} == 3); + + my $track_info = ""; + my $co2saving = ""; + if($cttpos->{$pid}->{int26}){ + $co2saving = $pri->co2calc($cttpos->{$pid}); + $cttpos->{$pid}->{int26} =~ s/\./,/; + $track_info = "→ - $co2saving kg CO² ($cttpos->{$pid}->{int26} km)"; + } + + if($node_meta->{ct_table} eq "contenttranspos"){ + my $start_station = "$cttpos->{$pid}->{int06}"; + my $end_station = "$cttpos->{$pid}->{int04}"; + $start_station = $q->a({-class=>"linknav3",-style=>"",-href=>"$script/$users_dms->{fullurl}/Waren/?detail_search=1&s_int04=$cttpos->{$pid}->{int06}",-title=>"Rad Warenstamm nach Station filtern"},"$cttpos->{$pid}->{int06}") if($ct4rel_ware->{$cttpos->{$pid}->{cc_id}}->{rel_id}); + $end_station = $q->a({-class=>"linknav3",-style=>"",-href=>"$script/$users_dms->{fullurl}/Waren/?detail_search=1&s_int04=$cttpos->{$pid}->{int04}",-title=>"Rad Warenstamm nach Station filtern"},"$cttpos->{$pid}->{int04}") if($ct4rel_ware->{$cttpos->{$pid}->{cc_id}}->{rel_id}); + my $kunde = $q->a({-class=>"linknav3",-style=>"$ware_style",-href=>"$script/$users_dms->{fullurl}/Kunden/?detail_search=1&s_c_id=$cttpos->{$pid}->{ca_id}",-title=>"Kunde im Kundenstamm"},"$cttpos->{$pid}->{txt08} ($cttpos->{$pid}->{ca_id})");#2021-05-24 saves kd name + + print $q->div({-style=>'float:left;margin-left:1em;font-size:0.91em;'}, "$i) $start_time – $end_time → $kunde → Start Station $start_station → End Station $end_station → Rad $bikenr $status $lock_state $track_info → $u_name $pos_id"),"\n"; + print $q->div({-style=>'float:left;margin-left:1em;font-size:0.91em;'}, "→ Faktura", $q->a({-class=>"linknav3",-style=>"$trans_style",-href=>"$script/$users_dms->{fullurl}/Faktura?ct_trans=open\&c_id4trans=$c_id4trans\&tpl_id4trans=$tpl_id4trans\&kind_of_trans=Faktura\&owner=$users_dms->{owner}",-title=>"Faktura Terminal öffnen"},"\#$ct_name")),"\n"; + print $q->div({-style=>'float:left;margin-left:1em;font-size:0.91em;'}, "$user_device"),"\n"; + + }elsif($node_meta->{ct_table} eq "contenttheftpos"){ + my $speed = 0; + if($cttpos->{$pid}->{int07} && $cttpos->{$pid}->{int07} > 0){ + $speed = $cttpos->{$pid}->{int07} * 1.852; + $speed = $lb->round_half($speed); + } + my $event_type = ""; + $event_type = "Diebstahlalarm" if($cttpos->{$pid}->{int01}); + $event_type = "GPS $cttpos->{$pid}->{txt06} → speed $speed km/h → distance $cttpos->{$pid}->{int08} Meter" if($cttpos->{$pid}->{int02}); + print $q->div({-style=>'float:left;margin-left:1em;font-size:0.91em;'}, "$i) $end_time → $event_type → Rad $bikenr → $u_name $pos_id"),"\n"; + + } + + print $q->div({-style=>"position:absolute;margin-left:$daymarker;border-right: solid thin #86cb00;height:1.5em;"}," "),"\n" if("$mon" eq "$mon_today"); + print $q->div({-style=>"position:static;margin-left:$day_stpx;width:$rent_day_px;height:1.5em;background-color:$scale_color;"}," "),"\n"; + print "\n"; + } + } + } + + print $q->end_table; + ### + + print "
    \n"; + + my $offset_nr = $offset + $nr; + + #backward | forward + print $q->div({-style=>'float:left;padding:0.5em;'}, "Zeile: $offset - $offset_nr"),"\n"; + print "
    \n"; + print $q->a({-class=>"linknav",-href=>"?go=backward_list;offset=$offset;limit=$limit",-title=>''},"< zurück ... ") if($offset >= $limit); + print $q->a({-class=>"linknav",-href=>"?go=forward_list;offset=$offset;limit=$limit",-title=>''}," ... vorwärts >") if($nr >= $limit-10); + print "
    \n"; + + print $q->end_form; +} +1; + diff --git a/copri4/main/src/Tpl/Liste3.pm b/copri4/main/src/Tpl/Liste3.pm new file mode 100644 index 0000000..4b5de53 --- /dev/null +++ b/copri4/main/src/Tpl/Liste3.pm @@ -0,0 +1,1517 @@ +package Liste3; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +# +#uncomment for perl -cw src/Tpl/Liste3.pm +#use lib qw(/var/www/copri4/main/src); +# +use strict; +use warnings; +use POSIX; +use CGI; +use CGI::Carp qw(fatalsToBrowser); +use CGI ':standard'; +use URI::Escape; +use Encode; +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Libenzdb; +use Mod::DBtank; +use Date::Calc qw(:all); +use Scalar::Util qw(looks_like_number); +use Storable; +use Mod::APIfunc; +use Data::Dumper; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my $node_meta = shift; + my $users_dms = shift; + my $u_group = shift; + my $return = shift; + + my $q = new CGI; + my @keywords = $q->param; + my $cf = new Config; + my $lb = new Libenz; + my $db = new Libenzdb; + my $but = new Buttons; + my $dbt = new DBtank; + my $apif = new APIfunc; + + my %varenv = $cf->envonline(); + my $script = $q->script_name(); + my $path_info = $q->path_info(); + my $path = $path_info; + #with meta_host, + if("$varenv{metahost}"){ + $path = "$script" . "$path_info"; + $script=""; + } + my $lang = "de"; + my $now_db = strftime("%d.%m.%Y %H:%M:%S",localtime(time)); + my $dbh = ""; + my $debug = 0; + + $path =~ s/\/login|\/user|\/manager|\/admin|\/$//; + my $user_agent = $q->user_agent(); + my $fullurl = $users_dms->{fullurl}; + my $saved_query = $q->url(-query=>1); + my %ib = $but->ibuttons(); + my $main_id = $node_meta->{main_id}; + my $tpl_id = $node_meta->{template_id}; + my $time = time; + my $today = strftime("%d.%m.%Y",localtime(time)); + my $now_date = strftime("%Y-%m-%d",localtime(time)); + #steht auch in Libenz + my @months = ("Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"); + my $mon = strftime "%m", localtime; + my $hh;my $mm; + my $day = strftime "%d", localtime; + my $mon = strftime "%m", localtime; + my $year = strftime "%Y", localtime; + ($year,$mon,$day,$hh,$mm) = $lb->split_date($users_dms->{cal_start}) if($users_dms->{cal_start}); + +################### new from Callib for collect_pos() ################ + + my $start_date_time = $R::start_date_time; + my $end_date_time = $R::end_date_time; + + $start_date_time = "01.$mon.$year" if(!$start_date_time); + + + my $days4month = Days_in_Month($year,$mon); + $end_date_time = "$days4month.$mon.$year" if(!$end_date_time); + + my $c_date; my $start_chck=0;my $end_chck=0;my $message; + if($start_date_time){ + ($start_date_time,$start_chck) = $lb->checkdate($start_date_time) if($start_date_time ne "%"); + $message .= ">>> Datum Eingabefehler: $start_date_time <<<" if($start_chck); + } + if($end_date_time){ + ($end_date_time,$end_chck) = $lb->checkdate($end_date_time) if($end_date_time ne "%"); + $message .= ">>> Datum Eingabefehler: $end_date_time <<<" if($end_chck); + } + + #sammle alle termine im definierten Zeitraum + my $search_startdt = $start_date_time; + my $search_enddt = $end_date_time; + #FIXME + $end_date_time .= " 23:59" if($end_date_time !~ / \d\:\d/); + + if("$start_date_time" eq "01.$mon.$year"){ + $search_startdt = "date \'$start_date_time\' - integer \'31\'" + }else{ + $search_startdt = "\'$start_date_time\'" + } + if("$end_date_time" eq "$days4month.$mon.$year"){ + $search_enddt = "date \'$end_date_time\' + integer \'31\'" + }else{ + $search_enddt = "\'$end_date_time\'" + } + + my $cttpos = {}; + my $cttpos_trans = {}; + my $cttpos_theft = {}; + if(($node_meta->{ct_table} eq "content") && ($node_meta->{tpl_id} == 205) && (!$start_chck && !$end_chck)){ + my $cttpos1 = $db->collect_postime("contenttranspos","$search_startdt","$search_enddt","$start_date_time","$end_date_time"); + foreach my $key (keys %$cttpos1){ + $cttpos_trans->{"trans_" . $key} = $cttpos1->{$key}; + } + my $cttpos2 = $db->collect_postime("contenttheftpos","$search_startdt","$search_enddt","$start_date_time","$end_date_time"); + foreach my $key (keys %$cttpos2){ + $cttpos_theft->{"theft_" . $key} = $cttpos2->{$key}; + } + } + + $cttpos = { %$cttpos_trans, %$cttpos_theft }; + +##################################################################### + + my $table = $node_meta->{ct_table} || "content"; + + my $hashfile = "$varenv{logdir}/$users_dms->{u_id}-$table-searchhash"; + + if((!$users_dms->{ek_view}) && ($table eq "content")){ + $node_meta->{tpl_order} =~ s/int01=EK €=5,//; + } + if($table eq "content"){ + $node_meta->{tpl_order} =~ s/txt17=[\w\s=]+,//; + $node_meta->{tpl_order} =~ s/byte01=[\w\s=]+,//; + } + if($table eq "contentadr" && $varenv{dbname} ne "sharee_primary"){ + $node_meta->{tpl_order} =~ s/txt17=[\w\s=]+,//; + $node_meta->{tpl_order} =~ s/txt19=[\w\s=]+,//; + } + $node_meta->{tpl_order} =~ s/c_id=raw=[\w\s=]+// if($users_dms->{u_id} != $dbt->{copri_conf}->{superu_id}); + + my @tpl_order = split /,/,$node_meta->{tpl_order}; + + my $scol = "c_id"; + $scol = "txt01" if($path =~ /Waren/); + #table columne check for col_sort + if($users_dms->{col_sort} eq "node_name" && ($table eq "contenttver")){ + $scol = "node_name"; + }elsif($users_dms->{col_sort} eq "date_time" && ($table =~ /contenttver|contenttrans/)){ + $scol = "end_time"; + }elsif($users_dms->{col_sort}){ + my $tinfo = $db->table_info($table); + foreach (keys(%$tinfo)){ + $scol = "$users_dms->{col_sort}" if("$users_dms->{col_sort}" eq "$tinfo->{$_}->{attname}"); + } + $db->users_up("col_sort","0",$users_dms->{owner}) if("$scol" ne "$users_dms->{col_sort}"); + } + + my $limit = $R::limit || $varenv{limit}; + my $offset = $R::offset || "0"; + if($node_meta->{int10} && $node_meta->{int10} < $varenv{limit}){ + $offset = 0; + } + + + #backward | forward + if($R::go && $R::go eq "backward_list"){ + $offset -= $limit if($offset >= $limit); + }elsif($R::go && $R::go eq "forward_list"){ + $offset += $limit; + } + + my ($daymarker,$raster_mmpx,$day4month) = $lb->month_line($users_dms); + my $rows = 0; + my $tpath = ""; + + #get Firma + my $ctf = $db->get_content1("contentuser","$dbt->{sharedms_conf}->{parent_id}"); + #get Benutzer + my $ctb = $db->get_content1("contentuser","$users_dms->{owner}"); + + + my ($umsatz,$edit,$new_key,$copy_key,$save_key,$delete_key,$c_id4csv); + my $ct4rel = {}; + my $ct4rel_parts = {}; + my $k=0; + my $message = ""; + + #print $q->end_form,"\n"; + print "
    \n"; + + my $v_journal = $R::v_journal || ""; + #if($path =~ /(\w+journal)/){ + # $v_journal = "$1" ; + #} + if($node_meta->{main_id} == $dbt->{shareeconf_dms}->{invoicejournal}){ + $v_journal = $node_meta->{node_name}; + } + + my $date = ""; + my $start_chck = 0; + my $end_chck = 0; + my $last_year = ""; + if($R::s_start_mtime){ + ($date,$start_chck) = $lb->checkdate($R::s_start_mtime) if($R::s_start_mtime !~ "%"); + $message .= ">>> Datum Eingabefehler: $date <<<" if($start_chck); + my ($c_dd,$c_mm,$c_yy) = split(/\./,$date); + $last_year = $c_yy if("$c_yy" eq "2011"); + } + if($R::s_end_mtime){ + ($date,$end_chck) = $lb->checkdate($R::s_end_mtime) if($R::s_end_mtime !~ "%"); + $message .= ">>> Datum Eingabefehler: $date <<<" if($end_chck); + my ($c_dd,$c_mm,$c_yy) = split(/\./,$date); + } + + my $searchref = {}; + + #Filter OPOS + if($path =~ /OPOS/){ + $R::detail_search="suchen"; + $searchref->{int14}=1; + $R::todo="Filter"; + $message .= ">>> Offene Payone Posten (Fehlgeschlagene Geldeinzüge) <<<"; + $offset=0; + $limit=10000; + } + + if($path =~ /langzeit/){ + $R::detail_search="suchen"; + $searchref->{long_rent}="1 day"; + $R::todo="Filter"; + $message .= ">>> langzeit Mieten (größer 1 Tag) sollten vor Faktura überprüft werden <<<"; + $offset=0; + $limit=10000; + } + + if(!$v_journal && !$R::detail_search && -f $hashfile && ($path =~ /letzte Suche/ || ($limit > $varenv{limit} && !$ctb->{int04}))){ + $R::todo="Filter"; + $message .= ">>> es wurden die letzten Suchparameter oder Filter geladen <<<"; + $offset=0; + $limit=10000; + } + + my $opos = ""; + if($node_meta->{node_name} eq "Tagesbericht"){ + $offset=0; + $limit = "1000"; + $R::detail_search="suchen"; + $v_journal = $node_meta->{node_name}; + $opos="null"; + $tpl_id = 218; + } + + + my $max_timestamp = ""; + $max_timestamp = "$1.$2.$3" if($ctf->{txt80} =~ /(\d{2})\.(\d{2})\.(\d{4})$/); + my $max_sum = $ctf->{int03} || ""; + if($max_timestamp){ + $limit = "2000"; + $message .= ">>> Buchbare Rechnungspositionen laut Einstellungen bis Buchungsdatum: $max_timestamp <<<"; + + } + if($max_sum){ + $message .= ">>> Buchbare Rechnungspositionen laut Einstellungen bis Verkaufssumme: $max_sum € <<<"; + } + $message=$R::message if($R::message); + + #CSV + my $export; + my $ck4ex = "@R::ck4ex" || ""; + $export = "check4export" if($R::ck4ex); + if($export || $R::ck4ex){ + $db->users_up("time4csv","$time",$users_dms->{u_id}); + $users_dms = $db->select_users($users_dms->{u_id}); + } + + #path-line + my $redirect; + $redirect = "(redirected)" if($R::redirected); + #top of bootstrap + my $header_style = ""; + $header_style = "border:2px solid #9f1f0e;" if($message); + + if($node_meta->{tpl_id} == 205){ + print $q->div({-class=>"copri_header",-style=>"background-color:$node_meta->{bg_color};"},"$path", $q->span({-style=>"padding:3px 10px;background-color:#86cbd7;color:white;"}, + " $months[$mon -1] $year", + $q->a({-class=>"linknav",-style=>"padding:0 0.5em;",-title=>"Monat zurück",-href=>"?cal_delta_start=0:-1:0"}," ← "), + $q->a({-class=>"linknav",-style=>"padding:0 0.5em;",-title=>"Monat aktuell",-href=>"?cal_today=1"},"•"), + $q->a({-class=>"linknav",-style=>"padding:0 0.5em;",-title=>"Monat vorwärts",-href=>"?cal_delta_start=0:1:0"}," → "), + "$message" + )),"\n"; + }else{ + print $q->div({-class=>"copri_header",-style=>"background-color:$node_meta->{bg_color};"},"$path $redirect",$q->span({-style=>"$header_style"},"$message")); + } + + print $q->start_form(-name=>'searchform'); + print $q->hidden(-name=>'todo', -value=>"Mindermenge") if($R::todo && $R::todo =~ /Mindermenge/); + print $q->hidden(-name=>'todo', -value=>"Waren-Summe") if($R::todo && $R::todo =~ /Waren-Summe/); + print $q->hidden(-name=>'offset', -value=>"$offset"); + print $q->hidden(-name=>'main_id', -value=>"$node_meta->{main_id}"); + print $q->hidden(-name=>'kind_of_trans', -value=>"$node_meta->{node_name}"); + print $q->hidden(-name=>'mode', -value=>"manager"); + print $q->hidden(-name=>'owner', -value=>"$users_dms->{u_id}"); + print $q->hidden(-name=>'template_id', -value=>"$node_meta->{template_id}"); + + my $tplids = "$tpl_id," || 0; + $tplids = "205,224,225,210,226,227,228,229" if(($table !~ /contentadr|contenttrans|contenttver|contentnel/) && !$export); + $tplids = 205 if($path =~ /Waren$/);#Defaults to only Verleih_list + + #collect depends Reparatur_list (AWs) template + my $ct_aw; my $ct4aw; + if($v_journal){ + $ct4aw = $db->collect_cid("content",$lang,"199"); + foreach my $aw_id (keys (%$ct4aw)){ + $ct_aw .= "$ct4aw->{$aw_id}->{c_id}|" + } + $ct_aw =~ s/\|$//; + } + + my $s_ct_name = $q->escapeHTML($R::s_ct_name) || ""; + my $s_barcode = $q->escapeHTML($R::s_barcode) || ""; + + #mandanten-modul abhängige rekursive suche + my $main_ids = ""; + if($v_journal && $v_journal =~ /Verleihjournal|Verkaufsjournal/){ + $main_ids = $dbt->{shareedms_conf}->{invoicejournal}; + $tplids = 209; + }else{ + $main_id = $dbt->{shareedms_conf}->{faktura} if($v_journal && $v_journal =~ /bericht/ || $R::todo);#starts at root + $main_ids = "$main_id,"; + my $excluded = "journal";#case is defined + $excluded = "Storno" if($R::todo && $R::todo eq "Filter"); + $main_ids .= $db->collect_noderec($main_id,$lang,"$excluded"); + } + $main_ids =~ s/,$//; + + if($v_journal){ + $offset=0; + $limit=10000; + $umsatz = "AW"; + } + + #Waren-nodes für Umsatz-Auswertung + my $w_nodes = ""; + my $verleih_nodes = ""; + + my $relnod = ""; + $relnod = $db->collect_rel4nodes($main_ids,"","","rel_id"); + + #Faktura/Verkaufsjournal menue (ex. Verleihjournal) + my $j_exist = $db->get_node4multi("300011",$lang); + + #nur für node_name in tabelle + my $nodes; + if($main_ids){ + $nodes = $db->collect_node2($main_ids); + }else{ + $lb->failure("Fehler! Es fehlen wichtige Einstellungen. ....journal-ID!"); + } + my $kt_sum=0; + my $ct_name_set1;my $ct_name_set2; + my $ct_ids;my $ct_aw_ids; my $last_ab; + + if($R::detail_search && $R::detail_search eq "suchen"){ + $offset = 0; + $limit = 10000; + } + + my $channel_map = $dbt->channel_map(); + my $mapref = {}; + my $ct_users = $dbt->users_map($dbh,$mapref);#get serviceAPP and DMS users from contentadr + + my @_users = (""); + foreach my $id (sort { $channel_map->{$a} cmp $channel_map->{$b} } keys (%$channel_map)){ + push (@_users, "$id:$channel_map->{$id}"); + if($R::s_owner && $channel_map->{$id} eq $R::s_owner){ + $searchref->{owner} = $id; + } + } + if(!$searchref->{owner}){ + foreach my $ctu_id (sort { $ct_users->{$a}->{txt01} cmp $ct_users->{$b}->{txt01} } keys (%$ct_users)){ + push (@_users, "$ct_users->{$ctu_id}->{c_id}:$ct_users->{$ctu_id}->{txt01}"); + if($ct_users->{$ctu_id}->{ct_name} && ($R::s_owner && $ct_users->{$ctu_id}->{txt01} =~ /$R::s_owner/i) || ($ct_users->{$ctu_id}->{c_id} eq $searchref->{owner})){ + $searchref->{owner} = $ct_users->{$ctu_id}->{c_id}; + } + } + } + + my $node = { template_id => 205,#Leihrad_liste + parent_id => 200013,#Waren + fetch => "all", + keyfield => "main_id", + }; + my $bike_nodes = $dbt->fetch_rel4tpl4nd($dbh,$node); + my $tariff_all = $db->collect_ct4rel("content","300026",$lang,"","","","","210"); + + my $ctrel = {}; + #only if permission read + if(($node_meta->{ct_table} eq "content" && $users_dms->{int01} >= 1) || ($node_meta->{ct_table} eq "contentadr" && $users_dms->{int02} >= 1) || ($node_meta->{ct_table} eq "contenttrans" && $users_dms->{int03} >= 1)){ + + my $c_id4trans = $R::c_id4trans || ""; + #Take only c_id from users if + if($users_dms->{c_id4trans} && $R::ct_trans && (($R::ct_trans eq "add_transadr" && $R::c_idadr) || ($R::ct_trans eq "add_transpos" && $R::c_id) || $R::ct_trans eq "new_trans")){ + $c_id4trans = $users_dms->{c_id4trans}; + } + + #only for adding to active transaction, disabled because of not browser tab save + #$ctrel = $db->get_ctrel("contenttrans","",$lang,"",$users_dms->{c_id4trans},$users_dms->{tpl_id4trans}); + + #without limit it will takes only one dataset + #if(($R::rel_id && $R::rel_id =~ /^\d+$/) || ($c_id4trans && $c_id4trans =~ /^\d+$/)){ + if((($R::rel_id && $R::rel_id =~ /^\d+$/) || ($c_id4trans && $c_id4trans =~ /^\d+$/)) && ($limit > $varenv{limit})){ + $ct4rel = $db->collect_cid($table,$lang,$tpl_id,$R::rel_id,$R::barcode,"c_id",$c_id4trans); + } + + #Suchen + elsif(!$start_chck && !$end_chck){ + #2020-12-01 changed to get last tablecontent, not only 1 by edit + #testing state + #if(!$start_chck && !$end_chck){ + $rows = $db->count_content($table,"$main_ids","$tplids"); + + #collect search keys + foreach my $postkey (@keywords){ + foreach(@tpl_order){ + my ($key,$val,$size) = split /=/,$_; + if($postkey =~ /s_$key|s_start_$key|s_end_$key/){ + my $val = $q->param($postkey); + $postkey =~ s/^s_//; + $searchref->{$postkey} = $val; + } + } + } + + #trying to save hashref + if(!$v_journal && $R::detail_search && ref($searchref) eq "HASH"){ + store $searchref, $hashfile; + }elsif(!$v_journal && !$R::detail_search && !$ctb->{int04} && -f $hashfile && ($path =~ /letzte Suche/ || $limit > $varenv{limit})){ + $searchref = {}; + $searchref = retrieve($hashfile); + } + + #print Dumper($searchref); + + + #Because of pre counting sum_pos + if($node_meta->{node_name} eq "Faktura"){ + if($v_journal && (!$R::detail_search || $R::s_start_mtime && $R::s_start_mtime =~ /letzt/)){ + my $xtime = "date \'$today\' + integer \'7\'";#just time + $last_ab = $db->get_content6("contenttrans","state","Kassenbestand","int09","$dbt->{shareedms_conf}->{parent_id}","int12","$j_exist->{main_id}","close_time","$xtime",""); + } + # + my $v_journalparts = $v_journal . "_parts"; + $ct4rel_parts = $db->search_content3($searchref,$table,$dbt->{shareedms_conf}->{parent_id},$node_meta->{node_name},$users_dms->{u_id},$lang,"$main_ids","$tplids","$ct_ids",$v_journalparts,$time,$R::s_kontext,$scol,$users_dms->{sort_updown},$offset,$limit,$export,$R::todo,$ck4ex,$opos); + + #collect invoice ids in kontext of parts + foreach my $cp_id (keys (%$ct4rel_parts)){ + $ct_ids .= "$ct4rel_parts->{$cp_id}->{ct_id}," if($R::detail_search && ($R::s_kontext && $R::s_kontext eq "Waren" || $export eq "FiBu")); + #pre collect of trans for AW + if(($umsatz eq "AW") && "$ct_aw" && ($ct4rel_parts->{$cp_id}->{cc_id} =~ /$ct_aw/)){ + $ct_aw_ids .= "$ct4rel_parts->{$cp_id}->{ct_id}|";# + } + } + } + + $ct4rel = $db->search_content3($searchref,$table,$dbt->{shareedms_conf}->{parent_id},$node_meta->{node_name},$users_dms->{owner},$lang,"$main_ids","$tplids","$ct_ids",$v_journal,$time,$R::s_kontext,$scol,$users_dms->{sort_updown},$offset,$limit,$export,$R::todo,$ck4ex,$opos); + }#end $ct4rel collect + }else{ + $return = "failure::Abbruch. Keine Zugriffsberechtigung"; + }#end permission read + + my $max_sum_pos = -10000; + my $max_op = ">="; + if($searchref->{int01} =~ /\d/){ + $max_sum_pos = $searchref->{int01}; + $max_sum_pos =~ s/\s//g; + $max_sum_pos =~ s/,/./g; + #$max_op = "=="; + if($max_sum_pos =~ /(\<\=|\>\=|\<|\>|\=\=)(\d+)/){ + $max_op = $1; + $max_sum_pos = $2; + } + } + print $q->div({-style=>'background-color:silver;height:10px;'}," "),"\n"; + my $hstyle = "border-right: solid thin gray;border-bottom: solid thin gray;"; + if($v_journal && $v_journal =~ /journal/){ + my ($a_check,$b_check,$c_check,$d_check,$f_check,$g_check); + $a_check = "1" if($R::s_kontext && $R::s_kontext eq "Waren"); + $umsatz="Summe der gefundenen Waren" if($R::s_kontext && $R::s_kontext eq "Waren"); + $b_check = "1" if($R::s_kontext && $R::s_kontext eq "Beleg" || !$R::s_kontext); + my @_s_time_defaults = ("0,manuelle Eingabe in \"bearbeitet\"","7,1 Woche","14,2 Wochen","28,4 Wochen","365,1 Jahr"); + #print $q->div({-style=>'float:left;background-color:silver;'}," Suchzeitraum: ",$but->selector("selected_start_mtime","130px","$R::selected_start_mtime",@_s_time_defaults)); + print "
    \n"; + print $q->span("Suchkontext: ",$but->radiobox("Beleg","s_kontext","$b_check"),"$node_meta->{node_name}/Kunde"); + print $q->span($but->radiobox("Waren","s_kontext","$a_check"),"Waren/FiBu"); + print "
    \n"; + } + print $q->hidden(-name=>'mandant_main_id', -value=>"$dbt->{shareedms_conf}->{parent_id}"),"\n"; + print $q->hidden(-name=>'tpl_id4trans', -value=>"$node_meta->{tpl_id}"),"\n"; + + print $q->start_table({ -style=>'clear:both;', -border=>'0', -width=>'100%',-align=>'center', -cellpadding=>'0', -cellspacing=>'0'}),"\n"; + #1. Zeile mit Suchfelder und NEU-Anlage + #table-switch!!! + my $sb_style = ""; + my $search = "search"; + if($v_journal =~ /journal/){ + $search = "search_export"; + $sb_style= "font-size:0.61em;"; + } + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-style=>"background-color:silver;$hstyle"},$but->singlesubmit1("detail_search","$search","","$sb_style;"),"\n"); + + $edit="rel_edit"; + $new_key="new_content"; + $save_key="save_content"; + $delete_key="delete_content"; + my $a_color = $node_meta->{bg_color} || "yellow"; + if($table eq "contentadr"){ + $edit="rel_edit"; + $new_key="new_adr"; + $save_key="save_adr"; + $delete_key="delete_adr"; + } + #contenttrans | contenttver via ct_trans + if($table eq "contenttrans"){ + $edit="ct_trans"; + $new_key="new_trans"; + $delete_key="delete_trans"; + }elsif($table eq "contenttver"){ + $edit="ct_trans"; + $new_key="new_tver"; + $delete_key="delete_tver"; + } + if($node_meta->{parent_id} >= "200000" && !$v_journal){ + print $q->td({-style=>"width:25px;background-color:$a_color;$hstyle"}, $but->singlesubmit2glyph("$edit","$new_key","$ib{$new_key}","background-color:$a_color;")); + print $q->hidden(-name=>'open_set_main_id', -value=>"$node_meta->{main_id}") if($table =~ /contenttrans/); + }else{ + print $q->td({-class=>'ebutton',-style=>"width:25px;background-color:$a_color;$hstyle"}," "),"\n"; + } + + #1. Search-fields + my $h=0; + my $s_val; + foreach(@tpl_order){ + $h++; + my ($key,$val,$size) = split /=/,$_; + if($size =~ /area/){ + $size = "10em"; + }elsif($key =~ /int0|c_id/){ + $size = "1em" if(!$size); + } + + $s_val = $searchref->{$key}; + #print "$key=$searchref->{$key}|"; + if($key =~ /byte|node|txt|int|uri|ct_name|c_id|barcode|sort|public/){ + if($table eq "content" && $tpl_id == 225 && $key eq "int04"){ + print $q->td({-class=>"search_line"},$q->textfield(-class=>'stxt',-name=>"s_$key",-default=>"$s_val",-size=>"$size",-maxlength=>40, -autofocus=>1),"\n"); + }elsif($table eq "content" && $key eq "barcode"){ + print $q->td({-class=>"search_line"},$q->textfield(-class=>'stxt',-name=>"s_$key",-default=>"$s_val",-size=>"$size",-maxlength=>40, -autofocus=>1),"\n"); + }elsif($table =~ /contentadr|contenttrans/ && $key eq "txt08"){ + print $q->td({-class=>"search_line"},$q->textfield(-class=>'stxt',-name=>"s_$key",-default=>"$s_val",-size=>"$size",-maxlength=>40, -autofocus=>1),"\n"); + }elsif($size =~ /select/ && $key =~ /int12|txt24/ && $tpl_id =~ /225|210/){#txt24=Flotten ID select + my @s_valxx = (""); + foreach my $rid (sort { $bike_nodes->{$a}->{node_name} cmp $bike_nodes->{$b}->{node_name} } keys (%$bike_nodes)){ + push (@s_valxx, "$bike_nodes->{$rid}->{main_id}:$bike_nodes->{$rid}->{node_name} - $bike_nodes->{$rid}->{main_id}"); + } + print $q->td({-class=>'search_line'},$but->selector_class("s_$key","","",$s_val,@s_valxx)),"\n"; + }elsif($size =~ /select/ && $key =~ /int21|int22/ && $tpl_id == 228){#Bonusnummern + my @s_valxx = (""); + foreach my $rid (sort { $tariff_all->{$a}->{barcode} <=> $tariff_all->{$b}->{barcode} } keys (%$tariff_all)){ + push (@s_valxx, "$tariff_all->{$rid}->{barcode}:$tariff_all->{$rid}->{barcode} - $tariff_all->{$rid}->{txt01}"); + } + print $q->td({-class=>'search_line'},$but->selector_class("s_$key","","",$s_val,@s_valxx)),"\n"; + }elsif($size =~ /select/ && $key !~ /txt23|txt24/){#txt23=color-code or txt24=Flotten ID select + my @s_valxx = (""); + my $s_hash = {}; + $s_hash = $dbt->{copri_conf}->{lock_state} if($tpl_id == 205 && $key eq "int20"); + $s_hash = $dbt->{copri_conf}->{bike_state} if($tpl_id == 205 && $key eq "int10"); + $s_hash = $dbt->{copri_conf}->{station_state} if($tpl_id == 225 && $key eq "int10"); + $s_hash = $dbt->{copri_conf}->{lock_system} if($tpl_id == 205 && $key eq "int11"); + $s_hash = $dbt->{copri_conf}->{sharing_type} if($tpl_id == 210 && $key eq "int18"); + $s_hash = { 1 => 1, 2 => 2, 3 => 3, 4 => 4 } if($tpl_id == 225 && $key eq "int07"); + while (my ($key, $value) = each %{ $s_hash }) { + push @s_valxx, "$key:$value";#[2:unlocked] + } + print $q->td({-class=>'search_line'},$but->selector_class("s_$key","","",$s_val,@s_valxx)),"\n"; + }else{ + print $q->td({-class=>"search_line"},$q->textfield(-class=>'stxt',-name=>"s_$key",-default=>"$s_val",-size=>"$size",-maxlength=>40),"\n"); + } + }elsif($key =~ /owner/){ + print $q->td({-class=>'search_line'},$but->selector("s_$key","80px","$s_val",@_users)),"\n"; + }elsif($key =~ /state/){ + my @_states = split(/\|/,$varenv{Zahlungsweise}); + my @_orderstates = split(/\|/,$varenv{order_state}); + push (@_states,@_orderstates); + print $q->td({-class=>'search_line'},$but->selector("s_$key","80px","$s_val",@_states)),"\n"; + } + my $s_mtime; my $e_mtime; + if($key eq "mtime"){ + $s_mtime = $searchref->{start_mtime}; + $e_mtime = $searchref->{end_mtime}; + } + if($key eq "atime"){ + $s_mtime = $searchref->{start_atime}; + $e_mtime = $searchref->{end_atime}; + } + if($key eq "bctime"){ + $s_mtime = $searchref->{start_bctime}; + $e_mtime = $searchref->{end_bctime}; + } + if($key eq "date_time"){ + $s_mtime = $searchref->{start_date_time}; + $e_mtime = $searchref->{end_date_time}; + } + + print $q->td({-nowrap=>1,-class=>"search_line"},$q->textfield(-id=>'datepicker1',-class=>'stxt',-name=>"s_start_$key",-default=>"$s_mtime",-size=>"$size",-maxlength=>20)),"\n" if($key =~ /time/); + } + + + #2. Tableheader + print $q->Tr(); + #permissions + if($users_dms->{int07} == 2){#only DMS-Account Admin + print $q->td({-style=>"background-color:silver;"},$q->checkbox(-name=>'toggle_all', -checked=>'', -value=>'off', -label=>'', -title=>'Alle auswählen', -onclick=>'CheckAll();')),"\n"; + }else{ + print $q->td({-style=>"background-color:silver;"}," "),"\n"; + } + my $i=0; + $i += 2; + if($R::ck4ex){ + print $q->th({-colspan=>2,-style=>'text-align:left;'},$q->a({-class=>'linknav3', href=>"$varenv{metahost}/pdf/$users_dms->{u_id}-$users_dms->{time4csv}.csv"},"CSV")," | ",$q->a({-class=>'linknav3', href=>"$varenv{metahost}/pdf/$users_dms->{u_id}-$users_dms->{time4csv}.xls"},"XLS")),"\n"; + }else{ + my $sort_up = "up"; + my $sort_down = "down"; + $sort_up = "$sort_up" if($users_dms->{sort_updown} eq "up"); + $sort_down = "$sort_down" if($users_dms->{sort_updown} eq "down"); + + print $q->th($q->a({-class=>"sortnav",-href=>"?sort_updown=up\&offset=$offset\&limit=$limit",-title=>'Aufsteigend sortieren'},"$sort_up"),"|",$q->a({-class=>"sortnav",-href=>"?sort_updown=down\&offset=$offset\&limit=$limit",-title=>'Absteigend sortieren'},"$sort_down")),"\n"; + print $q->th(""),"\n"; + } + foreach (@tpl_order){ + my ($key,$val,$size,$title) = split /=/,$_; + my $sort_title=" $title"; + $val = "$val" if($key eq $users_dms->{col_sort}); + if($key =~ /byte|txt|time|node|int|uri|save|state|owner|c_id|ct_name|barcode|sort|public/){ + $i++; + print $q->th($q->a({-class=>"sortnav",-href=>"?col_sort=$key\&offset=$offset\&limit=$limit",-title=>"$sort_title"},"$val")),"\n"; + } + } + + #TODO, chrome breaks timeline + #print $q->th(" "),"\n"; + my $tdcal = scalar @tpl_order; + #$tdcal++; + #print "$tdcal xxxxxxxxx"; + if($tpl_id == "205"){#205=Verleih + print $q->Tr(); + print $q->td({-style=>'background-color:silver;'},""),"\n"; + print $q->td({-class=>'tdtxt',-style=>'background-color:silver;',-colspan=>2},"$months[$mon -1] $year"),"\n"; + print $q->td({-style=>"font-size:0.71em;padding:0;border:0px solid green;",-colspan=>"$tdcal",-nowrap=>"1"},"$day4month"),"\n"; + } + #print $q->end_form,"\n"; + + my $sum_bar="0";my $sum_ec="0";my $sum_kredit="0";my $sum_abb="0";my $sum_ueb="0";my $sum_geka="0";my $sum_paypal="0";my $sum_SEPApayone="0";my $sum_CCpayone="0";my $sum_ausfall="0";my $sum_kasse="0";my $sum_start="0";my $close_time="";my $payment_time="";my $sum_waren;my $sum_verkauf;my $sum_kaution;my $sum_aw;my $sum_am;my $sum_park; my $sum_radd;my $sum_wst_ek=0; my $sum_wst_vk=0; my $sum_verleih; + my $nr=0;my $nx=0; + my $check_kaution=0; + my $rabatt_key; my $kost_key; + + #BIG LOOP loop content table + foreach my $id (sort { + if($users_dms->{sort_updown} eq "down"){ + if ($scol =~ /barcode|int/) { + $ct4rel->{$b}->{$scol} <=> $ct4rel->{$a}->{$scol} + }else{ + lc($ct4rel->{$b}->{$scol}) cmp lc($ct4rel->{$a}->{$scol}) + } + }else{ + if ($scol =~ /barcode|int/) { + $ct4rel->{$a}->{$scol} <=> $ct4rel->{$b}->{$scol} + }else{ + lc($ct4rel->{$a}->{$scol}) cmp lc($ct4rel->{$b}->{$scol}) + } + } + } keys(%$ct4rel)){ + + my ($set_style,$set_style4nr,$sum_error); + my $ecol=0; + + if($ct4rel->{$id}->{int01} > 0 && $ct4rel->{$id}->{int03} > 0){ + $sum_wst_ek += $ct4rel->{$id}->{int01} * $ct4rel->{$id}->{int03}; + } + if($ct4rel->{$id}->{int02} > 0 && $ct4rel->{$id}->{int03} > 0){ + $sum_wst_vk += $ct4rel->{$id}->{int02} * $ct4rel->{$id}->{int03}; + } + + #AWs Faktor from Firma + if($table eq "content" && $ctf->{int02} != 0 && $ct4rel->{$id}->{int09} != 0){ + $ct4rel->{$id}->{int02} = $ctf->{int02} * $ct4rel->{$id}->{int09}; + $ct4rel->{$id}->{int02} = $lb->cashme($ct4rel->{$id}->{int02}); + } + + # check sum_pos and sum_buchen + my $sum_pos=0; + #if($v_journal && $ct4rel->{$id}->{state} ne "Kassenbestand"){ + if($ct4rel->{$id}->{state} ne "Kassenbestand"){ + foreach my $cpid (keys (%$ct4rel_parts)){ + if(($ct4rel->{$id}->{c_id} eq $ct4rel_parts->{$cpid}->{ct_id}) && (looks_like_number($ct4rel_parts->{$cpid}->{int02}) && $ct4rel_parts->{$cpid}->{int02} != 0) && (looks_like_number($ct4rel_parts->{$cpid}->{int03}) && $ct4rel_parts->{$cpid}->{int03} != 0)){ + if($ct4rel_parts->{$cpid}->{int07} != 0){ + my $rabatt_eur = $ct4rel_parts->{$cpid}->{int07}; + $rabatt_eur = $ct4rel_parts->{$cpid}->{int02} * $ct4rel_parts->{$cpid}->{int03} * $ct4rel_parts->{$cpid}->{int07}/100 if($ct4rel_parts->{$cpid}->{int08} != 1);#wenn int08 != 1 alias € + #$rabatt_eur = $lb->round($rabatt_eur); + $sum_pos += $ct4rel_parts->{$cpid}->{int02} * $ct4rel_parts->{$cpid}->{int03} - $rabatt_eur; + }else{ + $sum_pos += $ct4rel_parts->{$cpid}->{int02} * $ct4rel_parts->{$cpid}->{int03}; + } + } + } + my $sum_chk = $ct4rel->{$id}->{int01}; + $sum_pos = $lb->round($sum_pos); + $sum_pos = $lb->cashme($sum_pos); + my $sum_chkdiff = $sum_chk - $sum_pos;#wegen $rabatt_eur kleine Rundungsfehler zulassen. + if($ct4rel->{$id}->{int01} && ($sum_pos ne $sum_chk) && ($sum_chkdiff > 0.02 || $sum_chkdiff < -0.02)){ + $sum_error = "1"; + } + $sum_error = "0" if($R::s_kontext && $R::s_kontext eq "Waren" || $R::node2edit || $R::ct_trans); + } + + + my $u_name = $ct4rel->{$id}->{owner}; + foreach my $ctu_id (keys (%$ct_users)){ + if($channel_map->{$u_name}){ + $u_name = $channel_map->{$u_name}; + }elsif($ct4rel->{$id}->{owner} eq $ct_users->{$ctu_id}->{c_id}){ + $u_name = $ct_users->{$ctu_id}->{txt01}; + } + } + + #print $q->start_form(-name=>'listeform'); + + $sum_kasse = $ct4rel->{$id}->{int01} if($ct4rel->{$id}->{state} eq "Kassenbestand"); + $sum_start = $ct4rel->{$id}->{int02} if($ct4rel->{$id}->{state} eq "Kassenbestand"); + + if(eval($sum_pos . $max_op . $max_sum_pos) || $table ne "contenttrans"){ + if(1==1){ + $nr++; + $nx=$nr; + $close_time = $ct4rel->{$id}->{close_time} if($ct4rel->{$id}->{close_time}); + $close_time = $lb->time4de($close_time,"1") if($close_time); + $payment_time = ""; + if($ct4rel->{$id}->{payment_time}){ + $payment_time = $ct4rel->{$id}->{payment_time}; + $payment_time = $lb->time4de($payment_time,"1"); + } + $sum_bar += $ct4rel->{$id}->{int01} if($ct4rel->{$id}->{state} && $ct4rel->{$id}->{state} =~ /^Bar/); + $sum_ec += $ct4rel->{$id}->{int01} if($ct4rel->{$id}->{state} && $ct4rel->{$id}->{state} =~ /EC/); + #$sum_kredit += $ct4rel->{$id}->{int01} if($ct4rel->{$id}->{state} && $ct4rel->{$id}->{state} =~ /Kredit/); + $sum_abb += $ct4rel->{$id}->{int01} if($ct4rel->{$id}->{state} && $ct4rel->{$id}->{state} =~ /Abbuchung/); + $sum_ueb += $ct4rel->{$id}->{int01} if($ct4rel->{$id}->{state} && $ct4rel->{$id}->{state} =~ /Überweisung/); + $sum_SEPApayone += $ct4rel->{$id}->{int01} if($ct4rel->{$id}->{state} && $ct4rel->{$id}->{state} =~ /SEPA.*payone|Zahlungseingang.*payone/); + $sum_CCpayone += $ct4rel->{$id}->{int01} if($ct4rel->{$id}->{state} && $ct4rel->{$id}->{state} =~ /Kreditkarte.*payone/); + $sum_ausfall += $ct4rel->{$id}->{int01} if($ct4rel->{$id}->{state} && $ct4rel->{$id}->{state} =~ /Zahlungsausfall/); + $c_id4csv .= "$ct4rel->{$id}->{c_id},"; + $ct4rel->{$id}->{ct_name} = $q->unescapeHTML($ct4rel->{$id}->{ct_name}) || ""; + $ct4rel->{$id}->{c_id} = $q->unescapeHTML($ct4rel->{$id}->{c_id}) || ""; + $set_style = "background-color:#fcfdfb;"; + $set_style = "background-color:#f4f1ee;" if($nx %= 2); + #$set_style = "background-color:#e4f1ee;" if($ct4rel->{$id}->{ct_name} eq $ct4rel->{$id}->{barcode}); + my $ccc_id = $R::c_id || $R::c_id4trans || $users_dms->{c_id4trans}; + $set_style = "background-color:$node_meta->{bg_color};" if(($R::rel_id && $R::rel_id eq $ct4rel->{$id}->{rel_id}) && !$R::empty_rel_id); + $set_style = "background-color:$node_meta->{bg_color};" if(($ccc_id && $ccc_id eq $ct4rel->{$id}->{content_id}) && ("$table" =~ /contenttrans/)); + $set_style = "background-color:$node_meta->{bg_color};" if(($ccc_id && $ccc_id eq $ct4rel->{$id}->{content_id}) && ("$table" =~ /contenttver/)); + + #red + $set_style = "background-color:#d39c9c;" if($sum_error && $sum_error == 1 && $node_meta->{node_name} eq "Faktura"); + $set_style4nr = $set_style; + my $m_id; + my $nodeline2; + my $nodeline_name2; + my $nodelist; + + + #Instanz Buttons-Logic + print $q->Tr(),"\n"; + #checkboxes + #permissions + if($users_dms->{int07} == 2){#only DMS-Account Admin + print $q->td({-style=>"background-color:silver;"}, $q->checkbox(-name=>"ck4ex", -checked=>'', -value=>"$ct4rel->{$id}->{c_id}", -label=>'')),"\n"; + }else{ + print $q->td({-style=>"background-color:silver;"}," "),"\n"; + } + #1.Spalte + if("$ct4rel->{$id}->{main_id}" eq "$node_meta->{main_id}" || "$ct4rel->{$id}->{main_id}" eq "$node_meta->{parent_id}"){ + if($table =~ /content$|contentadr|contentnel/){ + $ecol++; + print "\n"; + #2021-06-08 disabled because dms must be browser-tab save + if(1==2 && $table eq "content" && ($ct4rel->{$id}->{template_id} =~ /205|224|229/)){#bikes|Gutschein|Zubehör + print $q->a({-class=>"editnav",-href=>"$tpath?ct_trans=add_transpos\&mandant_main_id=$dbt->{shareedms_conf}->{parent_id}\&kind_of_trans=$users_dms->{kind_of_trans}\&c_id=$ct4rel->{$id}->{content_id}\&owner=$users_dms->{u_id}",-title=>"zum $users_dms->{kind_of_trans} \#$ctrel->{ct_name} $ctrel->{txt01} hinzufügen"}, $q->img({-src=>"$varenv{metahost}/glyphicons/glyphicons-512-copy.png", -style=>'height:1.3em;'})); + } + if($table eq "content" && ($ct4rel->{$id}->{template_id} =~ /205|225/)){ + my $rnid = $ct4rel->{$id}->{rel_id}; + my $node_names = "failure $rnid | $relnod->{$rnid}->{content_id} == $ct4rel->{$id}->{c_id}"; + if($relnod->{$rnid}->{content_id} && $relnod->{$rnid}->{content_id} == $ct4rel->{$id}->{c_id}){ + $node_names = $relnod->{$rnid}->{node_name}; + }else{ + my $subnode = $dbt->get_subrelnode($dbh,$node_meta->{main_id}); + $node_names = $subnode->{node_name}; + } + my $search_key = "s_barcode=$ct4rel->{$id}->{barcode}";#bike + $search_key = "s_int04=$ct4rel->{$id}->{int04}" if($ct4rel->{$id}->{template_id} == 225);#station + print $q->a({-class=>"editnav",-href=>"$path/$node_names?detail_search=1\&$search_key",-title=>"zur Liste der Rad $ct4rel->{$id}->{barcode} Servicearbeiten"}, $q->img({-src=>"$varenv{metahost}/glyphicons/glyphicons-440-wrench.png", -style=>'height:1em;'})); + } + ## + print "\n"; + }elsif($users_dms->{u_id} > 0 && "$table" =~ /contenttrans|contenttver/){ + print "\n"; + print "\n"; + }else{ + $ecol++; + print $q->td({-style=>"$set_style"}),"\n"; + } + }elsif($ct4rel->{$id}->{content_id} && !$v_journal){ + #2017-11-10 simple multi node_name directory view + $ecol++; + my $rnid = $ct4rel->{$id}->{rel_id}; + my $node_names = "failure $rnid | $relnod->{$rnid}->{content_id} == $ct4rel->{$id}->{c_id}"; + if($relnod->{$rnid}->{content_id} && $relnod->{$rnid}->{content_id} == $ct4rel->{$id}->{c_id}){ + $node_names = $relnod->{$rnid}->{node_name}; + }else{ + my $subnode = $dbt->get_subrelnode($dbh,$node_meta->{main_id}); + $node_names = $subnode->{node_name}; + } + + #node_names fails TODO + if(1==1 && $table eq "content" && ($ct4rel->{$id}->{template_id} =~ /205|225/)){ + my $search_key = "s_barcode=$ct4rel->{$id}->{barcode}";#bike + $search_key = "s_int04=$ct4rel->{$id}->{int04}" if($ct4rel->{$id}->{template_id} == 225);#station + print $q->td({-class=>'tdtxt',-colspan=>1,-style=>"$set_style", -nowrap=>1}, $q->a({-class=>"editnav",-href=>"$path/$node_names?detail_search=1\&$search_key",-title=>"zur Liste der Rad $ct4rel->{$id}->{barcode} Servicearbeiten $ct4rel->{$id}->{main_id}"},"$node_names")), "\n"; + }else{ + print $q->td({-class=>'tdtxt',-colspan=>1,-style=>"$set_style", -nowrap=>1},"$node_names"),"\n"; + } + + }elsif("$table" =~ /contenttrans/ && $v_journal){ + $ecol++; + print "\n"; + print $q->a({-class=>"editnav",-href=>"?ct_trans=open\&mode=manager\&c_id4trans=$ct4rel->{$id}->{c_id}\&tpl_id4trans=$ct4rel->{$id}->{template_id}\&kind_of_trans=$node_meta->{node_name}\&owner=$users_dms->{u_id}\&offset=$offset\&limit=$limit",-title=>"öffnen"}, $q->img({-src=>"$varenv{metahost}/img/actions/project-open.png"})); + print "\n"; + }else{ + $ecol++; + print $q->td({-class=>'element',-colspan=>1,-style=>"$set_style"},""),"\n"; + } + $ecol++; + + #2.Spalte + my $ny=""; + if($table eq "contentadr" && ($ct4rel->{$id}->{int12} || !$ct4rel->{$id}->{int04} || !$ct4rel->{$id}->{int13})){ + print $q->td({-class=>'tdicon',-style=>"$set_style color:red;"},"•","\n") if($ecol <= "2"); + }elsif($table eq "contenttrans" && (($ct4rel->{$id}->{txt28} && $ct4rel->{$id}->{txt28} =~ /error/i) || ($ct4rel->{$id}->{int14} && $ct4rel->{$id}->{int14} == 1))){ + print $q->td({-class=>'tdicon',-style=>"$set_style color:red;"},"•","\n") if($ecol <= "2"); + }elsif($table eq "content" && $ct4rel->{$id}->{template_id} == 227){ + my $dir_thumb = "$varenv{data}/$node_meta->{main_id}-thumb/$ct4rel->{$id}->{c_id}"; + my @pics = $lb->read_dirfiles($dir_thumb,"\.JPG|\.PNG","file",""); + my $dir_main = "$varenv{data}/$node_meta->{main_id}/$ct4rel->{$id}->{c_id}"; + my @docs = $lb->read_dirfiles($dir_main,"\.HTML","file",""); + + print "\n"; + + if( -d "$dir_thumb" && scalar(@pics) > 0){ + foreach(@pics){ + print $q->span($q->img({-style=>'max-width:75px;',-src=>"$varenv{metahost}/data/$node_meta->{main_id}-thumb/$ct4rel->{$id}->{c_id}/$_"},"$_")),"\n"; + print $q->br(),"\n" if(scalar(@pics) > 1); + } + } + print "\n"; + + }else{ + $ny = $nr if($path =~ /letzte Suche/); + print $q->td({-class=>'tdint',-style=>"$set_style color:grey;"},"$ny"),"\n" if($ecol <= "2"); + } + #print $q->td("$ecol\n") if($ecol <= "2"); + #my $ctimg = "000empty"; + #my $ct_name4img = "$ct4rel->{$id}->{ct_name}.jpg"; + #$ct_name4img =~ s/\s//g; + #my $title = "Foto nicht vorhanden"; + #if(-f "$varenv{img4thumb}/$ct_name4img"){ + # $ctimg = "$ct_name4img"; + # $title="$ct4rel->{$id}->{ct_name}"; + #} + #print $q->td({-class=>'element',-style=>"$set_style"},$q->a({-href=>"/img4ct/$ctimg",-rel=>'lightbox',-title=>"$title"},$q->img({-src=>"/img4thumb/$ctimg", -style=>'max-width:20px;border:1px solid silver;'}))); + + + #Tablecontent (parameter) + $k=0; + foreach (@tpl_order){ + $k++; + my ($key,$val,$size,$colorize) = split /=/,$_; + $rabatt_key = 1 if($key =~ /int07/); + $kost_key = 1 if($key =~ /node05|node08/); + my $txtstyle = "text-align:left;"; + my $isize = "26"; + if($key =~ /barcode|c_id|ct_name|int|state|sort|public/){ + $txtstyle = "text-align:right;max-width:8em;"; + $isize = "5"; + $isize = "5" if($key =~ /int/); + } + $isize = $size if($size =~ /\d/); + $ct4rel->{$id}->{$key} = $lb->time4de($ct4rel->{$id}->{$key},"1") if($key =~ /time/); + $ct4rel->{$id}->{$key} = $q->unescapeHTML($ct4rel->{$id}->{$key});# if($key !~ /byte/); + my $br4text = $R::node2edit || ""; + $ct4rel->{$id}->{$key} = $lb->newline($ct4rel->{$id}->{$key},"","$br4text"); + $set_style4nr = $set_style; + $set_style4nr="background-color:#e3dbc9;" if(($key eq "barcode") || ($key eq "int04")); + #$set_style4nr="background-color:#e3dbc9;" if($key eq "barcode"); + $ct4rel->{$id}->{$key} =~ s/\./,/ if($key =~ /int/); + + if($key eq "c_id" && $val eq "raw"){ + + my $pos_hash = $ct4rel->{$id}; + my $pos_details = ""; + foreach my $did (sort keys (%{$pos_hash})){ + my $teaser = ""; + if($pos_hash->{$did}){ + $teaser = substr($pos_hash->{$did},0,30); + } + $pos_details .= $did . " = " . $teaser . "
    "; + } + + my $pos_id = $q->div({-class=>"popup",-onclick=>"toggle_box('$id')"},"$ct4rel->{$id}->{c_id}", $q->span({-class=>"popuptext",-id=>"$id"},"$pos_details")); + print $q->td({-class=>'tdtxt',-style=>"font-weight:normal;$set_style4nr"},"$pos_id"),"\n"; + } + elsif($key =~ /ct_name|c_id/ && $ct4rel->{$id}->{$key}){ + if($table =~ /contenttrans|contenttver/){ + print $q->td({-class=>'tdint',-style=>"font-weight:normal;$set_style4nr"},$q->a({-class=>"linknav3",-href=>"?ct_trans=open\&mode=manager\&c_id4trans=$ct4rel->{$id}->{c_id}\&tpl_id4trans=$ct4rel->{$id}->{template_id}\&kind_of_trans=$node_meta->{node_name}\&owner=$users_dms->{u_id}\&offset=$offset\&limit=$limit",-title=>"Terminal öffnen"},"$ct4rel->{$id}->{$key}")); + }elsif($table =~ /content$|contentadr|contentnel/){ + if($varenv{wwwhost} =~ /regiox/ && $key =~ /ct_name/){ + print $q->td({-class=>"tdtxt",-style=>"font-weight:normal;$set_style4nr"},"$ct4rel->{$id}->{$key}"); + }else{ + print $q->td({-class=>"tdint",-style=>"font-weight:normal;$set_style4nr"},$q->a({-class=>"linknav3",-href=>"?node2edit=editpart\&mode=manager\&rel_id=$ct4rel->{$id}->{rel_id}\&offset=$offset\&limit=$limit",-title=>"Terminal öffnen"},"$ct4rel->{$id}->{$key}")),"\n"; + } + }elsif(($node_meta->{tpl_order} !~ /barcode/) || ("$ct4rel->{$id}->{$key}" ne "$ct4rel->{$id}->{barcode}")){ + print $q->td({-class=>'tdint',-style=>"font-weight:bold;$set_style4nr"},"$ct4rel->{$id}->{$key}"),"\n"; + }else{ + print $q->td({-class=>'tdint',-style=>"font-weight:bold;$set_style4nr"},""),"\n"; + } + }elsif($key =~ /txt01/ && $table =~ /contenttrans|contenttver/){ + print $q->td({-class=>'tdtxt',-style=>"font-weight:normal;$set_style4nr"},$q->a({-class=>"linknav3",-href=>"?ct_trans=open\&mode=manager\&c_id4trans=$ct4rel->{$id}->{c_id}\&tpl_id4trans=$ct4rel->{$id}->{template_id}\&kind_of_trans=$node_meta->{node_name}\&owner=$users_dms->{u_id}\&offset=$offset\&limit=$limit",-title=>"Terminal öffnen"},"$ct4rel->{$id}->{$key}")),"\n"; + + }elsif($key =~ /txt01/ && $table =~ /content$|contentadr/){ + my $txt01 = "---"; + $txt01 = "$ct4rel->{$id}->{$key}" if($ct4rel->{$id}->{$key}); + print $q->td({-class=>'tdtxt',-style=>"font-weight:normal;$set_style4nr"},$q->a({-class=>"linknav3",-href=>"?node2edit=editpart\&mode=manager\&rel_id=$ct4rel->{$id}->{rel_id}\&offset=$offset\&limit=$limit",-title=>"Terminal öffnen"},"$txt01")),"\n"; + }elsif($key =~ /barcode/ && $table =~ /content$|contentadr/ && $ct4rel->{$id}->{template_id} != 225){ + print $q->td({-class=>'tdint',-style=>"font-weight:normal;$set_style4nr"},$q->a({-class=>"linknav3",-href=>"?node2edit=editpart\&mode=manager\&rel_id=$ct4rel->{$id}->{rel_id}\&offset=$offset\&limit=$limit",-title=>"Terminal öffnen"},"$ct4rel->{$id}->{$key}")),"\n"; + }elsif($key =~ /int04/ && $table eq "content" && $ct4rel->{$id}->{template_id} == 225){ + print $q->td({-class=>'tdint',-style=>"font-weight:normal;$set_style4nr"},$q->a({-class=>"linknav3",-href=>"?node2edit=editpart\&mode=manager\&rel_id=$ct4rel->{$id}->{rel_id}\&offset=$offset\&limit=$limit",-title=>"Terminal öffnen"},"$ct4rel->{$id}->{$key}")),"\n"; + }elsif($key =~ /int04/ && $table eq "content" && $ct4rel->{$id}->{template_id} == 205){ + print $q->td({-class=>'tdint',-style=>"font-weight:normal;"},$q->a({-class=>"linknav3",-style=>"",-href=>"?detail_search=1&s_int04=$ct4rel->{$id}->{$key}",-title=>"Rad Warenstamm nach Station filtern"},"$ct4rel->{$id}->{$key}")); + }elsif($key =~ /date_time/){ + $ct4rel->{$id}->{start_time} = $lb->time4de($ct4rel->{$id}->{start_time},"1") if($ct4rel->{$id}->{start_time}); + $ct4rel->{$id}->{end_time} = $lb->time4de($ct4rel->{$id}->{end_time},"1") if($ct4rel->{$id}->{end_time}); + print $q->td({-class=>'tdtxt',-style=>"$txtstyle $set_style", -nowrap=>1},"$ct4rel->{$id}->{start_time} - $ct4rel->{$id}->{end_time}"),"\n"; + }elsif($key =~ /int01/ && $node_meta->{node_name} eq "Faktura"){ + if($ct4rel->{$id}->{state} eq "Kassenbestand"){ + print $q->td({-class=>'tdint',-style=>"$txtstyle $set_style"},$q->b("Tatsächl. $ct4rel->{$id}->{$key}")),"\n"; + }else{ + my $betrag = $ct4rel->{$id}->{$key} || "∑ $sum_pos";# pre counting + $betrag = $ct4rel->{$id}->{$key} if($v_journal); + $betrag =~ s/\./,/; + print $q->td({-class=>'tdint',-style=>"$txtstyle $set_style"},"$betrag"),"\n"; + } + }elsif($key =~ /int02/ && $ct4rel->{$id}->{state} eq "Kassenbestand"){ + print $q->td({-class=>'tdint',-style=>"$txtstyle $set_style"},$q->b("Anfangst. $ct4rel->{$id}->{$key}")),"\n"; + }elsif($key =~ /int03/ && "$table" eq "contenttrans"){ + print $q->td({-class=>'tdint',-style=>"$txtstyle $set_style"},""),"\n"; + }elsif($key =~ /mtime/ && $ct4rel->{$id}->{close_time}){ + my $close = "
    $close_time TaAb."; + my $payment = ""; + $payment = "
    $payment_time ZaEi." if($payment_time); + print $q->td({-class=>'tdint',-style=>"$txtstyle $set_style"},"$ct4rel->{$id}->{$key} $close $payment"),"\n"; + }elsif($key =~ /owner/){ + print $q->td({-class=>'tdint',-style=>"$txtstyle $set_style"},"$u_name"),"\n"; + }elsif($key =~ /state/){ + my $order_state = ""; + $order_state = "$ct4rel->{$id}->{txt22}" if($ct4rel->{$id}->{txt22}); + $order_state = "$ct4rel->{$id}->{txt22},
    " if($ct4rel->{$id}->{txt22} && $ct4rel->{$id}->{$key}); + my $capture_state = "$ct4rel->{$id}->{$key}"; + $capture_state = "$ct4rel->{$id}->{$key}" if($ct4rel->{$id}->{$key} =~ /payone/ && $ct4rel->{$id}->{int14} == 1); + print $q->td({-class=>'tdint',-style=>"$txtstyle $set_style"},"$order_state $capture_state"),"\n"; + }elsif($ct4rel->{$id}->{template_id} =~ /205|225/ && $key eq "int10"){#bike_state + my $colorize = ""; + $colorize = "color:#c63e3e;" if($ct4rel->{$id}->{$key} == 2 || $ct4rel->{$id}->{$key} == 3); + $colorize = "color:#bd2424;" if($ct4rel->{$id}->{$key} == 4 || $ct4rel->{$id}->{$key} == 5 || $ct4rel->{$id}->{$key} == 6); + print $q->td({-class=>'tdtxt',-style=>"$txtstyle $set_style $colorize"},"$dbt->{copri_conf}->{bike_state}->{$ct4rel->{$id}->{$key}}"),"\n"; + }elsif($ct4rel->{$id}->{template_id} == 205 && $key eq "int20"){#lock_state + my $colorize = ""; + $colorize = "color:#c63e3e;" if($ct4rel->{$id}->{$key} == 2 || $ct4rel->{$id}->{$key} == 3); + print $q->td({-class=>'tdtxt',-style=>"$txtstyle $set_style $colorize"},"$dbt->{copri_conf}->{lock_state}->{$ct4rel->{$id}->{$key}}"),"\n"; + }elsif($ct4rel->{$id}->{template_id} == 205 && $key eq "int11"){#lock_system + print $q->td({-class=>'tdtxt',-style=>"$txtstyle $set_style"},"$dbt->{copri_conf}->{lock_system}->{$ct4rel->{$id}->{$key}}"),"\n"; + }elsif($ct4rel->{$id}->{template_id} == 210 && $key eq "int18"){#sharing_type + print $q->td({-class=>'tdtxt',-style=>"$txtstyle $set_style"},"$dbt->{copri_conf}->{sharing_type}->{$ct4rel->{$id}->{$key}}"),"\n"; + }elsif($ct4rel->{$id}->{template_id} =~ /225|210/ && $key =~ /txt24|int12/){ + my $flotten = ""; + foreach my $rid (sort { $bike_nodes->{$a}->{node_name} cmp $bike_nodes->{$b}->{node_name} } keys (%$bike_nodes)){ + $flotten .= "$bike_nodes->{$rid}->{node_name} - $bike_nodes->{$rid}->{main_id}
    " if($ct4rel->{$id}->{$key} =~ /$bike_nodes->{$rid}->{main_id}/); + } + print $q->td({-class=>'tdtxt',-style=>"$txtstyle $set_style"},"$flotten"),"\n"; + }elsif($ct4rel->{$id}->{template_id} == 228 && $key =~ /int21|int22/){ + my $bonustarif = ""; + foreach my $rid (sort { $tariff_all->{$a}->{barcode} <=> $tariff_all->{$b}->{barcode} } keys (%$tariff_all)){ + $bonustarif .= "$tariff_all->{$rid}->{barcode} - $tariff_all->{$rid}->{txt01}
    " if($ct4rel->{$id}->{$key} == $tariff_all->{$rid}->{barcode}); + } + + print $q->td({-class=>'tdtxt',-style=>"$txtstyle $set_style"},"$bonustarif"),"\n"; + + }elsif($key =~ /int|save|time|sort|public/){ + if($key eq "int06" && $ct4rel->{$id}->{int06}){ + $ct4rel->{$id}->{int06} =~ s/,.*//; + } + + #if($colorize && $ct4rel->{$id}->{$key} == 1){ + # print $q->td({-class=>'tdicon',-style=>"$txtstyle $set_style color:$colorize;"},"•"),"\n"; + #}else{ + print $q->td({-class=>'tdint',-style=>"$txtstyle $set_style"},"$ct4rel->{$id}->{$key}"),"\n"; + #} + }elsif($key =~ /txt01/ && $v_journal){ + my $txt01 = "$ct4rel->{$id}->{$key}"; + $txt01 = "$txt01" if($ct4rel->{$id}->{state} eq "Kassenbestand"); + print $q->td({-class=>'tdtxt',-style=>"$txtstyle $set_style"},"$txt01"),"\n"; + }elsif($key =~ /txt03/ && $ct4rel->{$id}->{template_id} eq "227"){ + print $q->td({-class=>'tdtxt',-style=>"$txtstyle $set_style"},$q->a({-style=>"color:black;",-href=>"$varenv{metahost}/site/$ct4rel->{$id}->{$key}", -target=>'_blank',-title=>'download',-type=>'application/octet-stream'}, $q->img({-src=>"$varenv{metahost}/glyphicons/file-any.png", -style=>'height:1.3em;'}),"$ct4rel->{$id}->{$key}")),"\n"; + }elsif($key =~ /txt00/ && $v_journal){ + print $q->td({-class=>'tdtxt',-style=>"$txtstyle $set_style"},"$ct4rel->{$id}->{$key}"),"\n"; + }elsif($key =~ /txt08/ && $table eq "contentadr"){ + print $q->td({-class=>'tdtxt',-style=>"$txtstyle $set_style"},"$ct4rel->{$id}->{$key}"),"\n"; + #color code + }elsif($ct4rel->{$id}->{template_id} == 205 && $key eq "txt23"){ + my @service_code = split(/\s/,$ct4rel->{$id}->{$key}); + my $color_code = ""; + foreach(@service_code){ + $color_code .= ""; + } + print $q->td({-class=>'tdtxt',-style=>"$txtstyle $set_style"},"$color_code"),"\n"; + #teaser shorts longtext + }elsif(($table eq "contentadr" && $key =~ /txt29/) || ($table eq "content" && $key =~ /txt04/) || ($table eq "contenttrans" && $key =~ /txt23/)){ + my $teaser = ""; + if($ct4rel->{$id}->{$key}){ + $teaser = substr($ct4rel->{$id}->{$key},0,50) . " ..."; + } + print $q->td({-class=>'tdtxt',-style=>"$txtstyle $set_style; min-width:200px;"},"$teaser"),"\n"; + + #default to anything else + }elsif($key =~ /ct_name|node|txt|uri/){ + $txtstyle = "text-align:left;"; + print $q->td({-class=>'tdtxt',-style=>"$txtstyle $set_style"},"$ct4rel->{$id}->{$key}"),"\n"; + }elsif($key =~ /byte/){ + #$ct4rel->{$id}->{$key} =~ s/\\x//; + my $K_int = $ct4rel->{$id}->{$key}; + #$K_int =~ s/(.)/sprintf( "%x", ord($1))/eg; + my $K_int = unpack "H*", $ct4rel->{$id}->{$key}; + $txtstyle = "text-align:left;"; + print $q->td({-class=>'tdtxt',-style=>"$txtstyle $set_style"},"$K_int"),"\n"; + } + } + } + + #sub-table-row for rent Calendar + my $cal_count = 0; + foreach my $ctid (sort { $cttpos->{$b}->{end_time} cmp $cttpos->{$a}->{end_time} } keys (%$cttpos)){ + if($ct4rel->{$id}->{c_id} == $cttpos->{$ctid}->{cc_id}){ + $cal_count++; + if($cal_count <= 1){ + my $scale_color = "#86cbd7;"; + my $calement = "calement_86cbd7"; + if($ct4rel->{$id}->{int13} == $cttpos->{$ctid}->{int13} && $cttpos->{$ctid}->{int10} == 7){ + $scale_color = "#f0536e;"; + $calement = "calement_f0536e"; + } + + my ($year_st,$mon_st,$day_st,$hh_st,$mm_st) = $lb->split_date($cttpos->{$ctid}->{start_time}) if($cttpos->{$ctid}->{start_time}); + my ($year_en,$mon_en,$day_en,$hh_en,$mm_en) = $lb->split_date($cttpos->{$ctid}->{end_time}) if($cttpos->{$ctid}->{end_time}); + + if($year_st && $mon_st && $day_st && $hh_st && $mm_st && $year_en && $mon_en && $day_en && $hh_en && $mm_en){ + #generate px for rent scale + + my $start_nr = $year_st . $mon_st . $day_st . $hh_st . $mm_st; + my $end_nr = $year_en . $mon_en . $day_en . $hh_en . $mm_en; + my $day_stpx = 0; + my $rent_day_px = 0; + my $time_style; + if($start_nr <= $end_nr){ + ($day_stpx,$rent_day_px) = $lb->rent_scale($users_dms,$year_st,$mon_st,$day_st,$hh_st,$mm_st,$year_en,$mon_en,$day_en,$hh_en,$mm_en); + }else{ + $time_style="color:red;"; + } + print $q->Tr(); + print $q->td({-style=>'background-color:silver;'},""),"\n"; + print $q->td({-class=>"$calement",-colspan=>2,-style=>"$set_style;"},""),"\n"; + print "\n"; + #print $q->div({-style=>"position:absolute;margin-left:$daymarker;border-right: solid thin #86cb00;height:1.7em;"}," "),"\n";# if("$mon" eq "$mon_today"); + my $calpath = "Mietjournal"; + $calpath = "Alarmjournal" if($ct4rel->{$id}->{int13} == $cttpos->{$ctid}->{int13} && $cttpos->{$ctid}->{int10} == 7); + print $q->div({-style=>"position:static;margin-left:$day_stpx;width:$rent_day_px;background-color:$scale_color"},$q->a({-class=>"linknav3",-style=>"$time_style",-href=>"$script/$users_dms->{fullurl}/$calpath/?cttpos_id=$cttpos->{$ctid}->{c_id}",-title=>"Im $calpath öffnen"},"$hh_en:$mm_en")),"\n"; + print "\n"; + print $q->Tr(); + print $q->td({-style=>'padding-top:1px;'},""),"\n"; + } + } + } + } + + #sub-table-row, Journal mit Teileansicht + if($v_journal){ + my $o = "9"; + $o = 8 if($varenv{wwwhost} =~ /cofi/);#because of extra col ID + $o++ if($rabatt_key); #Verkaufjournal mit Rabatt + $o++ if($kost_key); #Verkaufjournal mit Kostenstelle + my $m = $k - $o; + foreach my $cpid (sort { $ct4rel_parts->{$a}->{c_id} <=> $ct4rel_parts->{$b}->{c_id} } keys(%$ct4rel_parts)){ + if($ct4rel->{$id}->{c_id} eq $ct4rel_parts->{$cpid}->{ct_id}){ + my $pos_style="color:grey;$set_style"; + my $sum_parts = $ct4rel_parts->{$cpid}->{int02} * $ct4rel_parts->{$cpid}->{int03}; + if($ct4rel_parts->{$cpid}->{int07} != 0){ + #my $rabatt_eur = $ct4rel_parts->{$cpid}->{int02} * $ct4rel_parts->{$cpid}->{int03} * $ct4rel_parts->{$cpid}->{int07}/100; + my $rabatt_eur = $ct4rel_parts->{$cpid}->{int07}; + $rabatt_eur = $ct4rel_parts->{$cpid}->{int02} * $ct4rel_parts->{$cpid}->{int03} * $ct4rel_parts->{$cpid}->{int07}/100 if($ct4rel_parts->{$cpid}->{int08} != 1);#wenn int08 != 1 alias € + $sum_parts = $ct4rel_parts->{$cpid}->{int02} * $ct4rel_parts->{$cpid}->{int03} - $rabatt_eur; + } + $sum_parts = $lb->round($sum_parts); + $sum_parts = $lb->cashme($sum_parts); + $sum_waren += $sum_parts; + $sum_verkauf += $sum_parts if($ct4rel_parts->{$cpid}->{ct_name} ne "999");#999=Ausgaben, Fixme + $ctf->{txt31} =~ s/,/|/; + if($ct4rel->{$id}->{state} =~ /^Bar/ && $ct4rel_parts->{$cpid}->{int12} =~ /$ctf->{txt31}/){ + $sum_kaution += $sum_parts; + $sum_bar -= $sum_parts; + } + + #Umsatz Fkt. + #AW Material Summen + $ct_aw_ids =~ s/\|$//; + #if($umsatz eq "AW" && $ct4rel_parts->{$cpid}->{ct_name} eq $ctf->{txt51}){ + if($umsatz eq "AW" && $ct4rel_parts->{$cpid}->{cc_id} =~ /$ct_aw/){ + $sum_aw += $sum_parts; + $sum_verkauf -= $sum_parts; + #$pos_style .= "background-color:#a69100;"; + }elsif($ct4rel_parts->{$cpid}->{ct_id} =~ /$ct_aw_ids/){ + $sum_am += $sum_parts; + $sum_verkauf -= $sum_parts; + #$pos_style .= "background-color:#c69133;"; + } + + if($umsatz eq "Rad-Station_Verkauf"){ + foreach my $nid (keys (%$w_nodes)){ + if($ct4rel_parts->{$cpid}->{int12} eq $w_nodes->{$nid}->{main_id}){ + if($w_nodes->{$nid}->{txt01} eq "Raddienst"){ + $sum_radd += $sum_parts; + $sum_verkauf -= $sum_parts; + #$pos_style .= "background-color:#a69100;"; + }elsif($w_nodes->{$nid}->{txt01} eq "Parkhaus"){ + $sum_park += $sum_parts; + $sum_verkauf -= $sum_parts; + #$pos_style .= "background-color:#a69100;"; + } + } + } + } + if($umsatz eq "Rad-Station_Verleih"){ + #besser, anhand der Verleih-Kostenstelle + foreach my $nid (keys (%$verleih_nodes)){ + if($ct4rel_parts->{$cpid}->{int12} eq $verleih_nodes->{$nid}->{main_id}){ + $sum_verleih += $sum_parts; + #$pos_style .= "background-color:#a69100;"; + } + } + } + + my $parts_time = ""; + if($ct4rel_parts->{$cpid}->{start_time} && $ct4rel_parts->{$cpid}->{end_time}){ + $ct4rel_parts->{$cpid}->{start_time} = $lb->time4de($ct4rel_parts->{$cpid}->{start_time},"1"); + $ct4rel_parts->{$cpid}->{end_time} = $lb->time4de($ct4rel_parts->{$cpid}->{end_time},"1"); + $parts_time = "$ct4rel_parts->{$cpid}->{start_time} - $ct4rel_parts->{$cpid}->{end_time}"; + } + print $q->Tr(),"\n"; + print $q->td({-style=>"background-color:silver;"},""),"\n"; + #print $q->td({-colspan=>'2',-style=>"$pos_style"},"$ct4rel->{$id}->{c_id} | $ct4rel_parts->{$cpid}->{ct_id}\n"); + print $q->td({-colspan=>'3',-style=>"$pos_style"},""),"\n"; + print $q->td({-class=>'tdtxt',-style=>"$pos_style"},"$ct4rel_parts->{$cpid}->{txt00}"),"\n"; + print $q->td({-colspan=>'1',-style=>"$pos_style"},""),"\n"; + print $q->td({-class=>'tdtxt',-style=>"$pos_style"},"$ct4rel_parts->{$cpid}->{txt01}"),"\n"; + print $q->td({-class=>'tdint',-style=>"$pos_style"},"$ct4rel_parts->{$cpid}->{ct_name}"),"\n"; + print $q->td({-colspan=>"$m",-style=>"$pos_style"},""),"\n"; + print $q->td({-class=>'tdint',-style=>"$pos_style"},"$ct4rel_parts->{$cpid}->{int03}"),"\n"; + print $q->td({-class=>'tdint',-style=>"$pos_style"},"$ct4rel_parts->{$cpid}->{int02}"),"\n"; + #Rabatt + if($rabatt_key && $ct4rel_parts->{$cpid}->{int07}){ + $ct4rel_parts->{$cpid}->{int07} .= " €" if($ct4rel_parts->{$cpid}->{int08} == 1);#wenn int08 != 1 alias €; + $ct4rel_parts->{$cpid}->{int07} .= " %" if($ct4rel_parts->{$cpid}->{int08} != 1);#wenn int08 != 1 alias €; + print $q->td({-class=>'tdint',-style=>"$pos_style",-nowrap=>1},"$ct4rel_parts->{$cpid}->{int07}"),"\n"; + }elsif($rabatt_key){ + print $q->td({-class=>'tdint',-style=>"$pos_style",-nowrap=>1},""),"\n"; + } + print $q->td({-class=>'tdint',-style=>"$pos_style"},"$sum_parts"),"\n"; + print $q->td({-colspan=>'1',-style=>"$pos_style"},""),"\n"; + } + } + } + } + }#journal offen ende + + + if($R::todo && $R::todo eq "Waren-Summe"){ + my $m = 9; + $sum_wst_ek = $lb->round($sum_wst_ek); + $sum_wst_vk = $lb->round($sum_wst_vk); + $sum_wst_ek = $lb->cashme($sum_wst_ek,","); + $sum_wst_vk = $lb->cashme($sum_wst_vk,","); + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-class=>'tdtxt',-style=>'text-align:center;background-color:silver;',-colspan=>"$m"},""); + print $q->td({-class=>'tdsum',-colspan=>"2",-style=>'background-color:silver;'},""); + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + #print $q->td({-class=>'tdsum',-colspan=>"$m"},$q->span({-style=>'color:silver;font-weight:normal;'},"(Vorsicht! incl. Ausgaben)"),$q->span("Waren-Stamm Summe")); + print $q->td({-class=>'tdsum',-colspan=>"$m"},"Waren-Stamm Summe"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},"$sum_wst_ek €"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},"$sum_wst_vk €"); + } + + #Kassenjournal alias Summe Bar und Kredit + if(($nr > 0) && ($v_journal || $R::v_abschluss) && (!$R::rel_id) && ("$R::s_kontext" ne "Waren")){ + #if(($nr > 0) && ($v_journal || $R::v_abschluss || $close_time) && (!$R::rel_id)){ +#print "($nr > 0) && ($v_journal || $R::v_abschluss || $close_time) && (!$R::rel_id)"; + $k="9" if(!$k); + my $m = $k; + $sum_bar = $lb->round($sum_bar); + $sum_bar = $lb->cashme($sum_bar); + $sum_ec = $lb->round($sum_ec); + $sum_ec = $lb->cashme($sum_ec); + #$sum_kredit = $lb->round($sum_kredit); + #$sum_kredit = $lb->cashme($sum_kredit); + $sum_abb = $lb->round($sum_abb); + $sum_abb = $lb->cashme($sum_abb); + $sum_ueb = $lb->round($sum_ueb); + $sum_ueb = $lb->cashme($sum_ueb); + $sum_geka = $lb->round($sum_geka); + $sum_geka = $lb->cashme($sum_geka); + $sum_paypal = $lb->round($sum_paypal); + $sum_paypal = $lb->cashme($sum_paypal); + + $sum_SEPApayone = $lb->round($sum_SEPApayone); + $sum_SEPApayone = $lb->cashme($sum_SEPApayone); + $sum_CCpayone = $lb->round($sum_CCpayone); + $sum_CCpayone = $lb->cashme($sum_CCpayone); + $sum_ausfall = $lb->round($sum_ausfall); + $sum_ausfall = $lb->cashme($sum_ausfall); + + + $sum_waren = $lb->round($sum_waren); + $sum_waren = $lb->cashme($sum_waren); + $sum_kaution = $lb->cashme($sum_kaution); + $sum_start = $lb->cashme($sum_start); + $sum_kasse = $lb->cashme($sum_kasse); + $close_time = $R::s_mtime if($R::s_mtime); + my $summiert = "Gesamt Umsätze"; + #my @_states = ("Bar","EC-Karte","Kreditkarte","Abbuchung","Überweisung"); + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-class=>'tdtxt',-style=>'text-align:center;background-color:silver;',-colspan=>"$m"},"$summiert"); + print $q->td({-class=>'tdsum',-colspan=>"1",-style=>'background-color:silver;'},""); + print $q->td({-class=>'tdsum',-colspan=>"1",-style=>'background-color:silver;'},""); + + + if(1==1){ + if($sum_ec != "0"){ + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-class=>'tdsum',-colspan=>"$m"},"EC-Karten Summe"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},"$sum_ec €"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},""); + } + #if($sum_kredit != "0"){ + # print $q->Tr(); + # print $q->td({-style=>"background-color:silver;"},""),"\n"; + # print $q->td({-class=>'tdsum',-colspan=>"$m"},"Kreditkarten Summe"); + # print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},"$sum_kredit €"); + #} + if($sum_abb != "0"){ + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-class=>'tdsum',-colspan=>"$m"},"Abbuchung Summe"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},"$sum_abb €"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},""); + } + if($sum_ueb != "0"){ + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-class=>'tdsum',-colspan=>"$m"},"Überweisung Summe"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},"$sum_ueb €"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},""); + } + if($sum_geka != "0"){ + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-class=>'tdsum',-colspan=>"$m"},"Geldkarte Summe"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},"$sum_geka €"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},""); + } + if($sum_paypal != "0"){ + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-class=>'tdsum',-colspan=>"$m"},"PayPal Summe"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},"$sum_paypal €"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},""); + } + if($sum_SEPApayone != "0"){ + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-class=>'tdsum',-colspan=>"$m"},"SEPA-Lastschrift (payone) Summe"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},"$sum_SEPApayone €"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},""); + } + if($sum_CCpayone != "0"){ + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-class=>'tdsum',-colspan=>"$m"},"Kreditkarte (payone) Summe"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},"$sum_CCpayone €"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},""); + } + if($sum_ausfall != "0"){ + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-class=>'tdsum',-colspan=>"$m"},"Zahlungsausfall Summe"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},"$sum_ausfall €"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},""); + } + + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-class=>'tdsum',-colspan=>"$m",-style=>'background-color:#eaeaec;'},"Bar Summe"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1",-style=>'background-color:#eaeaec;'},"$sum_bar €"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},""); + + if($v_journal eq "Tagesbericht" || ($v_journal && $R::s_start_mtime !~ /\d+[\.|,]\d+[\.|,]\d+/)){ + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + $sum_start = "$ctf->{int01}" if($sum_start == "0"); + my $sum_start_text = "(Kassenbestand Übernahme vom Vortag)" if(!$sum_start); + $sum_start = $last_ab->{int01} if(!$sum_start); + print $q->td({-class=>'tdsum',-colspan=>"$m",-style=>'background-color:#eaeaec;'},$q->span({-style=>'color:silver;font-weight:normal;'},"$sum_start_text"),"Anfangs Kassenbestand"); + if($close_time){ + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1",-style=>'background-color:#eaeaec;'},"$sum_start €"); + }else{ + print $q->td({-class=>'tdsum',-colspan=>"1",-style=>'background-color:#eaeaec;'}, $q->textfield(-class=>'etxt',-style=>'text-align:right;',-name=>"sum_start",-override=>'1',-default=>"$sum_start",-size=>"5",-maxlength=>10),"\n"); + } + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},""); + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-class=>'tdsum',-colspan=>"$m",-nowrap=>"1",-style=>'background-color:#eaeaec;'},"Tatsächlicher Kassenbestand"); + $sum_kasse = "$varenv{sum_start}" if($sum_kasse == "0"); + if($close_time){ + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1",-style=>'background-color:#eaeaec;'},"$sum_kasse €"); + }else{ + print $q->td({-class=>'tdsum',-colspan=>"1",-style=>'background-color:#eaeaec;'},$q->textfield(-class=>'etxt',-style=>'text-align:right;',-name=>"sum_kasse",-override=>'1',-default=>"$sum_kasse",-size=>"5",-maxlength=>10),"\n"); + } + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},""); + my $sum_diff = $sum_kasse - $sum_start - $sum_bar; + $sum_diff = $lb->round($sum_diff); + $sum_diff = $lb->cashme($sum_diff); + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-class=>'tdsum',-colspan=>"$m",-style=>'background-color:#eaeaec;'},$q->span({-style=>'color:silver;font-weight:normal;'},"($sum_kasse - $sum_start - $sum_bar = $sum_diff)"),"Kassenbestand - Bar Summe = Differenz"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1",-style=>'background-color:#eaeaec;'},"$sum_diff €"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},""); + } + ### + + #AW 2020-01-29 disabled + if(1==2 && $umsatz && $node_meta->{node_name} eq "Faktura"){ + my $sum_parts_all; + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-class=>'tdtxt',-style=>'text-align:center;background-color:silver;',-colspan=>"$m"},"Teil Umsätze"); + print $q->td({-class=>'tdsum',-colspan=>"1",-style=>'background-color:silver;'},""); + + if("$R::s_kontext" eq "Waren"){ + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-class=>'tdsum',-colspan=>"$m"},"Suchkontext Waren. Die Umsatz Summe der durch Suchbegriffe gefundenen Artikel"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},"$sum_waren €"); + } + + if($umsatz eq "Rad-Station_Verkauf"){ + $sum_radd = $lb->cashme($sum_radd); + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-class=>'tdsum',-colspan=>"$m"},"Raddienst Summe"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},"$sum_radd €"); + $sum_park = $lb->cashme($sum_park); + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-class=>'tdsum',-colspan=>"$m"},"Parkhaus Summe"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},"$sum_park €"); + } + + if($umsatz eq "Rad-Station_Verleih"){ + $sum_verleih = $lb->cashme($sum_verleih); + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-class=>'tdsum',-colspan=>"$m"},$q->span({-style=>'color:silver;font-weight:normal;'},""),"Verleih Summe"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},"$sum_verleih €"); + } + + if($umsatz eq "AW"){ + $sum_aw = $lb->round($sum_aw); + $sum_aw = $lb->cashme($sum_aw); + $sum_am = $lb->round($sum_am); + $sum_am = $lb->cashme($sum_am); + $sum_verkauf = $lb->round($sum_verkauf); + $sum_verkauf = $lb->cashme($sum_verkauf); + $sum_parts_all += $sum_aw; + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-class=>'tdsum',-colspan=>"$m"},"Arbeits-Werte Summe"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},"$sum_aw €"); + $sum_parts_all += $sum_am; + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-class=>'tdsum',-colspan=>"$m"},"Arbeits-Material Summe"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},"$sum_am €"); + $sum_parts_all += $sum_verkauf; + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-class=>'tdsum',-colspan=>"$m"},"Verkaufs-Material Summe"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},"$sum_verkauf €"); + $sum_parts_all = $lb->cashme($sum_parts_all); + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-class=>'tdsum',-colspan=>"$m"},"Gesamt Summe"); + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},"$sum_parts_all €"); + } + } + + if($users_dms->{u_id}){ + if($v_journal =~ /bericht/ && $j_exist->{main_id}){ + print $q->Tr(); + print $q->td({-style=>"background-color:silver;"},""),"\n"; + print $q->td({-style=>"background-color:silver;",-class=>'tdsum',-colspan=>"$m"},"Tagesabschluss"),"\n"; + print $q->td({-style=>"background-color:silver;",-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},$but->checkbox("1","close_trans","","Tagesbericht abschließen und in das Verkaufsjournal senden"),$but->singlesubmit("v_abschluss","Speichern")),"\n"; + print $q->td({-class=>'tdsum',-colspan=>"1",-nowrap=>"1"},""); + } + } + + } + } + print $q->end_table; + + print $q->hidden(-name=>'tpl_id',-override=>'1', -value=>"$tpl_id"); + print "
    \n"; + if($R::detail_search !~ /suchen/ && $rows > $limit && $nr > 0){ + print $q->div({-style=>'float:left;padding:6px 0 0 20px;'},"Datensätze pro Seite:",$q->textfield(-style=>'height:16px;',-name=>"limit",-default=>"$limit",-size=>"3",-maxlength=>10)),"\n"; + print $q->div({-style=>'float:left;padding:7px 0 0 10px;'},$but->singlesubmit3("detail_search","reload_search","$varenv{metahost}/img/refresh.png","height:15px;","Tabelle neu laden")),"\n"; + } + print $q->end_form; + + my $offset_nr = $offset + $nr; + my $counter = $node_meta->{int10} || $rows; + print $q->div({-style=>'float:left;padding:6px 0 0 10px;'},"Zeile: $offset - $offset_nr / $counter"); + + #backward | forward + print "
    \n"; + print $q->a({-class=>"linknav",-href=>"?go=backward_list;offset=$offset;limit=$limit",-title=>''},"< zurück ... ") if($offset >= $limit); + print $q->a({-class=>"linknav",-href=>"?go=forward_list;offset=$offset;limit=$limit",-title=>''}," ... vorwärts >") if($counter >= $limit-10); #if($rows > $limit && $nr > 0); + print "
    \n"; + print "
    \n"; + print $q->div({-style=>'padding:6px 0 6px 20px;text-decoration:underline;'}, "Symbol Legende"),"\n"; + if($table eq "contentadr"){ + print $q->div({-style=>'padding:0 20px;font-style:italic;'}, $q->span({-style=>'padding:0.1em 0.8em;',-style=>'color:red;'},"•"), "Der Verleih ist nicht freigeschaltet"),"\n"; + }elsif($table eq "contenttrans"){ + print $q->div({-style=>'padding:0 20px;font-style:italic;'}, $q->span({-style=>'padding:0.1em 0.8em;',-style=>'color:red;'},"•"), "payone error"),"\n"; + }elsif($table eq "content"){ + #print $q->div({-style=>'padding:0 20px;font-style:italic;'}, $q->span({-style=>'padding:0.1em 0.8em;'},$q->img({-src=>"$varenv{metahost}/glyphicons/glyphicons-512-copy.png", -style=>'height:1.3em;'})), "Artikel zur Rechnung hinzufügen ( Orange unterlegte Faktura Rechnung )"),"\n"; + print $q->div({-style=>'padding:0 20px;font-style:italic;'}, $q->span({-style=>'padding:0.1em 0.8em;'},$q->img({-src=>"$varenv{metahost}/glyphicons/glyphicons-440-wrench.png", -style=>'height:1.3em;'})), "Service-Wartung"),"\n"; + } + print $q->div({-style=>'padding:0.5em;'}, " "),"\n"; + + print "
    "; + + if($varenv{wwwhost} !~ /regiox/ && $node_meta->{main_id} > 300000 && $rows =~ /\d/){ + $db->updater("nodes","main_id",$node_meta->{main_id},"int10",$rows); + } + + #letzte Suche + if(!$v_journal && $R::detail_search && ref($searchref) eq "HASH" && $nr =~ /\d/){ + $db->updater("nodes","main_id","300023","int10",$nr); + } + #print Dumper($node_meta); + return $return; +} +1; diff --git a/copri4/main/src/Tpl/MandantConf.pm b/copri4/main/src/Tpl/MandantConf.pm new file mode 100644 index 0000000..4373ce6 --- /dev/null +++ b/copri4/main/src/Tpl/MandantConf.pm @@ -0,0 +1,139 @@ +package MandantConf; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +# +use strict; +use warnings; +use CGI; +use CGI::Carp qw(fatalsToBrowser); +use CGI ':standard'; +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Libenzdb; +use Mod::DBtank; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my $node_meta = shift; + my $users_dms = shift; + my $u_group = shift; + my $return = shift; + + my $q = new CGI; + my $cf = new Config; + my $lb = new Libenz; + my $db = new Libenzdb; + my $dbt = new DBtank; + my $but = new Buttons; + my %ib = $but->ibuttons(); + my %varenv = $cf->envonline(); + my $script = $q->script_name(); + my $path_info = $q->path_info(); + my $path = $path_info; + #with meta_host, + if("$varenv{metahost}"){ + $path = "$script" . "$path_info"; + $script=""; + } + $path =~ s/\/user|\/manager|\/admin//; + my $lang = "de"; + my $dbh = ""; + my $rel = {}; + my $ct = {}; + if($node_meta->{ct_table} eq "contentuser"){ + if(($node_meta->{node_name} eq "Firma") && ($users_dms->{u_id} eq $varenv{superu_id})){ + $rel = $db->get_rel4tpl($node_meta->{main_id},$lang,"","201","","",">0"); + $ct = $db->get_content1("contentuser",$rel->{content_id}); + }elsif(($node_meta->{node_name} eq "System") && ($users_dms->{u_id} eq $varenv{superu_id})){ + $rel = $db->get_rel4tpl($node_meta->{main_id},$lang,"","215","","",">0"); + $ct = $db->get_content1("contentuser",$rel->{content_id}); + }elsif($node_meta->{node_name} eq "Kontakt-Hotline" && $users_dms->{int08} >= 1){ + $rel = $db->get_rel4tpl($node_meta->{main_id},$lang,"","197","","",">0"); + $ct = $db->get_content1("contentuser",$rel->{content_id}); + }else{ + $return = "failure::Abbruch. Keine Zugriffsberechtigung"; + } + } + + my $tpl = $db->get_tpl($rel->{template_id}); + my @tpl_order = split /,/,$tpl->{tpl_order}; + my $u_name = $dbt->sys_username($dbh,$ct->{owner}); + $ct->{mtime} = $lb->time4de($ct->{mtime},"1"); + + print "
    "; + print $q->div({-class=>"copri_header",-style=>"background-color:#cccccc;"},"Pfad: $path"); + print $q->div({-style=>'background-color:silver;height:10px;'},""),"\n"; + print $q->start_form(); + + #Content + print $q->start_table({-border=>'0', -width=>'100%',-align=>'center', -cellpadding=>'3', -cellspacing=>'0'}); + print $q->Tr(); + if($R::config2edit){ + print ""; + print $q->hidden(-name=>'owner',-override=>'1', -value=>"$users_dms->{u_id}"); + print $q->hidden(-name=>'c_id',-override=>'1', -value=>"$ct->{c_id}"); + print $q->hidden(-name=>'rel_id',-override=>'1', -value=>"$rel->{rel_id}"); + print $but->singlesubmit7("rel_edit","save_user","$ib{save}"); + print "\n"; + }else{ + print ""; + print $q->a({-class=>"editnav",-href=>"$script$path?config2edit=1",-title=>'bearbeiten'}, $q->img({-src=>"$varenv{metahost}/glyphicons/glyphicons-151-edit.png"})); + print "\n"; + } + print $q->td({-style=>"background-color:white;padding-right:10px;border-bottom: 1px solid silver;text-align:right;font-size:12px;"}, "$u_name / $ct->{mtime}"); + + my $i=0; + foreach (@tpl_order){ + $i++; + my ($key,$des,$size) = split /=/,$_; + $size = "60" if($key =~ /ct_name|txt/ && !$size); + $ct->{$key} = $q->unescapeHTML("$ct->{$key}"); + $ct->{$key} = $lb->newline($ct->{$key}); + my $value = ""; + if($R::config2edit){ + if($size eq "area"){ + $value = ""; + }elsif($size =~ /\w\+\w/){ + my ($a,$b) = split /\+/,$size; + my $a_checked; + my $b_checked; + $a_checked = "checked" if($ct->{$key} eq "$a" || !$ct->{$key}); + $b_checked = "checked" if($ct->{$key} eq "$b"); + $value = "$a $b "; + }elsif($key =~ /txt|ct_name/){ + $value = ""; + }elsif($key =~ /int/){ + $value = ""; + }elsif($key =~ /img/){ + $value = ""; + } + }else{ + $value = "$ct->{$key}"; + } + print $q->Tr(); + if($key =~ /header/){ + print $q->td({-class=>'tdval2',-colspan=>'2'},$q->b("
    $des")),"\n"; + }elsif($users_dms->{u_id} eq $varenv{superu_id}){ + print $q->td({-class=>'tdescr2'},"$des ($key)"),"\n"; + }else{ + print $q->td({-class=>'tdescr2'},"$des"),"\n"; + } + print $q->td({-class=>'tdval2'}, "$value"),"\n" if($key !~ /header/); + } + print $q->end_table; + print $q->end_form; + print "
    "; + + return $return; +} +1; diff --git a/copri4/main/src/Tpl/SubListe.pm b/copri4/main/src/Tpl/SubListe.pm new file mode 100644 index 0000000..504967f --- /dev/null +++ b/copri4/main/src/Tpl/SubListe.pm @@ -0,0 +1,436 @@ +package SubListe; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +# +#uncomment for perl -cw src/Tpl/Liste3.pm +#use lib qw(/var/www/copri4/shareedms-primary/src); +# +use strict; +use warnings; +use POSIX; +use CGI; +use URI::Escape; +use Encode; +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Libenzdb; +use Mod::DBtank; +use Mod::APIfunc; + +use Date::Calc qw(:all); +use Storable; +use Data::Dumper; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my $node_meta = shift; + my $users_dms = shift; + my $u_group = shift; + my $return = shift; + + my $q = new CGI; + my @keywords = $q->param; + my $keycount = scalar(@keywords); + my $time = time; + my $now_db = strftime("%d.%m.%Y %H:%M:%S",localtime(time)); + my $cf = new Config; + my $lb = new Libenz; + my $db = new Libenzdb; + my $dbt = new DBtank; + my $apif = new APIfunc; + + my $but = new Buttons; + my %varenv = $cf->envonline(); + my $script = $q->script_name(); + my $path_info = $q->path_info(); + my $path = $path_info; + #with meta_host, + if("$varenv{metahost}"){ + $path = "$script" . "$path_info"; + $script=""; + } + my $lang = "de"; + my $dbh = ""; + + my $parent_node4rel = $db->get_node4rel($node_meta->{parent_id},"","","null"); + my %ib = $but->ibuttons(); + my $tpl_order = $node_meta->{tpl_order}; + if(1==2 && $node_meta->{tpl_id} >= 400 && $node_meta->{tpl_id} < 500){ + $tpl_order =~ s/barcode=Rad/barcode=Rad,txt10=Station-log,txt09=Wartungsprotokoll=area/; + $tpl_order =~ s/int04=Station/int04=Station,txt09=Wartungsprotokoll=area/ if($node_meta->{tpl_id} == 403); + } + my @tpl_order = split /,/,$tpl_order; + my $message = ""; + #$message = "Fehler: bitte Unter \"Servicetechnik\" die Datenklasse konfigurieren!" if(scalar(@tpl_order) < 1); + my $s_owner_id = ""; + #my $s_u_name = ""; + + my @viewsel = split /\//,$1 if($path =~ /^\/(.*)/); + my $depth = scalar(@viewsel); + my $view_base = $viewsel[1] || "nothing";#like Waren + my $node_mandant = $db->get_node("$view_base","$lang"); + + #TODO, build service path by pos.template_id or pos.barcode alis bike_id + #my $pref = { table => "content", + # table_pos => "contentpos", + #}; + #my $template_group = $dbt->pos_template_group($dbh,$pref); + #my $subrelnode = $dbt->get_subrelnode($dbh,$crecord->{main_id},$template_id_pos); + + my $searchref = {}; + my $channel_map = $dbt->channel_map(); + + my $mapref = {}; + my $ct_users = $dbt->users_map($dbh,$mapref);#get serviceAPP and DMS users from contentadr + + my @_users = (""); + foreach my $id (sort { $channel_map->{$a} cmp $channel_map->{$b} } keys (%$channel_map)){ + push (@_users, "$id:$channel_map->{$id}"); + if($channel_map->{$id} eq $R::s_owner){ + $searchref->{owner} = $id; + #$s_u_name = $channel_map->{$id}; + } + } + + foreach my $ctu_id (sort { $ct_users->{$a}->{txt01} cmp $ct_users->{$b}->{txt01} } keys (%$ct_users)){ + push (@_users, "$ct_users->{$ctu_id}->{c_id}:$ct_users->{$ctu_id}->{txt01}"); + if($ct_users->{$ctu_id}->{ct_name} && ($ct_users->{$ctu_id}->{txt01} =~ /$R::s_owner/i) || ($ct_users->{$ctu_id}->{c_id} eq $searchref->{owner})){ + $searchref->{owner} = $ct_users->{$ctu_id}->{c_id}; + #$s_u_name = $ct_users->{$ctu_id}->{txt01}; + } + } + + my $limit = $R::limit || $varenv{limit}; + my $offset = $R::offset || "0"; + if($node_meta->{int10} && $node_meta->{int10} < $varenv{limit}){ + $offset = 0; + } + #backward | forward + if($R::go eq "backward_list"){ + $offset -= $limit if($offset >= $limit); + }elsif($R::go eq "forward_list"){ + $offset += $limit; + } + + my $date; my $start_chck=0;my $end_chck=0; + my $last_year; + if($R::s_start_mtime){ + ($date,$start_chck) = $lb->checkdate($R::s_start_mtime) if($R::s_start_mtime !~ "%"); + $message .= ">>> Datum Eingabefehler: $date <<<" if($start_chck); + my ($c_dd,$c_mm,$c_yy) = split(/\./,$date); + $last_year = $c_yy if("$c_yy" eq "2011"); + } + if($R::s_end_mtime){ + ($date,$end_chck) = $lb->checkdate($R::s_end_mtime) if($R::s_end_mtime !~ "%"); + $message .= ">>> Datum Eingabefehler: $date <<<" if($end_chck); + my ($c_dd,$c_mm,$c_yy) = split(/\./,$date); + } + + #because of search we need parents + my $main_ids = $parent_node4rel->{main_id}; + my $tpl_ids = $parent_node4rel->{template_id}; + + my $rows = 0; + my $scol = "mtime"; + my $table = "content"; + $searchref->{table_pos} = "contentpos"; + if($node_meta->{tpl_id} > 600 && $node_meta->{tpl_id} < 700){ + $table = "contentadr"; + $searchref->{table_pos} = "contentadrpos"; + $searchref->{template_id_pos} = "$node_meta->{tpl_id}"; + } + if($node_meta->{tpl_id} == 198){ + my $mandant_id = 100002; + $table = "contentadr"; + $searchref->{table_pos} = "users"; + #$searchref->{template_id_pos} = "$node_meta->{tpl_id}"; + $main_ids = 200011; + $tpl_ids = 202; +print< + .ui-autocomplete { + text-align:left; + background:#eeeeee; + border:1px solid silver; + } + + + +EOF +; + + } + + #print Dumper($node_meta); + my $hashfile = "$varenv{logdir}/$users_dms->{u_id}-$searchref->{table_pos}-searchhash"; + my $ct4rel = {}; + if(!$start_chck && !$end_chck && $parent_node4rel ne "Servicetechnik" && $main_ids && $tpl_ids){ + #$rows = $db->count_content($searchref->{table_pos},"$main_ids","$tpl_ids"); + + #collect search keys + foreach my $postkey (@keywords){ + foreach(@tpl_order){ + my ($key,$val,$size) = split /=/,$_; + if($postkey =~ /s_$key|s_start_$key|s_end_$key/){ + my $val = $q->param($postkey); + $postkey =~ s/^s_//; + $searchref->{$postkey} = $val; + } + } + } + + #trying to save hashref + if($R::detail_search && ref($searchref) eq "HASH"){ + store $searchref, $hashfile; + }elsif($keycount > 0 && !$R::detail_search && -f $hashfile){ + $searchref = {}; + $searchref = retrieve($hashfile); + } + #print Dumper($searchref); + my $export = ""; + my $todo = ""; + my $ck4ex = ""; + #only if permission read + if(($node_meta->{ct_table} eq "users" && $users_dms->{int07} >= 1) || ($node_meta->{ct_table} eq "contentadrpos" && $users_dms->{int02} >= 1) || ($node_meta->{ct_table} eq "contentpos" && $users_dms->{int01} >= 1)){ + $ct4rel = $db->search_content3($searchref,$table,$node_mandant->{parent_id},"",$users_dms->{u_id},$lang,"$main_ids","$tpl_ids","","",$time,"",$scol,$users_dms->{sort_updown},$offset,$limit,$export,$todo,$ck4ex,""); + }else{ + $return = "failure::Abbruch. Keine Zugriffsberechtigung"; + } + } + + print "
    \n"; + if($varenv{syshost} ne "azn"){ + my $header_style = ""; + $header_style = "border:2px solid #9f1f0e;" if($message); + print $q->div({-class=>"copri_header",-style=>"background-color:$node_meta->{bg_color};"},"$path",$q->span({-style=>"$header_style"},"$message")); + } + print $q->div({-style=>'background-color:silver;height:10px;'},""),"\n"; + + print $q->start_form(-name=>'searchform'),"\n"; + print $q->hidden(-name=>'offset', -value=>"$offset"),"\n"; + print $q->hidden(-name=>'main_id', -value=>"$node_meta->{main_id}"),"\n"; + print $q->hidden(-name=>'mode', -value=>"manager"),"\n"; + print $q->hidden(-name=>'owner', -value=>"$users_dms->{u_id}"),"\n"; + print $q->hidden(-name=>'template_id', -value=>"$node_meta->{template_id}"),"\n"; + + my $hstyle = "width:20px;background-color:$node_meta->{bg_color};border-right: solid thin gray;border-bottom: solid thin gray;"; + print $q->start_table({ -style=>'clear:both;', -border=>'0', -width=>'100%',-align=>'center', -cellpadding=>'0', -cellspacing=>'0'}),"\n"; + + #new_edit and search (disabled for DMS-Account) + if($node_meta->{tpl_id} != 198){ + my $edit="rel_edit"; + my $new_key="service_done"; + + my $search = "search"; + print $q->Tr(),"\n"; + print $q->td({-style=>"background-color:silver;$hstyle"},$but->singlesubmit1("detail_search","$search","","")),"\n"; + + #https://tinkwwp.copri4.de/APIjsonserver?request=service_done&bike=202&work_id=txt11&work_val=aaa&authcookie=1842_ad720ed63bd40039e4abe8a9ad7315e1_34567890 + #disabled + if(1==2 && $node_meta->{tpl_id} >= 400 && $node_meta->{tpl_id} < 500){ + print $q->td({-style=>"$hstyle"}, $but->singlesubmit2glyph("$edit","$new_key","$ib{$new_key}","background-color:$node_meta->{bg_color};")),"\n"; + }else{ + print $q->td({-style=>"$hstyle"}," "),"\n"; + } + + #1. Search-fields + my $s_val; + foreach(@tpl_order){ + my ($key,$val,$size) = split /=/,$_; + $size = 15 if($size =~ /area/); + $size = 10 if($size =~ /time/); + $size = 2 if($size =~ /checkbox/); + + $s_val = $searchref->{$key}; + #print "$key=$searchref->{$key}|"; + if($key =~ /node|txt|int|uri|ct_name|_id|barcode|sort|public/){ + if($key =~ /barcode|int04/){ + print $q->td({-class=>"search_line"},$q->textfield(-class=>'stxt',-name=>"s_$key",-size=>"4",-default=>"$s_val",-maxlength=>40, -autofocus=>1)),"\n"; + }else{ + print $q->td({-class=>"search_line"},$q->textfield(-class=>'stxt',-name=>"s_$key",-size=>"$size",-default=>"$s_val",-maxlength=>40)),"\n"; + } + }elsif($key =~ /owner/){ + print $q->td({-class=>'search_line'},$but->selector("s_$key","","$s_val",@_users)),"\n"; + } + my $s_mtime; my $e_mtime; + if($key eq "mtime"){ + $s_mtime = $searchref->{start_mtime}; + $e_mtime = $searchref->{end_mtime}; + } + if($key eq "date_time"){ + $s_mtime = $searchref->{start_date_time}; + $e_mtime = $searchref->{end_date_time}; + } + + print $q->td({-nowrap=>1,-class=>"search_line"},$q->textfield(-id=>'datepicker1',-class=>'etxt',-name=>"s_start_$key",-default=>"$s_mtime",-size=>"$size",-maxlength=>20),"-",$q->textfield(-id=>'datepicker2',-class=>'etxt',-name=>"s_end_$key",-default=>"$e_mtime",-size=>"$size", -maxlength=>20)),"\n" if($key =~ /time/); + }#end Search-fields + } + + #2. Tableheader + print $q->Tr(); + my $i=0; + if($node_meta->{tpl_id} == 198){ + my $edit="base_edit"; + my $new_key="new_dmsusers"; + + print "\n"; + print $but->singlesubmit2glyph("$edit","$new_key","$ib{$new_key}","background-color:$node_meta->{bg_color};"),"\n"; + #print $q->hidden(-name=>'c_id4trans', -override=>'1', -value=>"$ctx->{c_id}"),"\n"; + #from json_selectadr + print $q->hidden(-id=>'c_idadr', -name=>"c_idadr", -override=>'1'),"\n"; + print $q->hidden(-id=>'vorname_name', -name=>"vorname_name", -override=>'1'),"\n"; + print $q->textfield(-style=>'border:1px solid grey;height:25px;width:80%;',-id=>"json_selectadr",-name=>"json_selectadr", -placeholder=>'Neuer DMS-Account', -value=>""),"\n"; + + print "\n"; + }else{ + print $q->th({-style=>""}," "),"\n"; + print $q->th({-style=>""}," "),"\n"; + } + #my $sort_up = "up"; + #my $sort_down = "down"; + #$sort_up = "$sort_up" if($users_dms->{sort_updown} eq "up"); + #$sort_down = "$sort_down" if($users_dms->{sort_updown} eq "down"); + #print $q->th($q->a({-class=>"sortnav",-href=>"?sort_updown=up\&offset=$offset\&limit=$limit",-title=>'Aufsteigend sortieren'},"$sort_up"),"|",$q->a({-class=>"sortnav",-href=>"?sort_updown=down\&offset=$offset\&limit=$limit",-title=>'Absteigend sortieren'},"$sort_down")),"\n"; + + foreach (@tpl_order){ + my ($key,$val,$size,$interval) = split /=/,$_; + my $divstyle = ""; + if($size =~ /checkbox/){ + $size = 2; + $divstyle = "width:20px;white-space:nowrap;overflow:hidden;"; + } + my $sort_title="| $val"; + $val = "$val" if($key eq $users_dms->{col_sort}); + $i++; + print $q->th({-style=>'padding:5px 0'},$q->div({-style=>"$divstyle"},$q->a({-class=>"sortnav",-href=>"?col_sort=$key\&offset=$offset\&limit=$limit",-title=>"$val"},"$val"))),"\n" if($key ne "u_id"); + }#end Tableheader + + + #BIG LOOP loop content table + #if($users_dms->{sort_updown} eq "up"){ + my $nr=0; + foreach my $id (sort { + if($users_dms->{sort_updown} eq "down"){ + if ($scol =~ /barcode|int/) { + $ct4rel->{$b}->{$scol} <=> $ct4rel->{$a}->{$scol} + }else{ + $ct4rel->{$b}->{$scol} cmp $ct4rel->{$a}->{$scol} + } + }else{ + if ($scol =~ /barcode|int/) { + $ct4rel->{$a}->{$scol} <=> $ct4rel->{$b}->{$scol} + }else{ + $ct4rel->{$a}->{$scol} cmp $ct4rel->{$b}->{$scol} + } + } + } keys(%$ct4rel)){ + + my $set_style = ""; + $nr++; + #Tablecontent (parameter) + print $q->Tr(),"\n"; + + if($node_meta->{tpl_id} != 198){ + print $q->td({-class=>'tdtxt',-style=>"$set_style"},""),"\n"; + print $q->td({-class=>'tdint',-style=>"$set_style"},""),"\n"; + } + my $k=0; + foreach (@tpl_order){ + $k++; + my ($key,$val,$size) = split /=/,$_; + $size = 15 if($size =~ /area/); + $size = 2 if($size =~ /checkbox/); + my $tdclass = "tdtxt"; + my $tdstyle = "text-align:left;"; + if($size =~ /\w\+\w/){ + $size = 5; + }elsif($key =~ /barcode|c_id|ct_name|int|state|sort|public/){ + $tdclass = "tdint"; + $tdstyle = "text-align:right;max-width:8em;$size px;"; + } + $ct4rel->{$id}->{$key} = $lb->time4de($ct4rel->{$id}->{$key},"1") if($key =~ /time/); + $ct4rel->{$id}->{$key} = $q->unescapeHTML("$ct4rel->{$id}->{$key}"); + $ct4rel->{$id}->{$key} = $lb->newline($ct4rel->{$id}->{$key},"",""); + if($key eq "owner"){ + my $u_name = $ct4rel->{$id}->{owner}; + foreach my $ctu_id (keys (%$ct_users)){ + if($channel_map->{$u_name}){ + $u_name = $channel_map->{$u_name}; + }elsif($ct4rel->{$id}->{owner} eq $ct_users->{$ctu_id}->{c_id}){ + $u_name = $ct_users->{$ctu_id}->{txt01}; + } + } + + #$u_name = $ct_users->{$ct4rel->{$id}->{$key}}->{txt01} || $ct4rel->{$id}->{$key}; + print $q->td({-class=>"$tdclass",-style=>"$tdstyle $set_style"},"$u_name"),"\n"; + }elsif($key eq "barcode" && $node_meta->{ct_table} eq "contentadrpos"){ + print $q->td({-class=>"$tdclass",-style=>"$tdstyle $set_style"},$q->a({-class=>"linknav3",-href=>"/$users_dms->{fullurl}/Waren/?detail_search=1\&s_barcode=$ct4rel->{$id}->{barcode}",-title=>"zum Rad "},"$ct4rel->{$id}->{barcode}")),"\n"; + #print $q->td({-class=>"$tdclass",-style=>"$tdstyle $set_style"},$q->a({-class=>"editnav",-href=>"/$users_dms->{fullurl}/Waren/?detail_search=1\&s_barcode=$ct4rel->{$id}->{barcode}",-title=>"zur Liste der Rad $ct4rel->{$id}->{barcode} Servicearbeiten"}, $q->img({-src=>"$varenv{metahost}/glyphicons/glyphicons-440-wrench.png", -style=>'height:1.3em;'}),"$ct4rel->{$id}->{barcode}")),"\n"; + + }elsif($key eq "u_id" && $node_meta->{ct_table} eq "users"){ + my $adref = { + table => "contentadr", + fetch => "one", + template_id => "202", + c_id => "$ct4rel->{$id}->{$key}", + }; + my $ctadr = $dbt->fetch_record($dbh,$adref); + + print $q->td({-class=>"$tdclass",-style=>"$tdstyle $set_style width:300px;"},$q->a({-class=>"linknav3",-href=>"?node2edit=editpart\&u_id=$ct4rel->{$id}->{u_id}",-title=>"edit"},"$ctadr->{txt01} - $ctadr->{txt08} ($ct4rel->{$id}->{$key})")),"\n"; + }elsif($key eq "txt08" && $node_meta->{ct_table} eq "contentadrpos"){ + my $subject = "sharee.bike feedback"; + my $body = "Hallo $ct4rel->{$id}->{txt01},\%0A\%0Avielen Dank für Ihre Nachricht \"$ct4rel->{$id}->{txt02}\""; + print $q->td({-class=>"$tdclass",-style=>"$tdstyle $set_style"},$q->a({-class=>"editnav",-href=>"mailto:$ct4rel->{$id}->{$key}?subject=$subject&body=$body"},$q->span({-class=>"bi bi-envelope"}," $ct4rel->{$id}->{$key}"))),"\n"; + }elsif($key =~ /int0[1-8]/ && $node_meta->{ct_table} eq "users"){ + print $q->td({-class=>"$tdclass",-style=>"$tdstyle $set_style",-nowrap=>1},"$dbt->{copri_conf}->{permission}->{$ct4rel->{$id}->{$key}}"),"\n"; + }elsif($key =~ /int09/ && $node_meta->{ct_table} eq "users"){ + print $q->td({-class=>"$tdclass",-style=>"$tdstyle $set_style",-nowrap=>1},"$dbt->{copri_conf}->{access}->{$ct4rel->{$id}->{$key}}"),"\n"; + }else{ + print $q->td({-class=>"$tdclass",-style=>"$tdstyle $set_style"},"$ct4rel->{$id}->{$key}"),"\n"; + } + } + } + + print $q->end_table; + + my $offset_nr = $offset + $nr; + print $q->div({-style=>'float:left;padding:0.5em;'},"Zeile: $offset - $offset_nr"); + + #backward | forward + print "
    \n"; + print $q->a({-class=>"linknav",-href=>"?go=backward_list;offset=$offset;limit=$limit",-title=>''},"< zurück ... ") if($offset >= $limit); + print $q->a({-class=>"linknav",-href=>"?go=forward_list;offset=$offset;limit=$limit",-title=>''}," ... vorwärts >") if($nr >= $limit-10); #if($rows > $limit && $nr > 0); + print "
    \n"; + + print $q->end_form,"\n"; + print "
    \n"; + my $debug = "(ct_table: $node_meta->{ct_table} | main_id: $node_meta->{main_id} | template_id: $node_meta->{template_id})"; + print $q->div({-style=>'position:fixed;bottom:1%;font-size:13px;'},"$debug"),"\n" if($users_dms->{u_id} eq $varenv{superu_id}); + + return $return; +} + +1; diff --git a/copri4/main/src/Tpl/TransPositionen.pm b/copri4/main/src/Tpl/TransPositionen.pm new file mode 100644 index 0000000..e0d5cf9 --- /dev/null +++ b/copri4/main/src/Tpl/TransPositionen.pm @@ -0,0 +1,559 @@ +package TransPositionen; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +# +use strict; +use warnings; +use POSIX; +use CGI; +use CGI::Carp qw(fatalsToBrowser); +use CGI ':standard'; +use DateTime; +use DateTime::Format::Pg; +use Date::Calc::Object qw(:ALL); +use Scalar::Util qw(looks_like_number); +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Libenzdb; +use Mod::DBtank; +use Mod::APIfunc; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my $self=shift; + my ($node_meta,$users_dms,$set_main_id,$main_id,$rel_id,$c_id,$u_id,$lang,$return,$node_name) = @_; + my $q = new CGI; + my $cf = new Config; + my $lb = new Libenz; + my $db = new Libenzdb; + my $dbt = new DBtank; + my $apif = new APIfunc; + my $but = new Buttons; + my %varenv = $cf->envonline(); + my $script = $q->script_name(); + my $path_info = $q->path_info(); + my $path = $path_info; + #with meta_host, + if("$varenv{metahost}"){ + $path = "$script" . "$path_info"; + $script=""; + } + my $users = $db->select_users($u_id); + my %ib = $but->ibuttons(); + my $today = strftime("%d.%m.%Y",localtime(time)); + my $dbh = ""; + my $channel_map = $dbt->channel_map(); + + my $mapref = {}; + my $ct_users = $dbt->users_map($dbh,$mapref);#get serviceAPP and DMS users from contentadr + + my $line_count2; + my $k=0; + my $spart_ct_name = $R::spart_ct_name || ""; + my $c_idpos = $R::c_idpos || $R::pos_id || ""; + + my $ctf = $db->get_content1("contentuser",$dbt->{shareedms_conf}->{parent_id}); + my $ctt = $db->get_content1("contenttrans",$c_id); + + my $umst1619 = $lb->umst_breaking($ctt,""); + + my $ctadr = $db->get_content1("contentadr",$ctt->{int10}); + my $buchen_mtime = $lb->time4de($ctt->{mtime}); + my $vibuchen_mtime = ""; + $vibuchen_mtime = "Payone post " . $lb->time4de($ctt->{pay_time},1) . " . " if($ctt->{pay_time}); + + my $tpl = $db->get_tpl($ctf->{txt36}); + my @tpl_order = split /,/,$tpl->{tpl_order}; + + my $txt20 = $R::txt20 || $ctt->{txt20} || "";#Leistungsdatum + my $int05 = $R::int05 || $ctt->{int05} || "";#manuell + my $max_timestamp = "210001012359"; + if($ctf->{txt80} && $txt20 =~ /(\d{2})\.(\d{2})\.(\d{4})$/){ + $max_timestamp = $3 . $2 . $1 . "2359"; + }elsif($ctf->{txt80} =~ /(\d{2})\.(\d{2})\.(\d{4})$/){ + $max_timestamp = $3 . $2 . $1 . "2359"; + } + my $max_sum = $ctf->{int03} || "10000"; + my $cttpos = { c_id => 0 }; + my $rows = 0; + ($cttpos,$rows) = $db->collect_contentpos("contenttrans",$c_id) if($c_id); + my $tpath; #Terminal target-path + if($users->{transaction_uri} =~ /Verkauf|Verleih|Faktur/){ + $tpath = "$users->{transaction_uri}"; + }elsif("$users->{fullurl}"){ + $tpath = "$script/$users->{fullurl}/$users->{kind_of_trans}"; + } +if($varenv{orga} eq "dms"){#obsolete after migrating lx-rad and mobile ... +print< + .ui-autocomplete { + text-align:left; + font-size:14px; + background:#eeeeee; + border:1px solid silver; + } + + + +EOF +; +} +#print $q->div({ -class=>"ui-widget"}, $q->label({ -for=>"birds"},"Birds: "),$q->input({ -id=>"birds"},"")),"\n"; + + + print $q->start_table({-class=>'list', -border=>'0', -width=>'100%',-align=>'left', -cellpadding=>'3', -cellspacing=>'0'}); + + + #my $action_sort = "itime"; + #Parts Header + print $q->start_form(-name=>'spartform'); + print $q->Tr(); $line_count2++; + print $q->th($but->singlesubmit("select_part","*"),"\n"); + foreach (@tpl_order){ + my ($key,$val) = split /=/,$_; + $k++ if($val); + if("$key" eq "ct_name"){ + my $ctpos; + print $q->hidden(-name=>'c_id4trans', -override=>'1', -value=>"$c_id"); + print $q->hidden(-id=>'c_id', -name=>"c_id", -override=>'1'); + print $q->hidden(-id=>'spart_ct_name', -name=>"spart_ct_name", -override=>'1'); + print $q->th($q->textfield(-class=>'etxt',-style=>'height:19px;width:140px;font-size:1.3em;text-align:right;',-id=>"json_select",-name=>"json_select",-value=>"", -override=>'1',-size=>"25",-maxlength=>50, -placeholder=>'Nummer'),""); + } + if($key =~ /int03/){ + print $q->th("$val"); + }elsif($key =~ /int|txt03/){ + print $q->th("$val"); + }elsif($key =~ /txt01/){ + + my $cal_button = ""; + my $ter_button = ""; + my $war_button = ""; + print $q->th("Beschreibung"),"\n"; + + }elsif($key =~ /txt/){ + print $q->th("$val"); + } + } + + $c_idpos = $1 if($return && $return =~ /pos_id=(\d+)/); + print $q->hidden(-name=>'trans2edit', -value=>"transpos", -override=>'1'); + print $q->hidden(-name=>'offset', -override=>'1', -value=>"$R::offset") if($R::offset); + print $q->hidden(-name=>'limit', -override=>'1', -value=>"$R::limit") if($R::limit); + print $q->hidden(-name=>'relids', -override=>'1', -value=>"$R::relids") if($R::relids); + print $q->end_form,"\n"; + + print $q->start_form(-name=>'transposform'),"\n"; + + #Tablecontent (buttons and ct_name(primary key)) + #my $scol = "c_id";#changed to itime because of Storno resorts + my $scol = "itime"; + my $sum_parts0=0; + my $sum_parts7=0; + my $sum_parts19=0; + my $diff7 = 100 + 7; + my $diff19 = 100 + $umst1619; + my $sum_umst7=0; + my $sum_umst19=0; + my $i=0; + my $accounting_start; + my $accounting_end; + + #foreach my $id (sort { $cttpos->{$b}->{$scol} <=> $cttpos->{$a}->{$scol} } keys(%$cttpos)){ + foreach my $id (sort { $cttpos->{$b}->{$scol} cmp $cttpos->{$a}->{$scol} } keys(%$cttpos)){ + my $set_style=""; + my $gesamt="0"; + my $occupied_style = ""; + my $time_style = ""; + #$occupied_style = "color:#ff1493" if($cttpos->{$id}->{txt10} =~ /occupied|requested|canceled/); + $occupied_style = "color:#ff1493" if($cttpos->{$id}->{int10} == 2 ||$cttpos->{$id}->{int10} == 3 || $cttpos->{$id}->{int10} == 6); + + my $cttpos_timestamp = $1 . $2 . $3 . "0000" if($cttpos->{$id}->{itime} =~ /(\d+)\-(\d+)\-(\d+)/); + #max. Rechnungspositionen + if(($cttpos_timestamp <= $max_timestamp) && ($sum_parts19 <= $max_sum)){ + $i++; + #print "$i (($id: $cttpos_timestamp <= $max_timestamp) && ($sum_parts19 <= $max_sum))
    "; + if($i==1){ + $accounting_end = "$3.$2.$1" if($cttpos->{$id}->{itime} =~ /(\d+)\-(\d+)\-(\d+)/); + }else{ + $accounting_start = "$3.$2.$1" if($cttpos->{$id}->{itime} =~ /(\d+)\-(\d+)\-(\d+)/); + } + #print "$accounting_start - $accounting_end
    "; + + my @line_txt01 = split(/\n/,$cttpos->{$id}->{txt01}); + if($cttpos->{$id}->{int02} != 0){ + $line_count2++; + #$line_count2 += scalar(@line_txt01); + } + my ($s_date,$s_dd,$s_mo,$s_yy,$s_hh,$s_mi,$e_date,$e_yy,$e_mo,$e_dd,$e_hh,$e_mi); + my $einzel = $cttpos->{$id}->{int02}; + my $menge = $cttpos->{$id}->{int03} || 0; + + #Make date and time + if($cttpos->{$id}->{start_time} && $cttpos->{$id}->{end_time}){ + ($s_yy,$s_mo,$s_dd,$s_hh,$s_mi) = $lb->split_date($cttpos->{$id}->{start_time}); + ($e_yy,$e_mo,$e_dd,$e_hh,$e_mi) = $lb->split_date($cttpos->{$id}->{end_time}); + } + + + my $dt1 = DateTime->new(year => 2018, month => 3, day => 20); + my $dt0 = $dt1; + my $dt2 = $dt1; + $dt0 = DateTime::Format::Pg->parse_datetime($cttpos->{$id}->{start_time}) if($cttpos->{$id}->{start_time}); + $dt2 = DateTime::Format::Pg->parse_datetime($cttpos->{$id}->{end_time}) if($cttpos->{$id}->{end_time}); + #if($dt2 < $dt0){ + #$time_style="color:red;"; + #} + + if(looks_like_number($einzel) && $einzel != 0 && looks_like_number($menge) && $menge != 0){ + $gesamt = $einzel * $menge; + + my $rabatt_val = $cttpos->{$id}->{int07} || ""; + if($rabatt_val != 0){ + my $rabatt_eur = $rabatt_val; + $rabatt_eur = $einzel * $menge * $rabatt_val/100 if($cttpos->{$id}->{int08} != 1);#wenn int08 != 1 alias € + $gesamt = $einzel * $menge - $rabatt_eur; + } + } + + $gesamt = $lb->round($gesamt); + $gesamt = $lb->cashme($gesamt); + $ctf->{txt13} = $1 if($ctf->{txt13} =~ /(\d+)/); + if($node_name =~ /steuerfrei/){#dirty hack + $sum_parts0 += $gesamt; + }elsif("$cttpos->{$id}->{int05}" =~ /\d/){ + $sum_parts0 += $gesamt if("$cttpos->{$id}->{int05}" == "0"); + $sum_parts7 += $gesamt if("$cttpos->{$id}->{int05}" == "7"); + #$sum_parts19 += $gesamt if("$cttpos->{$id}->{int05}" == "19"); + $sum_parts19 += $gesamt if($cttpos->{$id}->{int05} >= 16); + }else{ + #print "yyy $gesamt $ctf->{txt13} |"; + $sum_parts0 += $gesamt if("$ctf->{txt13}" == "0"); + $sum_parts7 += $gesamt if("$ctf->{txt13}" == "7"); + $sum_parts19 += $gesamt if("$ctf->{txt13}" >= "16"); + } + + #1. Spalte + print $q->Tr(),"\n"; + print ""; + if(($c_idpos == $cttpos->{$id}->{c_id}) && ($R::trans2edit && $R::trans2edit =~ /transpos/)){ + print $q->hidden(-name=>'c_idpos', -value=>"$cttpos->{$id}->{c_id}", -override=>'1'); + print $q->hidden(-name=>'cc_id', -value=>"$cttpos->{$id}->{cc_id}", -override=>'1'); + print $q->hidden(-name=>'c_id4trans', -override=>'1', -value=>"$c_id"); + print $but->singlesubmit2("ct_trans","save_pos","$ib{save_pos}","","ebutton5"), + $but->singlesubmit2("ct_trans","delete_pos","$ib{delete_pos}"),"\n"; + }elsif(!$ctt->{close_time}){ + print $q->a({-class=>"editnav",-href=>"$tpath?trans2edit=transpos\&c_idpos=$cttpos->{$id}->{c_id}\&c_id4trans=$c_id\&owner=$users->{u_id}",-title=>"Datensatz bearbeiten"}, $q->img({-src=>"$varenv{metahost}/glyphicons/glyphicons-151-edit.png"})),"\n"; + } + my $calpath = "Mietjournal"; + print $q->a({-class=>"linknav3", -style=>"background-color:$varenv{calendar_active_color}",-href=>"$script/$users->{fullurl}/$calpath/?cttpos_id=$cttpos->{$id}->{c_id}",-title=>"Im $calpath öffnen"},"

    ID $cttpos->{$id}->{c_id}"),"\n"; + print "\n"; + + #Tablecontent (parameter) + foreach (@tpl_order){ + my ($key,$val,$inputsize) = split /=/,$_; + $cttpos->{$id}->{$key} = $q->unescapeHTML($cttpos->{$id}->{$key}); + $cttpos->{$id}->{$key} = $lb->newline($cttpos->{$id}->{$key},"",$R::trans2edit) if($R::trans2edit); + my $ct_pos = "$cttpos->{$id}->{ct_name}"; + my $txtstyle = "text-align:left;min-width:150px;"; + my $isize = "30"; + $isize = $inputsize if($inputsize); + if($key =~ /int|txt03/){ #für zahlen etwas kleiner + $txtstyle = "text-align:right;min-width:50px;"; + $isize = "5"; + } + if(($c_idpos == $cttpos->{$id}->{c_id}) && ($R::trans2edit && $R::trans2edit =~ /transpos/)){ + if($key =~ /ct_name/){ + print $q->td({-class=>'element',-style=>"$set_style text-align:right;"}, $q->textfield(-class=>'etxt',-style=>"text-align:right;min-width:120px;",-name=>"ct_name",-default=>"$ct_pos", -override=>'1',-size=>10,-readonly=>'1'),"\n"); + }elsif($key =~ /int03/){ + print $q->td({-colspan=>'1',-class=>'element',-style=>"$txtstyle $set_style"},$q->textfield(-class=>'etxt',-style=>"$txtstyle",-name=>"col_$key",-default=>"$menge", -override=>'1',-size=>"$isize",-maxlength=>10, -autofocus=>1),"\n"); + }elsif($key =~ /int02/){ + print $q->td({-class=>'element',-style=>"$txtstyle $set_style"},$q->textfield(-class=>'etxt',-style=>"$txtstyle",-name=>"col_$key",-default=>"$einzel", -override=>'1',-size=>"$isize",-maxlength=>100),"\n"); + }elsif($key =~ /int07/){ + print $q->td({-class=>'element',-style=>"$txtstyle $set_style",-nowrap=>'1'},$q->textfield(-class=>'etxt',-style=>"$txtstyle",-name=>"col_$key",-default=>"$cttpos->{$id}->{$key}", -override=>'1',-size=>"$isize",-maxlength=>100),$but->selector("int08","40px","$cttpos->{$id}->{int08}",("0.00:%","1.00:€"))),"\n"; + }elsif($key =~ /int04/){ + print $q->td({-class=>'element',-style=>'text-align:right;padding:0.1em 0.5em;',-nowrap=>"1"},"$gesamt €"); + }elsif($key =~ /txt01/){ + if($cttpos->{$id}->{int09} && $cttpos->{$id}->{$key} !~ /Manuell/){ + $cttpos->{$id}->{$key} .= "\nManuell bearbeitet\n"; + } + print ""; + print $q->textarea(-class=>'autos',-style=>"border: 1px solid #ededed;background-color: #ededed;",-name=>"col_$key",-default=>"$cttpos->{$id}->{$key}", -override=>'1',-rows=>"1",-cols=>65),"
    \n"; + + if($cttpos->{$id}->{int09}){#2020-12-07 Verleihräder werden anhand der TarifNr als solches erkannt + print $q->span({-style=>"$txtstyle $set_style"}, + "Tarif Nr.: ", $q->textfield(-class=>'etxt',-name=>"int09",-default=>"$cttpos->{$id}->{int09}",-size=>"5",-maxlength=>5), + "Tarif Text", $q->textfield(-class=>'etxt',-name=>"txt04",-default=>"$cttpos->{$id}->{txt04}",-size=>"30",-maxlength=>50)),"
    \n"; + + print $q->span({-style=>"$txtstyle $set_style"}, + "Endstation: ", $q->textfield(-class=>'etxt',-name=>"int04",-default=>"$cttpos->{$id}->{int04}",-size=>"5",-maxlength=>40), + "GPS: ", $q->textfield(-class=>'etxt',-name=>"txt06",-default=>"$cttpos->{$id}->{txt06}",-size=>"35",-maxlength=>40)),"
    \n"; + + print $q->span({-style=>"$txtstyle $set_style"},"Mietzeit: ", + $q->textfield(-id=>'datepicker1',-class=>'etxt',-name=>"start_date",-default=>"$s_dd.$s_mo.$s_yy",-size=>"10",-maxlength=>10), + $q->textfield(-class=>'etxt',-name=>"s_hh",-default=>"$s_hh",-size=>"2",-maxlength=>2),":", + $q->textfield(-class=>'etxt',-name=>"s_mi",-default=>"$s_mi",-size=>"2",-maxlength=>2)," – ", + $q->textfield(-id=>'datepicker2',-class=>'etxt',-name=>"end_date",-default=>"$e_dd.$e_mo.$e_yy",-size=>"10",-maxlength=>10), + $q->textfield(-class=>'etxt',-name=>"e_hh",-default=>"$e_hh",-size=>"2",-maxlength=>2),":", + $q->textfield(-class=>'etxt',-name=>"e_mi",-default=>"$e_mi",-size=>"2",-maxlength=>2)),"\n"; + } + + print "\n"; + }elsif($key =~ /txt/){ + print $q->td({-class=>'element',-style=>"$txtstyle $set_style"},$q->textfield(-class=>'etxt',-style=>"$txtstyle",-name=>"col_$key",-default=>"$cttpos->{$id}->{$key}", -override=>'1',-size=>"$isize",-maxlength=>100),"\n"); + #}elsif($key =~ /save/){ + #print $q->td({-class=>'element',-style=>"$set_style"},$but->singlesubmit2("ct_trans","save_pos","$ib{save_pos}")); + }elsif($key =~ /int/){ + print $q->td({-class=>'tdint',-nowrap=>"1"}," \n"); + } + }else{ + if($key =~ /ct_name/){ + #print $q->td({-class=>'tdint',-style=>"min-width:60px;"},"$ct_pos"); + my $stamm_style = "background-color:#98c13b;padding:2px;"; + my $article = $cttpos->{$id}->{ct_name}; + if($cttpos->{$id}->{int09}){ + print $q->td({-class=>'tdint',-style=>"min-width:60px;padding-top:5px;"}, $q->a({-class=>"linknav3",-style=>"$stamm_style",-href=>"$script/$users->{fullurl}/Waren/?detail_search=1&s_barcode=$cttpos->{$id}->{barcode}",-title=>"Im Warenstamm"},"$article")),"\n"; + }else{ + print $q->td({-class=>'tdint'},"$article"),"\n"; + } + }elsif($key =~ /int02/){ + $einzel =~ s/\./,/; + print $q->td({-class=>'tdint'},"$einzel"),"\n"; + }elsif($key =~ /int03/){ + $menge =~ s/\./,/; + print $q->td({-colspan=>'1',-class=>'tdint'},"$menge"),"\n"; + }elsif($key =~ /int04/){ + $gesamt =~ s/\./,/; + print $q->td({-class=>'tdint',-nowrap=>"1"},"$gesamt €"),"\n"; + }elsif($key =~ /int02/){ + print $q->td({-class=>'tdint'},"$einzel"),"\n"; + }elsif($key =~ /int07/){ + my $proz=""; + $proz = "%" if($cttpos->{$id}->{$key} && $cttpos->{$id}->{$key} != 0); + $proz = "€" if($cttpos->{$id}->{$key} && $cttpos->{$id}->{$key} != 0 && $cttpos->{$id}->{int08} && $cttpos->{$id}->{int08} == 1); + print $q->td({-class=>'tdint',-nowrap=>"1"},"$cttpos->{$id}->{$key} $proz"),"\n"; + }elsif($key =~ /txt03/){ + print $q->td({-class=>'tdint'},"$cttpos->{$id}->{$key}"),"\n"; + }elsif($key =~ /txt01/){ + $cttpos->{$id}->{$key} = $q->unescapeHTML("$cttpos->{$id}->{$key}"); + $cttpos->{$id}->{$key} = $lb->newline($cttpos->{$id}->{$key},"",""); + print "\n"; + if($cttpos->{$id}->{barcode} && $cttpos->{$id}->{int09}){#bike with tariff-nr + my $u_name = $cttpos->{$id}->{owner}; + my $u_name_end = $cttpos->{$id}->{owner_end}; + foreach my $ctu_id (keys (%$ct_users)){ + if($channel_map->{$u_name}){ + $u_name = $channel_map->{$u_name}; + }elsif($cttpos->{$id}->{owner} eq $ct_users->{$ctu_id}->{c_id}){ + $u_name = $ct_users->{$ctu_id}->{txt01}; + } + if($channel_map->{$u_name_end}){ + $u_name_end = $channel_map->{$u_name_end}; + }elsif($cttpos->{$id}->{owner_end} eq $ct_users->{$ctu_id}->{c_id}){ + $u_name_end = $ct_users->{$ctu_id}->{txt01}; + } + } + if($cttpos->{$id}->{itime} =~ /(\d{4})-(\d{2})-(\d{2})\s(\d{2}):(\d{2})/){ + print $q->span("$dbt->{copri_conf}->{bike_state}->{$cttpos->{$id}->{int10}} → $dbt->{copri_conf}->{lock_state}->{$cttpos->{$id}->{int20}} → $u_name / $u_name_end"),"\n"; + print "
    \n"; + } + } + if($cttpos->{$id}->{txt01} || $cttpos->{$id}->{int09}){ + #$line_count2++; + $cttpos->{$id}->{txt01} =~ s/fixed/\fixed\<\/span\>/; + $cttpos->{$id}->{txt01} =~ s/defect/\defect\<\/span\>/; + my $bike=""; + my $tariff = ""; + $bike = "$cttpos->{$id}->{$key}" if($cttpos->{$id}->{$key}); + $tariff = ", Tarif: $cttpos->{$id}->{int09} $cttpos->{$id}->{txt04}" if($cttpos->{$id}->{txt04}); + print $q->span("$bike $tariff
    "),"\n"; + } + if($cttpos->{$id}->{int06} || $cttpos->{$id}->{int04}){ + print $q->span("Start/End Station: $cttpos->{$id}->{int06} / $cttpos->{$id}->{int04}, GPS: $cttpos->{$id}->{txt06}"),"\n"; + } + if($cttpos->{$id}->{start_time}){ + print "
    \n"; + print $q->span({-style=>"$time_style"}, "Mietzeit: $s_dd.$s_mo.$s_yy $s_hh:$s_mi – $e_dd.$e_mo.$e_yy $e_hh:$e_mi"),"\n"; + } + print "\n"; + }elsif($key =~ /txt/){ + print $q->td({-class=>'tdtxt'},"$cttpos->{$id}->{$key}"); + }elsif($key =~ /int/){ + print $q->td({-class=>'tdint',-nowrap=>"1"}," \n"); + } + } + } + } + }#foreach end + + if($sum_parts7 != "0"){ + $sum_umst7 = $sum_parts7 / $diff7 * 7; + $sum_umst7 = $lb->round($sum_umst7); + } + if($sum_parts19 != "0"){ + $sum_umst19 = $sum_parts19 / $diff19 * $umst1619; + $sum_umst19 = $lb->round($sum_umst19); + } + my $sum_netto7 = $sum_parts7 - $sum_umst7; + my $sum_netto19 = $sum_parts19 - $sum_umst19; + $sum_netto7 = $lb->cashme($sum_netto7); + $sum_netto19 = $lb->cashme($sum_netto19); + my $sum_nettoall = $sum_parts0 + $sum_netto7 + $sum_netto19; + $sum_nettoall = $lb->round($sum_nettoall); + $sum_nettoall = $lb->cashme($sum_nettoall,","); + my $sum_paid = $sum_parts0 + $sum_parts7 + $sum_parts19; + $sum_paid = $lb->round($sum_paid); + my $sum_preauth = $sum_paid || 0; + $sum_parts0 = $lb->cashme($sum_parts0,","); + $sum_parts7 = $lb->cashme($sum_parts7,","); + $sum_parts19 = $lb->cashme($sum_parts19,","); + $sum_umst7 = $lb->cashme($sum_umst7,","); + $sum_umst19 = $lb->round($sum_umst19); + $sum_umst19 = $lb->cashme($sum_umst19,","); + $sum_paid = $lb->cashme($sum_paid,","); + + my $n="5"; + my $m= 1 + $k - $n; + $m++ if($users->{kind_of_trans} =~ /Faktur|Verleih/); + print " \n"; + print $q->start_table({-class=>'list',-style=>'border-top:1px;border-style:solid;border-color:black;', -border=>'0', -width=>'100%',-align=>'center', -cellpadding=>'3', -cellspacing=>'0'}),"\n"; + print $q->Tr("\n"); + print $q->td(" "); + + #if($users->{kind_of_trans} ne "Einkauf" && $node_name !~ /steuerfrei/){ + if($node_name !~ /steuerfrei/){ + print $q->Tr("\n"); $line_count2++; + print $q->td({-class=>'tdint'},"Nettobetrag:"); + print $q->td({-class=>'tdint',-nowrap=>"1"},"$sum_nettoall €"); + + if($sum_parts0 != "0"){ + print $q->Tr("\n");$line_count2++; + print $q->td({-class=>'tdint',-nowrap=>"1"},"0% UmSt auf $sum_parts0 €:"); + print $q->td({-class=>'tdint',-nowrap=>"1"},"0,00 €"); + } + if($sum_netto7 != "0"){ + print $q->Tr("\n");$line_count2++; + print $q->td({-class=>'tdint',-nowrap=>"1"},"7% UmSt auf $sum_netto7 €:"); + print $q->td({-class=>'tdint',-nowrap=>"1"},"$sum_umst7 €"); + } + if($sum_netto19 != "0"){ + print $q->Tr("\n");$line_count2++; + print $q->td({-class=>'tdint',-nowrap=>"1"},"$umst1619% UmSt auf $sum_netto19 €:"); + print $q->td({-class=>'tdint',-nowrap=>"1"},"$sum_umst19 €"); + } + } + my $summe = "Summe"; + #$summe = "Nettosumme" if($users->{kind_of_trans} eq "Einkauf"); + print $q->Tr("\n");$line_count2++; + print $q->td({-class=>'tdsum'},"$summe:"); + print $q->td({-class=>'tdint',-nowrap=>"1"},"$sum_paid €"); + print $q->hidden(-name=>'sum_paid', -override=>'1',-value=>"$sum_paid"); + + print $q->end_table; + print " "; + print ""; + print $q->end_table; + + print $q->hidden(-name=>'owner', -override=>'1', -value=>"$users->{u_id}"); + print $q->hidden(-name=>'offset', -override=>'1', -value=>"$R::offset") if($R::offset); + print $q->hidden(-name=>'c_id4trans', -override=>'1', -value=>"$c_id"); + print $q->hidden(-name=>'offset', -override=>'1', -value=>"$R::offset") if($R::offset); + print $q->hidden(-name=>'limit', -override=>'1', -value=>"$R::limit") if($R::limit); + print $q->hidden(-name=>'relids', -override=>'1', -value=>"$R::relids") if($R::relids); + + $set_main_id=$main_id if($main_id && $main_id > "300000"); + print $q->hidden(-name=>'set_main_id', -value=>"$set_main_id", -override=>'1'); + + + #if(!$ctt->{close_time} && $varenv{Zahlungsweise} && $users->{u_id} == $dbt->{copri_conf}->{superu_id}){ + if($users_dms->{int03} == 2){ + #only if user is also a primary DMS user with invoice rw + my $dbh_primary = $dbt->dbconnect_extern("sharee_primary"); + my $users_dms_primary = { u_id => 0 }; + $users_dms_primary = $dbt->select_users($dbh_primary,$users_dms->{u_id},"and int03=2"); + + if($users_dms_primary->{int03} == 2 && !$ctt->{close_time} && $varenv{Zahlungsweise}){ + my @_paymentstate = split(/\|/,$varenv{Zahlungsweise}); + push @_paymentstate, ""; + my $kind_of_payment = ""; + if($ctadr->{int03} == 1 && ($ctadr->{ct_name} =~ /PO-\d+/ || $ctadr->{ct_name} =~ /TM-\d+/)){ + $kind_of_payment = "$_paymentstate[0]"; + }else{ + undef $_paymentstate[0]; + } + if($ctadr->{int03} == 2 && length($ctadr->{ct_name}) >= 19){ + $kind_of_payment = "$_paymentstate[1]"; + }else{ + undef $_paymentstate[1]; + } + $kind_of_payment = "$ctt->{state}" if($ctt->{state}); + + print $q->hidden(-name=>'printer_id', -value=>"PDF - Normalpapier", -override=>'1'); + my $send_invoice_checkbox = 1; + $send_invoice_checkbox = 0 if($ctt->{txt30}); + print $q->div({-class=>'element',-style=>'float:right;'}, + "buchen incl. drucken ",$but->checkbox("print_pdf","ct_trans","1","PDF drucken",""), + " eMail Versand ",$but->checkbox("1","send_invoice","$send_invoice_checkbox","eMail Rechnung",""), + $but->singlesubmit1("set_state","buchen"), + $but->selector("state","150px",$kind_of_payment,@_paymentstate),"\n") if($users->{kind_of_trans} =~ /Verkauf|Verleih|Faktur/); + } + } + + my $praefix = "$ctt->{txt00}-$varenv{praefix}"; + if($ctt->{state} && $ctt->{int01}){ + + $ctt->{int01} =~ s/\./,/; + my $style = "color:red;" if($ctt->{int01} ne $sum_paid); + my $opos = ""; + $opos = "OPOS" if($ctt->{int14} eq "1"); + print $q->div({-style=>"float:right;padding:0.71em;font-size:0.81em;$style"},"[$opos $vibuchen_mtime Gebucht $ctt->{int01} € \"$ctt->{state}\"]") if($ctt->{state}); + } + print $q->end_form; + print $q->div({-style=>"clear:both;height:0.1px;"},""),"\n"; + if($ctt->{txt30}){ + print $q->div({-style=>"padding:0.5em;font-size:0.81em;width:98%;text-align:right;"}, "$ctt->{txt30}"),"\n"; + }elsif( -f "$varenv{pdf}/$praefix-$ctt->{ct_name}.pdf" ){ + print $q->start_form(),"\n"; + print $q->hidden(-name=>'offset', -override=>'1', -value=>"$R::offset") if($R::offset); + print $q->hidden(-name=>'limit', -override=>'1', -value=>"$R::limit") if($R::limit); + print $q->hidden(-name=>'relids', -override=>'1', -value=>"$R::relids") if($R::relids); + print $q->div({-style=>"padding:0.5em;font-size:0.81em;width:98%;text-align:right;"}, "eMail wurde nicht versandt! Rechnung eMail ", $but->singlesubmit1("ct_trans","send_invoice_again","send_invoice_again")),"\n" if($users->{u_id} == $dbt->{copri_conf}->{superu_id}); + print $q->end_form; + } + + if( -f "$varenv{pdf}/$praefix-$ctt->{ct_name}.pdf" && $varenv{metahost}){ + print $q->div({-style=>"padding:0.5em;font-size:0.81em;width:98%;text-align:right;"}, "Download: ", $q->a({-href=>"$varenv{metahost}/pdf/$praefix-$ctt->{ct_name}.pdf", -target=>'_blank'},"$praefix-$ctt->{ct_name}.pdf")); + } + + + if($ctt->{state} && $ctt->{state} =~ /payone/ && $ctt->{txt28} && $ctt->{txt28} =~ /error/i){ + print $q->div({-style=>"clear:both;padding:0.5em;font-size:0.81em;width:98%;text-align:right;color:red;"}, "Payone error: $ctt->{txt28}"),"\n"; + }elsif($ctt->{txt28} =~ /settleaccount=yes/i){ + print $q->div({-style=>"clear:both;padding:0.5em;font-size:0.81em;width:98%;text-align:right;color:green;"}, "Payone SEPA-Lastschrifteinzug war erfolgreich"),"\n"; + } + + $db->updater("contenttrans","c_id","$c_id","txt20","$accounting_start - $accounting_end","","","","","no_time") if(!$int05 && $accounting_start && $accounting_end); + $db->updater("contenttrans","c_id","$c_id","int15","$sum_preauth","","","","","no_time") if($sum_preauth || $sum_preauth == 0); + return "$line_count2"; +} +1; diff --git a/copri4/main/src/scripts/Ilockauth.class b/copri4/main/src/scripts/Ilockauth.class new file mode 100644 index 0000000..4a2ad72 Binary files /dev/null and b/copri4/main/src/scripts/Ilockauth.class differ diff --git a/copri4/main/src/scripts/Ilockauth.java b/copri4/main/src/scripts/Ilockauth.java new file mode 100644 index 0000000..0e05944 --- /dev/null +++ b/copri4/main/src/scripts/Ilockauth.java @@ -0,0 +1,47 @@ +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; +import java.util.Arrays; + + + +public class Ilockauth { + public static void main( String args[] ) { + String db_id = args[0]; + String bike_id = args[1]; + Connection c = null; + Statement stmt = null; + try { + Class.forName("org.postgresql.Driver"); + c = DriverManager + .getConnection("jdbc:postgresql://localhost:5432/" + db_id, + "postgres", ""); + c.setAutoCommit(false); + //System.out.println("Opened database successfully"); + + stmt = c.createStatement(); + ResultSet rs = stmt.executeQuery( "SELECT * FROM content where barcode=" + bike_id + ";" ); + while ( rs.next() ) { + + byte[] randomNum = new byte[16]; + + byte[] K_int = rs.getBytes("byte01"); + + //example by byte[] + //byte[] K_int = {(byte) 0xA7, (byte) 0x99, (byte) 0x91, 0x12, 0x49, (byte) 0xE0, (byte) 0xBA, (byte) 0xD5, (byte) 0xF2, 0x48, (byte) 0x8D, (byte) 0xC1, 0x7E, 0x28, 0x2D, (byte) 0xD0}; + + System.out.println( "K_int = " + Arrays.toString(K_int)); + Ilockkeygen.generateKey(randomNum, K_int); + + } + rs.close(); + stmt.close(); + c.close(); + } catch ( Exception e ) { + System.err.println( e.getClass().getName()+": "+ e.getMessage() ); + System.exit(0); + } + //System.out.println("Operation done successfully"); + } +} diff --git a/copri4/main/src/scripts/Ilockit_CSV2DB.pl b/copri4/main/src/scripts/Ilockit_CSV2DB.pl new file mode 100755 index 0000000..e89328b --- /dev/null +++ b/copri4/main/src/scripts/Ilockit_CSV2DB.pl @@ -0,0 +1,143 @@ +#!/usr/bin/perl +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +#For pdf pw files +#"pdftotext -upw FksjxxxxxxfmC1h Teilrad_ISI_PLUS_BB01207.pdf" +#:1,$ s/^\n//g +#:1,$ s/\n/;/g +#:1,$ s/;C2-/\rC2-/g +#:1,$ s/;QR-/\rQR-/g +# +# +#check if UTF-8 +#file Teilrad_ISI_PLUS_BB01207.txt +#iconv -t utf-8 -f iso-8859-1 Ilockitkeys_110520.csv -o Ilockitkeys_110520_utf8.cs +# +#sudo su www-data -c "./src/scripts/Ilockit_CSV2DB.pl shareedms-fr01 Teilrad_ISI_GPS_BB01328.txt" +# +#do it twice to set hex-key and bike-nr! +# +use vars qw($syshost); + +BEGIN { + $syshost = $ARGV[0] || exit 1; +} + +use lib "/var/www/copri4/$syshost/src"; + +my $csv_file = $ARGV[1] || ""; + +use strict; +use warnings; +use POSIX; +use DBI; +use CGI ':standard'; +use Lib::Config; +use Mod::DBtank; +use Scalar::Util qw(looks_like_number); +use Data::Dumper; + +my $q = new CGI; +my $cf = new Config; +my %varenv = $cf->envonline("$syshost"); +print "$varenv{wwwhost}\n"; +my $dbt = new DBtank; +my $lang = "de"; +my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; +my $dbh = ""; +my $main_id = 300001;#TODO Mietrad Flotten ID +my $template_id = 205; + +### +#Start loop payone log and update userid ################################## +#### +#reading CSV + my $dbh_csv = DBI->connect("DBI:CSV:"); + $dbh_csv->{'csv_tables'}->{'ilockitcsv'} = { + 'eol' => "\n", + 'sep_char' => ";", + 'quote_char' => undef, + #'quote_char' => "\"", + 'escape_char' => undef, + 'file' => $csv_file, + 'col_names' => ["serialnr","ilockit_id","ilockit_key","c1","c2","c3","c4","c5","c6"] + }; + + my $sth = $dbh_csv->prepare("SELECT * FROM ilockitcsv where serialnr like 'C2-%'"); + my $rc = $sth->execute(); + my $csv = $sth->fetchall_hashref("serialnr"); + + my $i=0; + foreach my $id (sort { $csv->{$a}->{serialnr} cmp $csv->{$b}->{serialnr} } keys (%$csv)){ + $i++; + + if($csv->{$id}->{serialnr}){ + $csv->{$id}->{ilockit_id} =~ s/\+/\-/; + $csv->{$id}->{c1} =~ s/Rot/red/;$csv->{$id}->{c1} =~ s/Blau/blue/;$csv->{$id}->{c1} =~ s/Gr.+n/green/; + $csv->{$id}->{c2} =~ s/Rot/red/;$csv->{$id}->{c2} =~ s/Blau/blue/;$csv->{$id}->{c2} =~ s/Gr.+n/green/; + $csv->{$id}->{c3} =~ s/Rot/red/;$csv->{$id}->{c3} =~ s/Blau/blue/;$csv->{$id}->{c3} =~ s/Gr.+n/green/; + $csv->{$id}->{c4} =~ s/Rot/red/;$csv->{$id}->{c4} =~ s/Blau/blue/;$csv->{$id}->{c4} =~ s/Gr.+n/green/; + $csv->{$id}->{c5} =~ s/Rot/red/;$csv->{$id}->{c5} =~ s/Blau/blue/;$csv->{$id}->{c5} =~ s/Gr.+n/green/; + $csv->{$id}->{c6} =~ s/Rot/red/;$csv->{$id}->{c6} =~ s/Blau/blue/;$csv->{$id}->{c6} =~ s/Gr.+n/green/; + print "$i) $csv->{$id}->{serialnr}|\n"; + + my $ct = &select_content($csv->{$id}); + + my $data = { + table => "content", + main_id => "$main_id", + template_id => "$template_id", + txt22 => "$csv->{$id}->{serialnr}", + txt18 => "$csv->{$id}->{ilockit_id}", + byte01 => "\\x$csv->{$id}->{ilockit_key}", + int04 => "0",#station Werkstatt + int10 => "5",#defect + int11 => "2",#Ilockit + int20 => "1",#locked + txt01 => "unverbaut", #Bezeichnung #TODO + txt04 => "aus Lieferung vom 29.11.2021", #Besonderheiten + txt15 => "", #Firmware + txt17 => "", #GUID from APP + txt23 => "$csv->{$id}->{c1} $csv->{$id}->{c2} $csv->{$id}->{c3} $csv->{$id}->{c4} $csv->{$id}->{c5} $csv->{$id}->{c6}", + mtime => "now()", + owner => "1842", + }; + + if(ref($ct) eq "HASH" && $ct->{c_id} && ref($data) eq "HASH" && $csv->{$id}->{serialnr}){ + print "UPDATE $csv->{$id}->{serialnr} (c_id:$ct->{c_id})\n"; + $data->{barcode} = $ct->{c_id} if(!$ct->{barcode}); + $dbt->update_record($dbh,$data, { c_id => $ct->{c_id} }); + print Dumper($data) . "\n"; + }elsif(ref($data) eq "HASH" && $csv->{$id}->{serialnr}){ + print "INSERT $csv->{$id}->{serialnr}\n"; + $dbt->insert_contentoid($dbh,$data); + print Dumper($data) . "\n"; + }else{ + print "nothing todo\n"; + } + } +} + +#content check if still exists +sub select_content{ + my $ct_hash = shift; + my $fetch = { + table => "content", + main_id => "$main_id", + template_id => "$template_id", + fetch => "one", + }; + if(ref($ct_hash) eq "HASH" && $ct_hash->{serialnr}){ + $fetch = { %$fetch , txt22 => "=::$ct_hash->{serialnr}" }; + #$fetch = { %$fetch , barcode => "<::100" }; + #$fetch = { %$fetch , int10 => "!=::3" }; + #$fetch = { %$fetch , int11 => "!=::2" }; + } + + my $ct = $dbt->fetch_record($dbh,$fetch); + return $ct; +} + + diff --git a/copri4/main/src/scripts/Ilockit_cloud.pl b/copri4/main/src/scripts/Ilockit_cloud.pl new file mode 100755 index 0000000..d77bfa2 --- /dev/null +++ b/copri4/main/src/scripts/Ilockit_cloud.pl @@ -0,0 +1,377 @@ +#!/usr/bin/perl +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +#get lock event for last 20 minutes +#cronjob interval 15 minutes +#sudo su www-data -c "./src/scripts/Ilockit_cloud.pl shareedms-fr01 get_events" +# +#Ilockit GPS cloud +# +#4. Get a list of positions +#fetch_ >> https://tracking.ilockit.bike/api/positions?from=2021-05-31T07:44:10Z&to=2021-06-06T07:44:10Z&deviceId=4272 + +#5. Get a list of Events +#fetch_ >> https://tracking.ilockit.bike/api/reports/events?from=2021-05-31T07:44:10Z&to=2021-06-06T07:44:10Z&deviceId=4272 + +use vars qw($syshost); + +BEGIN { + $syshost = $ARGV[0] || die; +} + +use lib "/var/www/copri4/$syshost/src"; +use strict; +use warnings; +use POSIX; +use CGI; +use Lib::Config; +use JSON; +use LWP::UserAgent; +use DateTime; +use Time::Piece; + +my $cf = new Config; +use Mod::DBtank; +use Data::Dumper; + +my $q = new CGI; +my $dbt = new DBtank; +my %varenv = $cf->envonline($syshost); + +my $lang = "de"; +my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; + +my $api_file = "/var/www/copri4/shareeconf/apikeys.cfg"; +my $aconf = Config::General->new($api_file); +my %apikeyconf = $aconf->getall; +#print "---> " . $apikeyconf{Ilockitcloud}->{username} . "\n"; + +my $ua = LWP::UserAgent->new; +$ua->agent("sharee APIclient"); +$ua->credentials( 'tracking.ilockit.bike:443', 'api', "$apikeyconf{Ilockitcloud}->{username}", "$apikeyconf{Ilockitcloud}->{passwd}"); + +my $json = JSON->new->allow_nonref; +my $response_in = {}; +my $dbh = ""; +my $owner = 183; + +my $todo = $ARGV[1]; +my $deviceId = $ARGV[2] || ""; + +open(FILE,">>$varenv{logdir}/Ilockit_cloud.log"); +print FILE "\n\n*** $now_dt\n"; + +#my $endpoint = "https://tracking.ilockit.bike/api/commands"; +#utc to localtime +sub localizedtime { + my $date = shift; + + $date =~ s/\..*$//; + my $time = Time::Piece->strptime($date, "%Y-%m-%dT%H:%M:%S"); + print FILE "localizedtime GMT alias Zulu: " . $time->datetime . "\n";#GMT alias Zulu + $time = localtime($time->epoch);#epoch + print FILE "localizedtime localized date time: " . $time->datetime . "\n";#localized date time + + return $time->datetime; +} +#print localizedtime("2021-06-11T11:58:09.000+0000") . " example\n"; + +#localtime to utc +#my $now = strftime "%Y-%m-%dT%H:%M:%S", localtime; +#utctime($now); +sub utctime { + my $date = shift; + my $latency = shift || 0; + + $date =~ s/\..*$//; + $date =~ s/\+\d+$//; + print FILE "requested datetime: " . $date . "\n"; + + my $time = Time::Piece->strptime($date, "%Y-%m-%dT%H:%M:%S"); + print FILE "localtime: " . $time->datetime . "\n";#localtime + my $utc_epoch = $time->epoch; + #$utc_epoch -= 2*60*60;# -2 std + # + #only -1 hour, because of deviceTime and serverTime differs + #'deviceTime' => '2021-10-14T08:19:35.000+0000', + #'serverTime' => '2021-10-14T07:19:37.000+0000', + $utc_epoch -= 1*60*60;# -1 std + $utc_epoch += $latency; + $time = gmtime($utc_epoch);#epoch + print FILE "utctime: " . $time->datetime . "\n";#utc zulu date time + # + return $time->datetime; +} + + +#get all device localy +sub get_devicesONcontent_all { + my $deviceId = shift; + my $pref = { + table => "content", + fetch => "all", + keyfield => "int13", + template_id => "205", + int13 => ">::0", + }; + my $record = $dbt->fetch_record($dbh,$pref); + return $record; +} + +#get one device localy in contenttranspos to check if bike is locked +sub get_devicesONcontenttranspos { + my $deviceId = shift; + my $pref = { + table => "contenttranspos", + fetch => "one", + int13 => "$deviceId", + #int20 => "1",#locked + }; + my $record = $dbt->fetch_tablerecord($dbh,$pref); + return $record; +} + + +#get one device localy +sub get_devicesONcontent { + my $deviceId = shift; + my $pref = { + table => "content", + fetch => "one", + template_id => "205", + int13 => "$deviceId", + }; + my $record = $dbt->fetch_record($dbh,$pref); + return $record; +} + +#get and check if theft exist in contenttranspos not older than 1 day +sub get_devicesONcontenttheftpos { + my $key = shift; + my $id = shift; + my $pref = { + table => "contenttheftpos", + fetch => "one", + #mtime => ">::(now() - interval '1 day')", + $key => "$id", + }; + my $record = $dbt->fetch_tablerecord($dbh,$pref); + return $record; +} + + +#per cronjob once a day to get and update content with cloud device id +#sudo su www-data -c "./src/scripts/Ilockit_cloud.pl shareedms-fr01 get_devices" +&get_devices if($todo eq "get_devices"); +sub get_devices { + my $endpoint = "https://tracking.ilockit.bike/api/devices"; + my $rest = ""; + + my $ret_json = fetch_ilockit_cloud("","$endpoint",$rest); + $response_in = decode_json($ret_json); + + print FILE "ilockit get_devices response_in:" . Dumper($response_in); + #foreach my $result (@{ $response_in }) { + # if($result->{id}){ + # print $result->{id} . "\n"; + # print $result->{name} . "\n"; + # } + #} + + my $pref = { + table => "content", + fetch => "all", + keyfield => "barcode", + template_id => "205", + #int10 => "1",#1 = "available" + }; + my $record = $dbt->fetch_record($dbh,$pref); + my $rows = 0; + if(1==1 && ref($response_in) eq "ARRAY"){ + foreach my $id (sort { $record->{$a}->{barcode} <=> $record->{$b}->{barcode} } keys (%$record)){ + foreach my $resp (@{ $response_in }) { + #print "if($resp->{name} eq $record->{$id}->{txt18} && ($resp->{id} && $resp->{id} ne $record->{$id}->{int13}))\n"; + if($resp->{name} eq $record->{$id}->{txt18} && ($resp->{id} && $resp->{id} ne $record->{$id}->{int13})){ + my $update = { + table => "content", + mtime => "now()", + owner => "$owner", + int13 => "$resp->{id}", + }; + $rows = $dbt->update_record($dbh,$update,$record->{$id}); + print FILE "update_record content.int13=$resp->{id}" . $rows . "\n"; + } + } + } + } + +}#end if($todo eq "get_devices"){ + + +#sudo su www-data -c "./src/scripts/Ilockit_cloud.pl shareedms-fr01 get_events 6572 20" +&get_events if($todo eq "get_events"); +sub get_events { + + #1. select all devices on content + my $record_cc = get_devicesONcontent_all(); + my $today = DateTime->now( time_zone => "Europe/Berlin" ); + $today .= "Z"; + my $from_datetime = DateTime->now( time_zone => "Europe/Berlin" ); + $from_datetime->subtract( days => 1 ); + $from_datetime .= "Z"; + + my $endpoint = "https://tracking.ilockit.bike/api/reports/events"; + #my $rest = "from=2021-05-31T07:44:10Z\&to=2021-06-06T07:44:10Z\&deviceId=4272"; + #my $rest = "from=2021-06-11T07:44:10Z\&to=2021-06-11T12:44:10Z\&deviceId=$deviceId"; + # + #2. loope cloud + foreach my $id (sort { $record_cc->{$a}->{barcode} <=> $record_cc->{$b}->{barcode} } keys (%$record_cc)){ + + my $rest = "from=$from_datetime\&to=$today\&deviceId=$record_cc->{$id}->{int13}"; + + my $ret_json = fetch_ilockit_cloud("","$endpoint",$rest); + $response_in = decode_json($ret_json); + print FILE "ilockit get_events response_in:" . Dumper($response_in); + + + foreach my $resp (@{ $response_in }) { + #if($record_cc->{$id}->{int13} eq $resp->{deviceId} && $resp->{type} eq "deviceOnline"){ + if($record_cc->{$id}->{int13} && $record_cc->{$id}->{int13} eq $resp->{deviceId} && ref($resp->{attributes}) eq "HASH" && $resp->{attributes}->{statusCode} && $resp->{attributes}->{statusCode} eq "alarm"){ + my $theft_record = get_devicesONcontenttheftpos("int01",$resp->{id}); + print FILE "id: $resp->{id}\n"; + print FILE "deviceId: $resp->{deviceId}\n"; + print FILE "type: $resp->{type}\n"; + print FILE "statusCode: $resp->{attributes}->{statusCode}\n"; + print FILE "serverTime: $resp->{serverTime}\n\n"; + if(!$theft_record->{c_id}){ + my $serverTime = localizedtime($resp->{serverTime}); + my $insert = { + table => "contenttheftpos", + cc_id => "$record_cc->{$id}->{c_id}", + barcode => "$record_cc->{$id}->{barcode}", + int04 => "$record_cc->{$id}->{int04}",#end station + txt06 => "$record_cc->{$id}->{txt06}",#end gps + txt18 => "$record_cc->{$id}->{txt18}", + owner => $owner, + mtime => "now()", + int10 => "7",#theft alarm + int01 => "$resp->{id}",#keeps id for event_type + int13 => "$resp->{deviceId}", + start_time => "$serverTime", + end_time => "$serverTime", + }; + + my $c_id = $dbt->insert_contentoid($dbh,$insert); + print FILE "insert sub get_events:" . Dumper($insert); + } + } + } + } +}#end if($todo eq "get_events"){ + + +#sudo su www-data -c "./src/scripts/Ilockit_cloud.pl shareedms-fr01 get_positions 6572" +#2021-10-27, cron disabled, unspecific and not only alarm +&get_positions if($todo eq "get_positions"); +sub get_positions { + #1. select all devices on content + my $record_cc = get_devicesONcontent_all(); + my $today = DateTime->now( time_zone => "Europe/Berlin" ); + $today .= "Z"; + my $from_datetime = DateTime->now( time_zone => "Europe/Berlin" ); + $from_datetime->subtract( days => 1 ); + $from_datetime .= "Z"; + + + my $endpoint = "https://tracking.ilockit.bike/api/positions"; + #my $rest = "from=2021-06-11T07:44:10Z\&to=2021-06-11T12:44:10Z\&deviceId=$deviceId" if($deviceId); + #my $ret_json = fetch_ilockit_cloud("","$endpoint",$rest); + #$response_in = decode_json($ret_json); + #print Dumper($response_in); + + #2. loope cloud + foreach my $id (sort { $record_cc->{$a}->{barcode} <=> $record_cc->{$b}->{barcode} } keys (%$record_cc)){ + + my $ctpos = get_devicesONcontenttranspos("$record_cc->{$id}->{int13}"); + if($ctpos->{int20} == 1){#if locked then get position in range of end_time to now + print FILE "record_pos.int13: $ctpos->{int13} --> lock_state:$ctpos->{int20}| end_time:$ctpos->{end_time}\n"; + + #get only positions until smartlock end_time is locked + if($ctpos->{int13} && $ctpos->{end_time} =~ /(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/){ + $ctpos->{end_time} =~ s/\..*$//; + my $end_time = $ctpos->{end_time}; + $end_time =~ s/\s/T/; + $from_datetime = utctime($end_time,"0"); + $from_datetime .= "Z"; + + #keep in mind, api-from maybe deviceTime (end_time-1) and position timestamp is serverTime+2 + my $rest = "from=$from_datetime\&to=$today\&deviceId=$record_cc->{$id}->{int13}"; + my $ret_json = fetch_ilockit_cloud("","$endpoint",$rest); + $response_in = decode_json($ret_json); + print FILE "ilockit get_positions response_in:" . Dumper($response_in); + + foreach my $resp (@{ $response_in }) { + if($record_cc->{$id}->{int13} eq $resp->{deviceId}){ + my $theft_record = get_devicesONcontenttheftpos("int02",$resp->{id}); + print FILE "id: $resp->{id}\n"; + print FILE "deviceId: $resp->{deviceId}\n"; + print FILE "serverTime: $resp->{serverTime}\n\n"; + if(!$theft_record->{c_id}){ + my $serverTime = localizedtime($resp->{serverTime}); + my $insert = { + table => "contenttheftpos", + cc_id => "$record_cc->{$id}->{c_id}", + barcode => "$record_cc->{$id}->{barcode}", + txt06 => "$resp->{latitude}, $resp->{longitude}", + owner => $owner, + mtime => "now()", + int10 => "8",#gps position + int02 => "$resp->{id}",#keeps id for event_type + int07 => "$resp->{speed}", + int08 => "$resp->{attributes}->{distance}", + int09 => "$resp->{attributes}->{totalDistance}", + int13 => "$resp->{deviceId}", + start_time => "$serverTime", + end_time => "$serverTime", + }; + + my $c_id = $dbt->insert_contentoid($dbh,$insert); + print FILE "insert sub get_positions:" . Dumper($insert); + } + } + } + } + } + } + +}#end if($todo eq "get_positions"){ + + +#ilockit http request +sub fetch_ilockit_cloud { + my $self = shift; + my $ilockitserver = shift || ""; + my $rest = shift || ""; + my $ilockit_request = "$ilockitserver?$rest"; + + print FILE "fetch_ >> " . $ilockit_request . "\n"; + + my $req = HTTP::Request->new(GET => "$ilockit_request"); + #$req->content_type('application/x-www-form-urlencoded'); + $req->content_type('application/json'); + $req->content($rest); + + my $res = $ua->request($req); + if ($res->is_success) { + #print $res->content; + return $res->content; + print $res->status_line, "\n"; + }else { + print $res->status_line, "\n"; + } +} + +close(FILE); + diff --git a/copri4/main/src/scripts/Ilockit_trackingcloud.pl b/copri4/main/src/scripts/Ilockit_trackingcloud.pl new file mode 100755 index 0000000..6978f27 --- /dev/null +++ b/copri4/main/src/scripts/Ilockit_trackingcloud.pl @@ -0,0 +1,214 @@ +#!/usr/bin/perl +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +#get tracking by +#Ilockit trips by Ilockit cloud +# +#sudo su www-data -c "./src/scripts/Ilockit_trackingcloud.pl shareedms-fr01 get_tripsum 155884" +# +#2021-07-20 +#GPS tracking +#Unser System bieten für die Auswertung von Fahrtstrecken bereits Zusammenfassungen an. Hierfür können Sie einfach die folgenden Calls benutzen: +# +#GET /api/reports/summary?groupId=95& from=2021-07-17T18:30:00Z& to=2021-07-20T18:30:00Z - Gibt Ihnen eine Zusammenfassung aller Fahrstrecken für die Schlösser in der Gruppe zurück. +# +#GET /api/reports/trips?groupId=95& from=2020-07-17T18:30:00Z& to=2021-07-20T18:30:00Z - Gibt Ihnen einzelne Fahrtstrecken für die Schlösser in der Gruppe zurück. +# +# +use vars qw($syshost); + +BEGIN { + $syshost = $ARGV[0] || die; +} + +use lib "/var/www/copri4/$syshost/src"; +use strict; +use warnings; +use POSIX; +use CGI; +use Lib::Config; +use JSON; +use LWP::UserAgent; +use DateTime; +use Time::Piece; +use Mod::DBtank; +use Data::Dumper; + +my $q = new CGI; +my $dbt = new DBtank; +my $cf = new Config; +my %varenv = $cf->envonline($syshost); +my $lang = "de"; +my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; + +my $ua = LWP::UserAgent->new; +$ua->agent("sharee APIclient"); +$ua->credentials( 'tracking.ilockit.bike:443', 'api', 'r.guempelein@sharee.bike', 'mohj2ooN'); + +my $json = JSON->new->allow_nonref; +my $response_in = {}; +my $dbh = ""; +my $owner = 183; + +my $todo = $ARGV[1]; +#my $deviceId = $ARGV[2] || ""; +my $pos_id = $ARGV[2] || ""; + +open(FILE,">>$varenv{logdir}/Ilockit_tracking.log"); +print FILE "\n\n*** $now_dt\n"; + +#utc to localtime +sub localizedtime { + my $date = shift; + + $date =~ s/\..*$//; + my $time = Time::Piece->strptime($date, "%Y-%m-%dT%H:%M:%S"); + #print $time->datetime . "\n";#GMT alias Zulu + $time = localtime($time->epoch);#epoch + #print $time->datetime . "\n";#localized date time + # + return $time->datetime; +} + +#localtime to utc +#my $now = strftime "%Y-%m-%dT%H:%M:%S", localtime; +#utctime($now); +#exit; +# +sub utctime { + my $date = shift; + my $latency = shift || 0; + + $date =~ s/\..*$//; + $date =~ s/\+\d+$//; + print FILE "requested datetime: " . $date . "\n"; + my $time = Time::Piece->strptime($date, "%Y-%m-%dT%H:%M:%S"); + print FILE "localtime: " . $time->datetime . "\n";#localtime + my $utc_epoch = $time->epoch; + #$utc_epoch -= 2*60*60;# -2 std (Sommerzeit) + $utc_epoch -= 1*60*60;# -1 std (Winterzeit) + $utc_epoch += $latency; + $time = gmtime($utc_epoch);#epoch + print FILE "utctime: " . $time->datetime . "\n";#utc zulu date time + # + return $time->datetime; +} + +#get pos in contenttranspo +sub get_pos { + my $id = shift; + my $pref = { + table => "contenttranspos", + fetch => "one", + c_id => "$id", + }; + my $record = $dbt->fetch_tablerecord($dbh,$pref); + return $record; +} + + + +if($todo eq "get_tripsum" && $pos_id){ + print FILE "trying $todo && $pos_id" . "\n"; + my $rows = &get_tripsum($pos_id); + print FILE "got rows $rows" . "\n"; +}else{ + print FILE "failure: $todo && $pos_id" . "\n"; +} + +sub get_tripsum { + my $pos_id = shift; + my $ctpos = get_pos($pos_id); + + #TEST + #$ctpos->{int13} = 8385; + #$ctpos->{start_time} = "2021-10-04 08:12:29"; + #$ctpos->{end_time} = "2021-10-04 17:35:49"; + + #GET /api/reports/summary?groupId=95& from=2021-07-17T18:30:00Z& to=2021-07-20T18:30:00Z + my $endpoint = "https://tracking.ilockit.bike/api/reports/summary"; + + #GET /api/reports/trips?groupId=95& from=2020-07-17T18:30:00Z& to=2021-07-20T18:30:00Z + #my $endpoint = "https://tracking.ilockit.bike/api/reports/trips"; + #my $rest = "groupId=95\&from=$oneday\&to=$today"; + #my $rest = "deviceId=6574\&from=$oneday\&to=$today"; + # + my $rows = 0; + if($ctpos->{int13}){ + #start_time + $ctpos->{start_time} =~ s/\..*$//; + my $start_time = $ctpos->{start_time}; + $start_time =~ s/\s/T/; + my $utc_start_time = utctime($start_time,"0"); + $utc_start_time .= "Z"; + + #end_time + #my $end_time = strftime "%Y-%m-%dT%H:%M:%S", localtime; + $ctpos->{end_time} =~ s/\..*$//; + my $end_time = $ctpos->{end_time}; + $end_time =~ s/\s/T/; + my $utc_end_time = utctime($end_time,"+300");#add 5 minutes, 300sec for latency + $utc_end_time .= "Z"; + + my $rest = "deviceId=$ctpos->{int13}\&from=$utc_start_time\&to=$utc_end_time"; + #my $rest = "deviceId=$ctpos->{int13}\&from=2021-11-03T07:50:00Z\&to=2021-11-03T11:00:00Z"; + + my $ret_json = fetch_ilockit_cloud("","$endpoint",$rest); + $response_in = decode_json($ret_json); + print FILE "ilockit get_tripsum response_in:" . Dumper($response_in) . "\n"; + + if(1==1){ + my $update_pos = { + table => "contenttranspos", + owner => $owner, + mtime => "now()", + int26 => 0, + }; + foreach my $resp (@{ $response_in }) { + if($ctpos->{int13} eq $resp->{deviceId}){ + print FILE "device Id: $resp->{deviceId}" . "\n"; + print FILE "distance: $resp->{distance}" . "\n"; + if($resp->{distance}){ + #my $distance = $resp->{distance} / 1000 * 1.60934; #distance in Meilen + my $distance = $resp->{distance} / 1000; + $distance = sprintf('%.2f', $distance); + $update_pos->{int26} = $distance; + } + } + } + $rows = $dbt->update_record($dbh,$update_pos,$ctpos) if($ctpos->{c_id} && $update_pos->{int26}); + } + }else{ + print FILE "failure: There is no contenttranspo deviceId int13: $ctpos->{int13}" . "\n"; + } + return $rows; +}#end if($todo eq "get_tripsum"){ + + +#ilockit http request +sub fetch_ilockit_cloud { + my $self = shift; + my $ilockitserver = shift || ""; + my $rest = shift || ""; + my $ilockit_request = "$ilockitserver?$rest"; + + print FILE "fetch_ >> " . $ilockit_request . "\n"; + + my $req = HTTP::Request->new(GET => "$ilockit_request"); + $req->content_type('application/json'); + $req->content($rest); + + my $res = $ua->request($req); + if ($res->is_success) { + #print $res->content; + return $res->content; + print $res->status_line, "\n"; + }else { + print $res->status_line, "\n"; + } +} + +close(FILE); +1; diff --git a/copri4/main/src/scripts/Ilockkeygen.class b/copri4/main/src/scripts/Ilockkeygen.class new file mode 100644 index 0000000..6477d52 Binary files /dev/null and b/copri4/main/src/scripts/Ilockkeygen.class differ diff --git a/copri4/main/src/scripts/Ilockkeygen.java b/copri4/main/src/scripts/Ilockkeygen.java new file mode 100644 index 0000000..b5cb00b --- /dev/null +++ b/copri4/main/src/scripts/Ilockkeygen.java @@ -0,0 +1,102 @@ +/* +import android.util.Log; +*/ +import java.io.InputStream; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.Random; + +/** + * Created by Bjoern Kinberger on 04.10.18. + * + * This is a test class for the authentication process without a server + * + * Only use this for the development process, the key generation should be done on the server! + */ +public class Ilockkeygen { + //private static final String LOG_TAG = Ilockkeygen.class.getName(); + public static byte[] sha1Value; + + + public static void generateKey(byte[] randomNum, byte[] internKey) { + + //System.out.println( "K_int_byte = " + internKey ); + //System.out.println("K_int_string = " + new String(internKey)); + System.out.println("K_int = " + Arrays.toString(internKey)); + + byte[] filler = {0, 0, 0, 0}; + Random random = new Random(); + + for (int i = 0; i < 16; i++) { + randomNum[i] = (byte) random.nextInt(255); + } + + System.out.println("K_seed = " + Arrays.toString(randomNum)); + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try { + outputStream = new ByteArrayOutputStream(); + outputStream.write(randomNum); + outputStream.write(internKey); + } catch (IOException e) { + e.printStackTrace(); + } + + byte tempoKey[] = outputStream.toByteArray(); + System.out.println("K_temp = " + Arrays.toString(tempoKey)); +/* + Log.d(LOG_TAG, "onCreate: temp key " + Arrays.toString(tempoKey)); +*/ + try { + sha1Value = SHA1(tempoKey); + } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { + e.printStackTrace(); + } + + try { + outputStream = new ByteArrayOutputStream(); + outputStream.write(sha1Value); + outputStream.write(filler); + sha1Value = outputStream.toByteArray(); + } catch (IOException e) { + e.printStackTrace(); + } + + System.out.println("K_a = " + Arrays.toString(sha1Value)); +/* + Log.d(LOG_TAG, "onCreate: 1. " + Arrays.toString(sha1Value)); +*/ + + try { + sha1Value = SHA1(sha1Value); + } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { + e.printStackTrace(); + } + + try { + outputStream = new ByteArrayOutputStream(); + outputStream.write(sha1Value); + outputStream.write(filler); + sha1Value = outputStream.toByteArray(); + + } catch (IOException e) { + e.printStackTrace(); + } + System.out.println("K_u = " + Arrays.toString(sha1Value)); +/* + Log.d(LOG_TAG, "onCreate: 2. " + Arrays.toString(sha1Value)); +*/ + } + + private static byte[] SHA1(byte[] tempoKey) throws NoSuchAlgorithmException, UnsupportedEncodingException { + MessageDigest md = MessageDigest.getInstance("SHA-1"); + md.update(tempoKey); + return md.digest(); + } +} + diff --git a/copri4/main/src/scripts/Ilocktestauth.pl b/copri4/main/src/scripts/Ilocktestauth.pl new file mode 100755 index 0000000..5467597 --- /dev/null +++ b/copri4/main/src/scripts/Ilocktestauth.pl @@ -0,0 +1,50 @@ +#!/usr/bin/perl +# +#Autor ragu@gnu-systems.de +# +#Ilockit authentify test +# +#sudo su www-data -c "./src/scripts/Ilocktestauth.pl shareeapp_operator 1003" +# +# +use vars qw($syshost); + +BEGIN { + $syshost = $ARGV[0] || exit 1; +} + +use lib "/var/www/copri4/$syshost/src"; + +my $dbname = $ARGV[1] || ""; +my $bike = $ARGV[2] || ""; + +use strict; +use warnings; +use POSIX; +use CGI ':standard'; +use Lib::Config; +use Data::Dumper; + +my $q = new CGI; +my $cf = new Config; +my %varenv = $cf->envonline("$syshost"); +my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; + + +my @K_select = `cd /var/www/copri4/$varenv{syshost}/src/scripts && export CLASSPATH='.:/usr/share/java:/usr/share/java/postgresql.jar' && java Ilockauth $dbname $bike`; + foreach(@K_select){ + my ($K_key,$K_val) = split(/ = /, $_); + $K_val =~ s/\n//g; + print "$K_key: $K_val\n"; + } + +my $receiver_usb = "abcd"; +if($receiver_usb =~ /(\w)(\w)$/){ + my $a = ord($1); + my $b = ord($2); + print "$1|$2" . "\n"; + print "$a|$b" . "\n"; + my $receiver_id = sprintf( "%x", $a ) . sprintf( "%x", $b ); + print $receiver_id . "\n"; +} + diff --git a/copri4/main/src/scripts/newsletter_post.pl b/copri4/main/src/scripts/newsletter_post.pl new file mode 100755 index 0000000..45185cb --- /dev/null +++ b/copri4/main/src/scripts/newsletter_post.pl @@ -0,0 +1,133 @@ +#!/usr/bin/perl -w + +#2021-03-17 +#redisgn because of BEGIN, use Net::SMTP; and executed in src/scripts +# +#sudo su www-data -c "./src/scripts/newsletter_post.pl 'shareedms-primary' 'send_cardexpire'" +# +#TODO, migrate it all to MailTransport.pm +# +# +use vars qw($syshost); + +BEGIN { + $syshost = $ARGV[0] || exit 1; +} +use lib "/var/www/copri4/$syshost/src"; + + +use strict; +use warnings; +use utf8; +use Encode; +use CGI ':standard'; +use DBI; +use POSIX; +use Email::MIME; +use IO::All; +use Email::MIME::CreateHTML; +use Email::Sender::Simple qw(sendmail); +use Net::SMTP; +use Try::Tiny; +use URI::Encode; +my $uri_encode = URI::Encode->new( { encode_reserved => 1 } ); +use Data::Dumper; + +use Sys::Hostname; +my $hostname = hostname; + +use Lib::Config; +my $q = new CGI; +my $cf = new Config; +my %varenv = $cf->envonline("","$syshost"); + +my $today = strftime("%d.%m.%Y %H:%M:%S",localtime(time)); +my $todo = $ARGV[1]; + +open(EMA, ">> $varenv{logdir}/newsletter_post.log"); +print EMA "\n$today, start mailing\n"; +print EMA "'$todo\n"; + +my $smtp_return = ""; +if($todo eq "send_cardexpire"){ + my ($mail_to,$subject,$body,$signature) = send_cardexpire(\%varenv); + $smtp_return = transport(\%varenv,$mail_to,$subject,$body,$signature); +} + +#---------------------------------------------------- +sub send_cardexpire { + my $varenv = shift; + + my $mail_to = "ragu\@gnu-systems.de"; + my $name = "test"; + + my $subject = "Fahrradmietsystem Konstanz"; + my $body = <https://www.stadtwerke-konstanz.de/mobilitaet/rad-mietsystem ) haben Sie die Möglichkeit Ihre Daten zu überprüfen und ggf. zu erneuern. +Kontaktieren Sie uns bitte falls Ihr Account für den Verleih nicht automatisch freigeschaltet wurde. + +Für weitere Fragen wenden Sie sich bitte an unsere Buchhaltung unter: buchhaltung\@fahrradspezialitaeten.com oder telefonisch 0761/5158912 (Mo, Mi, Fr 9-12 Uhr) + +EOF +; + $body =~ s/\n/\
    /g; + + my $signature = ""; + + return ($mail_to,$subject,$body,$signature); +} +#--------------------------------------------------- +# +sub transport { + my $varenv = shift; + my $mail_to = shift; + my $subject = shift; + my $body = shift; + my $signature = shift; + + my $html = "$subject\n"; + $html .= "
    $body
    \n"; + $html .= "
    $signature
    \n"; + $html .= ""; + + my $smtp = Net::SMTP->new($varenv->{mail_gateway}, + Port => 465, + Hello => 'TeilRad', + Timeout => 30, + Debug => 0, + SSL => 1, + ); + $smtp->auth($varenv->{sasl_username},$varenv->{sasl_password}); + $smtp->mail($varenv->{mail_from}); + + if($hostname ne "$varenv->{live_hostname}"){ + $mail_to = $varenv->{mail_testto}; + $subject .= "* offline Test *"; + } + + if ($smtp->to($mail_to)) { + $smtp->data(); + $smtp->datasend("To: $mail_to\n"); + $smtp->datasend("Subject: $subject\nMIME-Version: 1.0\nContent-Type: text/html; charset=UTF-8 \n\n"); + $smtp->datasend($html); + $smtp->dataend(); + print EMA "$?\n"; + } else { + print EMA $smtp->message(); + } + + sleep 1; + return $?; +} +#---------------------------------------------------- + +print EMA "done mailing: $?\n"; +print EMA "\n\n"; +close EMA; + +1; diff --git a/copri4/main/src/scripts/payone_cron.pl b/copri4/main/src/scripts/payone_cron.pl new file mode 100755 index 0000000..05c9a0a --- /dev/null +++ b/copri4/main/src/scripts/payone_cron.pl @@ -0,0 +1,245 @@ +#!/usr/bin/perl +# +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +#Capture payone payment by cron +# + #> 1. auto-fixed RadBuchungen (bei service-fixed hat schon jemand die Buchung manuell bearbeitet, oder?) + #--> service fixed wird gesetzt wenn das Rad via COPRI terminiert wurde. D.h. das hat keine Aussage ob auch der RadBuchungs Datensatz bearbeitet wurde. Deshalb gilt hier die userid des Datensatz Bearbeiters als key ob Automatik angewandt werden kann.-->ok + #> 2. mit defect -->ok + #> 3. RadBuchungen länger als 1 Tag oder bei konrad > 9,- € und bei TINK > 15,- € -->ok if int03 <= 5 + #> 4. Gesamtbetrag > 50,- € -->ok + #> 5. OPOS, also bereits fehlgeschlagene Einzüge -->ok + # 6. "Internas und Bearbeitungstatus" wenn definiert und nicht Buchungsfreigabe, txid renew +# +#payone_cron cron Intervall 0=disabled, 1=weekly, 2=monthly +# +#All with coded conditions +#sudo su www-data -c "./src/scripts/payone_cron.pl tinkdms '' 1" + +#One invoice +#sudo su www-data -c "./src/scripts/payone_cron.pl tinkdms ctt_id 1" +# +# +use vars qw($syshost); + +BEGIN { + $syshost = $ARGV[0] || exit 1; +} + +use lib "/var/www/copri4/$syshost/src"; + +my $ctt_id = $ARGV[1] || ""; +my $intervall = $ARGV[2] || "1"; + +use strict; +use warnings; +use POSIX; +use Lib::Config; +use Mod::Libenz; +use Mod::DBtank; +use Mod::Payment; +use Data::Dumper; +use Scalar::Util qw(looks_like_number); + +my $cf = new Config; +my %varenv = $cf->envonline("$syshost"); +my $lb = new Libenz; +my $dbt = new DBtank; +my $pay = new Payment; +my $now_dt = strftime("%Y-%m-%d %H:%M:%S",localtime(time)); +my $owner = 179;#179=cron + +my $dbh = $dbt->dbconnect(); + + #get Firma in contentuser + my $fetchuser = { + table => "contentuser", + fetch => "one", + c_id => 100002, + }; + my $ctf = $dbt->fetch_tablerecord($dbh,$fetchuser); + + #collect open invoices + my $fetchtrans = { + table => "contenttrans", + fetch => "all", + keyfield => "c_id", + main_id => "300008",#Rechnung + template_id => "218",#Rechnung + state => "is::null",#never tried buchen + close_time => "",#invoice isn't closed + int14 => "is::null",#OPOS + owner => "!=::$owner",#not 179=cron, not still tried by payone_cron + }; + $fetchtrans = { %$fetchtrans , c_id => $ctt_id } if($ctt_id && $ctt_id =~ /^\d+$/); + my $ct4rel = $dbt->fetch_record($dbh,$fetchtrans); + + open(FILE,">>$varenv{logdir}/payone_cron.log"); + print FILE "\n\n*** $now_dt\n"; + + my $max_sum = $ctf->{int03} || "10000"; + my $max_timestamp = "210001012359"; + my $scol = "mtime"; + my $i=0; + + #loop invoices + #foreach my $id (sort { $ct4rel->{$a}->{$scol} cmp $ct4rel->{$b}->{$scol} }keys (%$ct4rel)){ + foreach my $id (sort { $ct4rel->{$b}->{$scol} cmp $ct4rel->{$a}->{$scol} }keys (%$ct4rel)){ + $i++; + + print FILE "\n$i)** loop $now_dt ---> payone_cron select invoice ct.c_id:$ct4rel->{$id}->{c_id}| ca.c_id:$ct4rel->{$id}->{int10}| ct.ct_name:$ct4rel->{$id}->{ct_name}| ct.mtime:$ct4rel->{$id}->{mtime}\n"; + if($ct4rel->{$id}->{int10} && !$ct4rel->{$id}->{txt22} && $ct4rel->{$id}->{ct_name} =~ /---|^\d+$/){ + + my $umst1619 = $lb->umst_breaking($ct4rel->{$id},$now_dt); + + #get Adresse from contentadr + my $fetchadr = { + table => "contentadr", + fetch => "one", + int16 => $intervall, + c_id => $ct4rel->{$id}->{int10}, + }; + my $ctadr = $dbt->fetch_tablerecord($dbh,$fetchadr); + + #payone_cron cron Intervall 0=disabled, 1=weekly, 2=monthly + if($ctadr->{int16}){ + #collect invoice positions + my $fetchpos = { + table => "contenttranspos", + fetch => "all", + keyfield => "c_id", + ct_id => $ct4rel->{$id}->{c_id}, + }; + my $cttpos = $dbt->fetch_tablerecord($dbh,$fetchpos); + + my $scol = "itime"; + my $sum_parts0=0; + my $sum_parts7=0; + my $sum_parts19=0; + my $sum_kaution=0; + my $diff7 = 100 + 7; + my $diff19 = 100 + $umst1619; + my $sum_umst7=0; + my $sum_umst19=0; + my $j=0; + my $accounting_start = ""; + my $accounting_end = ""; + my $k=0; + my $m=0; + + my $capture_condition=1;#1=false + + #loop invoice positions + foreach my $id (sort { $cttpos->{$b}->{$scol} cmp $cttpos->{$a}->{$scol} } keys(%$cttpos)){ + if(($cttpos->{$id}->{int12} && $cttpos->{$id}->{int12} !~ /300005|300024/) || (($cttpos->{$id}->{int10} && $cttpos->{$id}->{int10} == 1) && ($cttpos->{$id}->{int03} && $cttpos->{$id}->{int03} <= 5) && ($cttpos->{$id}->{txt01} && $cttpos->{$id}->{txt01} !~ /fixed|defect/ || ($cttpos->{$id}->{owner_end} && $cttpos->{$id}->{owner_end} > 1000)))){ + $j++; + + my $cttpos_timestamp = $1 . $2 . $3 . "0000" if($cttpos->{$id}->{itime} =~ /(\d+)\-(\d+)\-(\d+)/); + #max. Rechnungspositionen + if(($cttpos_timestamp <= $max_timestamp) && ($sum_parts19 <= $max_sum)){ + $k++; + #print "$i (($id: $cttpos_timestamp <= $max_timestamp) && ($sum_parts19 <= $max_sum))
    "; + if($k==1){ + $accounting_end = "$3.$2.$1" if($cttpos->{$id}->{itime} =~ /(\d+)\-(\d+)\-(\d+)/); + $accounting_start = $accounting_end; + }else{ + $accounting_start = "$3.$2.$1" if($cttpos->{$id}->{itime} =~ /(\d+)\-(\d+)\-(\d+)/); + } + + $capture_condition=0; + my $gesamt = 0; + my $einzel = $cttpos->{$id}->{int02}; + my $menge = $cttpos->{$id}->{int03}; + $gesamt = $einzel * $menge; + + my $rabatt_val = $cttpos->{$id}->{int07} || 0; + my $rabatt_eur = 0; + my $proz_eur = $cttpos->{$id}->{int08} || 0; + if($rabatt_val != 0){ + $rabatt_eur = $rabatt_val; + if($proz_eur != 1){#wenn int08 != 1 alias € + $rabatt_eur = $einzel * $menge * $rabatt_val/100; + } + $gesamt = $einzel * $menge - $rabatt_eur; + } + $m++ if($gesamt != 0); + print FILE "pos gesamt: $gesamt = $einzel * $menge - $rabatt_eur ($rabatt_val|$rabatt_eur)\n"; + + $gesamt = $lb->round($gesamt); + $gesamt = $lb->cashme($gesamt); + $ctf->{txt13} = $1 if($ctf->{txt13} =~ /(\d+)/); + if($ct4rel->{$id}->{node_name} && $ct4rel->{$id}->{node_name} =~ /steuerfrei/){ + $sum_parts0 += $gesamt; + }elsif($cttpos->{$id}->{int05} && $cttpos->{$id}->{int05} =~ /\d/){ + $sum_parts0 += $gesamt if($cttpos->{$id}->{int05} == 0); + $sum_parts7 += $gesamt if($cttpos->{$id}->{int05} == 7); + $sum_parts19 += $gesamt if($cttpos->{$id}->{int05} >= 16); + }else{ + $sum_parts0 += $gesamt if($ctf->{txt13} == 0); + $sum_parts7 += $gesamt if($ctf->{txt13} == 7); + $sum_parts19 += $gesamt if($ctf->{txt13} >= 16); + } + }#end timestamp + }else{#end conditons + $capture_condition=1; + #print "LAST LINE\n"; + last; + } + }#end loop invoice positions + + my $sum_paid = $sum_parts0 + $sum_parts7 + $sum_parts19; + $sum_paid = $lb->round($sum_paid); + my $sum_preauth = $sum_paid || 0; + $sum_paid = $lb->cashme($sum_paid,""); + my $line_count2 = $m+4; + + print FILE "---> payone_cron capture conditions c_id:$ct4rel->{$id}->{c_id}, capture_condition:$capture_condition, sum_paid:$sum_paid, sum_preauth:$sum_preauth, ($accounting_start - $accounting_end)\n"; + if($capture_condition==0 && $sum_paid > 0 && $sum_paid <= 50){ + my $update = { + table => "contenttrans", + int15 => "$sum_preauth", + txt20 => "$accounting_start - $accounting_end", + owner => "$owner",#cron + int04 => "14.$line_count2", + mtime => "now()", + }; + my $record = { c_id => $ct4rel->{$id}->{c_id} }; + my $rows = $dbt->update_record($dbh,$update,$record) if($record->{c_id} > 0); + + my ($return,$return_text) = $pay->payone_capture(\%varenv,$ctf,$ctadr,$ct4rel->{$id},$sum_paid,$owner); + print FILE "---> Payment.pm Modul things: $return_text\nFinally log payone-return-post.log\n"; + + sleep 20; + }elsif($sum_paid > 0){ + my $update = { + table => "contenttrans", + txt22 => "cronjob fail",#also defined in Config.pm + owner => "$owner",#cron + mtime => "now()", + }; + my $record = { c_id => $ct4rel->{$id}->{c_id} }; + my $rows = $dbt->update_record($dbh,$update,$record) if($record->{c_id} > 0); + print FILE "---> payone_cron c_id:$ct4rel->{$id}->{c_id} conditions fails\n"; + }else{ + print FILE "---> payone_cron c_id:$ct4rel->{$id}->{c_id} conditions fails at all, sum_paid: $sum_paid > 0\n"; + } + }#end if $ctadr->{int16} + }else{ + my $update = { + table => "contenttrans", + #txt22 => "cronjob fail",#disabled to keep fibu saved Bearbeitsungsstatus + owner => "$owner",#cron + mtime => "now()", + }; + my $record = { c_id => $ct4rel->{$id}->{c_id} }; + my $rows = $dbt->update_record($dbh,$update,$record) if($record->{c_id} > 0); + + print FILE "---> payone_cron c_id:$ct4rel->{$id}->{c_id} Failure: no ct.int10 or order_stat ct.txt22:$ct4rel->{$id}->{txt22}\n"; + } + }#end loop invoices + + close(FILE); + diff --git a/copri4/main/src/scripts/payone_operatorsloop.pl b/copri4/main/src/scripts/payone_operatorsloop.pl new file mode 100755 index 0000000..683dafa --- /dev/null +++ b/copri4/main/src/scripts/payone_operatorsloop.pl @@ -0,0 +1,35 @@ +#!/usr/bin/perl +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +#loops sharee operators for payone capture +#only primary should do this +# +#sudo su www-data -c "./src/scripts/payone_operatorsloop.pl 1" +# +#defined by cronjob +#weekly for $ARGV[0]=1 +#nonthly for $ARGV[0]=2 +# +use lib "/var/www/copri4/shareedms-primary/src"; + +use strict; +use warnings; +use POSIX; +use Config::General; + +die if(!$ARGV[0] || ($ARGV[0] != 1 && $ARGV[0] != 2)); + +my $globalconf_file = "/var/www/copri4/shareeconf/global.cfg"; +my $conf = Config::General->new($globalconf_file); +my %globalconf = $conf->getall; + +while (my ($key, $value) = each %{ $globalconf{"operator"} }) { + if(-d "/var/www/copri4/$value->{syshost}"){ + `/var/www/copri4/shareedms-primary/src/scripts/payone_cron.pl $value->{syshost} '' $ARGV[0]`; + die if($? != 0); + }else{ + print "/var/www/copri4/$value->{syshost} not available\n"; + } +} diff --git a/copri4/main/src/scripts/payone_post_Payment.pl b/copri4/main/src/scripts/payone_post_Payment.pl new file mode 100755 index 0000000..e520a6d --- /dev/null +++ b/copri4/main/src/scripts/payone_post_Payment.pl @@ -0,0 +1,97 @@ +#!/usr/bin/perl +# +#Autor ragu@gnu-systems.de +#sharee payone POST +# +#managemandate +#sudo su www-data -c "/var/www/copri4/shareeapp-primary/src/scripts/payone_post_Payment.pl shareeapp-fr01 managemandate contentadr 21250" +# +#captureSEPA +#sudo su www-data -c "/var/www/copri4/shareeapp-primary/src/scripts/payone_post_Payment.pl shareeapp-fr01 preauthorizationSEPA contentadr 22027 28845" +#sudo su www-data -c "/var/www/copri4/shareeapp-primary/src/scripts/payone_post_Payment.pl shareeapp-fr01 captureSEPA contenttrans '' 28845" +# +use vars qw($syshost); + +BEGIN { + $syshost = $ARGV[0] || die 'syshost not defined'; +} + +use lib "/var/www/copri4/$syshost/src"; + +use strict; +use warnings; +use POSIX; +use CGI ':standard'; +use Lib::Config; +use Mod::Libenzdb; +use Mod::Payment; +use Config::General; + +use Data::Dumper; +use Sys::Hostname; +my $hostname = hostname; + +my $q = new CGI; +my $cf = new Config; +my %varenv = $cf->envonline("$syshost"); +print "$varenv{dbname}\n"; + +my $db = new Libenzdb; +my $pay = new Payment; +my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; +my $owner = 178;#payone API + +my $todo = $ARGV[1]; +my $table = $ARGV[2]; +my $ctadr_id = $ARGV[3]; +my $ctt_id = $ARGV[4]; +my $sequenz = $ARGV[5] || 0; +my $set_time = $ARGV[6] || "";#no_time +my $renewed = $ARGV[7] || "";#for requesting new txid via script loop_payone_capture.pl +my $request_state = $ARGV[8] || "";#if request state=occupied , then never delete adr4xml + +my $globalconf_file = "/var/www/copri4/shareeconf/global.cfg"; +my $conf = Config::General->new($globalconf_file); +my %globalconf = $conf->getall; +#print Dumper(\%globalconf); + +my $refpre = $globalconf{operator}{$varenv{dbname}}->{oprefix};#FR KN ... +my $payone_conf = $globalconf{operator}{$varenv{dbname}}{payone_conf} || $globalconf{payone_conf}; + +my $ctadr = { c_id => 0 }; +my $ctt = { c_id => 0 }; +$ctadr = $db->get_contentrow("contentadr",$ctadr_id,"","","","","","") if($ctadr_id); +$ctt = $db->get_contentrow("contenttrans",$ctt_id,"","","","","","") if($ctt_id); + +#managemandate SEPA +#1. +#sudo su www-data -c "./src/scripts/payone_post.pl $varenv{syshost} managemandate contentadr $ctadr_id" +if($todo eq "managemandate" && $table eq "contentadr" && $ctadr->{c_id} > 0){ + $pay->managemandate_main(\%varenv,$ctadr,$ctt,$owner); +} +#preauthorizationSEPA +#2. +#sudo su www-data -c "./src/scripts/payone_post.pl $varenv{syshost} preauthorizationSEPA contentadr $ctadr_id $ctt_id" +if($todo eq "preauthorizationSEPA" && $table eq "contentadr" && $ctadr->{c_id} > 0 && $ctt->{c_id} > 0){ + $pay->preauthorizationSEPA_main(\%varenv,$ctadr,$ctt,$owner); +} +#captureSEPA +#3. +#sudo su www-data -c "./src/scripts/payone_post.pl $varenv{syshost} captureSEPA contenttrans '' $ctt_id" +if($todo eq "captureSEPA" && $table eq "contenttrans" && $ctt->{c_id} > 0){ + $pay->captureSEPA_main(\%varenv,$ctadr,$ctt,$owner); +} +#preauthorizationCC +#1.PayoneCC creditcardcheck ajaxCall +#2. +#sudo su www-data -c "./src/scripts/payone_post.pl $varenv{syshost} preauthorizationCC contentadr $ctadr_id $ctt_id" +if($todo eq "preauthorizationCC" && $table eq "contentadr" && $ctadr->{c_id} > 0 && $ctt->{c_id} > 0){ + $pay->preauthorizationCC_main(\%varenv,$ctadr,$ctt,$owner); +} +#captureCC +#3. +# +if($todo eq "captureCC" && $table eq "contenttrans" && $ctt->{c_id} > 0){ + $pay->captureCC_main(\%varenv,$ctadr,$ctt,$owner); +} + diff --git a/copri4/main/src/scripts/requested_timeout.pl b/copri4/main/src/scripts/requested_timeout.pl new file mode 100755 index 0000000..8207c0b --- /dev/null +++ b/copri4/main/src/scripts/requested_timeout.pl @@ -0,0 +1,70 @@ +#!/usr/bin/perl +# +#Autor ragu@gnu-systems.de +# +#set availabel if requested > 15min +# +#sudo su www-data -c "./src/scripts/requested_timeout.pl shareedms-fr01" +# +# +use vars qw($syshost); + +BEGIN { + $syshost = $ARGV[0] || die; +} + +use lib "/var/www/copri4/$syshost/src"; + +use strict; +use warnings; +use POSIX; +use CGI ':standard'; +use Lib::Config; +use Mod::DBtank; +use Data::Dumper; + +my $q = new CGI; +my $cf = new Config; +my %varenv = $cf->envonline("$syshost"); +my $dbt = new DBtank; +my $lang = "de"; +my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; +my $dbh = ""; + +#set available if requestes older than 15 minute +my $return={}; +my $pref = { + table => "contenttranspos", + fetch => "all", + keyfield => "c_id", + #txt10 => "requested", + int10 => "2", + owner => "!=::199",#don't select LV api requested bikes + start_time => "<=::(now() - interval '15 minutes')", +}; +my $record_cp = $dbt->fetch_tablerecord($dbh,$pref); + +my $update_cp = { + table => "contenttranspos", + #txt10 => "available", + int10 => "1", +}; +my $update_cc = { + table => "content", + int10 => "1", +}; + +my $rows = 0; +foreach my $id (sort { $record_cp->{$a}->{c_id} <=> $record_cp->{$b}->{c_id} } keys (%$record_cp)){ + my $record = { c_id => 0 }; + $record->{c_id} = $record_cp->{$id}->{c_id}; + #contenttranspos + $rows = $dbt->update_record($dbh,$update_cp,$record); + if($rows > 0 && $record_cp->{$id}->{cc_id}){ + $record->{c_id} = $record_cp->{$id}->{cc_id}; + #content + $dbt->update_record($dbh,$update_cc,$record); + } +} + +1; diff --git a/copri4/main/src/scripts/sms_gtx_SMSTransport.pl b/copri4/main/src/scripts/sms_gtx_SMSTransport.pl new file mode 100755 index 0000000..bd018c8 --- /dev/null +++ b/copri4/main/src/scripts/sms_gtx_SMSTransport.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl +# +#sudo su www-data -c "./src/scripts/sms_gtx_SMSTransport.pl shareeapp-operator '+491799xxxx72'" +# +use vars qw($syshost); + +BEGIN { + $syshost = $ARGV[0] || die 'syshost not defined'; +} + +use lib "/var/www/copri4/$syshost/src"; + +use strict; +use warnings; +use POSIX; +use Mod::SMSTransport; + +my $smstrans = new SMSTransport; + +my $phone = $ARGV[1] || die 'phone not defined'; +my $adrhash = { + txt07 => $phone, + txt34 => "nureinlangertestdigest", +}; + +my $ret_json = $smstrans->sms_ack_digest($adrhash); diff --git a/copri4/main/src/scripts/tests/index.pl b/copri4/main/src/scripts/tests/index.pl new file mode 100755 index 0000000..a83742e --- /dev/null +++ b/copri4/main/src/scripts/tests/index.pl @@ -0,0 +1,184 @@ +#!/usr/bin/perl +# +## SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use lib "/var/www/copri4/shareeweb-project/src"; +use strict; +use warnings; +use POSIX; +use CGI ':standard'; +use CGI::Carp qw(fatalsToBrowser); +use CGI::Cookie (); +use DBI; +use Lib::Config; +use Mod::DBtank; + +my $q = new CGI(); +$q->import_names('R'); +my $cf = new Config; +my $dbt = new DBtank; +my %varenv = $cf->envonline(); + + my $coo = $q->cookie('domcookie') || $q->param('sessionid') || ""; + + if($q->param('sessionid') && $q->param('sessionid') ne $q->cookie('domcookie')){ + $coo = $q->param('sessionid'); + my $cookie = CGI::Cookie->new(-name => 'domcookie',-value => $coo); + print $q->header(-charset=>"utf-8", -cookie=>$cookie); + }else{ + my $cookie = CGI::Cookie->new(-name => 'domcookie',-value => $coo); + print $q->header(-charset=>"utf-8", -cookie=>$cookie); + } + + die "no configuration available" if(!$varenv{wwwhost}); + my $lang = "de"; + my $dyn_js = " + function onLoad() { + console.log('hallo'); + + if ('geolocation' in navigator) { + console.log('geon'); + /* geolocation funktioniert */ + } else { + console.log('geoff'); + /* geolocation funktioniert NICHT */ + } + \$( '#no_javascript' ).hide(); + } + \n"; + + my $dyn_css = ""; + my $local_style = "$varenv{metahost}/$dbt->{shareeapp_conf}->{local_style}"; + my $jquery = "$varenv{metahost}/$dbt->{shareeapp_conf}->{jquery}"; + my $js_bootstrap = "$varenv{metahost}/$dbt->{shareeapp_conf}->{js_bootstrap}"; + my $style_bootstrap = "$varenv{metahost}/$dbt->{shareeapp_conf}->{style_bootstrap}"; + if($varenv{wwwhost} =~ /shareedms/){ + $local_style = "$varenv{metahost}/$dbt->{shareedms_conf}->{local_style}"; + $jquery = "$varenv{metahost}/$dbt->{shareedms_conf}->{jquery}"; + $js_bootstrap = "$varenv{metahost}/$dbt->{shareedms_conf}->{js_bootstrap}"; + $style_bootstrap = "$varenv{metahost}/$dbt->{shareedms_conf}->{style_bootstrap}"; + } + + + my $html5 = $q->start_html( + -title => "shareetest", + -lang => '', + -onload => "onLoad();", + -encoding => "utf-8", + -base => 'true', + -head => Link( + { + -rel => 'shortcut icon', + -type => 'image/x-icon', + -href => "/css/favicon.ico" + } + ), + -meta => { + 'viewport'=>"width=device-width,initial-scale=1,user-scalable=yes", + 'author' => "rainer guempelein", + 'publisher' => "", + 'copyright' => "", + }, + -script=>[ + {-language=>'JAVASCRIPT', + -src=>"$jquery"}, + {-language=>'JAVASCRIPT', + -src=>"$varenv{metahost}/$dbt->{copri_conf}->{jquery_ui}"}, + {-language=>'JAVASCRIPT', + -src=>"$varenv{metahost}/$dbt->{copri_conf}->{jquery_resize}"}, + {-language=>'JAVASCRIPT', + -src=>"$varenv{metahost}/$dbt->{copri_conf}->{jsscript}"}, + {-language=>'JAVASCRIPT', + -src=>"$varenv{metahost}/js/shareespecial.js"}, + {-language=>'JAVASCRIPT', + -code=>"$dyn_js"} + ], + -STYLE=>{ + -code=>"$dyn_css", + -src=>[ + "$local_style", + "$style_bootstrap", + "$varenv{metahost}/$dbt->{copri_conf}->{style_bootstrap_icons}", + "$varenv{metahost}/$dbt->{copri_conf}->{style_jquery_ui}" + ], + -verbatim=>"\@import url(\"$local_style\");", + -media=>'screen' + } + +); + + $html5 =~ s{}{}s; + $html5 =~ s{}{}s; + print $html5; + +## +my $uri = "$dbt->{primary}->{sharee_primary}->{primaryApp}/APIjsonserver"; +print $q->div({-style=>'margin:15px;'},$q->a({-href=>"/src/scripts/tests/index.pl"},"[ index ]")),"\n"; + +print $q->div({-style=>'margin:15px;'}," "),"\n"; +print $q->div({-style=>'margin:15px;'},"-------------- $uri --------------------"),"\n"; +my $authorization = "$uri?request=authorization&user_id=ragu\@gnu-systems.de&user_pw=mabel321&merchant_id=oiF2kahH&hw_id=g89g8o7goguzuzug"; +print $q->div({-style=>'margin:15px;'},$q->a({-target=>'_blank', -href=>"$authorization"},"[ authorization ]---> $authorization")),"\n"; + +my $authout = "$uri?request=authout&authcookie=$coo"; +print $q->div({-style=>'margin:15px;'},$q->a({-target=>'_blank', -href=>"$authout"},"[ authout ]---> $authout")),"\n"; + +my $bikes_all = "$uri?request=bikes_all&authcookie=$coo"; +print $q->div({-style=>'margin:15px;'},$q->a({-target=>'_blank', -href=>"$bikes_all"},"[ bikes_all ]---> $bikes_all")),"\n"; + +my $bikes_available = "$uri?request=bikes_available&authcookie=$coo"; +print $q->div({-style=>'margin:15px;'},$q->a({-target=>'_blank', -href=>"$bikes_available"},"[ bikes_available ]---> $bikes_available")),"\n"; + +my $stations_all = "$uri?request=stations_all&authcookie=$coo"; +print $q->div({-style=>'margin:15px;'},$q->a({-target=>'_blank', -href=>"$stations_all"},"[ stations_all ]---> $stations_all")),"\n"; + +my $stations_available = "$uri?request=stations_available&authcookie=$coo"; +print $q->div({-style=>'margin:15px;'},$q->a({-target=>'_blank', -href=>"$stations_available"},"[ stations_available ]---> $stations_available")),"\n"; + +my $user_bikes_occupied = "$uri?request=user_bikes_occupied&authcookie=$coo"; +print $q->div({-style=>'margin:15px;'},$q->a({-target=>'_blank', -href=>"$user_bikes_occupied"},"[ user_bikes_occupied ]---> $user_bikes_occupied")),"\n"; + +my $user_rentals_history = "$uri?request=user_rentals_history&authcookie=$coo"; +print $q->div({-style=>'margin:15px;'},$q->a({-target=>'_blank', -href=>"$user_rentals_history"},"[ user_rentals_history ]---> $user_rentals_history")),"\n"; + + +my $user_minianswer = "$uri?request=user_minianswer&q1=opt5&q2=opt4&q3=iuwehfiolbev&authcookie=$coo"; +print $q->div({-style=>'margin:15px;'},$q->a({-target=>'_blank', -href=>"$user_minianswer"},"[ user_minianswer ]---> $user_minianswer")),"\n"; + + +### +print $q->div({-style=>'margin:15px;'}," "),"\n"; +my $uriop = "$dbt->{operator}->{sharee_operator}->{operatorApp}/APIjsonserver"; +print $q->div({-style=>'margin:15px;'},"-------------- $uriop --------------------"),"\n"; +my $booking_request = "$uriop?request=booking_request&bike=FR1003&authcookie=$coo"; +print $q->div({-style=>'margin:15px;'},$q->a({-target=>'_blank', -href=>"$booking_request"},"[ booking_request ]---> $booking_request")),"\n"; + +my $booking_update_cancel = "$uriop?request=booking_update&bike=FR1003&state=canceled&authcookie=$coo"; +print $q->div({-style=>'margin:15px;'},$q->a({-target=>'_blank', -href=>"$booking_update_cancel"},"[ booking_update_cancel ]---> $booking_update_cancel")),"\n"; + +my $booking_update_locking = "$uriop?request=booking_update&bike=FR1003&lock_state=locking&authcookie=$coo"; +print $q->div({-style=>'margin:15px;'},$q->a({-target=>'_blank', -href=>"$booking_update_locking"},"[ booking_update_locking ]---> $booking_update_locking")),"\n"; +my $booking_update_locked = "$uriop?request=booking_update&bike=FR1003&lock_state=locked&authcookie=$coo"; +print $q->div({-style=>'margin:15px;'},$q->a({-target=>'_blank', -href=>"$booking_update_locked"},"[ booking_update_locked ]---> $booking_update_locked")),"\n"; +my $booking_update_unlocked = "$uriop?request=booking_update&bike=FR1003&lock_state=unlocked&authcookie=$coo"; +print $q->div({-style=>'margin:15px;'},$q->a({-target=>'_blank', -href=>"$booking_update_unlocked"},"[ booking_update_unlocked ]---> $booking_update_unlocked")),"\n"; + +my $booking_update_oc_ul = "$uriop?request=booking_update&bike=FR1003&state=occupied&lock_state=unlocked&authcookie=$coo"; +print $q->div({-style=>'margin:15px;'},$q->a({-target=>'_blank', -href=>"$booking_update_oc_ul"},"[ booking_update_oc_ul ]---> $booking_update_oc_ul")),"\n"; + +my $booking_request_oc_ul = "$uriop?request=booking_request&bike=FR1003&state=occupied&lock_state=unlocked&authcookie=$coo"; +print $q->div({-style=>'margin:15px;'},$q->a({-target=>'_blank', -href=>"$booking_request_oc_ul"},"[ booking_request_oc_ul ]---> $booking_request_oc_ul")),"\n"; + +my $booking_update_av_lo = "$uriop?request=booking_update&bike=FR1003&state=available&lock_state=locked&latitude=47.927738&longitude=7.973855&gps_age=300&user_device_manufaturer=samsung)&user_device_model=SM-G398FN&user_device_platform=Android&user_device_version=10&user_device_id=90af86831c10374d&authcookie=$coo"; +print $q->div({-style=>'margin:15px;'},$q->a({-target=>'_blank', -href=>"$booking_update_av_lo"},"[ booking_update_av_lo ]---> $booking_update_av_lo")),"\n"; + +my $user_feedback = "$uriop?request=user_feedback&bike=FR1003&bike_broken=1&message=testnachricht äöü&authcookie=$coo"; +print $q->div({-style=>'margin:15px;'},$q->a({-target=>'_blank', -href=>"$user_feedback"},"[ user_feedback ]---> $user_feedback")),"\n"; + +print "
    "; +print "
    Größere Karte anzeigen\n"; +print "
    \n"; + +print $q->end_html; +1; diff --git a/copri4/main/src/scripts/velofaktur_client.pl b/copri4/main/src/scripts/velofaktur_client.pl new file mode 100755 index 0000000..0cb5d4b --- /dev/null +++ b/copri4/main/src/scripts/velofaktur_client.pl @@ -0,0 +1,220 @@ +#!/usr/bin/perl +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +# velofaktur per REST JSON Payload with Bearer Token +# +# Abrufen einer Liste mit Stationen, Anzahl Slots + Name +# sudo su www-data -c "./src/scripts/velofaktur_client.pl shareedms-fr01 get_velo" +# +# bike ID Statusabfrage | Freigeben +# sudo su www-data -c "./src/scripts/velofaktur_client.pl shareedms-fr01 post_velo 8 1 200008 Statusabfrage" +# will be sent by booking_update $lock_state eq "unlocked" +# sudo su www-data -c "./src/scripts/velofaktur_client.pl shareedms-fr01 post_velo 8 1 200008 Freigeben "$record_pos->{c_id}"" +# +use vars qw($syshost); + +BEGIN { + $syshost = $ARGV[0] || die; +} + +use lib "/var/www/copri4/$syshost/src"; +use strict; +use warnings; +use POSIX; +use CGI; +use JSON; +use LWP::UserAgent; +use DateTime; +use Time::Piece; +use Lib::Config; +use Mod::DBtank; +use Mod::Basework; +use Data::Dumper; + +my $q = new CGI; +my $cf = new Config; +my $dbt = new DBtank; +my $bw = new Basework; +my $lang = "de"; +my $now_dt = strftime "%Y-%m-%d %H:%M:%S", localtime; + +my $api_file = "/var/www/copri4/shareeconf/apikeys.cfg"; +my $aconf = Config::General->new($api_file); +my %apikeyconf = $aconf->getall; +#print $apikeyconf{velofaktur}->{bearer}; + +my $ua = LWP::UserAgent->new; +$ua->agent("sharee veloclient"); +my $size = $ua->max_size; +my $bytes = 1000; +$ua->max_size( $bytes ); +$ua->default_header( 'Authorization' => $apikeyconf{velofaktur}->{bearer} ); + +my $json = JSON->new->allow_nonref; +my %varenv = $cf->envonline($syshost); +my $response_in = {}; +my $dbh = ""; +my $owner = 182; + +my $todo = $ARGV[1]; +my $Station = $ARGV[2] || ""; +my $Slot = $ARGV[3] || ""; +my $velo_id = $ARGV[4] || ""; +my $Befehl = $ARGV[5] || ""; +my $posc_id = $ARGV[6] || ""; + +open(FILE,">>$varenv{logdir}/APIvelo.log"); +print FILE "\n*** $now_dt 'sharee veloclient' \n"; + +&get_velo if($todo eq "get_velo"); +sub get_velo { + + #my $endpoint = "https://shareeapp-primary.copri-bike.de/APIvelo"; + my $endpoint = "https://cockpit.velofactur.de/api/portal/station"; + + my $rest_json = ""; + my $ret_json = getvelo_cloud("","$endpoint",$rest_json); + eval { + $response_in = decode_json($ret_json); + print FILE "<--- velofactur response_in:\n" . Dumper($response_in); + }; + if ($@){ + print FILE "<--- failure get_velo raw response_in:\n" . Dumper($ret_json) . "\n"; + warn $@; + } + +} + +#velofaktur http request +sub getvelo_cloud { + my $self = shift; + my $veloserver = shift || ""; + my $rest_json = shift || ""; + my $velo_request = "$veloserver"; + + print FILE "===> GET2velo >> " . $velo_request . "\n" . $rest_json . "\n"; + + my $req = HTTP::Request->new(GET => "$velo_request"); + $req->content_type('application/json'); + + $req->content($rest_json); + + my $res = $ua->request($req); + if ($res->is_success) { + #print $res->content; + return $res->content; + print $res->status_line, "\n"; + }else { + print $res->status_line, "\n"; + } +} +#end if($todo eq "get_velo"){ + +&post_velo($Station,$Slot,$velo_id,$Befehl,$posc_id) if($todo eq "post_velo"); +sub post_velo { + my $Station = shift; + my $Slot = shift; + my $velo_id = shift; + my $Befehl = shift; + + #local TEST + #my $endpoint = "https://shareeapp-primary.copri-bike.de/APIvelo"; + #LIVE + my $endpoint = "https://cockpit.velofactur.de/api/portal/befehl"; + + + my %json; + $json{Station} = "$Station"; + $json{Slot} = "$Slot"; + $json{Id} = "$velo_id"; + $json{Befehl} = "$Befehl"; + my $rest_json = encode_json(\%json); + + my $ret_json = post2velo_cloud("","$endpoint",$rest_json); + # + eval { + $response_in = decode_json($ret_json); + print FILE "<--- velofaktur response_in:\n" . Dumper($response_in); + print $ret_json . "\n"; + + my $record_cc = { c_id => 0 }; + if($velo_id && $velo_id > 0){ + my $pref_cc = { + table => "content", + fetch => "one", + template_id => "205", + int27 => $velo_id, + }; + + $record_cc = $dbt->fetch_record($dbh,$pref_cc); + my $update_cc = { + table => "content", + mtime => "now()", + owner => "$owner", + }; + $update_cc->{txt25} = $response_in->{status} if($response_in->{status}); + $dbt->update_record($dbh,$update_cc,$record_cc) if($record_cc->{c_id}); + $bw->log("update content velofactur response Status for bike $velo_id $record_cc->{barcode} $response_in->{status}",$update_cc,""); + } + + my $record_pos = { c_id => 0 }; + if($posc_id && $posc_id > 0){ + my $pref_pos = { + table => "contenttranspos", + fetch => "one", + c_id => $posc_id, + }; + + $record_pos = $dbt->fetch_record($dbh,$pref_pos); + + my $update_pos = { + table => "contenttranspos", + mtime => "now()", + owner => "$owner", + }; + $update_pos->{int27} = $velo_id if($velo_id); + $update_pos->{30} = $Station if($Station); + $update_pos->{31} = $Slot if($Slot); + $update_pos->{txt25} = $response_in->{status} if($response_in->{status}); + $dbt->update_record($dbh,$update_pos,$record_pos) if($record_pos->{c_id}); + $bw->log("update contenttranspos velofactur response Status for bike $velo_id $record_pos->{barcode} $response_in->{status}",$update_pos,""); + } + + + }; + if ($@){ + print FILE "<--- failure post_velo raw response_in:\n" . Dumper($ret_json) . "\n"; + warn $@; + } + +}#end if($todo eq "post_velo"){ + + +#velofaktur http POST request +sub post2velo_cloud { + my $self = shift; + my $veloserver = shift || ""; + my $rest_json = shift || ""; + my $velo_request = "$veloserver"; + + print FILE "===> POST2velo >> " . $velo_request . "\n" . $rest_json . "\n"; + + my $req = HTTP::Request->new(POST => "$velo_request"); + $req->content_type('application/json'); + + $req->content($rest_json); + + my $res = $ua->request($req); + if ($res->is_success) { + #print $res->content; + return $res->content; + print $res->status_line, "\n"; + }else { + print $res->status_line, "\n"; + } +} + +close(FILE); + diff --git a/copri4/main/src/wkhtmltopdf-amd64 b/copri4/main/src/wkhtmltopdf-amd64 new file mode 120000 index 0000000..8f8a92e --- /dev/null +++ b/copri4/main/src/wkhtmltopdf-amd64 @@ -0,0 +1 @@ +/usr/bin/wkhtmltopdf \ No newline at end of file diff --git a/copri4/main/startup.pl b/copri4/main/startup.pl new file mode 100755 index 0000000..1a6f9c9 --- /dev/null +++ b/copri4/main/startup.pl @@ -0,0 +1,2 @@ +use lib qw(/var/www/copri4/main/src); +1; diff --git a/copri4/mkaccess.sh b/copri4/mkaccess.sh new file mode 100755 index 0000000..e349c0a --- /dev/null +++ b/copri4/mkaccess.sh @@ -0,0 +1,93 @@ +#!/bin/bash + +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH + +chgrp -R www-data * +chmod go-w * +chmod -R o-rwx * +for i in $(find . -type d -and -name csv); do chmod -R ug+rwx $i;done +for i in $(find . -type d -and -name data); do chmod -R ug+rwx $i;done +for i in $(find . -type d -and -name ftp); do chmod -R ug+rwx $i;done +for i in $(find . -type d -and -name cache); do chmod -R ug+rwx $i;done +for i in $(find . -type d -and -name pdf); do chmod -R ug+rwx $i;done +for i in $(find . -type d -and -name xml); do chmod -R ug+rwx $i;done +for i in $(find . -type d -and -name site); do chmod -R ug+rwx $i;done +for i in $(find . -type d -and -name apk); do chmod -R ug+rwx $i;done + +for i in $(find . -type d -and -name sql); do chmod -R go-rwx $i;done +for i in $(find . -type d -and -name src); do chmod -R go-w $i;done +for i in $(find . -type d -and -name img); do chmod -R go-w $i;done +for i in $(find . -type d -and -name apache); do chmod -R go-w $i;done +for i in $(find . -type d -and -name css); do chmod -R go-w $i;done +for i in $(find . -type d -and -name js); do chmod -R go-w $i;done +for i in $(find . -type f -and -iname README*); do chmod -R go-rwx $i;done +for i in $(find . -type d -and -name docs); do chmod -R go-rwx $i;done +for i in $(find . -type f -and -name .htaccess); do chmod -R go-wx $i;done +for i in $(find . -type f -and -name startup.pl); do chmod -R go-w $i;done +for i in $(find . -type f -and -name robots.txt); do chmod -R go-wx $i;done +for i in $(find . -type d -and -name cronjobs); do chmod -R g-w $i/*;done +for i in $(find . -type d -and -name cronjobs); do chmod -R o+r $i/*;done +for i in $(find . -type d -and -name cronjobs); do chown -R root:root $i/*;done + + + +live_sharee="ginger" #sharee-primary and sharee-fr01 on ginger.copri.eu + +echo "You are on Server with hostname: $(hostname)"; +echo ""; + +#sharee +echo "KEEP in mind, SHAREE autoLinking is only done if $(hostname) == ${live_sharee}"; +echo "Checking payone links because of LIVE"; +if [[ $(hostname) == ${live_sharee} ]] +then + + #shareedms-operator + echo ""; + for i in $(find . -type l -and -name shareedms-operator.conf); do rm $i;done + for i in $(find . -type f -and -name shareedms-operator_live.conf) + do ( + echo $(dirname $(realpath $i)); + cd $(dirname $(realpath $i)); + ln -s $(basename $i) shareedms-operator.conf; + ls -al + ) + done + + #shareeapp-operator + echo ""; + for i in $(find . -type l -and -name shareeapp-operator.conf); do rm $i;done + for i in $(find . -type f -and -name shareeapp-operator_live.conf) + do ( + echo $(dirname $(realpath $i)); + cd $(dirname $(realpath $i)); + ln -s $(basename $i) shareeapp-operator.conf; + ls -al + ) + done + + + #shareeweb-project + echo ""; + for i in $(find . -type l -and -name shareeweb-project.conf); do rm $i;done + for i in $(find . -type f -and -name shareeweb-project_live.conf) + do ( + echo $(dirname $(realpath $i)); + cd $(dirname $(realpath $i)); + ln -s $(basename $i) shareeweb-project.conf; + ls -al + ) + done + + #shareeconf/global.cfg + #sharee's + echo ""; + for i in $(find . -type l -and -name global.cfg); do rm $i;done + ln -s /etc/shareeconf/global_live.cfg global.cfg; + ls -al + +fi + + diff --git a/copri4/shareeapp-operator/apache/shareeapp-operator.conf b/copri4/shareeapp-operator/apache/shareeapp-operator.conf new file mode 100644 index 0000000..db26787 --- /dev/null +++ b/copri4/shareeapp-operator/apache/shareeapp-operator.conf @@ -0,0 +1,112 @@ + + ServerName shareeapp-operator.copri-bike.de + ServerAlias shareeapp-operator1.copri-bike.de + + ServerAdmin info@gnu-systems.de + DocumentRoot /var/www/copri4/shareeapp-operator + + ErrorLog /var/log/apache2/shareeapp-operator-error.log + LogLevel info ssl:warn + CustomLog /var/log/apache2/shareeapp-operator-access.log combined + ServerSignature Off + RewriteEngine on + RewriteCond %{SERVER_NAME} =shareeapp-operator.copri-bike.de + RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent] + + + + + ServerName shareeapp-operator1.copri-bike.de + ServerAdmin info@gnu-systems.de + DocumentRoot /var/www/copri4/shareeapp-operator + AddHandler cgi-script .cgi .sh .pl + + + Options -Indexes +FollowSymLinks +ExecCGI + AllowOverride None + + + + Header set Access-Control-Allow-Origin "copri-bike.de" + + + + Options -Indexes +FollowSymLinks -ExecCGI + Order allow,deny + Allow from all + + + + Options -Indexes +FollowSymLinks + Order allow,deny + Allow from all + ForceType application/octet-stream + Header set Content-Disposition attachment + + + ErrorLog /var/log/apache2/shareeapp-operator-error.log + LogLevel info ssl:warn + CustomLog /var/log/apache2/shareeapp-operator-access.log combined + ServerSignature Off +Include /etc/letsencrypt/options-ssl-apache.conf + +SSLCertificateFile /etc/letsencrypt/live/copri-bike.de-0003/fullchain.pem +SSLCertificateKeyFile /etc/letsencrypt/live/copri-bike.de-0003/privkey.pem + + + + + ServerName shareeapp-operator.copri-bike.de + ServerAdmin info@gnu-systems.de + DocumentRoot /var/www/copri4/shareeapp-operator + + PerlOptions +Parent + PerlRequire /var/www/copri4/shareeapp-operator/startup.pl + + + SetHandler perl-script + PerlResponseHandler Mod::Indexsharee + PerlInitHandler Apache2::Reload + PerlOptions +ParseHeaders +GlobalRequest + Options -ExecCGI +FollowSymLinks + Order allow,deny + Allow from all + + + + SetHandler perl-script + PerlInitHandler Apache2::Reload + PerlResponseHandler Mod::APIvelo + + + + SetHandler perl-script + PerlInitHandler Apache2::Reload + PerlResponseHandler Mod::APIjsonserver + + + + SetHandler perl-script + PerlInitHandler Apache2::Reload + PerlResponseHandler Mod::FileOut + + + + RewriteEngine On + RedirectMatch ^/$ /app/Anmelden + SSLProxyEngine On + RewriteCond %{REQUEST_URI} ^/(site|img|data|css|js|jquery) + RewriteRule ^(.*)$ https://shareeapp-operator1.copri-bike.de/$1 [P,L] + + + ErrorLog /var/log/apache2/shareeapp-operator-error.log + LogLevel info ssl:warn + CustomLog /var/log/apache2/shareeapp-operator-access.log combined + ServerSignature Off +Include /etc/letsencrypt/options-ssl-apache.conf +SSLCertificateFile /etc/letsencrypt/live/copri-bike.de-0003/fullchain.pem +SSLCertificateKeyFile /etc/letsencrypt/live/copri-bike.de-0003/privkey.pem + + + + diff --git a/copri4/shareeapp-operator/css/bootstrap-icons-1.5.0 b/copri4/shareeapp-operator/css/bootstrap-icons-1.5.0 new file mode 120000 index 0000000..fc8bde9 --- /dev/null +++ b/copri4/shareeapp-operator/css/bootstrap-icons-1.5.0 @@ -0,0 +1 @@ +../../main/css/bootstrap-icons-1.5.0 \ No newline at end of file diff --git a/copri4/shareeapp-operator/css/local_style1344.css b/copri4/shareeapp-operator/css/local_style1344.css new file mode 100755 index 0000000..778cb38 --- /dev/null +++ b/copri4/shareeapp-operator/css/local_style1344.css @@ -0,0 +1,699 @@ + + + diff --git a/copri4/shareeapp-operator/csv b/copri4/shareeapp-operator/csv new file mode 120000 index 0000000..47f3d7b --- /dev/null +++ b/copri4/shareeapp-operator/csv @@ -0,0 +1 @@ +../shareedms-operator/csv \ No newline at end of file diff --git a/copri4/shareeapp-operator/glyphicons b/copri4/shareeapp-operator/glyphicons new file mode 120000 index 0000000..7393fbd --- /dev/null +++ b/copri4/shareeapp-operator/glyphicons @@ -0,0 +1 @@ +../main/glyphicons \ No newline at end of file diff --git a/copri4/shareeapp-operator/img b/copri4/shareeapp-operator/img new file mode 120000 index 0000000..39564ce --- /dev/null +++ b/copri4/shareeapp-operator/img @@ -0,0 +1 @@ +../main/img \ No newline at end of file diff --git a/copri4/shareeapp-operator/js b/copri4/shareeapp-operator/js new file mode 120000 index 0000000..6b66a30 --- /dev/null +++ b/copri4/shareeapp-operator/js @@ -0,0 +1 @@ +../main/js \ No newline at end of file diff --git a/copri4/shareeapp-operator/pdfinvoice b/copri4/shareeapp-operator/pdfinvoice new file mode 120000 index 0000000..0d3af23 --- /dev/null +++ b/copri4/shareeapp-operator/pdfinvoice @@ -0,0 +1 @@ +../shareedms-operator/pdfinvoice \ No newline at end of file diff --git a/copri4/shareeapp-operator/robots.txt b/copri4/shareeapp-operator/robots.txt new file mode 100755 index 0000000..1f53798 --- /dev/null +++ b/copri4/shareeapp-operator/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / diff --git a/copri4/shareeapp-operator/site b/copri4/shareeapp-operator/site new file mode 120000 index 0000000..c8d8403 --- /dev/null +++ b/copri4/shareeapp-operator/site @@ -0,0 +1 @@ +../shareedms-operator/site \ No newline at end of file diff --git a/copri4/shareeapp-operator/src/Lib/Config.pm b/copri4/shareeapp-operator/src/Lib/Config.pm new file mode 100644 index 0000000..969dc5d --- /dev/null +++ b/copri4/shareeapp-operator/src/Lib/Config.pm @@ -0,0 +1,77 @@ +package Config; + +#Deprecated config file +#Please use shareeconf/* + +use strict; +use warnings; +use CGI; +use Config::General; +my $q = new CGI; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + + +sub envonline(){ + my $self = shift; + + my $globalconf_file = "/var/www/copri4/shareeconf/global.cfg"; + my $conf = Config::General->new($globalconf_file); + my %globalconf = $conf->getall; + + my $basedir = "$globalconf{copri_conf}->{basedir}/$globalconf{operator}{sharee_operator}->{dir_app}"; + my $metahost = $globalconf{operator}{sharee_operator}->{operatorApp1}; + my %varenv = ( + dbname => $globalconf{operator}{sharee_operator}{database}->{dbname}, + dbuser => $globalconf{operator}{sharee_operator}{database}->{user}, + dbpassw => $globalconf{operator}{sharee_operator}{database}->{passwd}, + dbhost => $globalconf{operator}{sharee_operator}{database}->{host}, + syshost => $globalconf{operator}{sharee_operator}->{dir_app}, + wwwhost => $globalconf{operator}{sharee_operator}->{operatorApp}, + praefix => $globalconf{operator}{sharee_operator}{database}->{dbname}, + systype => "sharee",#(azn) + mandant => $globalconf{shareeapp_conf}->{parent_node}, + start => $globalconf{shareeapp_conf}->{start}, + profile => $globalconf{shareeapp_conf}->{profile}, + accounting_1 => $globalconf{shareeapp_conf}->{accounting_1}, + accounting_1_5 => $globalconf{shareeapp_conf}->{accounting_1_5}, + accounting_2 => $globalconf{shareeapp_conf}->{accounting_2}, + accounting_3 => $globalconf{shareeapp_conf}->{accounting_3}, + + superu_id => $globalconf{copri_conf}->{superu_id}, + debug => $globalconf{copri_conf}->{debug}, + logdir => $globalconf{copri_conf}->{logdir}, + live_hostname => $globalconf{primary}{sharee_primary}->{live_hostname}, + metahost=>"$metahost", + orga => "", + style_font => "$metahost/img/OfficinaSansITCStd-Book.otf", + font_family => "OfficinaSansITCStd-Book,Arial", + background_image => "", + background_size => "cover", + background_color => "white", + background_color2 => "#c7c8ca", + background_align => "center", + background_repeat => "no-repeat", + font_size => "100.01%", + line_height => "1", + basedir => "$basedir", + pdf => "$basedir/pdf", + pdfinvoice => "$basedir/pdfinvoice", + data => "$basedir/data", + xmlfile => "$basedir/xml", + ftp_getfile => "ftp/SWK_codes/got_last.csv", + ftp_putfile => "ftp/SWK_return/konrad_code_protokoll.csv", + head_logo => "", + barcode => "", + printer => "PDF" + ); + return %varenv; +} + +1; + diff --git a/copri4/shareeapp-operator/src/Lib/Mlogic.pm b/copri4/shareeapp-operator/src/Lib/Mlogic.pm new file mode 100644 index 0000000..22373e7 --- /dev/null +++ b/copri4/shareeapp-operator/src/Lib/Mlogic.pm @@ -0,0 +1,100 @@ +package Mlogic; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; +use CGI::Carp qw(fatalsToBrowser); +use CGI ':standard'; +use Mod::DBtank; + +use Data::Dumper; +my $q = new CGI; +my $dbt = new DBtank; + + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my $self = shift; + my ($node_meta,$users_dms,$mode,$varenv,$users_sharee,$return) = @_; + + my $session=""; + my $session_and=""; + if($R::sessionid && length($R::sessionid) > 20 && !$q->cookie(-name=>'domcookie')){ + $session = "?sessionid=$R::sessionid"; + $session_and = "&sessionid=$R::sessionid"; + } + my $bgcolor1 = $dbt->{primary}->{$varenv->{dbname}}->{bgcolor1}; + + if($users_sharee->{c_id} && $R::sharee_edit ne "delete_account2" && ($users_sharee->{c_id} eq $varenv->{superu_id} || $dbt->{copri_conf}->{stage} eq "test")){ + my $coo = $q->cookie('domcookie') || $q->param('sessionid') || ""; + print $q->div({-style=>'text-align:right;height:25px;padding:6px 15px 6px 0px;background-color:white'},$q->a({-style=>"color:#$bgcolor1;", -href=>"$varenv->{metahost}/src/scripts/tests/index.pl?sessionid=$coo", -target=>'_blank'}," [ booking-test ] "),"$users_sharee->{txt08}",$q->a({-style=>"color:#$bgcolor1;", -href=>"logout_sharee$session"},"logout")),"\n"; + } + + print "
    \n"; + print "
    \n"; + $self->tplselect($node_meta,$users_dms,$mode,$varenv,$users_sharee,$return); + print "
    \n"; + print "
    \n"; + #print "\n"; + +} + +#2021-05-05 changed to Mlogic +sub tplselect(){ + my $self = shift; + my $node_meta = shift; + my $users_dms = shift || ""; + my $mode = shift || ""; + my $varenv = shift; + my $users_sharee = shift || ""; + my $return = shift || ""; + + my $u_id = $users_dms->{u_id} || ""; + my $sort = ""; + my $lang = "de"; + my $tpl_id = $node_meta->{tpl_id}; + + if($node_meta->{main_id}){ + if($tpl_id == 2){ + require "Tpl/Anmelden.pm"; + &Anmelden::tpl($node_meta,$users_dms,$mode,$varenv,$users_sharee,$return); + + }elsif($tpl_id == 302 || $tpl_id == 302008 || $tpl_id == 302004){#Adresse + require "Tpl/FormEdit.pm"; + &FormEdit::tpl($node_meta,$users_dms,$mode,$varenv,$users_sharee,$return); + }elsif($tpl_id == 308){ + require "Tpl/PayoneSelect.pm"; + &PayoneSelect::tpl($node_meta,$users_dms,$mode,$varenv,$users_sharee,$return); + }elsif($tpl_id == 197){ + require "Tpl/Contact.pm"; + &Contact::tpl($node_meta,$users_dms,$mode,$varenv,$users_sharee,$return); + }elsif($tpl_id == 1 || $tpl_id == 3){ + require "Tpl/Listing.pm"; + &Listing::tpl($node_meta,$users_dms,$mode,$varenv,$users_sharee,$return); + + #require "Tpl/ModalboxDialog.pm"; + #&ModalboxDialog::mobox2($node_meta,$users_dms,$mode,$varenv,$users_sharee,$return); + + } + } + my $debug = "Mlogic --> (users_sharee->{c_id}: $users_sharee->{c_id} | ct_table: $node_meta->{ct_table} | parent_id: $node_meta->{parent_id} | main_id: $node_meta->{main_id} | tpl_id: $node_meta->{tpl_id} | u_id: $u_id | mode: $mode)"; + print $q->div({-style=>'position:fixed;bottom:0%;right:2%;z-index:10;font-size:13px;'},"$debug"),"\n" if($users_sharee->{c_id} eq $varenv->{superu_id}); + + if($return && $return =~ /failure/){ + require "Mod/Failure.pm"; + &Failure::tpl("",$u_id,"","","","",$return); + } +} + +1; + + diff --git a/copri4/shareeapp-operator/src/Lib/PDFGenerator.pm b/copri4/shareeapp-operator/src/Lib/PDFGenerator.pm new file mode 120000 index 0000000..1bebb95 --- /dev/null +++ b/copri4/shareeapp-operator/src/Lib/PDFGenerator.pm @@ -0,0 +1 @@ +../../../main/src/Lib/PDFGenerator.pm \ No newline at end of file diff --git a/copri4/shareeapp-operator/src/Lib/Printpreview.pm b/copri4/shareeapp-operator/src/Lib/Printpreview.pm new file mode 120000 index 0000000..5485ff7 --- /dev/null +++ b/copri4/shareeapp-operator/src/Lib/Printpreview.pm @@ -0,0 +1 @@ +../../../main/src/Lib/Printpreview.pm \ No newline at end of file diff --git a/copri4/shareeapp-operator/src/Mod b/copri4/shareeapp-operator/src/Mod new file mode 120000 index 0000000..d4b7ba5 --- /dev/null +++ b/copri4/shareeapp-operator/src/Mod @@ -0,0 +1 @@ +../../main/src/Mod \ No newline at end of file diff --git a/copri4/shareeapp-operator/src/Tpl/AccountSubmenu.pm b/copri4/shareeapp-operator/src/Tpl/AccountSubmenu.pm new file mode 100644 index 0000000..3a0f04c --- /dev/null +++ b/copri4/shareeapp-operator/src/Tpl/AccountSubmenu.pm @@ -0,0 +1,165 @@ +package AccountSubmenu; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; +use POSIX; +use CGI ':standard'; +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Libenzdb; +use Mod::DBtank; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my $self = shift; + my $node_meta = shift; + my $users_dms = shift || ""; + my $mode = shift || ""; + my $varenv = shift; + my $users_sharee = shift || ""; + my $return = shift || ""; + + my $q = new CGI; + my $cf = new Config; + my $but = new Buttons; + my $lb = new Libenz; + my $db = new Libenzdb; + my $dbt = new DBtank; + + my $lang = "de"; + my $script = $q->script_name(); + my $path_info = $q->path_info(); + my $path = $path_info; + #with meta_host, + if("$varenv->{metahost}"){ + $path = "$script" . "$path_info"; + $script=""; + } + + my $session=""; + if($R::sessionid && length($R::sessionid) > 20){ + $session = "?sessionid=$R::sessionid"; + } + + my @viewsel = split /\//,$1 if($path =~ /^\/(.*)/); + + #my $coo = $q->cookie(-name=>'domcookie') || $R::sessionid || ""; + my $coo = $R::authcookie || $R::sessionid || ""; + #my $merchant_id = ""; + #$merchant_id = $coo if($coo && length($coo) <= 10); + #$merchant_id = $1 if($coo =~ /_(\w+)$/); + + my $bgcolor1 = "009899";#sharee + #my $bgcolor1 = "e2001a"; + + $bgcolor1 = $dbt->{website}->{$varenv->{syshost}}->{bgcolor1} if($dbt->{website}->{$varenv->{syshost}}->{bgcolor1}); + + #$bgcolor1 = $dbt->{merchant_ids}->{$merchant_id}->{bgcolor1} if($merchant_id && $dbt->{merchant_ids}->{$merchant_id}->{bgcolor1}); + $bgcolor1 = $dbt->{merchant_ids}->{$varenv->{merchant_id}}->{bgcolor1} if($dbt->{merchant_ids}->{$varenv->{merchant_id}}->{bgcolor1}); + + #payable check + my $payable_check=0; + if(($users_sharee->{int03} == 1 && $users_sharee->{ct_name} =~ /\w{2}-\d+/) || ($users_sharee->{int03} == 2 && length($users_sharee->{ct_name}) >= 19)){ + $payable_check=1; + } + my $node1 = $db->collect_node($node_meta->{parent_id},$lang,"1"); + + #if(!$R::confirm_success){ + if(1==1){ + + #subMenue-------- + print "\n"; + + #print "
    \n"; + print "
      \n"; + foreach my $id1 (sort {$node1->{$a}->{n_sort} <=> $node1->{$b}->{n_sort}} keys (%$node1)){ + #Creditcard test switch for payone (tinkwwp) + if($users_sharee->{c_id} && ($path =~ /$varenv->{mandant}\/$varenv->{profile}/ || $path =~ /$varenv->{mandant}\/Account/)){ + my $mstyle_1=""; + my $mstyle_1_5=""; + my $mstyle_2=""; + my $mstyle_3=""; + + if($node_meta->{main_id} == $node1->{$id1}->{main_id}){ + $mstyle_1 .= "background-color: silver;" if("$node1->{$id1}->{node_name}" eq "$varenv->{accounting_1}"); + $mstyle_1_5 .= "background-color: silver;" if("$node1->{$id1}->{node_name}" eq "$varenv->{accounting_1_5}"); + $mstyle_2 .= "background-color: silver;" if("$node1->{$id1}->{node_name}" eq "$varenv->{accounting_2}"); + $mstyle_3 .= "background-color: silver;" if("$node1->{$id1}->{node_name}" eq "$varenv->{accounting_3}"); + + #Konrad & TINK & sharee AGB + if(!$users_sharee->{int14} && !$users_sharee->{int15} && !$users_sharee->{txt30}){ + print $q->li($q->a({-style=>"$mstyle_1",-title=>"$node1->{$id1}->{node_name}", -href=>"/$viewsel[0]/Account/$node1->{$id1}->{node_name}$session"}, "$node1->{$id1}->{node_name}")),"\n"; + } + elsif(!$users_sharee->{int03}){ + print $q->li($q->a({-style=>"$mstyle_1",-title=>"$varenv->{accounting_1}", -href=>"/$viewsel[0]/Account/$varenv->{accounting_1}$session"}, $q->img({-src=>"$varenv->{metahost}/glyphicons/glyphicons-265-vcard.png"}))),"\n"; + print $q->li($q->a({-style=>"$mstyle_1_5",-title=>"$varenv->{accounting_1_5}", -href=>"/$viewsel[0]/Account/$varenv->{accounting_1_5}$session"}, $q->img({-src=>"$varenv->{metahost}/glyphicons/glyphicons-268-credit-card.png"}))),"\n"; + } + #elsif($payable_check && $users_sharee->{int04}){ + elsif($payable_check){ + print $q->li($q->a({-style=>"$mstyle_1",-title=>"$varenv->{accounting_1}", -href=>"/$viewsel[0]/Account/$varenv->{accounting_1}$session"}, $q->img({-src=>"$varenv->{metahost}/glyphicons/glyphicons-265-vcard.png"}))),"\n"; + print $q->li($q->a({-style=>"$mstyle_1_5",-title=>"$varenv->{accounting_1_5}", -href=>"/$viewsel[0]/Account/$varenv->{accounting_1_5}$session"}, $q->img({-src=>"$varenv->{metahost}/glyphicons/glyphicons-268-credit-card.png"}))),"\n"; + print $q->li($q->a({-style=>"$mstyle_2",-title=>"$varenv->{accounting_2}", -href=>"/$viewsel[0]/Account/$varenv->{accounting_2}$session"},$q->img({-src=>"$varenv->{metahost}/glyphicons/glyphicons-326-wallet.png"}))),"\n"; + print $q->li($q->a({-style=>"$mstyle_3",-title=>"$varenv->{accounting_3}", -href=>"/$viewsel[0]/Account/$varenv->{accounting_3}$session"},$q->img({-src=>"$varenv->{metahost}/glyphicons/glyphicons-530-list-alt.png"}))),"\n"; + } + else{ + print $q->li($q->a({-style=>"$mstyle_1",-title=>"$varenv->{accounting_1}", -href=>"/$viewsel[0]/Account/$varenv->{accounting_1}$session"}, $q->img({-src=>"$varenv->{metahost}/glyphicons/glyphicons-265-vcard.png"}))),"\n"; + print $q->li($q->a({-style=>"$mstyle_1_5",-title=>"$varenv->{accounting_1_5}", -href=>"/$viewsel[0]/Account/$varenv->{accounting_1_5}$session"}, $q->img({-src=>"$varenv->{metahost}/glyphicons/glyphicons-268-credit-card.png"}))),"\n"; + print $q->li($q->a({-style=>"$mstyle_2",-title=>"$varenv->{accounting_2}", -href=>"/$viewsel[0]/Account/$varenv->{accounting_2}$session"}, $q->img({-src=>"$varenv->{metahost}/glyphicons/glyphicons-326-wallet.png"}))),"\n"; + } + + } + } + + } + print "
    \n"; + #print "
    \n"; + #----------------- + } + print $q->div({-style=>'position:fixed;bottom:4%;right:2%;z-index:10;font-size:13px;'},"--> $varenv->{syshost} | $varenv->{merchant_id} | $bgcolor1 | template -> $node_meta->{tpl_name} | $users_sharee->{c_id}"),"\n" if($users_sharee->{c_id} eq $dbt->{copri_conf}->{superu_id} || $dbt->{copri_conf}->{stage} eq "test"); +} +1; diff --git a/copri4/shareeapp-operator/src/Tpl/Anmelden.pm b/copri4/shareeapp-operator/src/Tpl/Anmelden.pm new file mode 100644 index 0000000..80bb362 --- /dev/null +++ b/copri4/shareeapp-operator/src/Tpl/Anmelden.pm @@ -0,0 +1,164 @@ +package Anmelden; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; +use CGI ':standard'; +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Libenzdb; +use Mod::DBtank; +use Mod::APIfunc; +use Mod::Pricing; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my $node_meta = shift; + my $users_dms = shift || ""; + my $mode = shift || ""; + my $varenv = shift; + my $users_sharee = shift || ""; + my $return = shift || ""; + + my $q = new CGI; + my $cf = new Config; + my $lb = new Libenz; + my $db = new Libenzdb; + my $dbt = new DBtank; + my $apif = new APIfunc; + my $but = new Buttons; + my $pri = new Pricing; + + my $script = $q->script_name(); + my $user_agent = $q->user_agent(); + + my $path_info = $q->path_info(); + my $path = $path_info; + my $clientIP = $q->remote_addr(); + + #with meta_host, + if("$varenv->{metahost}"){ + $path = "$script" . "$path_info"; + $script=""; + } + my %ib = $but->ibuttons_arch(); + my $tpl = $db->get_tpl($node_meta->{tpl_id}); + my @tpl_order = split /,/,$tpl->{tpl_order}; + my $coo = $q->cookie(-name=>'domcookie') || ""; + + my @viewsel = split /\//,$1 if($path =~ /^\/(.*)/); + my $bgcolor1 = "009899";#sharee + #my $bgcolor1 = "e2001a"; + + $bgcolor1 = $dbt->{website}->{$varenv->{syshost}}->{bgcolor1} if($dbt->{website}->{$varenv->{syshost}}->{bgcolor1}); + $bgcolor1 = $dbt->{merchant_ids}->{$varenv->{merchant_id}}->{bgcolor1} if($dbt->{merchant_ids}->{$varenv->{merchant_id}}->{bgcolor1}); + + print "
    \n"; + + if($viewsel[1] eq "Account"){ + if($R::sharee_edit =~ /delete_account/){ + my $dummy; + }elsif($R::sharee_edit =~ /password_forgotten/){ + print $q->div({-class=>'content2'}, "Es wurde eine Nachricht mit zurueckgesetzten Passwort an $R::email gesendet. Ersetzen Sie bitte das gesendete Passwort durch ein individuelles. Das neue Passwort muss min. 8 Zeichen mit 2 Zeichen ausserhalb des Alphabets beinhalten."),"\n"; + } + } + + print $q->start_multipart_form(-id=>'authform', -name=>'loginscreen'),"\n"; + print $q->hidden(-name=>"sessionid",-override=>1,-value=>"$R::sessionid") if($R::sessionid); + print $q->hidden(-name=>"clientIP",-override=>1,-value=>"$clientIP"); + + print "
    \n"; + + if($users_sharee->{c_id} && !$users_sharee->{int04} && $R::sharee_edit !~ /delete_account/){ + print $q->div({-class=>'content1',-style=>'padding-top:1em;'}, "E-Mail Bestätigung"),"\n"; + print $q->div({-class=>'content2'}, "Wir haben eine Nachricht an Ihre angegebene E-Mail Adresse versandt. Nach erfolgreicher Bestätigung können Sie unser Mietradsystem nutzen."),"\n"; + print $q->div({-class=>'content2'},$q->a({-href=>"$varenv->{wwwhost}?sharee_edit=send_email"},"Senden wiederholen")),"\n"; + + #Account löschen + }elsif($viewsel[1] eq "Account" && $R::sharee_edit =~ /delete_account/){ + if($R::sharee_edit eq "delete_account1" && $users_sharee->{c_id}){ + # + my ($ctpos,$operator_hash) = $apif->user_rentals_history($q,$users_sharee); + my $ctpos_count = 0; + my $sum = 0; + foreach my $id (keys(%$ctpos)){ + $ctpos_count++; + my $gesamt = 0; + my $rabatt = ""; + ($gesamt,$rabatt) = $pri->price2calc($ctpos->{$id}); + $sum += $gesamt; + } + $sum = $lb->round($sum); + if($ctpos_count > 0 && $sum > 0){ + print $q->div({-class=>'content2'}, "Ihr Konto ist nicht ausgeglichen ($sum). Bitte kontaktieren Sie uns damit wir Ihre Rechnungstellung beschleunigen. Anschließend können Sie Ihren Account löschen. Danke für Ihr Verständnis"),"\n"; + print $q->div({-style=>'margin-top:1em;'},$q->a({-class=>"btn btn-primary btn-lg btn-block",-href=>'javascript:history.back()'}, "zurück")),"\n"; + }else{ + print $q->div({-class=>'content2'}, "Wollen Sie wirklich Ihre Daten löschen?"),"\n"; + print $q->div({-style=>'margin-top:1em;'},""),"\n"; + } + }elsif($R::sharee_edit eq "delete_account2" && $users_sharee->{c_id}){ + my $rows = 0; + $rows = $dbt->update_operatorsloop($varenv->{dbname},$users_sharee->{c_id},"delete");#only operator + $rows += $dbt->delete_content("","contentadr",$users_sharee->{c_id});#final delete on primary + if($rows >= 1){ + print $q->div({-class=>'content2'}, "Ihr Zugang wurde gelöscht.
    Auf Wiedersehen."),"\n"; + }else{ + print $q->div({-class=>'content2'}, "Anscheinend ist hier etwas schief gelaufen.
    Bitte kontaktieren Sie uns damit wir das Problem lösen können."),"\n"; + } + } + #Passwort senden + }elsif($viewsel[1] eq "Account" && !$R::password_forgotten){ + print $q->div({-class=>'content2'}, "Wir benötigen dazu Ihre registrierte E-Mail Adresse."),"\n"; + print $q->label({-for=>'Email'},""),"\n"; + print $q->textfield(-class=>'form-control', -name=>'email', -value=>'', -override=>1, -type=>'email',-class=>'form-control', -id=>'Email', -placeholder=>'E-Mail Adresse', -required=>1, -autofocus=>1),"\n"; + + print $q->hidden(-name=>'password_forgotten',-value=>"1"); + print $q->div({-style=>'margin-top:1em;'},""),"\n"; + + #Login + }elsif(!$R::password_forgotten){ + if($R::conflict_failure){ + print $q->div({-class=>'content2',-style=>'color:#c83434'},"Registrierungsfehler!"),"\n"; + print $q->div({-class=>'content2'}, "Die Registrierung wurde abgebrochen weil bereits ein Account mit Ihrer e-Mail oder Telefonnr. existiert. Bitte kontaktieren Sie uns falls hier ein Missbrauch vorliegt. Falls Sie ein neues Passwort benötigen drücken Sie bitte:"),"\n"; + print $q->div({-style=>'margin-top:1em;'},$q->a({-class=>"", -style=>"color:#$bgcolor1;font-size:1.1em;text-decoration:underline;", -role=>"button", -href=>"$varenv->{wwwhost}/$varenv->{mandant}/Account"}, "Passwort vergessen?")),"\n"; + } + print $q->div({-class=>'content2'}, "Dein Zugang zum Lastenradmietsystem"),"\n"; + print $q->div({-style=>'color:#c83434'},"Login verweigert. ",$q->a({-class=>"", -style=>"color:gray;", -role=>"button", -href=>"$varenv->{wwwhost}/$varenv->{mandant}/Account"}, "Passwort vergessen?")),"\n" if($R::failure); + print $q->div({-style=>'color:#c83434'},"Login verweigert. "),"\n" if($R::basicauthfailure); + print $q->label({-for=>'Email'},""),"\n"; + print $q->textfield(-class=>'form-control', -name=>'user_id', -value=>'', -override=>1, -type=>'email',-class=>'form-control', -id=>'Email', -placeholder=>'E-Mail Adresse', -required=>1, -autofocus=>1),"\n"; + + print $q->label({-for=>'PW'},""),"\n"; + print $q->password_field(-class=>'form-control', -name=>'user_pw', -value=>'', -override=>1, -type=>'password',-class=>'form-control', -id=>'txt04', -placeholder=>'Passwort', -required=>1),"\n"; + print $q->div({-style=>'text-align:left;color:grey;'}, "", "Passwort anzeigen"),"\n"; + + + #js auth + # print $q->div({-style=>'margin-top:1em;'},"
    Anmelden
    "),"\n"; + print $q->div({-style=>'margin-top:1em;'},""),"\n"; + + print $q->div({-style=>'margin-top:1em;'},$q->a({-class=>"btn btn-default btn-lg btn-block", -style=>"color:#$bgcolor1;", -role=>"button", -href=>"$varenv->{wwwhost}/$varenv->{mandant}/Account/$varenv->{accounting_1}"}, "Registrieren")),"\n"; + print $q->div({-class=>'content2'}, "Zur Information! Falls Sie bereits einen \"konrad\" oder \"TINK\" Account besitzen, können Sie mit Ihren bestehendem Account die Nutzung beider Mietradsysteme einstellen! Einfach dazu die entsprechende AGB bestätigen."),"\n" if($varenv->{wwwhost} =~ /tink|konrad/); + + print $q->div({-style=>'margin-top:1em;'},$q->a({-class=>"", -style=>"color:#$bgcolor1;font-size:1.1em;text-decoration:underline;", -role=>"button", -href=>"$varenv->{wwwhost}/$varenv->{mandant}/Account"}, "Passwort vergessen?")),"\n"; + + } + print "
    \n"; + + print $q->end_form,"\n"; + + print $q->div({-style=>'position:fixed;bottom:2%;right:2%;z-index:10;font-size:13px;'},"--> $varenv->{syshost} | $varenv->{merchant_id} | $bgcolor1 | $node_meta->{tpl_name} | $users_sharee->{c_id}"),"\n" if($users_sharee->{c_id} eq $dbt->{copri_conf}->{superu_id} || $dbt->{copri_conf}->{stage} eq "test"); + + print "
    "; +} +1; diff --git a/copri4/shareeapp-operator/src/Tpl/Contact.pm b/copri4/shareeapp-operator/src/Tpl/Contact.pm new file mode 100644 index 0000000..648e23a --- /dev/null +++ b/copri4/shareeapp-operator/src/Tpl/Contact.pm @@ -0,0 +1,123 @@ +package Contact; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; +use CGI ':standard'; +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Libenzdb; +use Mod::DBtank; +use Encode; +use Data::Dumper; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my $node_meta = shift; + my $users_dms = shift || ""; + my $mode = shift || ""; + my $varenv = shift; + my $users_sharee = shift || ""; + my $return = shift || ""; + + my $q = new CGI; + my $cf = new Config; + my $but = new Buttons; + my $lb = new Libenz; + my $db = new Libenzdb; + my $dbt = new DBtank; + + my $lang = "de"; + my $script = $q->script_name(); + my $path_info = $q->path_info(); + my $path = $path_info; + #with meta_host, + if($varenv->{metahost}){ + $path = "$script" . "$path_info"; + $script=""; + } + my $user_agent = $q->user_agent(); + my %ib = $but->ibuttons_arch(); + my @tpl_order = split /,/,$node_meta->{tpl_order}; + my $main_ids = $node_meta->{main_id}; + my @viewsel = split /\//,$1 if($path =~ /^\/(.*)/); + + my $session=""; + my $session_and=""; + if(length($R::sessionid) > 20){ + $session = "?sessionid=$R::sessionid"; + $session_and = "&sessionid=$R::sessionid"; + } + + my $project = "all"; + $project = "Bayern" if($varenv->{syshost} eq "shareeweb-bayern"); + $project = "Konstanz" if($varenv->{syshost} eq "shareeweb-konstanz"); + + my $sort_updown = "up"; + my $content2 = "content2_contact"; + my $content_img = "pic-contact"; + my $record_cc = { c_id => 0 }; + my $pref_cc = { + table => "contentuser", + fetch => "one", + template_id => "197", + c_id => 1, + }; + + + print "
    \n"; + print $q->div({-class=>"$content2"},"Bei Fragen und Problemen bitte den örtlichen Betreiber kontaktieren"),"\n"; + + #BIG LOOP content table + #while (my ($mandant_conf, $value) = each %{ $dbt->{operator} }) { + foreach my $m_id (sort { $dbt->{operator}->{$b}->{oprefix} cmp $dbt->{operator}->{$a}->{oprefix} } keys(%{ $dbt->{operator} })) { + if($dbt->{operator}->{$m_id}->{project} eq $project || $project eq "all"){ + print $q->div({-class=>"$content2"}," "),"\n"; + + my $sharee_operator = $dbt->{operator}->{$m_id}->{database}->{dbname}; + my $dbh_operator = $dbt->dbconnect_extern($sharee_operator); + $record_cc = $dbt->fetch_record($dbh_operator,$pref_cc); + #print Dumper($node_meta->{tpl_order}) . "
    \n"; + + foreach (@tpl_order){ + my ($key,$des,$size) = split /=/,$_; + $record_cc->{$key} = $q->unescapeHTML("$record_cc->{$key}"); + $record_cc->{$key} = $lb->newline($record_cc->{$key},"",""); + + if($key =~ /ct_name/){ + print $q->div({-id=>"$record_cc->{c_id}",-class=>'content_title2'},"• $record_cc->{$key}"),"\n"; + }elsif($key =~ /txt|int/ && $record_cc->{$key} && $key !~ /txt85/){ + #phone tag + if($record_cc->{$key} =~ /\d+$/ && $des =~ /hotline|Telefon|phone/i){ + $record_cc->{$key} =~ s/([\s0-9-\/]+)/\$1\<\/a\>/; + } + #email tag with little coding against grabber + if($record_cc->{$key} =~ /(\w+\@[\w-]+\.\w+)/){ + $record_cc->{$key} =~ s/(\w+\@[\w-]+\.\w+)/\$1\<\/a\>/; + $record_cc->{$key} =~ s/\@/\&\#64\;/g; + } + $record_cc->{$key} =~ s/\\//g; + if($des =~ /hotline|e-Mail|zeiten/i){ + print $q->div({-class=>"$content2"}, "$des: $record_cc->{$key}"),"\n"; + print $q->div({-class=>"$content2"}," "),"\n" if($des =~ /e-Mail/i); + }else{ + print $q->div({-class=>"$content2"}, "$record_cc->{$key}"),"\n"; + } + + } + } + }#end if + } + print "
    \n"; +} +1; diff --git a/copri4/shareeapp-operator/src/Tpl/FormEdit.pm b/copri4/shareeapp-operator/src/Tpl/FormEdit.pm new file mode 100644 index 0000000..450d848 --- /dev/null +++ b/copri4/shareeapp-operator/src/Tpl/FormEdit.pm @@ -0,0 +1,633 @@ +package FormEdit; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; +use POSIX; +use CGI ':standard'; +use DateTime; +use DateTime::Format::Pg; + +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Libenzdb; +use Mod::DBtank; +use Mod::APIfunc; +use Mod::Pricing; +use Tpl::AccountSubmenu; +use Data::Dumper; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my $node_meta = shift; + my $users_dms = shift || ""; + my $mode = shift || ""; + my $varenv = shift; + my $users_sharee = shift || ""; + my $return = shift || ""; + + my $q = new CGI; + my $cf = new Config; + my $lb = new Libenz; + my $db = new Libenzdb; + my $dbt = new DBtank; + my $apif = new APIfunc; + my $pri = new Pricing; + my $but = new Buttons; + my $submenu = new AccountSubmenu; + my $script = $q->script_name(); + my $path_info = $q->path_info(); + my $path = $path_info; + #with meta_host, + if("$varenv->{metahost}"){ + $path = "$script" . "$path_info"; + $script=""; + } + my $dbh = "";#$dbt->dbconnect(); + my $user_agent = $q->user_agent(); + my %ib = $but->ibuttons_arch(); + my @viewsel = split /\//,$1 if($path =~ /^\/(.*)/); + my $red = "red"; + + my $coo = $q->cookie(-name=>'domcookie') || $R::sessionid; + my $session=""; + my $session_and=""; + if($R::sessionid && length($R::sessionid) > 20 && !$q->cookie(-name=>'domcookie')){ + $session = "?sessionid=$R::sessionid"; + $session_and = "&sessionid=$R::sessionid"; + } + + my $bgcolor1 = "009899";#sharee + #my $bgcolor1 = "e2001a"; + + $bgcolor1 = $dbt->{website}->{$varenv->{syshost}}->{bgcolor1} if($dbt->{website}->{$varenv->{syshost}}->{bgcolor1}); + $bgcolor1 = $dbt->{merchant_ids}->{$varenv->{merchant_id}}->{bgcolor1} if($dbt->{merchant_ids}->{$varenv->{merchant_id}}->{bgcolor1}); + + + my $ctrel = {}; + $ctrel = $users_sharee if(ref($users_sharee) eq "HASH" && $users_sharee->{c_id}); + # + #collect rentals on operators and get operator hash with dbname->uri_operator + #$q->param(-name=>'month',-value=>"18");#disabled because changing to not invoiced positions + my ($ctpos,$operator_hash) = $apif->user_rentals_history($q,$ctrel); + #print Dumper($ctpos); + + my $ctpos_count=0; + foreach my $id (keys(%$ctpos)){ + $ctpos_count++; + } + + my $ctt_all = {}; + #$ctt = $db->collect_content2("contenttrans","int10",$ctrel->{c_id}) if($ctrel->{c_id}); + # + #loop operator hash to get invoices for each operator + foreach my $sharee_operator (keys (%$operator_hash)){ + my $dbh_operator = $dbt->dbconnect_extern("$sharee_operator"); + my $pref = { + table => "contenttrans", + fetch => "all", + int10 => "$ctrel->{c_id}", + keyfield => "c_id", + }; + + if($ctrel->{c_id}){ + my $ctt = $dbt->fetch_tablerecord($dbh_operator,$pref); + foreach my $id (keys(%$ctt)){ + $ctt->{$id}->{wwwhost} = "$operator_hash->{$sharee_operator}"; + $ctt->{$id}->{praefix} = "$sharee_operator"; + #print "$ctt->{$id}->{praefix}|"; + } + $ctt_all = { %$ctt_all, %$ctt }; + } + } + + my $tpl_id = $node_meta->{tpl_id}; + #$tpl_id = "302004" if($viewsel[1] =~ /Mieten/ && $ctrel->{c_id}); + my $tpl = $db->get_tpl($tpl_id); + my $tpl01 = $tpl;#If nothing else, because of tpl_name Title in split_lates + my $tpl02 = ""; + my @split_lates = ("$tpl->{tpl_order}"); + my $template01 = "$tpl_id" . "001"; + my $template02 = "$tpl_id" . "002"; + if($tpl_id < 999){ + $tpl01 = $db->get_tpl($template01); + $tpl02 = $db->get_tpl($template02); + @split_lates = ("$tpl01->{tpl_order}","$tpl02->{tpl_order}"); + } + my $now_dt = strftime "%Y-%m-%d %H:%M", localtime; + my $start_date = strftime "%d.%m.%Y %H:%M", localtime; + + my ($end_date,$end_time) = split(/ /,$now_dt); + my ($e_yy,$e_mo,$e_dd) = split(/-/,$end_date); + my ($e_hh,$e_mi) = split(/\:/,$end_time); + + my $radID = $R::radID || ""; + + my $tink_agb_text; + $tink_agb_text = $db->get_content("2351",""); + $tink_agb_text->{txt01} = $q->unescapeHTML($tink_agb_text->{txt01}); + $tink_agb_text->{txt01} = $lb->newline($tink_agb_text->{txt01},"","0"); + + my $konrad_agb_text; + $konrad_agb_text = $db->get_content("3446",""); + $konrad_agb_text->{txt01} = $q->unescapeHTML($konrad_agb_text->{txt01}); + $konrad_agb_text->{txt01} = $lb->newline($konrad_agb_text->{txt01},"","0"); + + #TODO get and edit sharee AGB from Tarif content + my $sharee_agb_text; + $sharee_agb_text->{ct_name} = "AGB"; + $sharee_agb_text->{txt01} = ""; + + + print "
    \n"; + +print < + + +EOF +; + + my $debug=0; + $debug=1 if($users_sharee->{c_id} eq $dbt->{copri_conf}->{superu_id} || $dbt->{copri_conf}->{stage} eq "test"); + my $debug_message = ""; + + my $payable_check=0; + if(($ctrel->{int03} == 1 && $ctrel->{ct_name} =~ /\w{2}-\d+/) || ($ctrel->{int03} == 2 && length($ctrel->{ct_name}) >= 19)){ + $payable_check=1; + } + + #subMenue-------- + $submenu->tpl($node_meta,$users_dms,$mode,$varenv,$users_sharee,$return); + #----------------- + + my $catch_failure=0; + if(($R::failure && $R::failure =~ /\w+/) || ($ctrel->{txt31} && $ctrel->{txt31} =~ /\w/)){ + $debug_message = "($R::failure || $ctrel->{txt31})" if($debug); + $catch_failure=1; + print $q->div({-class=>'content2', -style=>"clear:both;color:$red"}, "* Es liegt noch mindestens ein Fehler vor. $debug_message"),"\n"; + } + + #confirm code manage + if($catch_failure && (!$ctrel->{int04} && !$ctrel->{int13}) && ($tpl_id =~ /^2$|302004/) && ($path =~ /$varenv->{accounting_3}/)){ + $debug_message = "$catch_failure && (!$ctrel->{int04} || !$ctrel->{int13}) && $tpl_id" if($debug); + print $q->div({-class=>'content2'}, "Erst nachdem Ihre Profildaten vollständig sind erhalten Sie die Bestätigung. $debug_message"),"\n"; + }elsif((!$ctrel->{int04} || !$ctrel->{int13}) && ($tpl_id =~ /^2$|302004/) && ($path =~ /$varenv->{accounting_3}/)){ + if(1==1){ + $debug_message = "(!$ctrel->{int04} || !$ctrel->{int13}) && $tpl_id" if($debug); + print $q->div({-class=>'content_title3',-style=>'clear:both;'}, "Fasst geschafft $debug_message"),"\n"; + print $q->div({-class=>'content2'}, "Es wurden Bestätigungs-Codes an Ihre e-Mail Adresse und per SMS an Ihre Telefonnr. versandt. Nach erfolgreicher Bestätigung können Sie unsere Mieträder nutzen. Bitte beachten Sie die Anweisungen."),"\n"; + #}else{ + #print $q->div({-class=>'content1',-style=>'padding-top:1em;clear:both;'}, "E-Mail Bestätigung"),"\n"; + #print $q->div({-class=>'content2'}, "Wir haben einen Bestätigungscode an Ihre angegebene e-Mail Adresse versandt. Nach erfolgreicher Bestätigung können Sie sich einloggen und ein Leihrad mieten. Bitte beachten Sie die Anweisungen."),"\n"; + } + print $q->start_form(-name=>'accountscreen', -action=>"/$varenv->{mandant}/Account/$varenv->{accounting_3}$session"),"\n"; + print $q->hidden(-name=>"sessionid",-override=>1,-value=>"$R::sessionid"); + my $required = ""; + if(!$ctrel->{int04}){ + my $des = "E-Mail Bestätigungscode"; + my $key = "confirm_code"; + my $label_des="* $des"; + $label_des = "Bitte \"$des\" korrigieren" if($R::failure); + print $q->label({-for=>"$key", -style=>'padding-top:1em;'},"$label_des"),"\n"; + print "\n"; + print $q->div({-class=>'content2'}, "Falls Sie keinen e-Mail Bestätigungs Code erhalten haben, überprüfen Sie bitte Ihre bei der Registrierung angegebene e-Mail Adresse und/oder den Spam Bereich in Ihrem e-Mail Programm. Hier können Sie erneut einen ",$q->a({-style=>"color:#$bgcolor1;",-href=>"$varenv->{wwwhost}?sharee_edit=send_email$session_and"},"e-Mail Code anfordern")),"\n"; + }else{ + print $q->div({-class=>'content2', -style=>'color:gray;'}, "* E-Mail Bestätigungs-Code wurde bereits erfolgreich eingegeben."),"\n"; + } + if(!$ctrel->{int13}){ + my $des = "SMS Bestätigungscode"; + my $key = "confirm_smscode"; + my $label_des="* $des"; + $label_des = "Bitte \"$des\" korrigieren" if($R::failure); + print $q->label({-for=>"$key", -style=>'padding-top:1em;'},"$label_des"),"\n"; + print "\n"; + print $q->div({-class=>'content2'}, "Falls Sie keinen SMS Bestätigungs Code erhalten haben, überprüfen Sie bitte Ihre bei der Registrierung angegebene mobile Telefonnummer. Hier können Sie erneut einen ",$q->a({-style=>"color:#$bgcolor1;",-href=>"$varenv->{wwwhost}?sharee_edit=send_sms$session_and"},"SMS Code anfordern")),"\n"; + }else{ + print $q->div({-class=>'content2', -style=>'color:gray;'}, "* SMS Bestätigungs-Code wurde bereits erfolgreich eingegeben."),"\n"; + } + + my $button_name = "Weiter"; + print $q->div({-style=>'margin-top:2em;'},""),"\n"; + print $q->end_form,"\n"; + + }else{ + + my $postaction = "/$varenv->{mandant}/Account/$varenv->{accounting_2}"; + if($ctrel->{c_id} && $path =~ /$varenv->{accounting_2}|$varenv->{accounting_3}|$varenv->{profile}/){ + $postaction = "/$varenv->{mandant}/Account/$varenv->{accounting_3}"; + }elsif($path =~ /$varenv->{accounting_1}/){ + $postaction = "/$varenv->{mandant}/Account/$varenv->{accounting_1_5}"; + }elsif($ctrel->{c_id} && $path =~ /$varenv->{accounting_1}/){ + $postaction = "/$varenv->{mandant}/Account/$varenv->{accounting_2}"; + } + + print $q->start_form(-name=>'accountscreen', -action=>"$postaction$session"),"\n"; + print $q->hidden(-name=>"sessionid",-override=>1,-value=>"$R::sessionid") if($R::sessionid); + + + print "
    \n"; + + my $i=0; + my @tpl_order; + foreach(@split_lates){ + $i++; + if($i==1){ + if($R::confirm_success){ + print $q->div({-class=>'content_title3'},"Anmeldung bestätigt"),"\n"; + }else{ + print $q->div({-class=>'content_title3'},"$tpl01->{tpl_name}"),"\n"; + } + + if($path =~ /$varenv->{accounting_1}/){ + print $q->div({-class=>'content2'}, "Damit Sie jederzeit und einfach ein Leihrad mieten können benötigen wir Anschrift und Zahlungsdaten."),"\n"; + } + if($path =~ /$varenv->{accounting_2}/){ + if($tpl_id == 302008){ + print $q->div({-class=>'content2'}, "Wähle die Zahlungsart."),"\n"; + }else{#old SEPA only style + print $q->div({-class=>'content2'}, "Durch das SEPA Mandat können wir die Leihrad Buchungen bequem einziehen."),"\n"; + } + } + + } + if($i==2){ + print $q->div({-class=>'content_title3'},"$tpl02->{tpl_name}"),"\n"; + print $q->div({-class=>'content2'}, "Das Login besteht aus Ihrer e-Mail Adresse und einem mindestens 8 stelligen Passwort."),"\n"; + + } + @tpl_order = split /,/,$_; + my $scol = "itime"; + foreach (@tpl_order){ + my ($key,$des,$size) = split /=/,$_; + $ctrel->{$key} = $q->unescapeHTML("$ctrel->{$key}"); + $ctrel->{$key} = $lb->newline($ctrel->{$key},"","1"); + + #radID & timeCode from contenttranspos---------------- + if($ctrel->{int03} && $path =~ /$varenv->{accounting_3}|$varenv->{profile}/){ + if(1==1){ + if($key =~ /ct_name/){ + if($ctrel->{int12}){ + print $q->div({-class=>'content2', -style=>'color:#c83434;'}, "Herzlich Willkommen. Wir mussten Ihren Zugang zu den Mieträdern sperren weil ein Problem mit Ihren Zahlungsdaten vorliegt. Bitte aktualisieren Sie Ihre Zahlungsdaten und kontaktieren Sie uns damit wir den Vorfall klären können."),"\n"; + }else{ + print $q->div({-class=>'content2'}, "Herzlich Willkommen. Sie können nach erfolgreicher Anmeldung unter dem Menue \"Fahrradstandortkarte\" ein Leihrad mieten."),"\n"; + } + print $q->div({-class=>'content2'}, "Nach der Mietradnutzung haben Sie hier die Möglichkeit die Mietvorgänge einzusehen und gebuchte Rechnungen als PDF herunterzuladen."),"\n"; + print $q->div({-class=>'content2'}, "Ihre Bonusnummer wurde akzeptiert. Bitte beachten Sie dass der Bonustarif im Kontext des Mietradbetreibers vergeben wird. Der Tarif wird bei der Mietrad Reservierung angezeigt."),"\n" if($R::success && $R::success eq "txt15"); + print $q->div({-class=>'content2'}, "Aktuell liegen keine Buchungen vor."),"\n" if(!$ctpos_count); + + }elsif($key =~ /barcode/ && $ctpos_count){ + + #print $q->div({-style=>'padding-top:1.5em;font-weight:bold;'},"Ihre Buchungsdaten der letzten 1 ½ Jahre im Überblick"),"\n"; + print $q->div({-style=>'padding-top:1.5em;font-weight:bold;'},"Folgende Positionen liegen zur nächsten Abbuchung vor"),"\n"; + + my @tpl_posorder = ("txt01=Beschreibung","int04=Station","ct_name=(Rad) Nummer","int26=CO2","int02=Betrag"); + + my $j=0; + my $nx=0; + my $sum = 0; + print "
    \n"; + print $q->start_table({-style=>'margin:15px 0;', -border=>'0', -width=>'auto',-align=>'left', -cellpadding=>'3', -cellspacing=>'0'}),"\n"; + print $q->Tr(),"\n"; + + foreach my $id (sort { lc($ctpos->{$b}->{$scol}) cmp lc($ctpos->{$a}->{$scol}) } keys(%$ctpos)){ + $j++; + $nx++; + + print $q->Tr(),"\n"; + foreach (@tpl_posorder){ + my ($key,$val) = split /=/,$_; + + my $occupied_style = "background-color:#fcfdfb;"; + $occupied_style = "background-color:#f4f1ee;" if($nx %= 2); + #$occupied_style = "color:#ff1493;" if($ctpos->{$id}->{txt10} =~ /occupied|requested/); + $occupied_style = "color:#ff1493;" if($ctpos->{$id}->{int10} == 2 || $ctpos->{$id}->{int10} == 3); + + if($key eq "txt01"){ + #print $q->td({-class=>'tdtxt', -style=>"$occupied_style"},"$ctpos->{$id}->{$key}"); + print "\n"; + if($ctpos->{$id}->{txt01}){ + $ctpos->{$id}->{$key} =~ s/\
    /;   /g; + print "$ctpos->{$id}->{$key}
    \n"; + } + if($ctpos->{$id}->{start_time}){ + $ctpos->{$id}->{start_time} = $lb->time4de($ctpos->{$id}->{start_time},"1"); + $ctpos->{$id}->{end_time} = $lb->time4de($ctpos->{$id}->{end_time},"1"); + print $q->span("→ $ctpos->{$id}->{start_time}
    ← $ctpos->{$id}->{end_time}"); + } + print "\n"; + }elsif($key =~ /int04/){ + if($ctpos->{$id}->{int09}){#if Tarifnr then bike + #print $q->td({-class=>'tdint', -style=>"$occupied_style"},"Station $ctpos->{$id}->{$key}"); + print "\n"; + print $q->span("Station
    → $ctpos->{$id}->{txt12}$ctpos->{$id}->{int06}
    ← $ctpos->{$id}->{txt13}$ctpos->{$id}->{int04}"); + print "\n"; + }else{ + print $q->td({-class=>'tdint', -style=>"$occupied_style"},"$ctpos->{$id}->{$key}"); + } + }elsif($key =~ /ct_name/){ + if($ctpos->{$id}->{int09}){#if Tarifnr then bike + print $q->td({-class=>'tdint', -style=>"$occupied_style"},"Rad
    $ctpos->{$id}->{$key}"); + }else{ + print $q->td({-class=>'tdint', -style=>"$occupied_style"},"$ctpos->{$id}->{$key}"); + } + }elsif($key eq "int26"){ + my $co2saving = ""; + if($ctpos->{$id}->{int26}){ + $co2saving = "Einsparung
    "; + my $co2diff = $pri->co2calc($ctpos->{$id}); + my $sprit_price = $pri->sprit2calc($ctpos->{$id}); + $co2saving .= "$co2diff kg CO²
    "; + $co2saving .= "$sprit_price EUR
    "; + $ctpos->{$id}->{int26} =~ s/\./,/; + $co2saving .= "bei $ctpos->{$id}->{int26} KM"; + } + print $q->td({-class=>'tdint', -style=>"$occupied_style", -nowrap=>1},"$co2saving"); + }elsif($key eq "int02"){ + my $gesamt = 0; + my $rabatt = ""; + ($gesamt,$rabatt) = $pri->price2calc($ctpos->{$id}); + $sum += $gesamt; + $gesamt = $lb->round($gesamt); + $gesamt = $lb->cashme($gesamt,","); + print $q->td({-class=>'tdint', -style=>"$occupied_style", -nowrap=>1},"$rabatt $gesamt €"); + } + } + } + if($j==0){ + print $q->Tr(),"\n"; + print $q->td({-class=>'tdint'},"Keine Daten vorhanden"); + }else{ + $sum = $lb->round($sum); + $sum = $lb->cashme($sum,","); + print $q->Tr(),"\n"; + print $q->td({-class=>'tdint', -colspan=>3},""); + print $q->td({-class=>'tdint'},"Gesamt"); + print $q->td({-class=>'tdint'},$q->b("$sum €")); + } + print $q->end_table; + print "
    \n"; + + my $i=0; + my $dtext = ""; + print "
    \n"; + foreach my $id (sort { $ctt_all->{$b}->{ct_name} cmp $ctt_all->{$a}->{ct_name} } keys(%$ctt_all)){ + + if($ctt_all->{$id}->{ct_name} =~ /\d/ && $coo){ + $i++; + my $invoice_time = $ctt_all->{$id}->{invoice_time} || $ctt_all->{$id}->{mtime}; + $invoice_time = $lb->time4de($invoice_time,0); + #$varenv->{praefix} only defined in sharee + my $webtarget = "_blank"; + my $dtext = ""; + if($varenv->{syshost} =~ /app/){ + $webtarget = "_self"; + $dtext = "(Der PDF download öffnet je nach System/Konfiguartion einen externen PDF-Viewer oder Webbrowser)"; + } + + if($i==1){ + print $q->div({-id=>'Rechnungen',-style=>'font-weight:bold;'},"Ihre Rechnungen"),"\n"; + print $q->div({-style=>'padding:0.5em;'},"$dtext"),"\n"; + } + print $q->div({-style=>'font-size:1em;padding:0.5em;border:0px solid #cccccc;'},$q->a({-href=>"$ctt_all->{$id}->{wwwhost}/FileOut?file=Rechnung-$ctt_all->{$id}->{praefix}-$ctt_all->{$id}->{ct_name}.pdf&sessionid=$coo", -target=>"$webtarget" , -type=>'application/octet-stream', -style=>'text-decoration:underline;'}, $q->img({-src=>"$varenv->{metahost}/glyphicons/file-any.png", -style=>'width:30px;'}), "Rechnung $ctt_all->{$id}->{ct_name}.pdf"), "   ($invoice_time)"),"\n"; + } + + } + print "
    \n"; + } + } + } + #------------------------------------------------------ + + my $label_des="* $des"; + my $autofocus=""; + if($key =~ /txt15|txt19/){ + $label_des="$des"; + } + + #sharee Tarife + if(1==2 && $key =~ /txt30/){ + #FIXME + print $q->div({-style=>'padding-top:10px;'}, "aktivierte Tarife: $ctrel->{$key}"),"\n" if($users_sharee->{txt08} =~ /gnu-systems|tux-edv/); + if(($R::failure && $R::failure =~ /^$key/) || ($ctrel->{txt31} && $ctrel->{txt31} =~ /$key/)){ + $autofocus = "autofocus"; + $label_des = "Bitte \"$des\" bestätigen"; + } + + my ($bike_group,$user_group,$tariff_all,$user_tour) = $apif->fetch_tariff($users_sharee,""); + my $required=""; + my @tariff = ("$ctrel->{$key}"); + @tariff = split(/\s/,$ctrel->{$key}) if($ctrel->{$key} =~ /\s/); + my $record_bonus = {c_id => 0}; + foreach my $rid (sort { $tariff_all->{$a}->{barcode} <=> $tariff_all->{$b}->{barcode} } keys (%$tariff_all)){ + print "xxxxxxxxxxxxx $tariff_all->{$rid}->{barcode} | $tariff_all->{$rid}->{int18}\n"; + }#end foreach tariff_all + + }elsif($key =~ /txt/ && $size eq "select" && $des eq "Land"){ + my $country = $lb->country_code(); + $ctrel->{$key} = "DE" if(!$ctrel->{$key}); + my @_valxx; + foreach (sort { $country->{$a} cmp $country->{$b} } keys (%$country)){ + push @_valxx, "$_:$country->{$_}"; + } + print $q->label({-for=>"$key",-style=>'padding-top:15px;'},"$label_des"),"\n"; + print $but->selector_class("$key","form-control","","$ctrel->{$key}",@_valxx); + + }elsif($key =~ /txt/ && $size eq "select"){ + my @_valxx = split(/,/,$varenv->{$des}); + print $q->label({-for=>"$key",-style=>'padding-top:15px;'},"$label_des"),"\n"; + print $but->selector_class("$key","form-control","","$ctrel->{$key}",@_valxx); + + }elsif($key =~ /txt/ && !$R::confirm_success){ + my $required="required"; + + #Gutschein + if($key =~ /txt16/ && $ctrel->{c_id}){ + $required=""; + $label_des = "$des"; + } + if($key eq "txt07" && $R::failure && $R::failure =~ /conflict_txt07/){ + $autofocus = "autofocus"; + my ($failkey,$failval) = split(/=/,$R::failure); + $label_des = "Achtung, es existiert bereits ein Account mit der Telefon Nr.: $failval"; + $ctrel->{$key} = $R::conflict_txt07; + } + elsif($key eq "txt08" && $R::failure && $R::failure =~ /conflict_txt08/){ + $autofocus = "autofocus"; + my ($failkey,$failval) = split(/=/,$R::failure); + $label_des = "Achtung, es existiert bereits ein Account mit der e-Mail Adresse: $failval"; + $ctrel->{$key} = $R::conflict_txt08; + } + #elsif($key eq "txt04" && $R::failure && $R::failure =~ /pwlazy_txt04/){ + # $autofocus = "autofocus"; + # $label_des = "Das Passwort ist zu kurz."; + #} + + elsif($key eq "txt15" && ($R::failure && $R::failure =~ /conflict_txt15/)){ + $autofocus = "autofocus"; + $label_des = "Die Bonusnummer kann pro Registrierung nur einmal verwendet werden. So wird verhindert dass weitere Personen von den 30-Freiminuten widerrechtlich Gebrauch nehmen.
    +Weitere Personen aus Ihrem Haushalt profitieren jedoch ebenfalls, falls Sie weitere Produkte (Gas, SeeConnect, Fähre- oder Bus-Zeitkarten) nutzen. Dann könnte sich die zweite Person mit der weiteren Nummer registrieren.
    "; + } + elsif($key eq "txt04" && $R::failure && $R::failure =~ /confirm_txt04/){ + $autofocus = "autofocus"; + $label_des = "Die Passwort Wiederholung ist fehlerhaft. Bitte korrigieren Sie Ihre Eingabe."; + } + elsif(($R::failure && $R::failure =~ /^$key/) || ($ctrel->{txt31} && $ctrel->{txt31} =~ /$key/)){ + $autofocus = "autofocus"; + $label_des = "Bitte \"$des\" Angabe korrigieren"; + $label_des = "Für das \"$des\" liegt ein Fehler vor." if($key eq "txt04"); + $label_des = "Bitte SMS Telefon Nr. mit Ländercode, Beispiel: +49 170 12345678" if($key eq "txt07"); + $label_des = "Die Bonusnummer ist leider nicht vorhanden. Bei nicht vorhandener Nummer das Feld bitte leer lassen." if($key =~ /txt15/); + } + #if($R::success eq $key){ + # $label_des = "Das hat geklappt. Der \"$des\" wurde erfolgreich hinzugefügt, s.u.."; + #} + + + if($key eq "txt04"){ + my $pw = "xxxxxxxx"; + $pw = "" if(!$ctrel->{c_id}); + print $q->label({-for=>"$key", -style=>'padding-top:1.5em;'},"$label_des"),"\n"; + print "
    \n"; + print $q->label({-for=>"confirm_$key"},"* Passwort wiederholen"),"\n"; + print "\n"; + print $q->div({-style=>'text-align:left;color:grey;'}, "", "Passwort anzeigen"),"\n" if($pw ne "xxxxxxxx"); + }else{ + #all other input textfields + $required = "";# if($key =~ /txt09|txt16/); + print $q->label({-for=>"$key", -style=>'padding-top:1.5em;'},"$label_des"),"\n"; + print "\n"; + } + + #all int checkboxes disabled because of AGB downunder + }elsif($key =~ /int/ && $size eq "checkbox"){ + if(($R::failure && $R::failure =~ /^$key/) || ($ctrel->{txt31} && $ctrel->{txt31} =~ /$key/)){ + $autofocus = "autofocus"; + $label_des = "Bitte \"$des\" bestätigen"; + } + my $required=""; + + #sharee AGB global new + if($key eq "int14" && $size eq "checkbox"){ + $required=""; + my $sharee_agb = "\n"; + print $q->label({-for=>"$key", -style=>'padding-top:20px;'},"$label_des"),"\n"; + print $q->div({-id=>"$key"},$but->checkbox("1","$key","$ctrel->{$key}","","$required"), " $sharee_agb"),"\n"; + print $q->hidden(-name=>"$key",-override=>1,-value=>"null"); + } + + #look also Shareework.pm save_account ret value + elsif(1==2 && $key =~ /int15/){#Konrad AGB + $required=1 if($varenv->{wwwhost} =~ /konrad/); + my $konrad_agb = "\n"; + print $q->label({-for=>"$key", -style=>'padding-top:20px;'},"$label_des"),"\n"; + print $q->div({-id=>"$key"},$but->checkbox("3429","$key","$ctrel->{$key}","","$required"), " $konrad_agb"),"\n"; + print $q->hidden(-name=>"$key",-override=>1,-value=>"0"); + }elsif(1==2 && $key =~ /int14/){#TINK AGB + $required=1 if($varenv->{wwwhost} !~ /konrad/); + my $tink_agb = "\n"; + print $q->label({-for=>"$key", -style=>'padding-top:20px;'},"$label_des"),"\n"; + print $q->div({-id=>"$key"},$but->checkbox("3428","$key","$ctrel->{$key}","","$required"), " $tink_agb"),"\n"; + print $q->hidden(-name=>"$key",-override=>1,-value=>"0"); + }elsif(1==2 && $key =~ /int02/){#newsletter + if($varenv->{wwwhost} !~ /konrad/){ + print $q->label({-for=>"$key", -style=>'padding-top:10px;'},""),"\n"; + print $q->div({-id=>"$key"},$but->checkbox("1","$key","$ctrel->{$key}","","$required"), " $des"),"\n"; + print $q->hidden(-name=>"$key",-override=>1,-value=>"0"); + } + + }else{ + print $q->label({-for=>"$key", -style=>'padding-top:10px;'},""),"\n"; + print $q->div({-id=>"$key"},$but->checkbox("1","$key","$ctrel->{$key}","","$required"), " $des"),"\n"; + print $q->hidden(-name=>"$key",-override=>1,-value=>"0"); + } + + }elsif($key =~ /int/){ + if(($R::failure && $R::failure =~ /^$key/) || ($ctrel->{txt31} && $ctrel->{txt31} =~ /$key/)){ + $autofocus = "autofocus"; + $label_des = "Bitte \"$des\" bestätigen"; + print $q->label({-for=>"$key", -style=>'padding-top:10px;'},"$label_des"),"\n"; + } + + if($key =~ /int03/){ + + print $q->div({-class=>'content2'}, " + Es werden die Kreditkartendaten von VISA und MasterCard akzeptiert.
    + Die Beträge für die Leihvorgänge werden gesammelt und i.d.R. wöchentlich eingezogen. D.h. der Belastungszeitpunkt bei Bankeinzeig oder via Karte findet in den darauffolgenden Tagen statt.
    + Gutschriften werden verrechnet und Ihrem Konto gutgeschrieben.
    + Die Datenübetragung findet per SSL-Verschlüsselung statt.
    + Nach erfolgreicher Anmeldung können Sie unter Ihren Verleihdaten die Leihrad Buchungen und Rechnungen jederzeit einsehen. + + "),"\n"; + + my $incasso="1"; + my $creditcard="2"; + my $checked_incasso; + my $checked_creditcard; + $checked_incasso=1 if($ctrel->{$key} == 1 || $ctrel->{$key} == 3); + $checked_creditcard=2 if($ctrel->{$key} == 2); + print $q->div({ -class=>'radio', -style=>'padding-top:20px;' },$but->radiobox_vertical("$key","$incasso","$checked_incasso",$q->img({-id=>"pic-payment" ,-style=>'height:50px;',-src=>"$varenv->{metahost}/img/payment-incasso2.png"}))),"\n"; + print $q->div({ -class=>'radio', -style=>'padding-bottom:20px;' },$but->radiobox_vertical("$key","$creditcard","$checked_creditcard",$q->img({-id=>"pic-payment" ,-style=>'height:30px;', -src=>"$varenv->{metahost}/img/payment-creditcard2.png"}))),"\n"; + print $q->hidden(-name=>"$key",-override=>1,-value=>"null"); + } + } + + if($key eq "txt16" && $ctrel->{c_id} && !$R::confirm_success){ + print $q->div({-style=>'margin-top:1em;'},""),"\n"; + } + + } + } + + if(($R::failure && $R::failure =~ /\w+/ && $R::failure !~ /txt15|txt16/) || ($ctrel->{txt31} && $ctrel->{txt31} =~ /\w/)){ + print $q->div({-class=>'content2', -style=>"color:$red"}, "* Eingabefehler.
    Bitte überprüfen Sie Ihre Profildaten damit wir das Fahrradmietsystem freischalten können. Es liegt ein Eingabefehler vor."),"\n"; + } + + if($path !~ /$varenv->{accounting_3}|$varenv->{profile}/){ + if($ctrel->{c_id}){ + my $button_name = "Speichern"; + $button_name = "Weiter" if($path =~ /$varenv->{accounting_1_5}|$varenv->{accounting_2}/); + print $q->hidden(-name=>"tinkc_id",-override=>1,-value=>"$ctrel->{c_id}"); + print $q->div({-style=>'margin-top:1em;'},""),"\n"; + if($path =~ /$varenv->{accounting_1}/){ + print $q->div({-style=>'margin-top:2em;text-align:center;'},$q->a({-style=>"color:#$bgcolor1;font-size:1.2em;", -role=>"button", -href=>"/$viewsel[0]/Account?sharee_edit=delete_account1$session_and"}, "Daten löschen?")),"\n";# if($ctrel->{txt08}); + } + }else{ + print $q->div({-style=>'margin-top:1em;'},""),"\n"; + } + } + + + }#ende e-Mail iif + print "
    \n"; + print $q->end_form,"\n"; + + print $q->div({-style=>'position:fixed;bottom:2%;right:2%;z-index:10;font-size:13px;'},"--> $varenv->{syshost} | $varenv->{merchant_id} | $bgcolor1 | template -> $node_meta->{tpl_name},$tpl_id ($template01,$template02) | $users_sharee->{c_id}"),"\n" if($users_sharee->{c_id} eq $dbt->{copri_conf}->{superu_id} || $dbt->{copri_conf}->{stage} eq "test"); + + print "
    "; +} +1; diff --git a/copri4/shareeapp-operator/src/Tpl/Karte.pm b/copri4/shareeapp-operator/src/Tpl/Karte.pm new file mode 100644 index 0000000..670ff8f --- /dev/null +++ b/copri4/shareeapp-operator/src/Tpl/Karte.pm @@ -0,0 +1,100 @@ +package Karte; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; +use CGI ':standard'; +use Lib::Config; +use Mod::DBtank; +use Mod::APIfunc; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my $node_meta = shift; + my $users_dms = shift || ""; + my $mode = shift || ""; + my $varenv = shift; + my $users_sharee = shift || { c_id => 0 }; + my $return = shift || ""; + + my $q = new CGI; + my $cf = new Config; + my $dbt = new DBtank; + my $apif = new APIfunc; + + my $api_file = "/var/www/copri4/shareeconf/apikeys.cfg"; + my $aconf = Config::General->new($api_file); + my %apikeyconf = $aconf->getall; + #print $apikeyconf{googlemap}->{google_key}; + + my $initMap = $dbt->{website}->{$varenv->{syshost}}->{initMap}; + $initMap =~ s/\s//g; + my ($lat,$lng) = split(/,/,$initMap); + + my $api_return = { authcookie => '' }; + my $coo = $q->cookie(-name=>'domcookie') || $R::sessionid; + ($api_return,$users_sharee) = $apif->auth_verify($q,$coo,""); + + require "Mod/KMLout.pm"; + my $kmlfile = Mod::KMLout::kmlGenerator($api_return,$varenv,$users_sharee); + + print "
    \n"; + + print "
    \n"; + +print< + + function initMap() { + var map = new google.maps.Map(document.getElementById('map'), { + scrollwheel: false, + draggable: !("ontouchend" in document), + center: {lat: $lat, lng: $lng}, + zoom: 8 + }); + + var ctaLayer = new google.maps.KmlLayer({ + position: map.getCenter(), + //preserveViewport: true, + //url: '$dbt->{primary}->{sharee_primary}->{primaryApp}/KMLout?kml=' + (new Date()).getTime() + '$users_sharee->{c_id}', + //url: '$varenv->{metahost}/xml/KMLout-3', + //url: '$varenv->{wwwhost}/?kml=' + (new Date()).getTime(), + url: '$varenv->{metahost}/xml/$kmlfile', + map: map + }); + console.log('$varenv->{metahost}/xml/$kmlfile'); + + }; + + + + +EOF +; + +print "
    \n"; + +print $q->div({-class=>"content2_legende", -style=>'font-weight:bold;'}, "• Ist ein Lastenrad an einer Mietradstation verfügbar?"),"\n"; +print $q->div({-class=>"content2_legende"}, $q->img({-style=>'height:30px;', -src=>"$varenv->{metahost}/img/Open_Green.png"}), "Lastenrad verfügbar"),"\n"; +print $q->div({-class=>"content2_legende"}, $q->img({-style=>'height:30px;', -src=>"$varenv->{metahost}/img/Open_Red.png"}), "Lastenrad nicht verfügbar"),"\n"; + + #if($R::ask_radID && $R::ask_radID =~ /^\d+$/){ + # require "Tpl/ModalboxDialog.pm"; + # &ModalboxDialog::mobox2($tpl_name,$tpl_id,$parent_id,$main_id,$u_id,$u_group,$lang,$users_sharee,$bg_color1,$bg_color2,$R::ask_radID); + # } + # + +} +1; + diff --git a/copri4/shareeapp-operator/src/Tpl/Listing.pm b/copri4/shareeapp-operator/src/Tpl/Listing.pm new file mode 100644 index 0000000..22fe01b --- /dev/null +++ b/copri4/shareeapp-operator/src/Tpl/Listing.pm @@ -0,0 +1,179 @@ +package Listing; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; +use CGI ':standard'; +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Libenzdb; +use Mod::DBtank; +use Encode; +use Data::Dumper; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my $node_meta = shift; + my $users_dms = shift || ""; + my $mode = shift || ""; + my $varenv = shift; + my $users_sharee = shift || ""; + my $return = shift || ""; + + my $q = new CGI; + my $cf = new Config; + my $but = new Buttons; + my $lb = new Libenz; + my $db = new Libenzdb; + my $dbt = new DBtank; + + my $lang = "de"; + my $script = $q->script_name(); + my $path_info = $q->path_info(); + my $path = $path_info; + #with meta_host, + if("$varenv->{metahost}"){ + $path = "$script" . "$path_info"; + $script=""; + } + my $user_agent = $q->user_agent(); + my %ib = $but->ibuttons_arch(); + my @tpl_order = split /,/,$node_meta->{tpl_order}; + my $main_ids = $node_meta->{main_id}; + my @viewsel = split /\//,$1 if($path =~ /^\/(.*)/); + + my $session=""; + my $session_and=""; + if(length($R::sessionid) > 20){ + $session = "?sessionid=$R::sessionid"; + $session_and = "&sessionid=$R::sessionid"; + } + + my $ct4rel = {}; + my $scol = "sort"; + my $sort_updown = "up"; + if($path =~ /NEWS/){ + $scol = "date_time01"; + $sort_updown = "down"; + #$scol = "date_time01"; + } + + my $content2 = "content2"; + my $content_img = "pic-float"; + $ct4rel = $db->collect_ct4rel2("content",$main_ids,$lang,"","","","","",$users_dms->{u_id}); + + print "
    \n"; + + #Content sequential + #BIG LOOP content table + foreach my $id (sort { + if($sort_updown eq "down"){ + if ($scol =~ /barcode|int|sort/) { + $ct4rel->{$b}->{$scol} <=> $ct4rel->{$a}->{$scol} + }else{ + lc($ct4rel->{$b}->{$scol}) cmp lc($ct4rel->{$a}->{$scol}) + } + }else{ + if ($scol =~ /barcode|int|sort/) { + $ct4rel->{$a}->{$scol} <=> $ct4rel->{$b}->{$scol} + }else{ + lc($ct4rel->{$a}->{$scol}) cmp lc($ct4rel->{$b}->{$scol}) + } + } + } keys(%$ct4rel)){ + + my $j=0; + my $date_time; + my $uritxt_key; + + foreach (@tpl_order){ + my ($key,$des,$size) = split /=/,$_; + $ct4rel->{$id}->{$key} = $q->unescapeHTML("$ct4rel->{$id}->{$key}"); + $ct4rel->{$id}->{$key} = $lb->newline($ct4rel->{$id}->{$key},"",""); + + my $datamain_id = $ct4rel->{$id}->{main_id}; + my $dir_main = "$varenv->{data}/$datamain_id/$ct4rel->{$id}->{c_id}"; + my $dir_thumb = "$varenv->{data}/$datamain_id-thumb/$ct4rel->{$id}->{c_id}"; + my $dir_resize = "$varenv->{data}/$datamain_id-resize/$ct4rel->{$id}->{c_id}"; + + + if($key =~ /img/ && $ct4rel->{$id}->{rel_id}){ + #print "
    \n"; + if( -d "$dir_resize"){ + my @pics = $lb->read_dirfiles($dir_resize,"\.JPG|\.JPEG|\.PNG","file"); + foreach(@pics){ + print $q->img({-id=>"$content_img" ,-src=>"$varenv->{metahost}/data/$datamain_id-resize/$ct4rel->{$id}->{c_id}/$_"}),"\n" if($_ =~ /\w/); + } + } + #print "
    \n"; + print $q->div({-style=>'clear:both;'},""),"\n"; + }elsif($key =~ /pdf/){ + if( -d "$dir_main"){ + my @pdfs = $lb->read_dirfiles($dir_main,"\.JPG|\.JPEG|\.PNG","file","not"); + foreach(@pdfs){ + #print $q->div({-class=>"$content2"}, $q->a({-href=>"$varenv->{metahost}/data/$datamain_id/$ct4rel->{$id}->{c_id}/$_", -target=>'_blank',-title=>'Download',-type=>'application/octet-stream'}, $q->img({-src=>"$varenv->{metahost}/glyphicons/file-any.png", -style=>'width:50px;'}), "$_")),"\n"; + print $q->div($q->a({-href=>"$varenv->{wwwhost}/FileOut?file=$datamain_id/$ct4rel->{$id}->{c_id}/$_$session_and", -target=>'_default', -title=>'Download',-type=>'application/octet-stream'}, $q->img({-src=>"$varenv->{metahost}/glyphicons/file-any.png", -style=>'width:50px;'}), "$_")),"\n"; + + } + } + + + }elsif($key =~ /date_time/ && $ct4rel->{$id}->{$key} =~ /\d{4}-\d{2}-\d{2}/){ + $date_time = $lb->time4de("$ct4rel->{$id}->{$key}","","Date_to_Text_Long"); + $date_time =~ s/^\w+,\s\w+//; + }elsif($key =~ /node_name/){ + my $ct_users; + $ct_users = $db->get_owner($ct4rel->{$id}->{owner}) if($ct4rel->{$id}->{owner}); + $ct4rel->{$id}->{mtime} = $lb->time4de($ct4rel->{$id}->{mtime},"1") if($ct4rel->{$id}->{mtime}); + print $q->div({-class=>'content2_group'},"Absender: $ct_users->{u_name} | $ct4rel->{$id}->{mtime}"),"\n"; + }elsif($key =~ /ct_name/){ + my $debug; + if($users_dms->{u_id}){ + print $q->div({-class=>'content_title2',-style=>"background-color:silver;padding:0.2em;"},$q->a({-class=>'editnav',-href=>"$path/manager?node2edit=edit_content\&rel_id=$ct4rel->{$id}->{rel_id}", -title=>"edit content"}, "$ct4rel->{$id}->{$key}"),$debug),"\n"; + print $q->div({-class=>'content_title2'},"$date_time"),"\n" if($date_time); + }elsif(!$R::sharee_edit){ + print $q->div({-class=>'content_title2'},"$date_time"),"\n" if($date_time); + print $q->div({-id=>"$ct4rel->{$id}->{c_id}",-class=>'content_title2'},"$ct4rel->{$id}->{$key}"),"\n" if($ct4rel->{$id}->{$key} =~ /[A-Za-z]/); + print $q->div({-style=>""},"$debug"),"\n"; + } + }elsif($key =~ /uri(\d+)/ && $ct4rel->{$id}->{$key} =~ /http/){ + $uritxt_key = "txt" . $1; + print $q->div({-class=>'content_direct2',-style=>'font-size:14px;'},$q->a({-href=>"$ct4rel->{$id}->{$key}"},"zum Projekt")),"\n"; + }elsif($key =~ /txt|int/ && $ct4rel->{$id}->{$key} && "$key" ne "$uritxt_key"){ + if($key =~ /txt/ && $size =~ /area(\d+)/ && $ct4rel->{$id}->{$key}){ + #phone tag + if($ct4rel->{$id}->{$key} =~ /Telefon|Mobile/){ + $ct4rel->{$id}->{$key} =~ s/([\s0-9-]+)/\
    $1\<\/a\>/; + } + #email tag with little coding against grabber + if($ct4rel->{$id}->{$key} =~ /(\w+\@[\w-]+\.de)/){ + $ct4rel->{$id}->{$key} =~ s/(\w+\@[\w-]+\.de)/\$1\<\/a\>/; + $ct4rel->{$id}->{$key} =~ s/\@/\&\#64\;/g; + #$ct4rel->{$id}->{$key} =~ s/\.de/\&\#46\;de/g; + } + #Development + if($ct4rel->{$id}->{$key} =~ /(www\.GNU-Systems\.de)/){ + $ct4rel->{$id}->{$key} =~ s/(www\.[\w-]+\.de)/\$1\<\/a\>/g; + } + $ct4rel->{$id}->{$key} =~ s/\\//g; + print $q->div({-class=>"$content2"}, "$ct4rel->{$id}->{$key}"),"\n"; + }elsif($ct4rel->{$id}->{$key} && $size !~ /checkbox/){ + print $q->div({-class=>"$content2"}, "$ct4rel->{$id}->{$key}"),"\n"; + } + } + } + print $q->div({-class=>"$content2"}," "),"\n"; + }#end if + print "
    \n"; +} +1; diff --git a/copri4/shareeapp-operator/src/Tpl/ModalboxDialog.pm b/copri4/shareeapp-operator/src/Tpl/ModalboxDialog.pm new file mode 100644 index 0000000..8d8e7b9 --- /dev/null +++ b/copri4/shareeapp-operator/src/Tpl/ModalboxDialog.pm @@ -0,0 +1,262 @@ +package ModalboxDialog; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; + +use CGI::Cookie (); +use CGI ':standard'; +use DateTime; +use DateTime::Format::Pg; +use Lib::Config; +use Mod::Buttons; +use Mod::DBtank; +use Mod::APIfunc; +use Mod::Libenzdb; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +sub mobox2(){ + my $node_meta = shift; + my $users_dms = shift || ""; + my $mode = shift || ""; + my $varenv = shift; + my $users_sharee = shift || ""; + my $return = shift || ""; + my $ask_radID = shift || ""; + + my $q = new CGI; + my $cf = new Config; + my $dbt = new DBtank; + my $apif = new APIfunc; + + my $db = new Libenzdb; + my $but = new Buttons; + my $script = $q->script_name(); + my $path_info = $q->path_info(); + my $path = $path_info; + #with meta_host, + if("$varenv->{metahost}"){ + $path = "$script" . "$path_info"; + $script=""; + } + my $dbh = ""; + my $bg_color = "white"; + my $bg_color2 = $varenv->{brand_color} || ""; + + my $session=""; + my $session_and=""; + if(length($R::sessionid) > 20){ + $session = "?sessionid=$R::sessionid"; + $session_and = "&sessionid=$R::sessionid"; + } + + my $ctadr = $users_sharee if(ref($users_sharee) eq "HASH" && $users_sharee->{c_id}); + + my $main_ids; + my ($bike_group,$user_group,$tariff_content,$user_tour) = $apif->fetch_tariff($ctadr,""); + $main_ids = join(",",@{$bike_group}); + $main_ids =~ s/[a-z_]+//ig; + + my $title = ""; + my $ct = {}; + if($ask_radID){ + my $pref_cc = { + table => "content", + fetch => "one", + main_id => "IN::($main_ids)", + barcode => $ask_radID, + int10 => 1, + }; + + $ct = $dbt->fetch_record($dbh,$pref_cc) if($ask_radID && $main_ids); + $title = "Fahrrad Buchungsbestätigung"; + } + + my $height = "250"; + my $width = "400"; + +print< + .ui-dialog .ui-dialog-content { + background: $bg_color; + } + .ui-dialog > .ui-widget-header { + color:$varenv->{color}; + font-weight:normal; + border:1px solid $bg_color2; + background: $bg_color2; + } + .ui-widget-overlay { + background: #666 url("$varenv->{metahost}/jquery-ui/images/ui-bg_diagonals-thick_20_666666_40x40.png") 50% 50% repeat; + opacity: .5; + filter: Alpha(Opacity=50); + } + +EOF +; + +#int04 != 1 --> no mailACK +#int13 != 1 --> no telACK +#int01 != 3 --> no sync +#int12 == 1 --> Vde + + my $ctadr_int13 = 1;#default to activ + if($varenv->{telAck_startdate} && $ctadr->{mtime}){ + my ($ty,$tm,$td) = split(/-/,$varenv->{telAck_startdate}); + my $dt1telAck_start = DateTime->new(year => $ty, month => $tm, day => $td); + my $dt2mtime = DateTime::Format::Pg->parse_datetime($ctadr->{mtime}); + #will be only evaluated if mtime never than global conf + if($ctadr->{owner} == 197 && $dt2mtime > $dt1telAck_start){ + $ctadr_int13 = $ctadr->{int13}; + } + } +if($node_meta->{main_id} && $ctadr->{c_id} && ($ctadr->{int04} != 1 || $ctadr_int13 != 1 || $ctadr->{int12} || $ask_radID)){ + + +print< + \$(function() { + \$( "#dialog-form2" ) + .css("background-color","$bg_color") + .dialog({ + height: $height, + width: $width, + closeOnEscape: false, + modal: true + }); + \$('.ui-widget-overlay').click(function() { + \$(".ui-dialog-titlebar-close").trigger('click');}); + + \$( "#btn_no1" ).click(function() { + \$( "#dialog-form2" ).dialog( "close" ); + }); + \$( "#btn_no2" ).click(function() { + \$( "#dialog-form2" ).dialog( "close" ); + }); + + \$( "#btn_yes" ).click(function() { + window.location.href = '$varenv->{wwwhost}?radID=$ask_radID$session_and'; + }); + + }); + +EOF +; + + print "
    "; + + + print $q->start_form(-name=>'modaldialog'); + print $q->hidden(-name=>"sessionid",-override=>1,-value=>"$R::sessionid"); + + print "
    \n"; + + if($ctadr->{int04} != 1 || $ctadr_int13 != 1){ + my $required = "required"; + if($ctadr->{int04} != 1){ + my $des = "E-Mail Bestätigungscode"; + my $key = "confirm_code"; + my $label_des="* $des"; + print $q->label({-for=>"$key", -style=>'padding-top:1em;'},"$label_des"),"\n"; + print "\n"; + }else{ + print $q->div({-class=>'content2', -style=>'color:gray;'}, "* E-Mail Bestätigungscode wurde bereits erfolgreich eingegeben."),"\n"; + } + if($ctadr_int13 != 1 && $varenv->{telAck_startdate}){ + my $des = "SMS Bestätigungscode"; + my $key = "confirm_smscode"; + my $label_des="* $des"; + print $q->label({-for=>"$key", -style=>'padding-top:1em;'},"$label_des"),"\n"; + print "\n"; + }elsif($varenv->{telAck_startdate}){ + print $q->div({-class=>'content2', -style=>'color:gray;'}, "* SMS Bestätigungscode wurde bereits erfolgreich eingegeben."),"\n"; + } + my $button_name = "Weiter"; + print $q->div({-style=>'margin-top:1em;'},""),"\n"; + + }elsif($ctadr->{int04} && $R::confirm_code){ + + my $des = "Danke! Die Bestätigung war erfolgreich."; + my $key = "nothing"; + my $label_des="$des"; + print $q->label({-for=>"$key", -style=>'padding-top:2.5em;'},"$label_des"),"\n"; + print $q->div({-style=>'margin-top:2em;text-align:center;'},""),"\n"; + + + }elsif($ctadr->{int12} || $ctadr->{int01} != 3 || !$ct->{c_id}){ + my $des = "Leider ist das Fahrradmietsystem für Ihren Account nicht freigeschaltet.

    Bitte überprüfen Sie Ihre Profildaten auf Vollständigkeit."; + $des = "Leider ist das Fahrradmietsystem für Ihren Account nicht freigeschaltet.

    Bitte kontaktieren Sie uns damit wir das Problem lösen und Ihren Account wieder freischalten können.
    ." if($ctadr->{int12} == 2); + my $key = "nothing"; + my $label_des="$des"; + print $q->label({-for=>"$key", -style=>'padding-top:2.5em;'},"$label_des"),"\n"; + print $q->div({-style=>'margin-top:2em;text-align:center;'},""),"\n"; + + + + }elsif($ask_radID){ + + my $des = "Fahrrad Nr. $R::ask_radID kostenlos für 15 Min. reservieren?"; + my $key = "radID"; + my $label_des="$des"; + print $q->label({-for=>"$key", -style=>'padding-top:2.5em;'},"$label_des"),"\n"; + #print "\n"; + #print $q->hidden(-name=>"$key",-override=>1,-value=>"$ask_radID"); + print $q->div({-style=>'margin-top:2em;text-align:center;'},"",""),"\n"; + + } + + print "
    \n"; + + print $q->end_form,"\n"; + print "
    \n"; + + }elsif($ask_radID){ +#If no Login +print< + \$(function() { + \$( "#dialog-form2" ) + .css("background-color","$bg_color") + .dialog({ + height: $height, + width: $width, + closeOnEscape: false, + modal: true + }); + \$('.ui-widget-overlay').click(function() { + \$(".ui-dialog-titlebar-close").trigger('click');}); + + \$( "#btn_no3" ).click(function() { + \$( "#dialog-form2" ).dialog( "close" ); + }); + \$( "#btn_anmelden" ).click(function() { + window.location.href = '$varenv->{wwwhost}/$varenv->{mandant}/Anmelden'; + }); + + }); + +EOF +; + print "
    "; + print "
    \n"; + + my $des = "Bitte erst anmelden."; + my $label_des="$des"; + print $q->label({-for=>"no_access", -style=>'padding-top:2.5em;'},"$label_des"),"\n"; + print $q->div({-style=>'margin-top:2em;text-align:center;'},"",""),"\n"; + + + print "
    \n"; + print "
    \n"; + + } +} +1; diff --git a/copri4/shareeapp-operator/src/Tpl/PayoneCCclient.pm b/copri4/shareeapp-operator/src/Tpl/PayoneCCclient.pm new file mode 100644 index 0000000..69b3bd8 --- /dev/null +++ b/copri4/shareeapp-operator/src/Tpl/PayoneCCclient.pm @@ -0,0 +1,266 @@ +package PayoneCCclient; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; +use CGI ':standard'; +use Config::General; +use Mod::DBtank; + + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my $self = shift; + my $tpl_id = shift; + my $node_meta = shift; + my $users_dms = shift || ""; + my $mode = shift || ""; + my $varenv = shift; + my $users_sharee = shift || ""; + my $return = shift || ""; + + my $q = new CGI; + my $dbt = new DBtank; + + my $globalconf_file = "/var/www/copri4/shareeconf/global.cfg"; + my $conf = Config::General->new($globalconf_file); + my %globalconf = $conf->getall; + my $payone_conf = $globalconf{payone_conf}; + + my $bgcolor1 = "009899";#sharee + #my $bgcolor1 = "e2001a"; + + $bgcolor1 = $dbt->{website}->{$varenv->{syshost}}->{bgcolor1} if($dbt->{website}->{$varenv->{syshost}}->{bgcolor1}); + $bgcolor1 = $dbt->{merchant_ids}->{$varenv->{merchant_id}}->{bgcolor1} if($dbt->{merchant_ids}->{$varenv->{merchant_id}}->{bgcolor1}); + + print "
    \n"; + + print $q->div({-class=>'content_title3'},"Kreditkartendaten"),"\n"; + + print $q->div({-class=>'content2'},"Kreditkartendaten werden von uns nicht gespeichert sondern direkt an unseren Zahlungsdienstleister Payone übermittelt. Deshalb sehen Sie hier nur leere Eingabefelder."),"\n"; + #print $q->div({-class=>'content2'}, "Zur Validierung Ihrer Zahlungsdaten wird eine 1,- € Testbuchung vorgenommen. Wir werden nach erfolgreicher Abbuchung den Betrag als Mietgutschrift in Ihrem Account hinterlegen."),"\n"; + if($users_sharee->{int03} && $users_sharee->{int03} == 2 && $users_sharee->{txt28} && $users_sharee->{txt28} =~ /\w/){ + print $q->div({-class=>'content2', -style=>'color:#c83434;'},"Ihre Zahlungsdaten konnten nicht erfolgreich validiert werden. Bitte überprüfen Sie Ihre Eingaben."),"\n"; + } + + my $ccerror=""; + #my $ccerror="Entschuldigung, die Zahlungsart Kreditkarten ist im Augenblick nicht verfügbar."; + $ccerror = "Status not APPROVED" if($R::not_approved); + print ""; + print $q->div({-id=>'ccerror'},"$ccerror"),"\n"; + +if(1==1){ + +print< +fieldset { +padding: 1em; +border: 1px solid #$bgcolor1; +width: 275px; +margin: 10px; +} +label { +margin-right: 10px; +float: left; +width: 80px; +padding-top: 0.3em; +text-align: left; +} +input, select{ +font-size: 1em; +border: 1px solid black; +padding: 0.1em; +} +select { +margin-right: 10px; +} +input, .inputIframe, select { +display: block; +margin-bottom: 10px; +} +input { +width: 175px; +} +#paymentsubmit { +width: 100%; +font-size:1.2em; +padding: 5px; +margin-top:20px; +color:#FFF; +background-color:#$bgcolor1; +} +#errorOutput { +text-align: center; +color: #ff0000; +display: block; +} + + + +EOF +; + +print< +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + + +
    + + +EOF +; +} +print "
    \n"; + + +} +1; diff --git a/copri4/shareeapp-operator/src/Tpl/PayoneSEPA.pm b/copri4/shareeapp-operator/src/Tpl/PayoneSEPA.pm new file mode 100644 index 0000000..351a8f1 --- /dev/null +++ b/copri4/shareeapp-operator/src/Tpl/PayoneSEPA.pm @@ -0,0 +1,166 @@ +package PayoneSEPA; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; +use POSIX; +use CGI ':standard'; +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Shareework; +use Mod::DBtank; +use Sys::Hostname; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my $self = shift; + my $tpl_id = shift; + my $node_meta = shift; + my $users_dms = shift || ""; + my $mode = shift || ""; + my $varenv = shift; + my $users_sharee = shift || ""; + my $return = shift || ""; + + my $q = new CGI; + my $cf = new Config; + my $lb = new Libenz; + my $tk = new Shareework; + my $dbt = new DBtank; + my $but = new Buttons; + my $hostname = hostname; + + $q->import_names('R'); + my @keywords = $q->param; + my $script = $q->script_name(); + my $path_info = $q->path_info(); + my $path = $path_info; + #with meta_host, + if("$varenv->{metahost}"){ + $path = "$script" . "$path_info"; + $script=""; + } + my $now_dt = strftime "%Y-%m-%d %H:%M", localtime; + my @viewsel = split /\//,$1 if($path =~ /^\/(.*)/); + + my $coo = $q->cookie(-name=>'domcookie') || $R::sessionid; + my $ctadr = $users_sharee if(ref($users_sharee) eq "HASH" && $users_sharee->{c_id}); + + my $tpl = $dbt->get_tpl($tpl_id); + my @tpl_order = split /,/,$tpl->{tpl_order}; + + print $q->start_form(),"\n"; + print $q->hidden(-name=>"sessionid",-override=>1,-value=>"$R::sessionid"); + print $q->hidden(-name=>"tinkc_id",-override=>1,-value=>"$ctadr->{c_id}"); + print $q->hidden(-name=>"request",-override=>1,-value=>"managemandate"); + + #Standard parameter + #foreach (keys (%$base_request)){ + # print $q->hidden(-name=>"$_",-value=>"$base_request->{$_}"),"\n"; + #} + + print "
    \n"; + + print $q->div({-class=>'content_title3'},"Kontoverbindung"),"\n"; + print $q->div({-class=>'content2'}, "Durch das SEPA Mandat können wir die Leihrad Buchungen bequem einziehen."),"\n"; + #print $q->div({-class=>'content2'}, "Zur Validierung Ihrer Zahlungsdaten wird eine 1,- € Testbuchung vorgenommen. Wir werden nach erfolgreicher Abbuchung den Betrag als Mietgutschrift in Ihrem Account hinterlegen."),"\n"; + + + foreach (@tpl_order){ + my ($key,$des,$size) = split /=/,$_; + $ctadr->{$key} = $q->unescapeHTML("$ctadr->{$key}"); + + my $label_des=""; + my $red = "#c83434"; + my $required="required"; + if($key eq "txt22"){ + if($R::IBAN){ + $label_des = "IBAN Fehler"; + $ctadr->{$key} = $R::IBAN; + } + if($R::failure eq $key){ + $label_des = "Bitte \"$des\" Angabe korrigieren"; + } + print $q->label({-for=>"$key", -style=>'padding-top:1.5em;'},"$label_des"),"\n"; + print "\n"; + + }elsif($key eq "txt23"){ + print $q->label({-for=>"$key", -style=>'padding-top:1.5em;'},"$label_des"),"\n"; + print "\n"; + + #------------------------ + }elsif($key =~ /int03/ && $size eq "checkbox"){ + + if($ctadr->{$key} != 1){ + + my $int03 = ""; + $int03 = $ctadr->{$key} if($ctadr->{$key} == 1); + print $q->div({-style=>'margin:10px 0;'},"Damit wir die SEPA-Lastschrift von Ihrem Konto einziehen können, benötigen wir von Ihnen ein SEPA-Lastschriftmandat. Das Mandat wird bei uns als PDF zu Ihren Zahldaten hinterlegt. Sie können nach der Anmeldung das Mandat als PDF herunterladen"),"\n"; + + if($ctadr->{txt27} !~ /active|pending/ && $R::failure eq $key){ + $label_des = "Bitte \"$des\" bestätigen"; + print $q->label({-for=>"$key", -style=>'padding-top:10px;'},"$label_des"),"\n"; + } + + my $des = "Ich möchte das Mandat erteilen (elektronische Übermittlung)"; + print $q->div({-id=>"$key"},$but->checkbox("1","$key","$int03","","$required"), " $des"),"\n"; + #print $q->hidden(-name=>"$key",-override=>1,-value=>"3"); + + }else{ + + if($ctadr->{txt28} =~ /SEPA-Lastschriftmandat/){ + print $q->div({-class=>'content2'}, ""),"\n"; + $ctadr->{txt28} = $q->unescapeHTML("$ctadr->{txt28}"); + use URI::Encode qw(uri_encode uri_decode); + $ctadr->{txt28} = uri_decode($ctadr->{txt28}); + $ctadr->{txt28} =~ s/\+/ /g; + print $q->div({-style=>'padding:10px;margin:10px 0;border:1px solid silver;'},$ctadr->{txt28}),"\n"; + } + + #if payone fails/error + if($ctadr->{txt27} =~ /active|pending/){ + #print $q->div({-style=>'padding:10px;margin:10px 0;border:1px solid silver;'}, "Das Mandat ist aktiviert"),"\n"; + if($ctadr->{ct_name} && ($ctadr->{ct_name} =~ /PO-/ || $ctadr->{ct_name} =~ /TM-/) && $coo){ + #print $q->div({-style=>'padding:10px;margin:10px 0;'}, "Download:", $q->a({-href=>"/PDFinvoice?session=$coo\&sepa=$ctadr->{ct_name}", -target=>'_blank'}, "SEPA-Lastschriftmandat.pdf")),"\n" if($coo); + #$varenv->{praefix} only defined in sharee + my $webtarget = "_blank"; + my $dtext = ""; + if($varenv->{syshost} =~ /app/){ + $webtarget = "_self"; + $dtext = "
    (Der PDF download öffnet je nach System/Konfiguartion einen externen PDF-Viewer oder Webbrowser)"; + } + print $q->div({-style=>'padding:10px;margin:10px 0;'},$q->a({-href=>"$varenv->{wwwhost}/FileOut?file=SEPA-Lastschriftmandat-$varenv->{praefix}-$ctadr->{ct_name}.pdf", -target=>"$webtarget" , -type=>'application/octet-stream', -style=>'text-decoration:underline;font-size:1.1em;'}, $q->img({-src=>"$varenv->{metahost}/glyphicons/file-any.png", -style=>'width:30px;'}), "SEPA-Lastschriftmandat.pdf"),"$dtext"),"\n"; + }else{ + print $q->div({-style=>'padding:10px;margin:10px 0;border:1px solid silver;color:#c83434;'},"Es gibt ein Problem! Das SEPA Mandat konnte nicht eingeholt werden. Bitte wenden Sie sich bei Bedarf an den unter \"Kontakt\" hinterlegten Support."),"\n"; + } + }elsif($ctadr->{txt22}){ #if IBAN but no mandat_status + print $q->div({-style=>'padding:10px;margin:10px 0;border:1px solid silver;color:#c83434;'}, "Fehler. Das Mandat ist nicht aktiv. "),"\n"; + + $ctadr->{txt28} = $q->unescapeHTML("$ctadr->{txt28}"); + $ctadr->{txt28} = $lb->newline($ctadr->{txt28},"","0"); + + #print $q->div({-style=>'padding:10px;margin:10px 0;border:1px solid silver;color:#c83434;'}, "Fehlermeldung: $ctadr->{txt28}"),"\n" if($ctadr->{txt28} !~ /SEPA-Lastschriftmandat/); + } + print $q->hidden(-name=>"$key",-override=>1,-value=>"1"); + } + } + #-------------------- + } + + print $q->div({-style=>'margin-top:1em;'},""),"\n"; + + + print "
    \n"; + print $q->end_form,"\n"; +} +1; diff --git a/copri4/shareeapp-operator/src/Tpl/PayoneSelect.pm b/copri4/shareeapp-operator/src/Tpl/PayoneSelect.pm new file mode 100644 index 0000000..23da31f --- /dev/null +++ b/copri4/shareeapp-operator/src/Tpl/PayoneSelect.pm @@ -0,0 +1,81 @@ +package PayoneSelect; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +use strict; +use warnings; +use POSIX; +use CGI ':standard'; +use Lib::Config; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Libenzdb; +use Tpl::AccountSubmenu; +use Tpl::PayoneSEPA; +use Tpl::PayoneCCclient; + + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my $node_meta = shift; + my $users_dms = shift || ""; + my $mode = shift || ""; + my $varenv = shift; + my $users_sharee = shift || ""; + my $return = shift || ""; + + my $q = new CGI; + my $cf = new Config; + my $lb = new Libenz; + my $db = new Libenzdb; + my $but = new Buttons; + my $submenu = new AccountSubmenu; + my $paySEPA = new PayoneSEPA; + my $payCC = new PayoneCCclient; + + $q->import_names('R'); + my @keywords = $q->param; + + my $script = $q->script_name(); + my $path_info = $q->path_info(); + my $path = $path_info; + #with meta_host, + if("$varenv->{metahost}"){ + $path = "$script" . "$path_info"; + $script=""; + } + my $time = time; + my $now_dt = strftime "%Y-%m-%d %H:%M", localtime; + + my %ib = $but->ibuttons_arch(); + my @viewsel = split /\//,$1 if($path =~ /^\/(.*)/); + + my $ctrel = $users_sharee if(ref($users_sharee) eq "HASH" && $users_sharee->{c_id}); + my $ctt = $db->collect_content2("contenttrans","int10",$ctrel->{c_id}); + my $tpl = $db->get_tpl($node_meta->{tpl_id}); + + print "
    \n"; + + #subMenue-------- + $submenu->tpl($node_meta,$users_dms,$mode,$varenv,$users_sharee,$return); + #----------------- + + #Selected Payment + if($ctrel->{int03} == 1 || $ctrel->{int03} == 3){ + $paySEPA->tpl("309",$node_meta,$users_dms,$mode,$varenv,$users_sharee,$return); + }elsif($ctrel->{int03} == 2){ + $payCC->tpl("310",$node_meta,$users_dms,$mode,$varenv,$users_sharee,$return); + } + + print "
    \n"; + +} +1; diff --git a/copri4/shareeapp-operator/src/scripts b/copri4/shareeapp-operator/src/scripts new file mode 120000 index 0000000..8705f56 --- /dev/null +++ b/copri4/shareeapp-operator/src/scripts @@ -0,0 +1 @@ +../../main/src/scripts \ No newline at end of file diff --git a/copri4/shareeapp-operator/src/wkhtmltopdf-amd64 b/copri4/shareeapp-operator/src/wkhtmltopdf-amd64 new file mode 120000 index 0000000..2e6c34b --- /dev/null +++ b/copri4/shareeapp-operator/src/wkhtmltopdf-amd64 @@ -0,0 +1 @@ +../../main/src/wkhtmltopdf-amd64 \ No newline at end of file diff --git a/copri4/shareeapp-operator/startup.pl b/copri4/shareeapp-operator/startup.pl new file mode 100755 index 0000000..ed145fe --- /dev/null +++ b/copri4/shareeapp-operator/startup.pl @@ -0,0 +1,2 @@ +use lib qw(/var/www/copri4/shareeapp-operator/src); +1; diff --git a/copri4/shareeapp-operator/xml b/copri4/shareeapp-operator/xml new file mode 120000 index 0000000..ac9e2f3 --- /dev/null +++ b/copri4/shareeapp-operator/xml @@ -0,0 +1 @@ +../shareedms-operator/xml \ No newline at end of file diff --git a/copri4/shareeconf/apikeys.cfg b/copri4/shareeconf/apikeys.cfg new file mode 120000 index 0000000..dc6515e --- /dev/null +++ b/copri4/shareeconf/apikeys.cfg @@ -0,0 +1 @@ +/etc/shareeconf/apikeys.cfg \ No newline at end of file diff --git a/copri4/shareeconf/global.cfg b/copri4/shareeconf/global.cfg new file mode 120000 index 0000000..a3e8ffd --- /dev/null +++ b/copri4/shareeconf/global.cfg @@ -0,0 +1 @@ +/etc/shareeconf/global_devel.cfg \ No newline at end of file diff --git a/copri4/shareeconf/mailx.cfg b/copri4/shareeconf/mailx.cfg new file mode 120000 index 0000000..b88542f --- /dev/null +++ b/copri4/shareeconf/mailx.cfg @@ -0,0 +1 @@ +/etc/shareeconf/mailx.cfg \ No newline at end of file diff --git a/copri4/shareedms-operator/apache/shareedms-operator.conf b/copri4/shareedms-operator/apache/shareedms-operator.conf new file mode 100644 index 0000000..682a7b5 --- /dev/null +++ b/copri4/shareedms-operator/apache/shareedms-operator.conf @@ -0,0 +1,113 @@ + + ServerName shareedms-operator.copri-bike.de + ServerAlias shareedms-operator1.copri-bike.de + + ServerAdmin info@gnu-systems.de + DocumentRoot /var/www/copri4/shareedms-operator + + ErrorLog /var/log/apache2/shareedms-operator-error.log + LogLevel info ssl:warn + CustomLog /var/log/apache2/shareedms-operator-access.log combined + ServerSignature Off + RewriteEngine on + RewriteCond %{SERVER_NAME} =shareedms-operator.copri-bike.de + RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent] + + + + + + ServerName shareedms-operator1.copri-bike.de + ServerAdmin info@gnu-systems.de + DocumentRoot /var/www/copri4/shareedms-operator + AddHandler cgi-script .cgi .sh .pl + + + Options -Indexes +FollowSymLinks +ExecCGI + AllowOverride None + + + + Header set Access-Control-Allow-Origin "*" + + + + Options +Indexes +FollowSymLinks -ExecCGI + Order allow,deny + Allow from all + + + + Options -Indexes +FollowSymLinks + Order allow,deny + Allow from all + ForceType application/octet-stream + Header set Content-Disposition attachment + + + ErrorLog /var/log/apache2/shareedms-operator-error.log + #LogLevel debug + LogLevel info ssl:warn + CustomLog /var/log/apache2/shareedms-operator-access.log combined + ServerSignature Off + + Include /etc/letsencrypt/options-ssl-apache.conf + SSLCertificateFile /etc/letsencrypt/live/copri-bike.de-0003/fullchain.pem + SSLCertificateKeyFile /etc/letsencrypt/live/copri-bike.de-0003/privkey.pem + + + + ServerName shareedms-operator.copri-bike.de + ServerAdmin info@gnu-systems.de + DocumentRoot /var/www/copri4/shareedms-operator + + + PerlOptions +Parent + PerlRequire /var/www/copri4/shareedms-operator/startup.pl + + SetHandler perl-script + PerlResponseHandler Mod::Indexsharee + PerlInitHandler Apache2::Reload + PerlOptions +ParseHeaders +GlobalRequest + Options -ExecCGI +FollowSymLinks + Order allow,deny + Allow from all + + + + SetHandler perl-script + PerlInitHandler Apache2::Reload + PerlResponseHandler Mod::ajax_json + + + + SetHandler perl-script + PerlInitHandler Apache2::Reload + PerlResponseHandler Mod::ajax_post + + + + SetHandler perl-script + PerlInitHandler Apache2::Reload + PerlResponseHandler Mod::FileOut + + + + RewriteEngine On + RedirectMatch ^/$ /DMS/Mietjournal + SSLProxyEngine On + RewriteCond %{REQUEST_URI} ^/(site|img|data|css|js|jquery) + RewriteRule ^(.*)$ https://shareedms-operator1.copri-bike.de/$1 [P,L] + + + ErrorLog /var/log/apache2/shareedms-operator-error.log + LogLevel info ssl:warn + CustomLog /var/log/apache2/shareedms-operator-access.log combined + ServerSignature Off + Include /etc/letsencrypt/options-ssl-apache.conf + + SSLCertificateFile /etc/letsencrypt/live/copri-bike.de-0003/fullchain.pem + SSLCertificateKeyFile /etc/letsencrypt/live/copri-bike.de-0003/privkey.pem + + + diff --git a/copri4/shareedms-operator/css/bootstrap-icons-1.5.0 b/copri4/shareedms-operator/css/bootstrap-icons-1.5.0 new file mode 120000 index 0000000..fc8bde9 --- /dev/null +++ b/copri4/shareedms-operator/css/bootstrap-icons-1.5.0 @@ -0,0 +1 @@ +../../main/css/bootstrap-icons-1.5.0 \ No newline at end of file diff --git a/copri4/shareedms-operator/css/favicon.ico b/copri4/shareedms-operator/css/favicon.ico new file mode 120000 index 0000000..28b50e2 --- /dev/null +++ b/copri4/shareedms-operator/css/favicon.ico @@ -0,0 +1 @@ +../../main/css/favicon.ico \ No newline at end of file diff --git a/copri4/shareedms-operator/css/local_style_2.css b/copri4/shareedms-operator/css/local_style_2.css new file mode 120000 index 0000000..bb065e7 --- /dev/null +++ b/copri4/shareedms-operator/css/local_style_2.css @@ -0,0 +1 @@ +../../main/css/local_style_2.css \ No newline at end of file diff --git a/copri4/shareedms-operator/glyphicons b/copri4/shareedms-operator/glyphicons new file mode 120000 index 0000000..7393fbd --- /dev/null +++ b/copri4/shareedms-operator/glyphicons @@ -0,0 +1 @@ +../main/glyphicons \ No newline at end of file diff --git a/copri4/shareedms-operator/img b/copri4/shareedms-operator/img new file mode 120000 index 0000000..39564ce --- /dev/null +++ b/copri4/shareedms-operator/img @@ -0,0 +1 @@ +../main/img \ No newline at end of file diff --git a/copri4/shareedms-operator/js b/copri4/shareedms-operator/js new file mode 120000 index 0000000..6b66a30 --- /dev/null +++ b/copri4/shareedms-operator/js @@ -0,0 +1 @@ +../main/js \ No newline at end of file diff --git a/copri4/shareedms-operator/pdfinvoice b/copri4/shareedms-operator/pdfinvoice new file mode 120000 index 0000000..6089659 --- /dev/null +++ b/copri4/shareedms-operator/pdfinvoice @@ -0,0 +1 @@ +pdf \ No newline at end of file diff --git a/copri4/shareedms-operator/robots.txt b/copri4/shareedms-operator/robots.txt new file mode 100755 index 0000000..1f53798 --- /dev/null +++ b/copri4/shareedms-operator/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / diff --git a/copri4/shareedms-operator/src/Lib/Config.pm b/copri4/shareedms-operator/src/Lib/Config.pm new file mode 100644 index 0000000..3022f32 --- /dev/null +++ b/copri4/shareedms-operator/src/Lib/Config.pm @@ -0,0 +1,82 @@ +package Config; + +#Deprecated config file +#Please use shareeconf/* + +use strict; +use warnings; +use CGI; +use Config::General; +my $q = new CGI; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +sub envonline(){ + my $self = shift; + + my $globalconf_file = "/var/www/copri4/shareeconf/global.cfg"; + my $conf = Config::General->new($globalconf_file); + my %globalconf = $conf->getall; + + my $basedir = "$globalconf{copri_conf}->{basedir}/$globalconf{operator}{sharee_operator}->{dir_dms}"; + my $metahost = $globalconf{operator}{sharee_operator}->{operatorDMS1}; + + my %varenv = ( + dbname => $globalconf{operator}{sharee_operator}{database}->{dbname}, + dbuser => $globalconf{operator}{sharee_operator}{database}->{user}, + dbpassw => $globalconf{operator}{sharee_operator}{database}->{passwd}, + dbhost => $globalconf{operator}{sharee_operator}{database}->{host}, + syshost => $globalconf{operator}{sharee_operator}->{dir_app}, + wwwhost => $globalconf{operator}{sharee_operator}->{operatorDMS}, + praefix => $globalconf{operator}{sharee_operator}{database}->{dbname}, + systype => "sharee",#(azn) + mandant => $globalconf{shareedms_conf}->{parent_node}, + start => $globalconf{shareedms_conf}->{start}, + profile => $globalconf{shareedms_conf}->{profile}, + + superu_id => $globalconf{copri_conf}->{superu_id}, + debug => $globalconf{copri_conf}->{debug}, + logdir => $globalconf{copri_conf}->{logdir}, + live_hostname => $globalconf{primary}{sharee_primary}->{live_hostname}, + metahost=>"$metahost", + orga => "dms", + term_active_color => "#$globalconf{shareedms_conf}->{term_active_color}", + background_image => "", + background_size => "cover", + background_color => "#5c5c5c", + background_color2 => "#a7a18f", + background_align => "center", + background_repeat => "no-repeat", + font_family => "Arial", + font_size => "100.01%", + line_height => "1", + basedir => "$basedir", + csv => "$basedir/csv", + pdf => "$basedir/pdf", + data => "$basedir/data", + xmlfile => "$basedir/xml", + ftp_getfile => "ftp/SWK_codes/got_last.csv", + ftp_putfile => "ftp/SWK_return/konrad_code_protokoll.csv", + map_activ => "", + min_width => "1100", + head_logo => "$metahost/img/sharee_bike_Logo.jpg", + barcode => "", + limit => "200", + waren_main_id => $globalconf{shareedms_conf}->{waren}, + Zahlungsweise => "SEPA-Lastschrift (payone)|Kreditkarte (payone)|Zahlungseingang (payone txid)|Abbuchung|Bar|EC-Karte|Überweisung|Zahlungsausfall", + order_state => "|angerufen|eMail gesendet|in Arbeit|an FiBu delegiert|txid renewed|cronjob fail|payone Mahnung|COPRI Mahnung", + 'Ziel Datei' => "privacy.html|agb.html|impress.html|tariff_info.html|bike_info.html", + printer => "PDF" + ); + return %varenv; + +} + +1; + + diff --git a/copri4/shareedms-operator/src/Lib/Mlogic.pm b/copri4/shareedms-operator/src/Lib/Mlogic.pm new file mode 100644 index 0000000..f71bfb6 --- /dev/null +++ b/copri4/shareedms-operator/src/Lib/Mlogic.pm @@ -0,0 +1,371 @@ +package Mlogic; +# +# SPDX-License-Identifier: AGPL-3.0-or-later +# Copyright (c) Rainer Gümpelein, TeilRad GmbH +# +# +use strict; +use warnings; +use CGI::Carp qw(fatalsToBrowser); +use CGI ':standard'; +use Config::General; +use Mod::Buttons; +use Mod::Libenz; +use Mod::Libenzdb; +use Mod::DBtank; +use POSIX; +use Data::Dumper; + +sub new { + my $class = shift; + my $self = {}; + bless($self,$class); + return $self; +} + +#Template +sub tpl(){ + my $self = shift; + my ($node_meta,$users_dms,$mode,$varenv,$users_sharee,$return) = @_; + + my $q = new CGI; + my $lb = new Libenz; + my $db = new Libenzdb; + my $dbt = new DBtank; + my $but = new Buttons; + my %ib = $but->ibuttons(); + my $script = $q->script_name(); + my $path_info = $q->path_info(); + my $path = $path_info; + if("$varenv->{metahost}"){ + $path = "$script" . "$path_info"; + $script=""; + } + my $coo = $q->cookie(-name=>'domcookie'); + my $debug = ""; + my $lang = "de"; + my @viewsel = split /\//,$1 if($path =~ /^\/(.*)/); + my $view_root = $viewsel[0] || ""; + my $mandant = $db->get_node("$view_root","$lang"); + my $parent_id = $node_meta->{parent_id}; + my $main_id = $node_meta->{main_id}; + + my $title = ""; + $title .= $dbt->{primary}->{$varenv->{dbname}}->{pprefix} if($dbt->{primary}->{$varenv->{dbname}}->{pprefix}); + $title .= $dbt->{operator}->{$varenv->{dbname}}->{project} if($dbt->{operator}->{$varenv->{dbname}}->{project}); + $title .= " " . $dbt->{operator}->{$varenv->{dbname}}->{oprefix} if($dbt->{operator}->{$varenv->{dbname}}->{oprefix}); + $title .= $dbt->{website}->{$varenv->{syshost}}->{project} if($dbt->{website}->{$varenv->{syshost}}->{project}); + $title .= " DEVEL $varenv->{dbname}" if($dbt->{copri_conf}->{stage} eq "test"); + + + ###User Panel + if($users_dms->{u_id}){ + + ###header start + print "
    \n"; + print "
    \n"; + + #cleanup + if(!$mandant->{node_name} || "$mandant->{node_name}" ne "$users_dms->{fullurl}"){ + $db->cleanup_users($users_dms->{owner}) if($users_dms->{owner}); + } + + if($users_dms->{c_id4trans} && $users_dms->{tpl_id4trans} && $users_dms->{kind_of_trans}){ + my $table = "contenttrans"; + if($users_dms->{kind_of_trans} =~ /Veranstaltung|Proje/){ + $table = "contenttver"; + } + + my $limit = $R::limit || $varenv->{limit}; + my $offset = $R::offset || "0"; + if($R::go && $R::go eq "backward_list"){ + $offset -= $limit if($offset >= $limit); + }elsif($R::go && $R::go eq "forward_list"){ + $offset += $limit; + } + my $ctrel = $db->get_ctrel($table,"",$lang,"",$users_dms->{c_id4trans},$users_dms->{tpl_id4trans}); + my $uri = "/$users_dms->{fullurl}/$users_dms->{kind_of_trans}"; + print $q->div({-id=>'Headerlogin',-style=>"background-color:$varenv->{term_active_color};"},$q->a({-class=>'elinkbutton1',-title=>"$users_dms->{kind_of_trans} Terminal öffnen",-href=>"$uri?ct_trans=open\&c_id4trans=$users_dms->{c_id4trans}\&tpl_id4trans=$users_dms->{tpl_id4trans}\&kind_of_trans=$users_dms->{kind_of_trans}\&owner=$users_dms->{owner}\&offset=$offset\&limit=$limit\&relids=$R::relids\&no_redirect=1"}," $users_dms->{kind_of_trans} \#$ctrel->{ct_name} $ctrel->{txt01}", $q->span({-id=>"c_id4trans", -style=>"color:$varenv->{term_active_color}"}, "$users_dms->{c_id4trans}"))) if($ctrel->{ct_name}); + } + + print $q->div({-id=>'Headerlogin'},"$users_sharee->{txt08} ", $q->span({-id=>"owner", -style=>"color:silver"}, "($users_dms->{u_id})")),"\n"; + print $q->div({-id=>'Headerlogin'},$q->a({-href=>"logout"},$q->img({-style=>'padding:0px 10px;',-src=>"$varenv->{metahost}/img/logout.svg"}))),"\n"; + print "
    "; + print "
    "; + } + #end user panel + ###header end + + + #Mainlogin + if(!$users_dms->{u_id}){ + + print "
    \n"; + + print $q->start_multipart_form(-id=>'authform', -name=>'loginscreen'),"\n"; + print $q->hidden(-name=>"sessionid",-override=>1,-value=>"$R::sessionid"); + + print "
    \n"; + #Login + print $q->div({-class=>'content2'}, "Zugang zum $title"),"\n"; + print $q->div({-style=>'color:#c83434'},"Login failure"),"\n" if("$R::login_dms" eq "Login" && !$users_dms->{u_id}); + print $q->label({-for=>'Userid'},""),"\n"; + print $q->textfield(-class=>'form-control', -name=>'user_id', -value=>'', -override=>1, -type=>'email',-class=>'form-control', -id=>'Userid', -placeholder=>'NutzerIn', -required=>1, -autofocus=>1),"\n"; + print $q->label({-for=>'PW'},""),"\n"; + print $q->password_field(-class=>'form-control', -name=>'user_pw', -value=>'', -override=>1, -type=>'password',-class=>'form-control', -id=>'PW', -placeholder=>'Passwort', -required=>1),"\n"; + print $q->div({-style=>'margin-top:1em;'},""),"\n"; + + print "
    \n"; + print $q->end_form,"\n"; + print "
    "; + + exit 0; + } + + if($users_dms->{u_id} && $main_id){ + $return = $lb->return_feedback($return,$users_dms->{kind_of_trans},$users_dms->{owner}) if($return !~ /shareejson/); + + if($main_id >= "100000"){ + my $mstyle=""; + + ###Top Menu + #bootstrap menue + print "\n"; + ###end bootstrap menue + + #node_name=DMS + if($varenv->{dbname} eq "sharee_primary" && $main_id == "100002"){ + my $big2menu=""; + while (my ($key, $value) = each %{ $dbt->{operator} }) { + if($value->{operatorApp}){ + $big2menu .= $but->lia_button("$value->{operatorDMS}","$key","","","",""); + } + } + print $q->div({-style=>'width:100%;margin:0;padding-top:90px;color:white;'}, "sharee.bike Operatoren"),"\n"; + print $q->div({-style=>'width:100%;margin:0;'}, $q->ul({-id=>'BigNavi'},$big2menu)),"\n"; + } + + print "
    \n"; + #lefsitemenue disabled 2021-06.03 + print "
    \n"; + + + $debug = "(c_id4trans:$users_dms->{c_id4trans} && tpl_id4trans:$users_dms->{tpl_id4trans} && kind_of_trans:$users_dms->{kind_of_trans}) $node_meta->{tpl_name},$node_meta->{tpl_id},$node_meta->{ct_table},$parent_id,$main_id, permissions: ($users_dms->{int01},$users_dms->{int02},$users_dms->{int03},$users_dms->{int07},$users_dms->{int08},$users_dms->{int09})" if($users_dms->{u_id} == $dbt->{copri_conf}->{superu_id}); + print $q->div({-style=>'position:fixed;bottom:0%;right:1%;z-index:10;padding:2px;font-size:13px;'},"$debug",$q->a({-style=>'color:black;text-decoration: none;',-href=>'https://sharee.bike',-target=>'_blank'},"sharee.bike © TeilRad GmbH 2021")),"\n"; + + +#update c_id4trans on changing browser tab 2019-10-08 +#FIXME, we need all $R::c_id4trans,$R::tpl_id4trans,$R::kind_of_trans +if(1==2 && $mode eq "manager"){ +print< + +function postc_id4trans(c_val,o_val) { + \$.ajax({ + url: '$varenv->{wwwhost}/ajax_post', + type: 'POST', + async: true, + cache: false, + data: { c_id4trans: c_val, owner: o_val }, + }); +} + +document.addEventListener('visibilitychange', function () { + if(document.visibilityState != 'hidden') { + var c_id4trans = document.getElementById("c_id4trans").innerText; + var owner = document.getElementById("owner").innerText; + if(c_id4trans){ + postc_id4trans(c_id4trans,owner); + } + console.log("postc_id4trans:" + c_id4trans + " " + owner); + } +}, false); + + + +EOF +; +} + + $self->tplselect($node_meta,$users_dms,$mode,$varenv,$return); + print "\n"; + }#end logedin environment + +} + +#2021-05-05 changed to Mlogic +sub tplselect(){ + my $self = shift; + my $node_meta = shift; + my $users_dms = shift; + my $mode = shift || ""; + my $varenv = shift; + my $return = shift || ""; + + my $sort = ""; + my $lang = "de"; + my $tpl_name = $node_meta->{tpl_name}; + my $tpl_id = $node_meta->{tpl_id}; + my $ct_table = $node_meta->{ct_table}; + my $parent_id = $node_meta->{parent_id}; + my $main_id = $node_meta->{main_id}; + my $u_id = $users_dms->{u_id}; + #print Dumper($node_meta); + #exit; + +print < + \$(function(){ + \$('.autos').autosize({append: '\\n'}); + }); + +EOF +; + + if($mode eq "supervisor" || $node_meta->{tpl_name} eq "AttributMatrix"){ + $tpl_name = "AttributMatrix"; + require "Tpl/AttributMatrix.pm"; + $return = &AttributMatrix::tpl($node_meta,$users_dms,$mode,$return); + #}elsif($tpl_id && $tpl_id >= 400 && $tpl_id <= 699){#contentpos or contentadrpos + }elsif($node_meta->{ct_table} =~ /contentpos|contentadrpos|users$/){#contentpos or contentadrpos + require "Tpl/SubListe.pm"; + $return = &SubListe::tpl($node_meta,$users_dms,$mode,$return); + }elsif($node_meta->{ct_table} =~ /content$|contentadr$|contenttrans$/){ + require "Tpl/Liste3.pm"; + $return = &Liste3::tpl($node_meta,$users_dms,$mode,$return); + }elsif($node_meta->{ct_table} eq "contentuser"){ + require "Tpl/MandantConf.pm"; + $return = &MandantConf::tpl($node_meta,$users_dms,$mode,$return); + #}elsif($tpl_name =~ /Statistik/){ + #require "Tpl/Statistik.pm"; + #&Statistik::tpl($main_id,$u_id,$lang,"","",$sort); + }elsif($node_meta->{ct_table} =~ /contenttranspos|contenttheftpos/){ + require "Tpl/Calorin.pm"; + &Calorin::tpl($node_meta,$users_dms,$mode,$return); + } +##Modalbox things## + if($return !~ /failure/){ + if(($R::ct_trans !~ /close/) && ($ct_table =~ /contenttrans/ || $R::kind_of_trans =~ /Faktur|Verleih/) && ($R::ct_trans || $R::trans2edit || $R::ctpos_activ || $R::select_part || $R::set_main_id)){ + &Modalbox::mobox($node_meta,$users_dms,$mode,$return); + }elsif(($R::ct_trans !~ /close/) && ($ct_table =~ /content$|contentadr|contenttver|contentpos|users$/ && ($R::ct_trans || $R::rel_edit || $R::base_edit)) || ($R::node2edit && $R::node2edit =~ /edit/)){ + &Modalbox3::mobox3($node_meta,$users_dms,$mode,$return) if($R::rel_edit !~ /delete|save/ && $R::ct_trans !~ /delete/ && $R::base_edit !~ /delete|save/ && !$R::service_id); + } + } + + if($return =~ /failure/){ + require "Mod/Failure.pm"; + &Failure::tpl("",$u_id,"","","","",$return); + } +} + +1; + + diff --git a/copri4/shareedms-operator/src/Lib/PDFGenerator.pm b/copri4/shareedms-operator/src/Lib/PDFGenerator.pm new file mode 120000 index 0000000..1bebb95 --- /dev/null +++ b/copri4/shareedms-operator/src/Lib/PDFGenerator.pm @@ -0,0 +1 @@ +../../../main/src/Lib/PDFGenerator.pm \ No newline at end of file diff --git a/copri4/shareedms-operator/src/Lib/Printpreview.pm b/copri4/shareedms-operator/src/Lib/Printpreview.pm new file mode 120000 index 0000000..5485ff7 --- /dev/null +++ b/copri4/shareedms-operator/src/Lib/Printpreview.pm @@ -0,0 +1 @@ +../../../main/src/Lib/Printpreview.pm \ No newline at end of file diff --git a/copri4/shareedms-operator/src/Mod b/copri4/shareedms-operator/src/Mod new file mode 120000 index 0000000..d4b7ba5 --- /dev/null +++ b/copri4/shareedms-operator/src/Mod @@ -0,0 +1 @@ +../../main/src/Mod \ No newline at end of file diff --git a/copri4/shareedms-operator/src/Tpl b/copri4/shareedms-operator/src/Tpl new file mode 120000 index 0000000..61cf65a --- /dev/null +++ b/copri4/shareedms-operator/src/Tpl @@ -0,0 +1 @@ +../../main/src/Tpl \ No newline at end of file diff --git a/copri4/shareedms-operator/src/scripts b/copri4/shareedms-operator/src/scripts new file mode 120000 index 0000000..8705f56 --- /dev/null +++ b/copri4/shareedms-operator/src/scripts @@ -0,0 +1 @@ +../../main/src/scripts \ No newline at end of file diff --git a/copri4/shareedms-operator/src/wkhtmltopdf-amd64 b/copri4/shareedms-operator/src/wkhtmltopdf-amd64 new file mode 120000 index 0000000..2e6c34b --- /dev/null +++ b/copri4/shareedms-operator/src/wkhtmltopdf-amd64 @@ -0,0 +1 @@ +../../main/src/wkhtmltopdf-amd64 \ No newline at end of file diff --git a/copri4/shareedms-operator/startup.pl b/copri4/shareedms-operator/startup.pl new file mode 100755 index 0000000..74344fb --- /dev/null +++ b/copri4/shareedms-operator/startup.pl @@ -0,0 +1,2 @@ +use lib qw(/var/www/copri4/shareedms-operator/src); +1; diff --git a/copri4/shareeweb-project/apache/index.html b/copri4/shareeweb-project/apache/index.html new file mode 100644 index 0000000..d8964f8 --- /dev/null +++ b/copri4/shareeweb-project/apache/index.html @@ -0,0 +1,35 @@ + + + + + iFrame message passing test + + + + + +
    +
    Lastenrad Bayern
    + + + +
    Registrieren + +
    + + + + + + + + + + + +
    + + diff --git a/copri4/shareeweb-project/apache/shareeweb-operator.conf b/copri4/shareeweb-project/apache/shareeweb-operator.conf new file mode 120000 index 0000000..3706f94 --- /dev/null +++ b/copri4/shareeweb-project/apache/shareeweb-operator.conf @@ -0,0 +1 @@ +shareeweb-operator_devel.conf \ No newline at end of file diff --git a/copri4/shareeweb-project/apache/shareeweb-operator_devel.conf b/copri4/shareeweb-project/apache/shareeweb-operator_devel.conf new file mode 100644 index 0000000..45a41ec --- /dev/null +++ b/copri4/shareeweb-project/apache/shareeweb-operator_devel.conf @@ -0,0 +1,114 @@ + + ServerName shareeweb-project.copri-bike.de + ServerAlias shareeweb-project1.copri-bike.de + + ServerAdmin info@gnu-systems.de + DocumentRoot /var/www/copri4/shareeweb-project + + ErrorLog /var/log/apache2/shareeweb-project-error.log + LogLevel info ssl:warn + CustomLog /var/log/apache2/shareeweb-project-access.log combined + ServerSignature Off + RewriteEngine on + RewriteCond %{SERVER_NAME} =shareeweb-project.copri-bike.de + RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent] + + + + + ServerName shareeweb-project1.copri-bike.de + + ServerAdmin info@gnu-systems.de + DocumentRoot /var/www/copri4/shareeweb-project + AddHandler cgi-script .cgi .sh .pl + + + Options -Indexes +FollowSymLinks +ExecCGI + AllowOverride None + + + + Header set Access-Control-Allow-Origin "copri-bike.de" + + + + Options -Indexes +FollowSymLinks -ExecCGI + Order allow,deny + Allow from all + + + + Options -Indexes +FollowSymLinks + Order allow,deny + Allow from all + ForceType application/octet-stream + Header set Content-Disposition attachment + + + ErrorLog /var/log/apache2/shareeweb-project-error.log + LogLevel info ssl:warn + CustomLog /var/log/apache2/shareeweb-project-access.log combined + ServerSignature Off +Include /etc/letsencrypt/options-ssl-apache.conf + +SSLCertificateFile /etc/letsencrypt/live/copri-bike.de-0003/fullchain.pem +SSLCertificateKeyFile /etc/letsencrypt/live/copri-bike.de-0003/privkey.pem + + + + + ServerName shareeweb-project.copri-bike.de + + ServerAdmin info@gnu-systems.de + DocumentRoot /var/www/copri4/shareeweb-project + + PerlOptions +Parent + PerlRequire /var/www/copri4/shareeweb-project/startup.pl + + + SetHandler perl-script + PerlResponseHandler Mod::Indexsharee + PerlInitHandler Apache2::Reload + PerlOptions +ParseHeaders +GlobalRequest + Options -ExecCGI +FollowSymLinks + Order allow,deny + Allow from all + + + + SetHandler perl-script + PerlInitHandler Apache2::Reload + PerlResponseHandler Mod::APIvelo + + + + SetHandler perl-script + PerlInitHandler Apache2::Reload + PerlResponseHandler Mod::APIjsonserver + + + + SetHandler perl-script + PerlInitHandler Apache2::Reload + PerlResponseHandler Mod::FileOut + + + + RewriteEngine On + RedirectMatch ^/$ /frame/Karte + SSLProxyEngine On + RewriteCond %{REQUEST_URI} ^/(site|img|data|css|js|jquery) + RewriteRule ^(.*)$ https://shareeweb-project1.copri-bike.de/$1 [P,L] + + + ErrorLog /var/log/apache2/shareeweb-project-error.log + LogLevel info ssl:warn + CustomLog /var/log/apache2/shareeweb-project-access.log combined + ServerSignature Off +Include /etc/letsencrypt/options-ssl-apache.conf +SSLCertificateFile /etc/letsencrypt/live/copri-bike.de-0003/fullchain.pem +SSLCertificateKeyFile /etc/letsencrypt/live/copri-bike.de-0003/privkey.pem + + + + diff --git a/copri4/shareeweb-project/css b/copri4/shareeweb-project/css new file mode 120000 index 0000000..7e8b615 --- /dev/null +++ b/copri4/shareeweb-project/css @@ -0,0 +1 @@ +../shareeapp-operator/css \ No newline at end of file diff --git a/copri4/shareeweb-project/glyphicons b/copri4/shareeweb-project/glyphicons new file mode 120000 index 0000000..7393fbd --- /dev/null +++ b/copri4/shareeweb-project/glyphicons @@ -0,0 +1 @@ +../main/glyphicons \ No newline at end of file diff --git a/copri4/shareeweb-project/img b/copri4/shareeweb-project/img new file mode 120000 index 0000000..39564ce --- /dev/null +++ b/copri4/shareeweb-project/img @@ -0,0 +1 @@ +../main/img \ No newline at end of file diff --git a/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/css/bootstrap.css b/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/css/bootstrap.css new file mode 100644 index 0000000..7caee93 --- /dev/null +++ b/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/css/bootstrap.css @@ -0,0 +1,6760 @@ +/*! + * Bootstrap v3.3.6 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ +html { + font-family: sans-serif; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +body { + margin: 0; +} +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; +} +audio, +canvas, +progress, +video { + display: inline-block; + vertical-align: baseline; +} +audio:not([controls]) { + display: none; + height: 0; +} +[hidden], +template { + display: none; +} +a { + background-color: transparent; +} +a:active, +a:hover { + outline: 0; +} +abbr[title] { + border-bottom: 1px dotted; +} +b, +strong { + font-weight: bold; +} +dfn { + font-style: italic; +} +h1 { + margin: .67em 0; + font-size: 2em; +} +mark { + color: #000; + background: #ff0; +} +small { + font-size: 80%; +} +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -.5em; +} +sub { + bottom: -.25em; +} +img { + border: 0; +} +svg:not(:root) { + overflow: hidden; +} +figure { + margin: 1em 40px; +} +hr { + height: 0; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +pre { + overflow: auto; +} +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} +button, +input, +optgroup, +select, +textarea { + margin: 0; + font: inherit; + color: inherit; +} +button { + overflow: visible; +} +button, +select { + text-transform: none; +} +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; + cursor: pointer; +} +button[disabled], +html input[disabled] { + cursor: default; +} +button::-moz-focus-inner, +input::-moz-focus-inner { + padding: 0; + border: 0; +} +input { + line-height: normal; +} +input[type="checkbox"], +input[type="radio"] { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + padding: 0; +} +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} +input[type="search"] { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + -webkit-appearance: textfield; +} +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +fieldset { + padding: .35em .625em .75em; + margin: 0 2px; + border: 1px solid #c0c0c0; +} +legend { + padding: 0; + border: 0; +} +textarea { + overflow: auto; +} +optgroup { + font-weight: bold; +} +table { + border-spacing: 0; + border-collapse: collapse; +} +td, +th { + padding: 0; +} +/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */ +@media print { + *, + *:before, + *:after { + color: #000 !important; + text-shadow: none !important; + background: transparent !important; + -webkit-box-shadow: none !important; + box-shadow: none !important; + } + a, + a:visited { + text-decoration: underline; + } + a[href]:after { + content: " (" attr(href) ")"; + } + abbr[title]:after { + content: " (" attr(title) ")"; + } + a[href^="#"]:after, + a[href^="javascript:"]:after { + content: ""; + } + pre, + blockquote { + border: 1px solid #999; + + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + img { + max-width: 100% !important; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } + .navbar { + display: none; + } + .btn > .caret, + .dropup > .btn > .caret { + border-top-color: #000 !important; + } + .label { + border: 1px solid #000; + } + .table { + border-collapse: collapse !important; + } + .table td, + .table th { + background-color: #fff !important; + } + .table-bordered th, + .table-bordered td { + border: 1px solid #ddd !important; + } +} +@font-face { + font-family: 'Glyphicons Halflings'; + + src: url('../fonts/glyphicons-halflings-regular.eot'); + src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); +} +.glyphicon { + position: relative; + top: 1px; + display: inline-block; + font-family: 'Glyphicons Halflings'; + font-style: normal; + font-weight: normal; + line-height: 1; + + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.glyphicon-asterisk:before { + content: "\002a"; +} +.glyphicon-plus:before { + content: "\002b"; +} +.glyphicon-euro:before, +.glyphicon-eur:before { + content: "\20ac"; +} +.glyphicon-minus:before { + content: "\2212"; +} +.glyphicon-cloud:before { + content: "\2601"; +} +.glyphicon-envelope:before { + content: "\2709"; +} +.glyphicon-pencil:before { + content: "\270f"; +} +.glyphicon-glass:before { + content: "\e001"; +} +.glyphicon-music:before { + content: "\e002"; +} +.glyphicon-search:before { + content: "\e003"; +} +.glyphicon-heart:before { + content: "\e005"; +} +.glyphicon-star:before { + content: "\e006"; +} +.glyphicon-star-empty:before { + content: "\e007"; +} +.glyphicon-user:before { + content: "\e008"; +} +.glyphicon-film:before { + content: "\e009"; +} +.glyphicon-th-large:before { + content: "\e010"; +} +.glyphicon-th:before { + content: "\e011"; +} +.glyphicon-th-list:before { + content: "\e012"; +} +.glyphicon-ok:before { + content: "\e013"; +} +.glyphicon-remove:before { + content: "\e014"; +} +.glyphicon-zoom-in:before { + content: "\e015"; +} +.glyphicon-zoom-out:before { + content: "\e016"; +} +.glyphicon-off:before { + content: "\e017"; +} +.glyphicon-signal:before { + content: "\e018"; +} +.glyphicon-cog:before { + content: "\e019"; +} +.glyphicon-trash:before { + content: "\e020"; +} +.glyphicon-home:before { + content: "\e021"; +} +.glyphicon-file:before { + content: "\e022"; +} +.glyphicon-time:before { + content: "\e023"; +} +.glyphicon-road:before { + content: "\e024"; +} +.glyphicon-download-alt:before { + content: "\e025"; +} +.glyphicon-download:before { + content: "\e026"; +} +.glyphicon-upload:before { + content: "\e027"; +} +.glyphicon-inbox:before { + content: "\e028"; +} +.glyphicon-play-circle:before { + content: "\e029"; +} +.glyphicon-repeat:before { + content: "\e030"; +} +.glyphicon-refresh:before { + content: "\e031"; +} +.glyphicon-list-alt:before { + content: "\e032"; +} +.glyphicon-lock:before { + content: "\e033"; +} +.glyphicon-flag:before { + content: "\e034"; +} +.glyphicon-headphones:before { + content: "\e036595"; +} +.glyphicon-volume-off:before { + content: "\e036"; +} +.glyphicon-volume-down:before { + content: "\e037"; +} +.glyphicon-volume-up:before { + content: "\e038"; +} +.glyphicon-qrcode:before { + content: "\e039"; +} +.glyphicon-barcode:before { + content: "\e040"; +} +.glyphicon-tag:before { + content: "\e041"; +} +.glyphicon-tags:before { + content: "\e042"; +} +.glyphicon-book:before { + content: "\e043"; +} +.glyphicon-bookmark:before { + content: "\e044"; +} +.glyphicon-print:before { + content: "\e045"; +} +.glyphicon-camera:before { + content: "\e046"; +} +.glyphicon-font:before { + content: "\e047"; +} +.glyphicon-bold:before { + content: "\e048"; +} +.glyphicon-italic:before { + content: "\e049"; +} +.glyphicon-text-height:before { + content: "\e050"; +} +.glyphicon-text-width:before { + content: "\e051"; +} +.glyphicon-align-left:before { + content: "\e052"; +} +.glyphicon-align-center:before { + content: "\e053"; +} +.glyphicon-align-right:before { + content: "\e054"; +} +.glyphicon-align-justify:before { + content: "\e055"; +} +.glyphicon-list:before { + content: "\e056"; +} +.glyphicon-indent-left:before { + content: "\e057"; +} +.glyphicon-indent-right:before { + content: "\e058"; +} +.glyphicon-facetime-video:before { + content: "\e059"; +} +.glyphicon-picture:before { + content: "\e060"; +} +.glyphicon-map-marker:before { + content: "\e062"; +} +.glyphicon-adjust:before { + content: "\e063"; +} +.glyphicon-tint:before { + content: "\e064"; +} +.glyphicon-edit:before { + content: "\e065"; +} +.glyphicon-share:before { + content: "\e066"; +} +.glyphicon-check:before { + content: "\e067"; +} +.glyphicon-move:before { + content: "\e068"; +} +.glyphicon-step-backward:before { + content: "\e069"; +} +.glyphicon-fast-backward:before { + content: "\e070"; +} +.glyphicon-backward:before { + content: "\e071"; +} +.glyphicon-play:before { + content: "\e072"; +} +.glyphicon-pause:before { + content: "\e073"; +} +.glyphicon-stop:before { + content: "\e074"; +} +.glyphicon-forward:before { + content: "\e075"; +} +.glyphicon-fast-forward:before { + content: "\e076"; +} +.glyphicon-step-forward:before { + content: "\e077"; +} +.glyphicon-eject:before { + content: "\e078"; +} +.glyphicon-chevron-left:before { + content: "\e079"; +} +.glyphicon-chevron-right:before { + content: "\e080"; +} +.glyphicon-plus-sign:before { + content: "\e081"; +} +.glyphicon-minus-sign:before { + content: "\e082"; +} +.glyphicon-remove-sign:before { + content: "\e083"; +} +.glyphicon-ok-sign:before { + content: "\e084"; +} +.glyphicon-question-sign:before { + content: "\e085"; +} +.glyphicon-info-sign:before { + content: "\e086"; +} +.glyphicon-screenshot:before { + content: "\e087"; +} +.glyphicon-remove-circle:before { + content: "\e088"; +} +.glyphicon-ok-circle:before { + content: "\e089"; +} +.glyphicon-ban-circle:before { + content: "\e090"; +} +.glyphicon-arrow-left:before { + content: "\e091"; +} +.glyphicon-arrow-right:before { + content: "\e092"; +} +.glyphicon-arrow-up:before { + content: "\e093"; +} +.glyphicon-arrow-down:before { + content: "\e094"; +} +.glyphicon-share-alt:before { + content: "\e095"; +} +.glyphicon-resize-full:before { + content: "\e096"; +} +.glyphicon-resize-small:before { + content: "\e097"; +} +.glyphicon-exclamation-sign:before { + content: "\e101"; +} +.glyphicon-gift:before { + content: "\e102"; +} +.glyphicon-leaf:before { + content: "\e103"; +} +.glyphicon-fire:before { + content: "\e104"; +} +.glyphicon-eye-open:before { + content: "\e105"; +} +.glyphicon-eye-close:before { + content: "\e106"; +} +.glyphicon-warning-sign:before { + content: "\e107"; +} +.glyphicon-plane:before { + content: "\e108"; +} +.glyphicon-calendar:before { + content: "\e109"; +} +.glyphicon-random:before { + content: "\e110"; +} +.glyphicon-comment:before { + content: "\e111"; +} +.glyphicon-magnet:before { + content: "\e112"; +} +.glyphicon-chevron-up:before { + content: "\e113"; +} +.glyphicon-chevron-down:before { + content: "\e114"; +} +.glyphicon-retweet:before { + content: "\e115"; +} +.glyphicon-shopping-cart:before { + content: "\e116"; +} +.glyphicon-folder-close:before { + content: "\e117"; +} +.glyphicon-folder-open:before { + content: "\e118"; +} +.glyphicon-resize-vertical:before { + content: "\e119"; +} +.glyphicon-resize-horizontal:before { + content: "\e120"; +} +.glyphicon-hdd:before { + content: "\e121"; +} +.glyphicon-bullhorn:before { + content: "\e122"; +} +.glyphicon-bell:before { + content: "\e123"; +} +.glyphicon-certificate:before { + content: "\e124"; +} +.glyphicon-thumbs-up:before { + content: "\e125"; +} +.glyphicon-thumbs-down:before { + content: "\e126"; +} +.glyphicon-hand-right:before { + content: "\e127"; +} +.glyphicon-hand-left:before { + content: "\e128"; +} +.glyphicon-hand-up:before { + content: "\e129"; +} +.glyphicon-hand-down:before { + content: "\e130"; +} +.glyphicon-circle-arrow-right:before { + content: "\e131"; +} +.glyphicon-circle-arrow-left:before { + content: "\e132"; +} +.glyphicon-circle-arrow-up:before { + content: "\e133"; +} +.glyphicon-circle-arrow-down:before { + content: "\e134"; +} +.glyphicon-globe:before { + content: "\e135"; +} +.glyphicon-wrench:before { + content: "\e136"; +} +.glyphicon-tasks:before { + content: "\e137"; +} +.glyphicon-filter:before { + content: "\e138"; +} +.glyphicon-briefcase:before { + content: "\e139"; +} +.glyphicon-fullscreen:before { + content: "\e140"; +} +.glyphicon-dashboard:before { + content: "\e141"; +} +.glyphicon-paperclip:before { + content: "\e142"; +} +.glyphicon-heart-empty:before { + content: "\e143"; +} +.glyphicon-link:before { + content: "\e144"; +} +.glyphicon-phone:before { + content: "\e145"; +} +.glyphicon-pushpin:before { + content: "\e146"; +} +.glyphicon-usd:before { + content: "\e148"; +} +.glyphicon-gbp:before { + content: "\e149"; +} +.glyphicon-sort:before { + content: "\e150"; +} +.glyphicon-sort-by-alphabet:before { + content: "\e151"; +} +.glyphicon-sort-by-alphabet-alt:before { + content: "\e152"; +} +.glyphicon-sort-by-order:before { + content: "\e153"; +} +.glyphicon-sort-by-order-alt:before { + content: "\e154"; +} +.glyphicon-sort-by-attributes:before { + content: "\e155"; +} +.glyphicon-sort-by-attributes-alt:before { + content: "\e156"; +} +.glyphicon-unchecked:before { + content: "\e157"; +} +.glyphicon-expand:before { + content: "\e158"; +} +.glyphicon-collapse-down:before { + content: "\e159"; +} +.glyphicon-collapse-up:before { + content: "\e160"; +} +.glyphicon-log-in:before { + content: "\e161"; +} +.glyphicon-flash:before { + content: "\e162"; +} +.glyphicon-log-out:before { + content: "\e163"; +} +.glyphicon-new-window:before { + content: "\e164"; +} +.glyphicon-record:before { + content: "\e165"; +} +.glyphicon-save:before { + content: "\e166"; +} +.glyphicon-open:before { + content: "\e167"; +} +.glyphicon-saved:before { + content: "\e168"; +} +.glyphicon-import:before { + content: "\e169"; +} +.glyphicon-export:before { + content: "\e170"; +} +.glyphicon-send:before { + content: "\e171"; +} +.glyphicon-floppy-disk:before { + content: "\e172"; +} +.glyphicon-floppy-saved:before { + content: "\e173"; +} +.glyphicon-floppy-remove:before { + content: "\e174"; +} +.glyphicon-floppy-save:before { + content: "\e175"; +} +.glyphicon-floppy-open:before { + content: "\e176"; +} +.glyphicon-credit-card:before { + content: "\e177"; +} +.glyphicon-transfer:before { + content: "\e178"; +} +.glyphicon-cutlery:before { + content: "\e179"; +} +.glyphicon-header:before { + content: "\e180"; +} +.glyphicon-compressed:before { + content: "\e181"; +} +.glyphicon-earphone:before { + content: "\e182"; +} +.glyphicon-phone-alt:before { + content: "\e183"; +} +.glyphicon-tower:before { + content: "\e184"; +} +.glyphicon-stats:before { + content: "\e185"; +} +.glyphicon-sd-video:before { + content: "\e186"; +} +.glyphicon-hd-video:before { + content: "\e187"; +} +.glyphicon-subtitles:before { + content: "\e188"; +} +.glyphicon-sound-stereo:before { + content: "\e189"; +} +.glyphicon-sound-dolby:before { + content: "\e190"; +} +.glyphicon-sound-5-1:before { + content: "\e191"; +} +.glyphicon-sound-6-1:before { + content: "\e192"; +} +.glyphicon-sound-7-1:before { + content: "\e193"; +} +.glyphicon-copyright-mark:before { + content: "\e194"; +} +.glyphicon-registration-mark:before { + content: "\e195"; +} +.glyphicon-cloud-download:before { + content: "\e197"; +} +.glyphicon-cloud-upload:before { + content: "\e198"; +} +.glyphicon-tree-conifer:before { + content: "\e199"; +} +.glyphicon-tree-deciduous:before { + content: "\e200"; +} +.glyphicon-cd:before { + content: "\e201"; +} +.glyphicon-save-file:before { + content: "\e202"; +} +.glyphicon-open-file:before { + content: "\e203"; +} +.glyphicon-level-up:before { + content: "\e204"; +} +.glyphicon-copy:before { + content: "\e205"; +} +.glyphicon-paste:before { + content: "\e206"; +} +.glyphicon-alert:before { + content: "\e209"; +} +.glyphicon-equalizer:before { + content: "\e210"; +} +.glyphicon-king:before { + content: "\e211"; +} +.glyphicon-queen:before { + content: "\e212"; +} +.glyphicon-pawn:before { + content: "\e213"; +} +.glyphicon-bishop:before { + content: "\e214"; +} +.glyphicon-knight:before { + content: "\e215"; +} +.glyphicon-baby-formula:before { + content: "\e216"; +} +.glyphicon-tent:before { + content: "\26fa"; +} +.glyphicon-blackboard:before { + content: "\e218"; +} +.glyphicon-bed:before { + content: "\e219"; +} +.glyphicon-apple:before { + content: "\f8ff"; +} +.glyphicon-erase:before { + content: "\e221"; +} +.glyphicon-hourglass:before { + content: "\231b"; +} +.glyphicon-lamp:before { + content: "\e223"; +} +.glyphicon-duplicate:before { + content: "\e224"; +} +.glyphicon-piggy-bank:before { + content: "\e225"; +} +.glyphicon-scissors:before { + content: "\e226"; +} +.glyphicon-bitcoin:before { + content: "\e227"; +} +.glyphicon-btc:before { + content: "\e227"; +} +.glyphicon-xbt:before { + content: "\e227"; +} +.glyphicon-yen:before { + content: "\00a5"; +} +.glyphicon-jpy:before { + content: "\00a5"; +} +.glyphicon-ruble:before { + content: "\20bd"; +} +.glyphicon-rub:before { + content: "\20bd"; +} +.glyphicon-scale:before { + content: "\e230"; +} +.glyphicon-ice-lolly:before { + content: "\e231"; +} +.glyphicon-ice-lolly-tasted:before { + content: "\e232"; +} +.glyphicon-education:before { + content: "\e233"; +} +.glyphicon-option-horizontal:before { + content: "\e234"; +} +.glyphicon-option-vertical:before { + content: "\e235"; +} +.glyphicon-menu-hamburger:before { + content: "\e236"; +} +.glyphicon-modal-window:before { + content: "\e237"; +} +.glyphicon-oil:before { + content: "\e238"; +} +.glyphicon-grain:before { + content: "\e239"; +} +.glyphicon-sunglasses:before { + content: "\e240"; +} +.glyphicon-text-size:before { + content: "\e241"; +} +.glyphicon-text-color:before { + content: "\e242"; +} +.glyphicon-text-background:before { + content: "\e243"; +} +.glyphicon-object-align-top:before { + content: "\e244"; +} +.glyphicon-object-align-bottom:before { + content: "\e245"; +} +.glyphicon-object-align-horizontal:before { + content: "\e246"; +} +.glyphicon-object-align-left:before { + content: "\e247"; +} +.glyphicon-object-align-vertical:before { + content: "\e248"; +} +.glyphicon-object-align-right:before { + content: "\e249"; +} +.glyphicon-triangle-right:before { + content: "\e250"; +} +.glyphicon-triangle-left:before { + content: "\e251"; +} +.glyphicon-triangle-bottom:before { + content: "\e252"; +} +.glyphicon-triangle-top:before { + content: "\e253"; +} +.glyphicon-console:before { + content: "\e254"; +} +.glyphicon-superscript:before { + content: "\e255"; +} +.glyphicon-subscript:before { + content: "\e256"; +} +.glyphicon-menu-left:before { + content: "\e257"; +} +.glyphicon-menu-right:before { + content: "\e258"; +} +.glyphicon-menu-down:before { + content: "\e259"; +} +.glyphicon-menu-up:before { + content: "\e260"; +} +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +*:before, +*:after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +html { + font-size: 10px; + + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} +body { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 1.42857143; + color: #008dd2; + background-color: #008dd2; +} +input, +button, +select, +textarea { + font-family: inherit; + font-size: inherit; + line-height: inherit; +} +a { + color: #008dd2; + text-decoration: none; +} +a:hover, +a:focus { + color: #036595; + text-decoration: underline; +} +a:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +figure { + margin: 0; +} +img { + vertical-align: middle; +} +.img-responsive, +.thumbnail > img, +.thumbnail a > img, +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + display: block; + max-width: 100%; + height: auto; +} +.img-rounded { + border-radius: 0; +} +.img-thumbnail { + display: inline-block; + max-width: 100%; + height: auto; + padding: 4px; + line-height: 1.42857143; + background-color: #008dd2; + border: 1px solid #ddd; + border-radius: 0; + -webkit-transition: all .2s ease-in-out; + -o-transition: all .2s ease-in-out; + transition: all .2s ease-in-out; +} +.img-circle { + border-radius: 50%; +} +hr { + margin-top: 20px; + margin-bottom: 20px; + border: 0; + border-top: 1px solid #008dd2; +} +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; +} +.sr-only-focusable:active, +.sr-only-focusable:focus { + position: static; + width: auto; + height: auto; + margin: 0; + overflow: visible; + clip: auto; +} +[role="button"] { + cursor: pointer; +} +h1, +h2, +h3, +h4, +h5, +h6, +.h1, +.h2, +.h3, +.h4, +.h5, +.h6 { + font-family: inherit; + font-weight: 500; + line-height: 1.1; + color: inherit; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small, +.h1 small, +.h2 small, +.h3 small, +.h4 small, +.h5 small, +.h6 small, +h1 .small, +h2 .small, +h3 .small, +h4 .small, +h5 .small, +h6 .small, +.h1 .small, +.h2 .small, +.h3 .small, +.h4 .small, +.h5 .small, +.h6 .small { + font-weight: normal; + line-height: 1; + color: #008dd2; +} +h1, +.h1, +h2, +.h2, +h3, +.h3 { + margin-top: 20px; + margin-bottom: 10px; +} +h1 small, +.h1 small, +h2 small, +.h2 small, +h3 small, +.h3 small, +h1 .small, +.h1 .small, +h2 .small, +.h2 .small, +h3 .small, +.h3 .small { + font-size: 65%; +} +h4, +.h4, +h5, +.h5, +h6, +.h6 { + margin-top: 10px; + margin-bottom: 10px; +} +h4 small, +.h4 small, +h5 small, +.h5 small, +h6 small, +.h6 small, +h4 .small, +.h4 .small, +h5 .small, +.h5 .small, +h6 .small, +.h6 .small { + font-size: 75%; +} +h1, +.h1 { + font-size: 36px; +} +h2, +.h2 { + font-size: 30px; +} +h3, +.h3 { + font-size: 24px; +} +h4, +.h4 { + font-size: 18px; +} +h5, +.h5 { + font-size: 14px; +} +h6, +.h6 { + font-size: 12px; +} +p { + margin: 0 0 10px; +} +.lead { + margin-bottom: 20px; + font-size: 16px; + font-weight: 300; + line-height: 1.4; +} +@media (min-width: 768px) { + .lead { + font-size: 21px; + } +} +small, +.small { + font-size: 85%; +} +mark, +.mark { + padding: .2em; + background-color: #fcf8e3; +} +.text-left { + text-align: left; +} +.text-right { + text-align: right; +} +.text-center { + text-align: center; +} +.text-justify { + text-align: justify; +} +.text-nowrap { + white-space: nowrap; +} +.text-lowercase { + text-transform: lowercase; +} +.text-uppercase { + text-transform: uppercase; +} +.text-capitalize { + text-transform: capitalize; +} +.text-muted { + color: #008dd2; +} +.text-primary { + color: #008dd2; +} +a.text-primary:hover, +a.text-primary:focus { + color: #036595; +} +.text-success { + color: #3c763d; +} +a.text-success:hover, +a.text-success:focus { + color: #2b542c; +} +.text-info { + color: #31708f; +} +a.text-info:hover, +a.text-info:focus { + color: #245269; +} +.text-warning { + color: #8a6d3b; +} +a.text-warning:hover, +a.text-warning:focus { + color: #66512c; +} +.text-danger { + color: #a94442; +} +a.text-danger:hover, +a.text-danger:focus { + color: #843534; +} +.bg-primary { + color: #fff; + background-color: #008dd2; +} +a.bg-primary:hover, +a.bg-primary:focus { + background-color: #036595; +} +.bg-success { + background-color: #dff0d8; +} +a.bg-success:hover, +a.bg-success:focus { + background-color: #c1e2b3; +} +.bg-info { + background-color: #d9edf7; +} +a.bg-info:hover, +a.bg-info:focus { + background-color: #afd9ee; +} +.bg-warning { + background-color: #fcf8e3; +} +a.bg-warning:hover, +a.bg-warning:focus { + background-color: #f7ecb5; +} +.bg-danger { + background-color: #f2dede; +} +a.bg-danger:hover, +a.bg-danger:focus { + background-color: #e4b9b9; +} +.page-header { + padding-bottom: 9px; + margin: 40px 0 20px; + border-bottom: 1px solid #008dd2; +} +ul, +ol { + margin-top: 0; + margin-bottom: 10px; +} +ul ul, +ol ul, +ul ol, +ol ol { + margin-bottom: 0; +} +.list-unstyled { + padding-left: 0; + list-style: none; +} +.list-inline { + padding-left: 0; + margin-left: -5px; + list-style: none; +} +.list-inline > li { + display: inline-block; + padding-right: 5px; + padding-left: 5px; +} +dl { + margin-top: 0; + margin-bottom: 20px; +} +dt, +dd { + line-height: 1.42857143; +} +dt { + font-weight: bold; +} +dd { + margin-left: 0; +} +@media (min-width: 768px) { + .dl-horizontal dt { + float: left; + width: 160px; + overflow: hidden; + clear: left; + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; + } + .dl-horizontal dd { + margin-left: 180px; + } +} +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted #008dd2; +} +.initialism { + font-size: 90%; + text-transform: uppercase; +} +blockquote { + padding: 10px 20px; + margin: 0 0 20px; + font-size: 17.5px; + border-left: 5px solid #008dd2; +} +blockquote p:last-child, +blockquote ul:last-child, +blockquote ol:last-child { + margin-bottom: 0; +} +blockquote footer, +blockquote small, +blockquote .small { + display: block; + font-size: 80%; + line-height: 1.42857143; + color: #008dd2; +} +blockquote footer:before, +blockquote small:before, +blockquote .small:before { + content: '\2014 \00A0'; +} +.blockquote-reverse, +blockquote.pull-right { + padding-right: 15px; + padding-left: 0; + text-align: right; + border-right: 5px solid #008dd2; + border-left: 0; +} +.blockquote-reverse footer:before, +blockquote.pull-right footer:before, +.blockquote-reverse small:before, +blockquote.pull-right small:before, +.blockquote-reverse .small:before, +blockquote.pull-right .small:before { + content: ''; +} +.blockquote-reverse footer:after, +blockquote.pull-right footer:after, +.blockquote-reverse small:after, +blockquote.pull-right small:after, +.blockquote-reverse .small:after, +blockquote.pull-right .small:after { + content: '\00A0 \2014'; +} +address { + margin-bottom: 20px; + font-style: normal; + line-height: 1.42857143; +} +code, +kbd, +pre, +samp { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; +} +code { + padding: 2px 4px; + font-size: 90%; + color: #c7254e; + background-color: #f9f2f4; + border-radius: 0; +} +kbd { + padding: 2px 4px; + font-size: 90%; + color: #fff; + background-color: #ccc; + border-radius: 0; + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25); +} +kbd kbd { + padding: 0; + font-size: 100%; + font-weight: bold; + -webkit-box-shadow: none; + box-shadow: none; +} +pre { + display: block; + padding: 9.5px; + margin: 0 0 10px; + font-size: 13px; + line-height: 1.42857143; + color: #008dd2; + word-break: break-all; + word-wrap: break-word; + background-color: #f5f5f5; + border: 1px solid #ccc; + border-radius: 0; +} +pre code { + padding: 0; + font-size: inherit; + color: inherit; + white-space: pre-wrap; + background-color: transparent; + border-radius: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +.container { + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} +@media (min-width: 768px) { + .container { + width: 750px; + } +} +@media (min-width: 992px) { + .container { + width: 970px; + } +} +@media (min-width: 1200px) { + .container { + width: 1170px; + } +} +.container-fluid { + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} +.row { + margin-right: -15px; + margin-left: -15px; +} +.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { + position: relative; + min-height: 1px; + padding-right: 15px; + padding-left: 15px; +} +.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 { + float: left; +} +.col-xs-12 { + width: 100%; +} +.col-xs-11 { + width: 91.66666667%; +} +.col-xs-10 { + width: 83.33333333%; +} +.col-xs-9 { + width: 75%; +} +.col-xs-8 { + width: 66.66666667%; +} +.col-xs-7 { + width: 58.33333333%; +} +.col-xs-6 { + width: 50%; +} +.col-xs-5 { + width: 41.66666667%; +} +.col-xs-4 { + width: 33.33333333%; +} +.col-xs-3 { + width: 25%; +} +.col-xs-2 { + width: 16.66666667%; +} +.col-xs-1 { + width: 8.33333333%; +} +.col-xs-pull-12 { + right: 100%; +} +.col-xs-pull-11 { + right: 91.66666667%; +} +.col-xs-pull-10 { + right: 83.33333333%; +} +.col-xs-pull-9 { + right: 75%; +} +.col-xs-pull-8 { + right: 66.66666667%; +} +.col-xs-pull-7 { + right: 58.33333333%; +} +.col-xs-pull-6 { + right: 50%; +} +.col-xs-pull-5 { + right: 41.66666667%; +} +.col-xs-pull-4 { + right: 33.33333333%; +} +.col-xs-pull-3 { + right: 25%; +} +.col-xs-pull-2 { + right: 16.66666667%; +} +.col-xs-pull-1 { + right: 8.33333333%; +} +.col-xs-pull-0 { + right: auto; +} +.col-xs-push-12 { + left: 100%; +} +.col-xs-push-11 { + left: 91.66666667%; +} +.col-xs-push-10 { + left: 83.33333333%; +} +.col-xs-push-9 { + left: 75%; +} +.col-xs-push-8 { + left: 66.66666667%; +} +.col-xs-push-7 { + left: 58.33333333%; +} +.col-xs-push-6 { + left: 50%; +} +.col-xs-push-5 { + left: 41.66666667%; +} +.col-xs-push-4 { + left: 33.33333333%; +} +.col-xs-push-3 { + left: 25%; +} +.col-xs-push-2 { + left: 16.66666667%; +} +.col-xs-push-1 { + left: 8.33333333%; +} +.col-xs-push-0 { + left: auto; +} +.col-xs-offset-12 { + margin-left: 100%; +} +.col-xs-offset-11 { + margin-left: 91.66666667%; +} +.col-xs-offset-10 { + margin-left: 83.33333333%; +} +.col-xs-offset-9 { + margin-left: 75%; +} +.col-xs-offset-8 { + margin-left: 66.66666667%; +} +.col-xs-offset-7 { + margin-left: 58.33333333%; +} +.col-xs-offset-6 { + margin-left: 50%; +} +.col-xs-offset-5 { + margin-left: 41.66666667%; +} +.col-xs-offset-4 { + margin-left: 33.33333333%; +} +.col-xs-offset-3 { + margin-left: 25%; +} +.col-xs-offset-2 { + margin-left: 16.66666667%; +} +.col-xs-offset-1 { + margin-left: 8.33333333%; +} +.col-xs-offset-0 { + margin-left: 0; +} +@media (min-width: 768px) { + .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 { + float: left; + } + .col-sm-12 { + width: 100%; + } + .col-sm-11 { + width: 91.66666667%; + } + .col-sm-10 { + width: 83.33333333%; + } + .col-sm-9 { + width: 75%; + } + .col-sm-8 { + width: 66.66666667%; + } + .col-sm-7 { + width: 58.33333333%; + } + .col-sm-6 { + width: 50%; + } + .col-sm-5 { + width: 41.66666667%; + } + .col-sm-4 { + width: 33.33333333%; + } + .col-sm-3 { + width: 25%; + } + .col-sm-2 { + width: 16.66666667%; + } + .col-sm-1 { + width: 8.33333333%; + } + .col-sm-pull-12 { + right: 100%; + } + .col-sm-pull-11 { + right: 91.66666667%; + } + .col-sm-pull-10 { + right: 83.33333333%; + } + .col-sm-pull-9 { + right: 75%; + } + .col-sm-pull-8 { + right: 66.66666667%; + } + .col-sm-pull-7 { + right: 58.33333333%; + } + .col-sm-pull-6 { + right: 50%; + } + .col-sm-pull-5 { + right: 41.66666667%; + } + .col-sm-pull-4 { + right: 33.33333333%; + } + .col-sm-pull-3 { + right: 25%; + } + .col-sm-pull-2 { + right: 16.66666667%; + } + .col-sm-pull-1 { + right: 8.33333333%; + } + .col-sm-pull-0 { + right: auto; + } + .col-sm-push-12 { + left: 100%; + } + .col-sm-push-11 { + left: 91.66666667%; + } + .col-sm-push-10 { + left: 83.33333333%; + } + .col-sm-push-9 { + left: 75%; + } + .col-sm-push-8 { + left: 66.66666667%; + } + .col-sm-push-7 { + left: 58.33333333%; + } + .col-sm-push-6 { + left: 50%; + } + .col-sm-push-5 { + left: 41.66666667%; + } + .col-sm-push-4 { + left: 33.33333333%; + } + .col-sm-push-3 { + left: 25%; + } + .col-sm-push-2 { + left: 16.66666667%; + } + .col-sm-push-1 { + left: 8.33333333%; + } + .col-sm-push-0 { + left: auto; + } + .col-sm-offset-12 { + margin-left: 100%; + } + .col-sm-offset-11 { + margin-left: 91.66666667%; + } + .col-sm-offset-10 { + margin-left: 83.33333333%; + } + .col-sm-offset-9 { + margin-left: 75%; + } + .col-sm-offset-8 { + margin-left: 66.66666667%; + } + .col-sm-offset-7 { + margin-left: 58.33333333%; + } + .col-sm-offset-6 { + margin-left: 50%; + } + .col-sm-offset-5 { + margin-left: 41.66666667%; + } + .col-sm-offset-4 { + margin-left: 33.33333333%; + } + .col-sm-offset-3 { + margin-left: 25%; + } + .col-sm-offset-2 { + margin-left: 16.66666667%; + } + .col-sm-offset-1 { + margin-left: 8.33333333%; + } + .col-sm-offset-0 { + margin-left: 0; + } +} +@media (min-width: 992px) { + .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 { + float: left; + } + .col-md-12 { + width: 100%; + } + .col-md-11 { + width: 91.66666667%; + } + .col-md-10 { + width: 83.33333333%; + } + .col-md-9 { + width: 75%; + } + .col-md-8 { + width: 66.66666667%; + } + .col-md-7 { + width: 58.33333333%; + } + .col-md-6 { + width: 50%; + } + .col-md-5 { + width: 41.66666667%; + } + .col-md-4 { + width: 33.33333333%; + } + .col-md-3 { + width: 25%; + } + .col-md-2 { + width: 16.66666667%; + } + .col-md-1 { + width: 8.33333333%; + } + .col-md-pull-12 { + right: 100%; + } + .col-md-pull-11 { + right: 91.66666667%; + } + .col-md-pull-10 { + right: 83.33333333%; + } + .col-md-pull-9 { + right: 75%; + } + .col-md-pull-8 { + right: 66.66666667%; + } + .col-md-pull-7 { + right: 58.33333333%; + } + .col-md-pull-6 { + right: 50%; + } + .col-md-pull-5 { + right: 41.66666667%; + } + .col-md-pull-4 { + right: 33.33333333%; + } + .col-md-pull-3 { + right: 25%; + } + .col-md-pull-2 { + right: 16.66666667%; + } + .col-md-pull-1 { + right: 8.33333333%; + } + .col-md-pull-0 { + right: auto; + } + .col-md-push-12 { + left: 100%; + } + .col-md-push-11 { + left: 91.66666667%; + } + .col-md-push-10 { + left: 83.33333333%; + } + .col-md-push-9 { + left: 75%; + } + .col-md-push-8 { + left: 66.66666667%; + } + .col-md-push-7 { + left: 58.33333333%; + } + .col-md-push-6 { + left: 50%; + } + .col-md-push-5 { + left: 41.66666667%; + } + .col-md-push-4 { + left: 33.33333333%; + } + .col-md-push-3 { + left: 25%; + } + .col-md-push-2 { + left: 16.66666667%; + } + .col-md-push-1 { + left: 8.33333333%; + } + .col-md-push-0 { + left: auto; + } + .col-md-offset-12 { + margin-left: 100%; + } + .col-md-offset-11 { + margin-left: 91.66666667%; + } + .col-md-offset-10 { + margin-left: 83.33333333%; + } + .col-md-offset-9 { + margin-left: 75%; + } + .col-md-offset-8 { + margin-left: 66.66666667%; + } + .col-md-offset-7 { + margin-left: 58.33333333%; + } + .col-md-offset-6 { + margin-left: 50%; + } + .col-md-offset-5 { + margin-left: 41.66666667%; + } + .col-md-offset-4 { + margin-left: 33.33333333%; + } + .col-md-offset-3 { + margin-left: 25%; + } + .col-md-offset-2 { + margin-left: 16.66666667%; + } + .col-md-offset-1 { + margin-left: 8.33333333%; + } + .col-md-offset-0 { + margin-left: 0; + } +} +@media (min-width: 1200px) { + .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 { + float: left; + } + .col-lg-12 { + width: 100%; + } + .col-lg-11 { + width: 91.66666667%; + } + .col-lg-10 { + width: 83.33333333%; + } + .col-lg-9 { + width: 75%; + } + .col-lg-8 { + width: 66.66666667%; + } + .col-lg-7 { + width: 58.33333333%; + } + .col-lg-6 { + width: 50%; + } + .col-lg-5 { + width: 41.66666667%; + } + .col-lg-4 { + width: 33.33333333%; + } + .col-lg-3 { + width: 25%; + } + .col-lg-2 { + width: 16.66666667%; + } + .col-lg-1 { + width: 8.33333333%; + } + .col-lg-pull-12 { + right: 100%; + } + .col-lg-pull-11 { + right: 91.66666667%; + } + .col-lg-pull-10 { + right: 83.33333333%; + } + .col-lg-pull-9 { + right: 75%; + } + .col-lg-pull-8 { + right: 66.66666667%; + } + .col-lg-pull-7 { + right: 58.33333333%; + } + .col-lg-pull-6 { + right: 50%; + } + .col-lg-pull-5 { + right: 41.66666667%; + } + .col-lg-pull-4 { + right: 33.33333333%; + } + .col-lg-pull-3 { + right: 25%; + } + .col-lg-pull-2 { + right: 16.66666667%; + } + .col-lg-pull-1 { + right: 8.33333333%; + } + .col-lg-pull-0 { + right: auto; + } + .col-lg-push-12 { + left: 100%; + } + .col-lg-push-11 { + left: 91.66666667%; + } + .col-lg-push-10 { + left: 83.33333333%; + } + .col-lg-push-9 { + left: 75%; + } + .col-lg-push-8 { + left: 66.66666667%; + } + .col-lg-push-7 { + left: 58.33333333%; + } + .col-lg-push-6 { + left: 50%; + } + .col-lg-push-5 { + left: 41.66666667%; + } + .col-lg-push-4 { + left: 33.33333333%; + } + .col-lg-push-3 { + left: 25%; + } + .col-lg-push-2 { + left: 16.66666667%; + } + .col-lg-push-1 { + left: 8.33333333%; + } + .col-lg-push-0 { + left: auto; + } + .col-lg-offset-12 { + margin-left: 100%; + } + .col-lg-offset-11 { + margin-left: 91.66666667%; + } + .col-lg-offset-10 { + margin-left: 83.33333333%; + } + .col-lg-offset-9 { + margin-left: 75%; + } + .col-lg-offset-8 { + margin-left: 66.66666667%; + } + .col-lg-offset-7 { + margin-left: 58.33333333%; + } + .col-lg-offset-6 { + margin-left: 50%; + } + .col-lg-offset-5 { + margin-left: 41.66666667%; + } + .col-lg-offset-4 { + margin-left: 33.33333333%; + } + .col-lg-offset-3 { + margin-left: 25%; + } + .col-lg-offset-2 { + margin-left: 16.66666667%; + } + .col-lg-offset-1 { + margin-left: 8.33333333%; + } + .col-lg-offset-0 { + margin-left: 0; + } +} +table { + background-color: transparent; +} +caption { + padding-top: 8px; + padding-bottom: 8px; + color: #008dd2; + text-align: left; +} +th { + text-align: left; +} +.table { + width: 100%; + max-width: 100%; + margin-bottom: 20px; +} +.table > thead > tr > th, +.table > tbody > tr > th, +.table > tfoot > tr > th, +.table > thead > tr > td, +.table > tbody > tr > td, +.table > tfoot > tr > td { + padding: 8px; + line-height: 1.42857143; + vertical-align: top; + border-top: 1px solid #008dd2; +} +.table > thead > tr > th { + vertical-align: bottom; + border-bottom: 2px solid #008dd2; +} +.table > caption + thead > tr:first-child > th, +.table > colgroup + thead > tr:first-child > th, +.table > thead:first-child > tr:first-child > th, +.table > caption + thead > tr:first-child > td, +.table > colgroup + thead > tr:first-child > td, +.table > thead:first-child > tr:first-child > td { + border-top: 0; +} +.table > tbody + tbody { + border-top: 2px solid #008dd2; +} +.table .table { + background-color: #008dd2; +} +.table-condensed > thead > tr > th, +.table-condensed > tbody > tr > th, +.table-condensed > tfoot > tr > th, +.table-condensed > thead > tr > td, +.table-condensed > tbody > tr > td, +.table-condensed > tfoot > tr > td { + padding: 5px; +} +.table-bordered { + border: 1px solid #008dd2; +} +.table-bordered > thead > tr > th, +.table-bordered > tbody > tr > th, +.table-bordered > tfoot > tr > th, +.table-bordered > thead > tr > td, +.table-bordered > tbody > tr > td, +.table-bordered > tfoot > tr > td { + border: 1px solid #008dd2; +} +.table-bordered > thead > tr > th, +.table-bordered > thead > tr > td { + border-bottom-width: 2px; +} +.table-striped > tbody > tr:nth-of-type(odd) { + background-color: #f9f9f9; +} +.table-hover > tbody > tr:hover { + background-color: #f5f5f5; +} +table col[class*="col-"] { + position: static; + display: table-column; + float: none; +} +table td[class*="col-"], +table th[class*="col-"] { + position: static; + display: table-cell; + float: none; +} +.table > thead > tr > td.active, +.table > tbody > tr > td.active, +.table > tfoot > tr > td.active, +.table > thead > tr > th.active, +.table > tbody > tr > th.active, +.table > tfoot > tr > th.active, +.table > thead > tr.active > td, +.table > tbody > tr.active > td, +.table > tfoot > tr.active > td, +.table > thead > tr.active > th, +.table > tbody > tr.active > th, +.table > tfoot > tr.active > th { + background-color: #f5f5f5; +} +.table-hover > tbody > tr > td.active:hover, +.table-hover > tbody > tr > th.active:hover, +.table-hover > tbody > tr.active:hover > td, +.table-hover > tbody > tr:hover > .active, +.table-hover > tbody > tr.active:hover > th { + background-color: #e8e8e8; +} +.table > thead > tr > td.success, +.table > tbody > tr > td.success, +.table > tfoot > tr > td.success, +.table > thead > tr > th.success, +.table > tbody > tr > th.success, +.table > tfoot > tr > th.success, +.table > thead > tr.success > td, +.table > tbody > tr.success > td, +.table > tfoot > tr.success > td, +.table > thead > tr.success > th, +.table > tbody > tr.success > th, +.table > tfoot > tr.success > th { + background-color: #dff0d8; +} +.table-hover > tbody > tr > td.success:hover, +.table-hover > tbody > tr > th.success:hover, +.table-hover > tbody > tr.success:hover > td, +.table-hover > tbody > tr:hover > .success, +.table-hover > tbody > tr.success:hover > th { + background-color: #d0e9c6; +} +.table > thead > tr > td.info, +.table > tbody > tr > td.info, +.table > tfoot > tr > td.info, +.table > thead > tr > th.info, +.table > tbody > tr > th.info, +.table > tfoot > tr > th.info, +.table > thead > tr.info > td, +.table > tbody > tr.info > td, +.table > tfoot > tr.info > td, +.table > thead > tr.info > th, +.table > tbody > tr.info > th, +.table > tfoot > tr.info > th { + background-color: #d9edf7; +} +.table-hover > tbody > tr > td.info:hover, +.table-hover > tbody > tr > th.info:hover, +.table-hover > tbody > tr.info:hover > td, +.table-hover > tbody > tr:hover > .info, +.table-hover > tbody > tr.info:hover > th { + background-color: #c4e3f3; +} +.table > thead > tr > td.warning, +.table > tbody > tr > td.warning, +.table > tfoot > tr > td.warning, +.table > thead > tr > th.warning, +.table > tbody > tr > th.warning, +.table > tfoot > tr > th.warning, +.table > thead > tr.warning > td, +.table > tbody > tr.warning > td, +.table > tfoot > tr.warning > td, +.table > thead > tr.warning > th, +.table > tbody > tr.warning > th, +.table > tfoot > tr.warning > th { + background-color: #fcf8e3; +} +.table-hover > tbody > tr > td.warning:hover, +.table-hover > tbody > tr > th.warning:hover, +.table-hover > tbody > tr.warning:hover > td, +.table-hover > tbody > tr:hover > .warning, +.table-hover > tbody > tr.warning:hover > th { + background-color: #faf2cc; +} +.table > thead > tr > td.danger, +.table > tbody > tr > td.danger, +.table > tfoot > tr > td.danger, +.table > thead > tr > th.danger, +.table > tbody > tr > th.danger, +.table > tfoot > tr > th.danger, +.table > thead > tr.danger > td, +.table > tbody > tr.danger > td, +.table > tfoot > tr.danger > td, +.table > thead > tr.danger > th, +.table > tbody > tr.danger > th, +.table > tfoot > tr.danger > th { + background-color: #f2dede; +} +.table-hover > tbody > tr > td.danger:hover, +.table-hover > tbody > tr > th.danger:hover, +.table-hover > tbody > tr.danger:hover > td, +.table-hover > tbody > tr:hover > .danger, +.table-hover > tbody > tr.danger:hover > th { + background-color: #ebcccc; +} +.table-responsive { + min-height: .01%; + overflow-x: auto; +} +@media screen and (max-width: 767px) { + .table-responsive { + width: 100%; + margin-bottom: 15px; + overflow-y: hidden; + -ms-overflow-style: -ms-autohiding-scrollbar; + border: 1px solid #008dd2; + } + .table-responsive > .table { + margin-bottom: 0; + } + .table-responsive > .table > thead > tr > th, + .table-responsive > .table > tbody > tr > th, + .table-responsive > .table > tfoot > tr > th, + .table-responsive > .table > thead > tr > td, + .table-responsive > .table > tbody > tr > td, + .table-responsive > .table > tfoot > tr > td { + white-space: nowrap; + } + .table-responsive > .table-bordered { + border: 0; + } + .table-responsive > .table-bordered > thead > tr > th:first-child, + .table-responsive > .table-bordered > tbody > tr > th:first-child, + .table-responsive > .table-bordered > tfoot > tr > th:first-child, + .table-responsive > .table-bordered > thead > tr > td:first-child, + .table-responsive > .table-bordered > tbody > tr > td:first-child, + .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; + } + .table-responsive > .table-bordered > thead > tr > th:last-child, + .table-responsive > .table-bordered > tbody > tr > th:last-child, + .table-responsive > .table-bordered > tfoot > tr > th:last-child, + .table-responsive > .table-bordered > thead > tr > td:last-child, + .table-responsive > .table-bordered > tbody > tr > td:last-child, + .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; + } + .table-responsive > .table-bordered > tbody > tr:last-child > th, + .table-responsive > .table-bordered > tfoot > tr:last-child > th, + .table-responsive > .table-bordered > tbody > tr:last-child > td, + .table-responsive > .table-bordered > tfoot > tr:last-child > td { + border-bottom: 0; + } +} +fieldset { + min-width: 0; + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 20px; + font-size: 21px; + line-height: inherit; + color: #008dd2; + border: 0; + border-bottom: 1px solid #e5e5e5; +} +label { + display: inline-block; + max-width: 100%; + margin-bottom: 5px; + font-weight: normal; +} +input[type="search"] { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px \9; + line-height: normal; +} +input[type="file"] { + display: block; +} +input[type="range"] { + display: block; + width: 100%; +} +select[multiple], +select[size] { + height: auto; +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +output { + display: block; + padding-top: 7px; + font-size: 14px; + line-height: 1.42857143; + color: #008dd2; +} +.form-control { + display: block; + width: 100%; + height: 34px; + padding: 6px 12px; + font-size: 14px; + line-height: 1.42857143; + color: #000000; + background-color: #fff; + background-image: none; + border: 1px solid #ccc; + border-radius: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s; + -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; +} +.form-control:focus { + border-color: #66afe9; + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6); +} +.form-control::-moz-placeholder { + color: #999; + opacity: 1; +} +.form-control:-ms-input-placeholder { + color: #999; +} +.form-control::-webkit-input-placeholder { + color: #999; +} +.form-control::-ms-expand { + background-color: transparent; + border: 0; +} +.form-control[disabled], +.form-control[readonly], +fieldset[disabled] .form-control { + background-color: #008dd2; + opacity: 1; +} +.form-control[disabled], +fieldset[disabled] .form-control { + cursor: not-allowed; +} +textarea.form-control { + height: auto; +} +input[type="search"] { + -webkit-appearance: none; +} +@media screen and (-webkit-min-device-pixel-ratio: 0) { + input[type="date"].form-control, + input[type="time"].form-control, + input[type="datetime-local"].form-control, + input[type="month"].form-control { + line-height: 34px; + } + input[type="date"].input-sm, + input[type="time"].input-sm, + input[type="datetime-local"].input-sm, + input[type="month"].input-sm, + .input-group-sm input[type="date"], + .input-group-sm input[type="time"], + .input-group-sm input[type="datetime-local"], + .input-group-sm input[type="month"] { + line-height: 30px; + } + input[type="date"].input-lg, + input[type="time"].input-lg, + input[type="datetime-local"].input-lg, + input[type="month"].input-lg, + .input-group-lg input[type="date"], + .input-group-lg input[type="time"], + .input-group-lg input[type="datetime-local"], + .input-group-lg input[type="month"] { + line-height: 46px; + } +} +.form-group { + margin-bottom: 15px; +} +.radio, +.checkbox { + position: relative; + display: block; + margin-top: 10px; + margin-bottom: 10px; +} +.radio label, +.checkbox label { + min-height: 20px; + padding-left: 20px; + margin-bottom: 0; + font-weight: normal; + cursor: pointer; +} +.radio input[type="radio"], +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { + position: absolute; + margin-top: 4px \9; + margin-left: -20px; +} +.radio + .radio, +.checkbox + .checkbox { + margin-top: -5px; +} +.radio-inline, +.checkbox-inline { + position: relative; + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + font-weight: normal; + vertical-align: middle; + cursor: pointer; +} +.radio-inline + .radio-inline, +.checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; +} +input[type="radio"][disabled], +input[type="checkbox"][disabled], +input[type="radio"].disabled, +input[type="checkbox"].disabled, +fieldset[disabled] input[type="radio"], +fieldset[disabled] input[type="checkbox"] { + cursor: not-allowed; +} +.radio-inline.disabled, +.checkbox-inline.disabled, +fieldset[disabled] .radio-inline, +fieldset[disabled] .checkbox-inline { + cursor: not-allowed; +} +.radio.disabled label, +.checkbox.disabled label, +fieldset[disabled] .radio label, +fieldset[disabled] .checkbox label { + cursor: not-allowed; +} +.form-control-static { + min-height: 34px; + padding-top: 7px; + padding-bottom: 7px; + margin-bottom: 0; +} +.form-control-static.input-lg, +.form-control-static.input-sm { + padding-right: 0; + padding-left: 0; +} +.input-sm { + height: 30px; + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 0; +} +select.input-sm { + height: 30px; + line-height: 30px; +} +textarea.input-sm, +select[multiple].input-sm { + height: auto; +} +.form-group-sm .form-control { + height: 30px; + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 0; +} +.form-group-sm select.form-control { + height: 30px; + line-height: 30px; +} +.form-group-sm textarea.form-control, +.form-group-sm select[multiple].form-control { + height: auto; +} +.form-group-sm .form-control-static { + height: 30px; + min-height: 32px; + padding: 6px 10px; + font-size: 12px; + line-height: 1.5; +} +.input-lg { + height: 46px; + padding: 10px 16px; + font-size: 18px; + line-height: 1.3333333; + border-radius: 0; +} +select.input-lg { + height: 46px; + line-height: 46px; +} +textarea.input-lg, +select[multiple].input-lg { + height: auto; +} +.form-group-lg .form-control { + height: 46px; + padding: 10px 16px; + font-size: 18px; + line-height: 1.3333333; + border-radius: 0; +} +.form-group-lg select.form-control { + height: 46px; + line-height: 46px; +} +.form-group-lg textarea.form-control, +.form-group-lg select[multiple].form-control { + height: auto; +} +.form-group-lg .form-control-static { + height: 46px; + min-height: 38px; + padding: 11px 16px; + font-size: 18px; + line-height: 1.3333333; +} +.has-feedback { + position: relative; +} +.has-feedback .form-control { + padding-right: 42.5px; +} +.form-control-feedback { + position: absolute; + top: 0; + right: 0; + z-index: 2; + display: block; + width: 34px; + height: 34px; + line-height: 34px; + text-align: center; + pointer-events: none; +} +.input-lg + .form-control-feedback, +.input-group-lg + .form-control-feedback, +.form-group-lg .form-control + .form-control-feedback { + width: 46px; + height: 46px; + line-height: 46px; +} +.input-sm + .form-control-feedback, +.input-group-sm + .form-control-feedback, +.form-group-sm .form-control + .form-control-feedback { + width: 30px; + height: 30px; + line-height: 30px; +} +.has-success .help-block, +.has-success .control-label, +.has-success .radio, +.has-success .checkbox, +.has-success .radio-inline, +.has-success .checkbox-inline, +.has-success.radio label, +.has-success.checkbox label, +.has-success.radio-inline label, +.has-success.checkbox-inline label { + color: #3c763d; +} +.has-success .form-control { + border-color: #3c763d; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); +} +.has-success .form-control:focus { + border-color: #2b542c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168; +} +.has-success .input-group-addon { + color: #3c763d; + background-color: #dff0d8; + border-color: #3c763d; +} +.has-success .form-control-feedback { + color: #3c763d; +} +.has-warning .help-block, +.has-warning .control-label, +.has-warning .radio, +.has-warning .checkbox, +.has-warning .radio-inline, +.has-warning .checkbox-inline, +.has-warning.radio label, +.has-warning.checkbox label, +.has-warning.radio-inline label, +.has-warning.checkbox-inline label { + color: #8a6d3b; +} +.has-warning .form-control { + border-color: #8a6d3b; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); +} +.has-warning .form-control:focus { + border-color: #66512c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b; +} +.has-warning .input-group-addon { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #8a6d3b; +} +.has-warning .form-control-feedback { + color: #8a6d3b; +} +.has-error .help-block, +.has-error .control-label, +.has-error .radio, +.has-error .checkbox, +.has-error .radio-inline, +.has-error .checkbox-inline, +.has-error.radio label, +.has-error.checkbox label, +.has-error.radio-inline label, +.has-error.checkbox-inline label { + color: #a94442; +} +.has-error .form-control { + border-color: #a94442; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); +} +.has-error .form-control:focus { + border-color: #843534; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483; +} +.has-error .input-group-addon { + color: #a94442; + background-color: #f2dede; + border-color: #a94442; +} +.has-error .form-control-feedback { + color: #a94442; +} +.has-feedback label ~ .form-control-feedback { + top: 25px; +} +.has-feedback label.sr-only ~ .form-control-feedback { + top: 0; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 10px; + color: #21a7ff; +} +@media (min-width: 768px) { + .form-inline .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .form-inline .form-control-static { + display: inline-block; + } + .form-inline .input-group { + display: inline-table; + vertical-align: middle; + } + .form-inline .input-group .input-group-addon, + .form-inline .input-group .input-group-btn, + .form-inline .input-group .form-control { + width: auto; + } + .form-inline .input-group > .form-control { + width: 100%; + } + .form-inline .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio, + .form-inline .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio label, + .form-inline .checkbox label { + padding-left: 0; + } + .form-inline .radio input[type="radio"], + .form-inline .checkbox input[type="checkbox"] { + position: relative; + margin-left: 0; + } + .form-inline .has-feedback .form-control-feedback { + top: 0; + } +} +.form-horizontal .radio, +.form-horizontal .checkbox, +.form-horizontal .radio-inline, +.form-horizontal .checkbox-inline { + padding-top: 7px; + margin-top: 0; + margin-bottom: 0; +} +.form-horizontal .radio, +.form-horizontal .checkbox { + min-height: 27px; +} +.form-horizontal .form-group { + margin-right: -15px; + margin-left: -15px; +} +@media (min-width: 768px) { + .form-horizontal .control-label { + padding-top: 7px; + margin-bottom: 0; + text-align: right; + } +} +.form-horizontal .has-feedback .form-control-feedback { + right: 15px; +} +@media (min-width: 768px) { + .form-horizontal .form-group-lg .control-label { + padding-top: 11px; + font-size: 18px; + } +} +@media (min-width: 768px) { + .form-horizontal .form-group-sm .control-label { + padding-top: 6px; + font-size: 12px; + } +} +.btn { + display: inline-block; + padding: 6px 12px; + margin-bottom: 0; + font-size: 14px; + font-weight: normal; + line-height: 1.42857143; + text-align: center; + white-space: nowrap; + vertical-align: middle; + -ms-touch-action: manipulation; + touch-action: manipulation; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-image: none; + border: 1px solid transparent; + border-radius: 0; +} +.btn:focus, +.btn:active:focus, +.btn.active:focus, +.btn.focus, +.btn:active.focus, +.btn.active.focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn:hover, +.btn:focus, +.btn.focus { + color: #ccc; + text-decoration: none; +} +.btn:active, +.btn.active { + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); +} +.btn.disabled, +.btn[disabled], +fieldset[disabled] .btn { + cursor: not-allowed; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + box-shadow: none; + opacity: .65; +} +a.btn.disabled, +fieldset[disabled] a.btn { + pointer-events: none; +} +.btn-default { + color: #ccc; + background-color: #fff; + border-color: #ccc; +} +.btn-default:focus, +.btn-default.focus { + color: #ccc; + background-color: #e6e6e6; + border-color: #8c8c8c; +} +.btn-default:hover { + color: #ccc; + background-color: #e6e6e6; + border-color: #adadad; +} +.btn-default:active, +.btn-default.active, +.open > .dropdown-toggle.btn-default { + color: #ccc; + background-color: #e6e6e6; + border-color: #adadad; +} +.btn-default:active:hover, +.btn-default.active:hover, +.open > .dropdown-toggle.btn-default:hover, +.btn-default:active:focus, +.btn-default.active:focus, +.open > .dropdown-toggle.btn-default:focus, +.btn-default:active.focus, +.btn-default.active.focus, +.open > .dropdown-toggle.btn-default.focus { + color: #ccc; + background-color: #d4d4d4; + border-color: #8c8c8c; +} +.btn-default:active, +.btn-default.active, +.open > .dropdown-toggle.btn-default { + background-image: none; +} +.btn-default.disabled:hover, +.btn-default[disabled]:hover, +fieldset[disabled] .btn-default:hover, +.btn-default.disabled:focus, +.btn-default[disabled]:focus, +fieldset[disabled] .btn-default:focus, +.btn-default.disabled.focus, +.btn-default[disabled].focus, +fieldset[disabled] .btn-default.focus { + background-color: #fff; + border-color: #ccc; +} +.btn-default .badge { + color: #fff; + background-color: #ccc; +} +.btn-primary { + color: #fff; + background-color: #008dd2; + border-color: #008dd2; +} +.btn-primary:focus, +.btn-primary.focus { + color: #fff; + background-color: #036595; + border-color: #000508; +} +.btn-primary:hover { + color: #fff; + background-color: #036595; + border-color: #036595; +} +.btn-primary:active, +.btn-primary.active, +.open > .dropdown-toggle.btn-primary { + color: #fff; + background-color: #036595; + border-color: #036595; +} +.btn-primary:active:hover, +.btn-primary.active:hover, +.open > .dropdown-toggle.btn-primary:hover, +.btn-primary:active:focus, +.btn-primary.active:focus, +.open > .dropdown-toggle.btn-primary:focus, +.btn-primary:active.focus, +.btn-primary.active.focus, +.open > .dropdown-toggle.btn-primary.focus { + color: #fff; + background-color: #036595; + border-color: #000508; +} +.btn-primary:active, +.btn-primary.active, +.open > .dropdown-toggle.btn-primary { + background-image: none; +} +.btn-primary.disabled:hover, +.btn-primary[disabled]:hover, +fieldset[disabled] .btn-primary:hover, +.btn-primary.disabled:focus, +.btn-primary[disabled]:focus, +fieldset[disabled] .btn-primary:focus, +.btn-primary.disabled.focus, +.btn-primary[disabled].focus, +fieldset[disabled] .btn-primary.focus { + background-color: #008dd2; + border-color: #008dd2; +} +.btn-primary .badge { + color: #008dd2; + background-color: #fff; +} +.btn-success { + color: #fff; + background-color: #5cb85c; + border-color: #4cae4c; +} +.btn-success:focus, +.btn-success.focus { + color: #fff; + background-color: #449d44; + border-color: #255625; +} +.btn-success:hover { + color: #fff; + background-color: #449d44; + border-color: #398439; +} +.btn-success:active, +.btn-success.active, +.open > .dropdown-toggle.btn-success { + color: #fff; + background-color: #449d44; + border-color: #398439; +} +.btn-success:active:hover, +.btn-success.active:hover, +.open > .dropdown-toggle.btn-success:hover, +.btn-success:active:focus, +.btn-success.active:focus, +.open > .dropdown-toggle.btn-success:focus, +.btn-success:active.focus, +.btn-success.active.focus, +.open > .dropdown-toggle.btn-success.focus { + color: #fff; + background-color: #398439; + border-color: #255625; +} +.btn-success:active, +.btn-success.active, +.open > .dropdown-toggle.btn-success { + background-image: none; +} +.btn-success.disabled:hover, +.btn-success[disabled]:hover, +fieldset[disabled] .btn-success:hover, +.btn-success.disabled:focus, +.btn-success[disabled]:focus, +fieldset[disabled] .btn-success:focus, +.btn-success.disabled.focus, +.btn-success[disabled].focus, +fieldset[disabled] .btn-success.focus { + background-color: #5cb85c; + border-color: #4cae4c; +} +.btn-success .badge { + color: #5cb85c; + background-color: #fff; +} +.btn-info { + color: #fff; + background-color: #5bc0de; + border-color: #46b8da; +} +.btn-info:focus, +.btn-info.focus { + color: #fff; + background-color: #31b0d5; + border-color: #1b6d85; +} +.btn-info:hover { + color: #fff; + background-color: #31b0d5; + border-color: #269abc; +} +.btn-info:active, +.btn-info.active, +.open > .dropdown-toggle.btn-info { + color: #fff; + background-color: #31b0d5; + border-color: #269abc; +} +.btn-info:active:hover, +.btn-info.active:hover, +.open > .dropdown-toggle.btn-info:hover, +.btn-info:active:focus, +.btn-info.active:focus, +.open > .dropdown-toggle.btn-info:focus, +.btn-info:active.focus, +.btn-info.active.focus, +.open > .dropdown-toggle.btn-info.focus { + color: #fff; + background-color: #269abc; + border-color: #1b6d85; +} +.btn-info:active, +.btn-info.active, +.open > .dropdown-toggle.btn-info { + background-image: none; +} +.btn-info.disabled:hover, +.btn-info[disabled]:hover, +fieldset[disabled] .btn-info:hover, +.btn-info.disabled:focus, +.btn-info[disabled]:focus, +fieldset[disabled] .btn-info:focus, +.btn-info.disabled.focus, +.btn-info[disabled].focus, +fieldset[disabled] .btn-info.focus { + background-color: #5bc0de; + border-color: #46b8da; +} +.btn-info .badge { + color: #5bc0de; + background-color: #fff; +} +.btn-warning { + color: #fff; + background-color: #f0ad4e; + border-color: #eea236; +} +.btn-warning:focus, +.btn-warning.focus { + color: #fff; + background-color: #ec971f; + border-color: #985f0d; +} +.btn-warning:hover { + color: #fff; + background-color: #ec971f; + border-color: #d58512; +} +.btn-warning:active, +.btn-warning.active, +.open > .dropdown-toggle.btn-warning { + color: #fff; + background-color: #ec971f; + border-color: #d58512; +} +.btn-warning:active:hover, +.btn-warning.active:hover, +.open > .dropdown-toggle.btn-warning:hover, +.btn-warning:active:focus, +.btn-warning.active:focus, +.open > .dropdown-toggle.btn-warning:focus, +.btn-warning:active.focus, +.btn-warning.active.focus, +.open > .dropdown-toggle.btn-warning.focus { + color: #fff; + background-color: #d58512; + border-color: #985f0d; +} +.btn-warning:active, +.btn-warning.active, +.open > .dropdown-toggle.btn-warning { + background-image: none; +} +.btn-warning.disabled:hover, +.btn-warning[disabled]:hover, +fieldset[disabled] .btn-warning:hover, +.btn-warning.disabled:focus, +.btn-warning[disabled]:focus, +fieldset[disabled] .btn-warning:focus, +.btn-warning.disabled.focus, +.btn-warning[disabled].focus, +fieldset[disabled] .btn-warning.focus { + background-color: #f0ad4e; + border-color: #eea236; +} +.btn-warning .badge { + color: #f0ad4e; + background-color: #fff; +} +.btn-danger { + color: #fff; + background-color: #d9534f; + border-color: #d43f3a; +} +.btn-danger:focus, +.btn-danger.focus { + color: #fff; + background-color: #c9302c; + border-color: #761c19; +} +.btn-danger:hover { + color: #fff; + background-color: #c9302c; + border-color: #ac2925; +} +.btn-danger:active, +.btn-danger.active, +.open > .dropdown-toggle.btn-danger { + color: #fff; + background-color: #c9302c; + border-color: #ac2925; +} +.btn-danger:active:hover, +.btn-danger.active:hover, +.open > .dropdown-toggle.btn-danger:hover, +.btn-danger:active:focus, +.btn-danger.active:focus, +.open > .dropdown-toggle.btn-danger:focus, +.btn-danger:active.focus, +.btn-danger.active.focus, +.open > .dropdown-toggle.btn-danger.focus { + color: #fff; + background-color: #ac2925; + border-color: #761c19; +} +.btn-danger:active, +.btn-danger.active, +.open > .dropdown-toggle.btn-danger { + background-image: none; +} +.btn-danger.disabled:hover, +.btn-danger[disabled]:hover, +fieldset[disabled] .btn-danger:hover, +.btn-danger.disabled:focus, +.btn-danger[disabled]:focus, +fieldset[disabled] .btn-danger:focus, +.btn-danger.disabled.focus, +.btn-danger[disabled].focus, +fieldset[disabled] .btn-danger.focus { + background-color: #d9534f; + border-color: #d43f3a; +} +.btn-danger .badge { + color: #d9534f; + background-color: #fff; +} +.btn-link { + font-weight: normal; + color: #008dd2; + border-radius: 0; +} +.btn-link, +.btn-link:active, +.btn-link.active, +.btn-link[disabled], +fieldset[disabled] .btn-link { + background-color: transparent; + -webkit-box-shadow: none; + box-shadow: none; +} +.btn-link, +.btn-link:hover, +.btn-link:focus, +.btn-link:active { + border-color: transparent; +} +.btn-link:hover, +.btn-link:focus { + color: #036595; + text-decoration: underline; + background-color: transparent; +} +.btn-link[disabled]:hover, +fieldset[disabled] .btn-link:hover, +.btn-link[disabled]:focus, +fieldset[disabled] .btn-link:focus { + color: #008dd2; + text-decoration: none; +} +.btn-lg, +.btn-group-lg > .btn { + padding: 10px 16px; + font-size: 18px; + line-height: 1.3333333; + border-radius: 0; +} +.btn-sm, +.btn-group-sm > .btn { + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 0; +} +.btn-xs, +.btn-group-xs > .btn { + padding: 1px 5px; + font-size: 12px; + line-height: 1.5; + border-radius: 0; +} +.btn-block { + display: block; + width: 100%; +} +.btn-block + .btn-block { + margin-top: 5px; +} +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} +.fade { + opacity: 0; + -webkit-transition: opacity .15s linear; + -o-transition: opacity .15s linear; + transition: opacity .15s linear; +} +.fade.in { + opacity: 1; +} +.collapse { + display: none; +} +.collapse.in { + display: block; +} +tr.collapse.in { + display: table-row; +} +tbody.collapse.in { + display: table-row-group; +} +.collapsing { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition-timing-function: ease; + -o-transition-timing-function: ease; + transition-timing-function: ease; + -webkit-transition-duration: .35s; + -o-transition-duration: .35s; + transition-duration: .35s; + -webkit-transition-property: height, visibility; + -o-transition-property: height, visibility; + transition-property: height, visibility; +} +.caret { + display: inline-block; + width: 0; + height: 0; + margin-left: 2px; + vertical-align: middle; + border-top: 4px dashed; + border-top: 4px solid \9; + border-right: 4px solid transparent; + border-left: 4px solid transparent; +} +.dropup, +.dropdown { + position: relative; +} +.dropdown-toggle:focus { + outline: 0; +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + font-size: 14px; + text-align: left; + list-style: none; + background-color: #fff; + -webkit-background-clip: padding-box; + background-clip: padding-box; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, .15); + border-radius: 0; + -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175); + box-shadow: 0 6px 12px rgba(0, 0, 0, .175); +} +.dropdown-menu.pull-right { + right: 0; + left: auto; +} +.dropdown-menu .divider { + height: 1px; + margin: 9px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.dropdown-menu > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 1.42857143; + color: #008dd2; + white-space: nowrap; +} +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + color: #008dd2; + text-decoration: none; + background-color: #f5f5f5; +} +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + color: #fff; + text-decoration: none; + background-color: #008dd2; + outline: 0; +} +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #008dd2; +} +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + text-decoration: none; + cursor: not-allowed; + background-color: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.open > .dropdown-menu { + display: block; +} +.open > a { + outline: 0; +} +.dropdown-menu-right { + right: 0; + left: auto; +} +.dropdown-menu-left { + right: auto; + left: 0; +} +.dropdown-header { + display: block; + padding: 3px 20px; + font-size: 12px; + line-height: 1.42857143; + color: #008dd2; + white-space: nowrap; +} +.dropdown-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 990; +} +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + content: ""; + border-top: 0; + border-bottom: 4px dashed; + border-bottom: 4px solid \9; +} +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +@media (min-width: 768px) { + .navbar-right .dropdown-menu { + right: 0; + left: auto; + } + .navbar-right .dropdown-menu-left { + right: auto; + left: 0; + } +} +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-block; + vertical-align: middle; +} +.btn-group > .btn, +.btn-group-vertical > .btn { + position: relative; + float: left; +} +.btn-group > .btn:hover, +.btn-group-vertical > .btn:hover, +.btn-group > .btn:focus, +.btn-group-vertical > .btn:focus, +.btn-group > .btn:active, +.btn-group-vertical > .btn:active, +.btn-group > .btn.active, +.btn-group-vertical > .btn.active { + z-index: 2; +} +.btn-group .btn + .btn, +.btn-group .btn + .btn-group, +.btn-group .btn-group + .btn, +.btn-group .btn-group + .btn-group { + margin-left: -1px; +} +.btn-toolbar { + margin-left: -5px; +} +.btn-toolbar .btn, +.btn-toolbar .btn-group, +.btn-toolbar .input-group { + float: left; +} +.btn-toolbar > .btn, +.btn-toolbar > .btn-group, +.btn-toolbar > .input-group { + margin-left: 5px; +} +.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { + border-radius: 0; +} +.btn-group > .btn:first-child { + margin-left: 0; +} +.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.btn-group > .btn:last-child:not(:first-child), +.btn-group > .dropdown-toggle:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group > .btn-group { + float: left; +} +.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child, +.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group > .btn + .dropdown-toggle { + padding-right: 8px; + padding-left: 8px; +} +.btn-group > .btn-lg + .dropdown-toggle { + padding-right: 12px; + padding-left: 12px; +} +.btn-group.open .dropdown-toggle { + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); +} +.btn-group.open .dropdown-toggle.btn-link { + -webkit-box-shadow: none; + box-shadow: none; +} +.btn .caret { + margin-left: 0; +} +.btn-lg .caret { + border-width: 5px 5px 0; + border-bottom-width: 0; +} +.dropup .btn-lg .caret { + border-width: 0 5px 5px; +} +.btn-group-vertical > .btn, +.btn-group-vertical > .btn-group, +.btn-group-vertical > .btn-group > .btn { + display: block; + float: none; + width: 100%; + max-width: 100%; +} +.btn-group-vertical > .btn-group > .btn { + float: none; +} +.btn-group-vertical > .btn + .btn, +.btn-group-vertical > .btn + .btn-group, +.btn-group-vertical > .btn-group + .btn, +.btn-group-vertical > .btn-group + .btn-group { + margin-top: -1px; + margin-left: 0; +} +.btn-group-vertical > .btn:not(:first-child):not(:last-child) { + border-radius: 0; +} +.btn-group-vertical > .btn:first-child:not(:last-child) { + border-top-left-radius: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn:last-child:not(:first-child) { + border-top-left-radius: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child, +.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child { + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.btn-group-justified { + display: table; + width: 100%; + table-layout: fixed; + border-collapse: separate; +} +.btn-group-justified > .btn, +.btn-group-justified > .btn-group { + display: table-cell; + float: none; + width: 1%; +} +.btn-group-justified > .btn-group .btn { + width: 100%; +} +.btn-group-justified > .btn-group .dropdown-menu { + left: auto; +} +[data-toggle="buttons"] > .btn input[type="radio"], +[data-toggle="buttons"] > .btn-group > .btn input[type="radio"], +[data-toggle="buttons"] > .btn input[type="checkbox"], +[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] { + position: absolute; + clip: rect(0, 0, 0, 0); + pointer-events: none; +} +.input-group { + position: relative; + display: table; + border-collapse: separate; +} +.input-group[class*="col-"] { + float: none; + padding-right: 0; + padding-left: 0; +} +.input-group .form-control { + position: relative; + z-index: 2; + float: left; + width: 100%; + margin-bottom: 0; +} +.input-group .form-control:focus { + z-index: 3; +} +.input-group-lg > .form-control, +.input-group-lg > .input-group-addon, +.input-group-lg > .input-group-btn > .btn { + height: 46px; + padding: 10px 16px; + font-size: 18px; + line-height: 1.3333333; + border-radius: 0; +} +select.input-group-lg > .form-control, +select.input-group-lg > .input-group-addon, +select.input-group-lg > .input-group-btn > .btn { + height: 46px; + line-height: 46px; +} +textarea.input-group-lg > .form-control, +textarea.input-group-lg > .input-group-addon, +textarea.input-group-lg > .input-group-btn > .btn, +select[multiple].input-group-lg > .form-control, +select[multiple].input-group-lg > .input-group-addon, +select[multiple].input-group-lg > .input-group-btn > .btn { + height: auto; +} +.input-group-sm > .form-control, +.input-group-sm > .input-group-addon, +.input-group-sm > .input-group-btn > .btn { + height: 30px; + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 0; +} +select.input-group-sm > .form-control, +select.input-group-sm > .input-group-addon, +select.input-group-sm > .input-group-btn > .btn { + height: 30px; + line-height: 30px; +} +textarea.input-group-sm > .form-control, +textarea.input-group-sm > .input-group-addon, +textarea.input-group-sm > .input-group-btn > .btn, +select[multiple].input-group-sm > .form-control, +select[multiple].input-group-sm > .input-group-addon, +select[multiple].input-group-sm > .input-group-btn > .btn { + height: auto; +} +.input-group-addon, +.input-group-btn, +.input-group .form-control { + display: table-cell; +} +.input-group-addon:not(:first-child):not(:last-child), +.input-group-btn:not(:first-child):not(:last-child), +.input-group .form-control:not(:first-child):not(:last-child) { + border-radius: 0; +} +.input-group-addon, +.input-group-btn { + width: 1%; + white-space: nowrap; + vertical-align: middle; +} +.input-group-addon { + padding: 6px 12px; + font-size: 14px; + font-weight: normal; + line-height: 1; + color: #008dd2; + text-align: center; + background-color: #008dd2; + border: 1px solid #ccc; + border-radius: 0; +} +.input-group-addon.input-sm { + padding: 5px 10px; + font-size: 12px; + border-radius: 0; +} +.input-group-addon.input-lg { + padding: 10px 16px; + font-size: 18px; + border-radius: 0; +} +.input-group-addon input[type="radio"], +.input-group-addon input[type="checkbox"] { + margin-top: 0; +} +.input-group .form-control:first-child, +.input-group-addon:first-child, +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .btn-group > .btn, +.input-group-btn:first-child > .dropdown-toggle, +.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle), +.input-group-btn:last-child > .btn-group:not(:last-child) > .btn { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.input-group-addon:first-child { + border-right: 0; +} +.input-group .form-control:last-child, +.input-group-addon:last-child, +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .btn-group > .btn, +.input-group-btn:last-child > .dropdown-toggle, +.input-group-btn:first-child > .btn:not(:first-child), +.input-group-btn:first-child > .btn-group:not(:first-child) > .btn { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.input-group-addon:last-child { + border-left: 0; +} +.input-group-btn { + position: relative; + font-size: 0; + white-space: nowrap; +} +.input-group-btn > .btn { + position: relative; +} +.input-group-btn > .btn + .btn { + margin-left: -1px; +} +.input-group-btn > .btn:hover, +.input-group-btn > .btn:focus, +.input-group-btn > .btn:active { + z-index: 2; +} +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .btn-group { + margin-right: -1px; +} +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .btn-group { + z-index: 2; + margin-left: -1px; +} +.nav { + padding-left: 0; + margin-bottom: 0; + list-style: none; +} +.nav > li { + position: relative; + display: block; +} +.nav > li > a { + position: relative; + display: block; + padding: 10px 15px; +} +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #008dd2; +} +.nav > li.disabled > a { + color: #008dd2; +} +.nav > li.disabled > a:hover, +.nav > li.disabled > a:focus { + color: #008dd2; + text-decoration: none; + cursor: not-allowed; + background-color: transparent; +} +.nav .open > a, +.nav .open > a:hover, +.nav .open > a:focus { + background-color: #008dd2; + border-color: #008dd2; +} +.nav .nav-divider { + height: 1px; + margin: 9px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.nav > li > a > img { + max-width: none; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + float: left; + margin-bottom: -1px; +} +.nav-tabs > li > a { + margin-right: 2px; + line-height: 1.42857143; + border: 1px solid transparent; + border-radius: 0 0 0 0; +} +.nav-tabs > li > a:hover { + border-color: #008dd2 #008dd2 #ddd; +} +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + color: #008dd2; + cursor: default; + background-color: #008dd2; + border: 1px solid #ddd; + border-bottom-color: transparent; +} +.nav-tabs.nav-justified { + width: 100%; + border-bottom: 0; +} +.nav-tabs.nav-justified > li { + float: none; +} +.nav-tabs.nav-justified > li > a { + margin-bottom: 5px; + text-align: center; +} +.nav-tabs.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-tabs.nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs.nav-justified > li > a { + margin-right: 0; + border-radius: 0; +} +.nav-tabs.nav-justified > .active > a, +.nav-tabs.nav-justified > .active > a:hover, +.nav-tabs.nav-justified > .active > a:focus { + border: 1px solid #ddd; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li > a { + border-bottom: 1px solid #ddd; + border-radius: 0 0 0 0; + } + .nav-tabs.nav-justified > .active > a, + .nav-tabs.nav-justified > .active > a:hover, + .nav-tabs.nav-justified > .active > a:focus { + border-bottom-color: #008dd2; + } +} +.nav-pills > li { + float: left; +} +.nav-pills > li > a { + border-radius: 0; +} +.nav-pills > li + li { + margin-left: 2px; +} +.nav-pills > li.active > a, +.nav-pills > li.active > a:hover, +.nav-pills > li.active > a:focus { + color: #fff; + background-color: #008dd2; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li + li { + margin-top: 2px; + margin-left: 0; +} +.nav-justified { + width: 100%; +} +.nav-justified > li { + float: none; +} +.nav-justified > li > a { + margin-bottom: 5px; + text-align: center; +} +.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs-justified { + border-bottom: 0; +} +.nav-tabs-justified > li > a { + margin-right: 0; + border-radius: 0; +} +.nav-tabs-justified > .active > a, +.nav-tabs-justified > .active > a:hover, +.nav-tabs-justified > .active > a:focus { + border: 1px solid #ddd; +} +@media (min-width: 768px) { + .nav-tabs-justified > li > a { + border-bottom: 1px solid #ddd; + border-radius: 0 0 0 0; + } + .nav-tabs-justified > .active > a, + .nav-tabs-justified > .active > a:hover, + .nav-tabs-justified > .active > a:focus { + border-bottom-color: #008dd2; + } +} +.tab-content > .tab-pane { + display: none; +} +.tab-content > .active { + display: block; +} +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.navbar { + position: relative; + min-height: 70px; + margin-bottom: 20px; + border: 1px solid transparent; +} +@media (min-width: 768px) { + .navbar { + border-radius: 0; + } +} +@media (min-width: 768px) { + .navbar-header { + float: left; + } +} +.navbar-collapse { + padding-right: 15px; + padding-left: 15px; + overflow-x: visible; + -webkit-overflow-scrolling: touch; + border-top: 1px solid transparent; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1); +} +.navbar-collapse.in { + overflow-y: auto; +} +@media (min-width: 768px) { + .navbar-collapse { + width: auto; + border-top: 0; + -webkit-box-shadow: none; + box-shadow: none; + } + .navbar-collapse.collapse { + display: block !important; + height: auto !important; + padding-bottom: 0; + overflow: visible !important; + } + .navbar-collapse.in { + overflow-y: visible; + } + .navbar-fixed-top .navbar-collapse, + .navbar-static-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + padding-right: 0; + padding-left: 0; + } +} +.navbar-fixed-top .navbar-collapse, +.navbar-fixed-bottom .navbar-collapse { + max-height: 340px; +} +@media (max-device-width: 480px) and (orientation: landscape) { + .navbar-fixed-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + max-height: 200px; + } +} +.container > .navbar-header, +.container-fluid > .navbar-header, +.container > .navbar-collapse, +.container-fluid > .navbar-collapse { + margin-right: -15px; + margin-left: -15px; +} +@media (min-width: 768px) { + .container > .navbar-header, + .container-fluid > .navbar-header, + .container > .navbar-collapse, + .container-fluid > .navbar-collapse { + margin-right: 0; + margin-left: 0; + } +} +.navbar-static-top { + z-index: 1000; + border-width: 0 0 1px; +} +@media (min-width: 768px) { + .navbar-static-top { + border-radius: 0; + } +} +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; +} +@media (min-width: 768px) { + .navbar-fixed-top, + .navbar-fixed-bottom { + border-radius: 0; + } +} +.navbar-fixed-top { + top: 0; + border-width: 0 0 1px; +} +.navbar-fixed-bottom { + bottom: 0; + margin-bottom: 0; + border-width: 1px 0 0; +} +.navbar-brand { + float: left; + height: 70px; + padding: 25px 15px; + font-size: 18px; + line-height: 20px; +} +.navbar-brand:hover, +.navbar-brand:focus { + text-decoration: none; +} +.navbar-brand > img { + display: block; +} +@media (min-width: 768px) { + .navbar > .container .navbar-brand, + .navbar > .container-fluid .navbar-brand { + margin-left: -15px; + } +} +.navbar-toggle { + position: relative; + float: right; + padding: 9px 10px; + margin-top: 18px; + margin-right: 15px; + margin-bottom: 18px; + background-color: transparent; + background-image: none; + border: 1px solid transparent; + border-radius: 0; +} +.navbar-toggle:focus { + outline: 0; +} +.navbar-toggle .icon-bar { + display: block; + width: 22px; + height: 2px; + border-radius: 1px; +} +.navbar-toggle .icon-bar + .icon-bar { + margin-top: 4px; +} +@media (min-width: 768px) { + .navbar-toggle { + display: none; + } +} +.navbar-nav { + margin: 12.5px -15px; +} +.navbar-nav > li > a { + padding-top: 10px; + padding-bottom: 10px; + line-height: 20px; +} +@media (max-width: 767px) { + .navbar-nav .open .dropdown-menu { + position: static; + float: none; + width: auto; + margin-top: 0; + background-color: transparent; + border: 0; + -webkit-box-shadow: none; + box-shadow: none; + } + .navbar-nav .open .dropdown-menu > li > a, + .navbar-nav .open .dropdown-menu .dropdown-header { + padding: 5px 15px 5px 25px; + } + .navbar-nav .open .dropdown-menu > li > a { + line-height: 20px; + } + .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-nav .open .dropdown-menu > li > a:focus { + background-image: none; + } +} +@media (min-width: 768px) { + .navbar-nav { + float: left; + margin: 0; + } + .navbar-nav > li { + float: left; + } + .navbar-nav > li > a { + padding-top: 25px; + padding-bottom: 25px; + } +} +.navbar-form { + padding: 10px 15px; + margin-top: 18px; + margin-right: -15px; + margin-bottom: 18px; + margin-left: -15px; + border-top: 1px solid transparent; + border-bottom: 1px solid transparent; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1); +} +@media (min-width: 768px) { + .navbar-form .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .navbar-form .form-control-static { + display: inline-block; + } + .navbar-form .input-group { + display: inline-table; + vertical-align: middle; + } + .navbar-form .input-group .input-group-addon, + .navbar-form .input-group .input-group-btn, + .navbar-form .input-group .form-control { + width: auto; + } + .navbar-form .input-group > .form-control { + width: 100%; + } + .navbar-form .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .radio, + .navbar-form .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .radio label, + .navbar-form .checkbox label { + padding-left: 0; + } + .navbar-form .radio input[type="radio"], + .navbar-form .checkbox input[type="checkbox"] { + position: relative; + margin-left: 0; + } + .navbar-form .has-feedback .form-control-feedback { + top: 0; + } +} +@media (max-width: 767px) { + .navbar-form .form-group { + margin-bottom: 5px; + } + .navbar-form .form-group:last-child { + margin-bottom: 0; + } +} +@media (min-width: 768px) { + .navbar-form { + width: auto; + padding-top: 0; + padding-bottom: 0; + margin-right: 0; + margin-left: 0; + border: 0; + -webkit-box-shadow: none; + box-shadow: none; + } +} +.navbar-nav > li > .dropdown-menu { + margin-top: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { + margin-bottom: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.navbar-btn { + margin-top: 18px; + margin-bottom: 18px; +} +.navbar-btn.btn-sm { + margin-top: 20px; + margin-bottom: 20px; +} +.navbar-btn.btn-xs { + margin-top: 24px; + margin-bottom: 24px; +} +.navbar-text { + margin-top: 25px; + margin-bottom: 25px; +} +@media (min-width: 768px) { + .navbar-text { + float: left; + margin-right: 15px; + margin-left: 15px; + } +} +@media (min-width: 768px) { + .navbar-left { + float: left !important; + } + .navbar-right { + float: right !important; + margin-right: -15px; + } + .navbar-right ~ .navbar-right { + margin-right: 0; + } +} +.navbar-default { + background-color: #008dd2; + border-color: #008dd2; +} +.navbar-default .navbar-brand { + color: #fff; +} +.navbar-default .navbar-brand:hover, +.navbar-default .navbar-brand:focus { + color: #e6e6e6; + background-color: transparent; +} +.navbar-default .navbar-text { + color: #fff; +} +.navbar-default .navbar-nav > li > a { + color: #fff; +} +.navbar-default .navbar-nav > li > a:hover, +.navbar-default .navbar-nav > li > a:focus { + color: #ccc; + background-color: transparent; +} +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a:focus { + color: #ccc; + background-color: #008dd2; +} +.navbar-default .navbar-nav > .disabled > a, +.navbar-default .navbar-nav > .disabled > a:hover, +.navbar-default .navbar-nav > .disabled > a:focus { + color: #ccc; + background-color: transparent; +} +.navbar-default .navbar-toggle { + border-color: #ddd; +} +.navbar-default .navbar-toggle:hover, +.navbar-default .navbar-toggle:focus { + background-color: #ddd; +} +.navbar-default .navbar-toggle .icon-bar { + background-color: #888; +} +.navbar-default .navbar-collapse, +.navbar-default .navbar-form { + border-color: #008dd2; +} +.navbar-default .navbar-nav > .open > a, +.navbar-default .navbar-nav > .open > a:hover, +.navbar-default .navbar-nav > .open > a:focus { + color: #ccc; + background-color: #008dd2; +} +@media (max-width: 767px) { + .navbar-default .navbar-nav .open .dropdown-menu > li > a { + color: #fff; + } + .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { + color: #ccc; + background-color: transparent; + } + .navbar-default .navbar-nav .open .dropdown-menu > .active > a, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #ccc; + background-color: #008dd2; + } + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #ccc; + background-color: transparent; + } +} +.navbar-default .navbar-link { + color: #fff; +} +.navbar-default .navbar-link:hover { + color: #ccc; +} +.navbar-default .btn-link { + color: #fff; +} +.navbar-default .btn-link:hover, +.navbar-default .btn-link:focus { + color: #ccc; +} +.navbar-default .btn-link[disabled]:hover, +fieldset[disabled] .navbar-default .btn-link:hover, +.navbar-default .btn-link[disabled]:focus, +fieldset[disabled] .navbar-default .btn-link:focus { + color: #ccc; +} +.navbar-inverse { + background-color: #222; + border-color: #080808; +} +.navbar-inverse .navbar-brand { + color: #008fee; +} +.navbar-inverse .navbar-brand:hover, +.navbar-inverse .navbar-brand:focus { + color: #fff; + background-color: transparent; +} +.navbar-inverse .navbar-text { + color: #008fee; +} +.navbar-inverse .navbar-nav > li > a { + color: #008fee; +} +.navbar-inverse .navbar-nav > li > a:hover, +.navbar-inverse .navbar-nav > li > a:focus { + color: #fff; + background-color: transparent; +} +.navbar-inverse .navbar-nav > .active > a, +.navbar-inverse .navbar-nav > .active > a:hover, +.navbar-inverse .navbar-nav > .active > a:focus { + color: #fff; + background-color: #080808; +} +.navbar-inverse .navbar-nav > .disabled > a, +.navbar-inverse .navbar-nav > .disabled > a:hover, +.navbar-inverse .navbar-nav > .disabled > a:focus { + color: #444; + background-color: transparent; +} +.navbar-inverse .navbar-toggle { + border-color: #ccc; +} +.navbar-inverse .navbar-toggle:hover, +.navbar-inverse .navbar-toggle:focus { + background-color: #ccc; +} +.navbar-inverse .navbar-toggle .icon-bar { + background-color: #fff; +} +.navbar-inverse .navbar-collapse, +.navbar-inverse .navbar-form { + border-color: #101010; +} +.navbar-inverse .navbar-nav > .open > a, +.navbar-inverse .navbar-nav > .open > a:hover, +.navbar-inverse .navbar-nav > .open > a:focus { + color: #fff; + background-color: #080808; +} +@media (max-width: 767px) { + .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { + border-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu .divider { + background-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { + color: #008fee; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { + color: #fff; + background-color: transparent; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #fff; + background-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #444; + background-color: transparent; + } +} +.navbar-inverse .navbar-link { + color: #008fee; +} +.navbar-inverse .navbar-link:hover { + color: #fff; +} +.navbar-inverse .btn-link { + color: #008fee; +} +.navbar-inverse .btn-link:hover, +.navbar-inverse .btn-link:focus { + color: #fff; +} +.navbar-inverse .btn-link[disabled]:hover, +fieldset[disabled] .navbar-inverse .btn-link:hover, +.navbar-inverse .btn-link[disabled]:focus, +fieldset[disabled] .navbar-inverse .btn-link:focus { + color: #444; +} +.breadcrumb { + padding: 8px 15px; + margin-bottom: 20px; + list-style: none; + background-color: #f5f5f5; + border-radius: 0; +} +.breadcrumb > li { + display: inline-block; +} +.breadcrumb > li + li:before { + padding: 0 5px; + color: #ccc; + content: "/\00a0"; +} +.breadcrumb > .active { + color: #008dd2; +} +.pagination { + display: inline-block; + padding-left: 0; + margin: 20px 0; + border-radius: 0; +} +.pagination > li { + display: inline; +} +.pagination > li > a, +.pagination > li > span { + position: relative; + float: left; + padding: 6px 12px; + margin-left: -1px; + line-height: 1.42857143; + color: #008dd2; + text-decoration: none; + background-color: #fff; + border: 1px solid #ddd; +} +.pagination > li:first-child > a, +.pagination > li:first-child > span { + margin-left: 0; + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.pagination > li:last-child > a, +.pagination > li:last-child > span { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.pagination > li > a:hover, +.pagination > li > span:hover, +.pagination > li > a:focus, +.pagination > li > span:focus { + z-index: 2; + color: #036595; + background-color: #008dd2; + border-color: #ddd; +} +.pagination > .active > a, +.pagination > .active > span, +.pagination > .active > a:hover, +.pagination > .active > span:hover, +.pagination > .active > a:focus, +.pagination > .active > span:focus { + z-index: 3; + color: #fff; + cursor: default; + background-color: #008dd2; + border-color: #008dd2; +} +.pagination > .disabled > span, +.pagination > .disabled > span:hover, +.pagination > .disabled > span:focus, +.pagination > .disabled > a, +.pagination > .disabled > a:hover, +.pagination > .disabled > a:focus { + color: #008dd2; + cursor: not-allowed; + background-color: #fff; + border-color: #ddd; +} +.pagination-lg > li > a, +.pagination-lg > li > span { + padding: 10px 16px; + font-size: 18px; + line-height: 1.3333333; +} +.pagination-lg > li:first-child > a, +.pagination-lg > li:first-child > span { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.pagination-lg > li:last-child > a, +.pagination-lg > li:last-child > span { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.pagination-sm > li > a, +.pagination-sm > li > span { + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; +} +.pagination-sm > li:first-child > a, +.pagination-sm > li:first-child > span { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.pagination-sm > li:last-child > a, +.pagination-sm > li:last-child > span { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.pager { + padding-left: 0; + margin: 20px 0; + text-align: center; + list-style: none; +} +.pager li { + display: inline; +} +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + border-radius: 15px; +} +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #008dd2; +} +.pager .next > a, +.pager .next > span { + float: right; +} +.pager .previous > a, +.pager .previous > span { + float: left; +} +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: #008dd2; + cursor: not-allowed; + background-color: #fff; +} +.label { + display: inline; + padding: .2em .6em .3em; + font-size: 75%; + font-weight: bold; + line-height: 1; + color: #fff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25em; +} +a.label:hover, +a.label:focus { + color: #fff; + text-decoration: none; + cursor: pointer; +} +.label:empty { + display: none; +} +.btn .label { + position: relative; + top: -1px; +} +.label-default { + background-color: #008dd2; +} +.label-default[href]:hover, +.label-default[href]:focus { + background-color: #036595; +} +.label-primary { + background-color: #008dd2; +} +.label-primary[href]:hover, +.label-primary[href]:focus { + background-color: #036595; +} +.label-success { + background-color: #5cb85c; +} +.label-success[href]:hover, +.label-success[href]:focus { + background-color: #449d44; +} +.label-info { + background-color: #5bc0de; +} +.label-info[href]:hover, +.label-info[href]:focus { + background-color: #31b0d5; +} +.label-warning { + background-color: #f0ad4e; +} +.label-warning[href]:hover, +.label-warning[href]:focus { + background-color: #ec971f; +} +.label-danger { + background-color: #d9534f; +} +.label-danger[href]:hover, +.label-danger[href]:focus { + background-color: #c9302c; +} +.badge { + display: inline-block; + min-width: 10px; + padding: 3px 7px; + font-size: 12px; + font-weight: bold; + line-height: 1; + color: #fff; + text-align: center; + white-space: nowrap; + vertical-align: middle; + background-color: #008dd2; + border-radius: 10px; +} +.badge:empty { + display: none; +} +.btn .badge { + position: relative; + top: -1px; +} +.btn-xs .badge, +.btn-group-xs > .btn .badge { + top: 0; + padding: 1px 5px; +} +a.badge:hover, +a.badge:focus { + color: #fff; + text-decoration: none; + cursor: pointer; +} +.list-group-item.active > .badge, +.nav-pills > .active > a > .badge { + color: #008dd2; + background-color: #fff; +} +.list-group-item > .badge { + float: right; +} +.list-group-item > .badge + .badge { + margin-right: 5px; +} +.nav-pills > li > a > .badge { + margin-left: 3px; +} +.jumbotron { + padding-top: 30px; + padding-bottom: 30px; + margin-bottom: 30px; + color: inherit; + background-color: #008dd2; +} +.jumbotron h1, +.jumbotron .h1 { + color: inherit; +} +.jumbotron p { + margin-bottom: 15px; + font-size: 21px; + font-weight: 200; +} +.jumbotron > hr { + border-top-color: #036595; +} +.container .jumbotron, +.container-fluid .jumbotron { + padding-right: 15px; + padding-left: 15px; + border-radius: 0; +} +.jumbotron .container { + max-width: 100%; +} +@media screen and (min-width: 768px) { + .jumbotron { + padding-top: 48px; + padding-bottom: 48px; + } + .container .jumbotron, + .container-fluid .jumbotron { + padding-right: 60px; + padding-left: 60px; + } + .jumbotron h1, + .jumbotron .h1 { + font-size: 63px; + } +} +.thumbnail { + display: block; + padding: 4px; + margin-bottom: 20px; + line-height: 1.42857143; + background-color: #008dd2; + border: 1px solid #ddd; + border-radius: 0; + -webkit-transition: border .2s ease-in-out; + -o-transition: border .2s ease-in-out; + transition: border .2s ease-in-out; +} +.thumbnail > img, +.thumbnail a > img { + margin-right: auto; + margin-left: auto; +} +a.thumbnail:hover, +a.thumbnail:focus, +a.thumbnail.active { + border-color: #008dd2; +} +.thumbnail .caption { + padding: 9px; + color: #008dd2; +} +.alert { + padding: 15px; + margin-bottom: 20px; + border: 1px solid transparent; + border-radius: 0; +} +.alert h4 { + margin-top: 0; + color: inherit; +} +.alert .alert-link { + font-weight: bold; +} +.alert > p, +.alert > ul { + margin-bottom: 0; +} +.alert > p + p { + margin-top: 5px; +} +.alert-dismissable, +.alert-dismissible { + padding-right: 35px; +} +.alert-dismissable .close, +.alert-dismissible .close { + position: relative; + top: -2px; + right: -21px; + color: inherit; +} +.alert-success { + color: #3c763d; + background-color: #dff0d8; + border-color: #d6e9c6; +} +.alert-success hr { + border-top-color: #c9e2b3; +} +.alert-success .alert-link { + color: #2b542c; +} +.alert-info { + color: #31708f; + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-info hr { + border-top-color: #a6e1ec; +} +.alert-info .alert-link { + color: #245269; +} +.alert-warning { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #faebcc; +} +.alert-warning hr { + border-top-color: #f7e1b5; +} +.alert-warning .alert-link { + color: #66512c; +} +.alert-danger { + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; +} +.alert-danger hr { + border-top-color: #e4b9c0; +} +.alert-danger .alert-link { + color: #843534; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +@-o-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +.progress { + height: 20px; + margin-bottom: 20px; + overflow: hidden; + background-color: #f5f5f5; + border-radius: 0; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1); +} +.progress-bar { + float: left; + width: 0; + height: 100%; + font-size: 12px; + line-height: 20px; + color: #fff; + text-align: center; + background-color: #008dd2; + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15); + -webkit-transition: width .6s ease; + -o-transition: width .6s ease; + transition: width .6s ease; +} +.progress-striped .progress-bar, +.progress-bar-striped { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + background-size: 40px 40px; +} +.progress.active .progress-bar, +.progress-bar.active { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-bar-success { + background-color: #5cb85c; +} +.progress-striped .progress-bar-success { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); +} +.progress-bar-info { + background-color: #5bc0de; +} +.progress-striped .progress-bar-info { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); +} +.progress-bar-warning { + background-color: #f0ad4e; +} +.progress-striped .progress-bar-warning { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); +} +.progress-bar-danger { + background-color: #d9534f; +} +.progress-striped .progress-bar-danger { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); +} +.media { + margin-top: 15px; +} +.media:first-child { + margin-top: 0; +} +.media, +.media-body { + overflow: hidden; + zoom: 1; +} +.media-body { + width: 10000px; +} +.media-object { + display: block; +} +.media-object.img-thumbnail { + max-width: none; +} +.media-right, +.media > .pull-right { + padding-left: 10px; +} +.media-left, +.media > .pull-left { + padding-right: 10px; +} +.media-left, +.media-right, +.media-body { + display: table-cell; + vertical-align: top; +} +.media-middle { + vertical-align: middle; +} +.media-bottom { + vertical-align: bottom; +} +.media-heading { + margin-top: 0; + margin-bottom: 5px; +} +.media-list { + padding-left: 0; + list-style: none; +} +.list-group { + padding-left: 0; + margin-bottom: 20px; +} +.list-group-item { + position: relative; + display: block; + padding: 10px 15px; + margin-bottom: -1px; + background-color: #fff; + border: 1px solid #ddd; +} +.list-group-item:first-child { + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.list-group-item:last-child { + margin-bottom: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +a.list-group-item, +button.list-group-item { + color: #fff; +} +a.list-group-item .list-group-item-heading, +button.list-group-item .list-group-item-heading { + color: #ccc; +} +a.list-group-item:hover, +button.list-group-item:hover, +a.list-group-item:focus, +button.list-group-item:focus { + color: #fff; + text-decoration: none; + background-color: #f5f5f5; +} +button.list-group-item { + width: 100%; + text-align: left; +} +.list-group-item.disabled, +.list-group-item.disabled:hover, +.list-group-item.disabled:focus { + color: #008dd2; + cursor: not-allowed; + background-color: #008dd2; +} +.list-group-item.disabled .list-group-item-heading, +.list-group-item.disabled:hover .list-group-item-heading, +.list-group-item.disabled:focus .list-group-item-heading { + color: inherit; +} +.list-group-item.disabled .list-group-item-text, +.list-group-item.disabled:hover .list-group-item-text, +.list-group-item.disabled:focus .list-group-item-text { + color: #008dd2; +} +.list-group-item.active, +.list-group-item.active:hover, +.list-group-item.active:focus { + z-index: 2; + color: #fff; + background-color: #008dd2; + border-color: #008dd2; +} +.list-group-item.active .list-group-item-heading, +.list-group-item.active:hover .list-group-item-heading, +.list-group-item.active:focus .list-group-item-heading, +.list-group-item.active .list-group-item-heading > small, +.list-group-item.active:hover .list-group-item-heading > small, +.list-group-item.active:focus .list-group-item-heading > small, +.list-group-item.active .list-group-item-heading > .small, +.list-group-item.active:hover .list-group-item-heading > .small, +.list-group-item.active:focus .list-group-item-heading > .small { + color: inherit; +} +.list-group-item.active .list-group-item-text, +.list-group-item.active:hover .list-group-item-text, +.list-group-item.active:focus .list-group-item-text { + color: #6ec5ff; +} +.list-group-item-success { + color: #3c763d; + background-color: #dff0d8; +} +a.list-group-item-success, +button.list-group-item-success { + color: #3c763d; +} +a.list-group-item-success .list-group-item-heading, +button.list-group-item-success .list-group-item-heading { + color: inherit; +} +a.list-group-item-success:hover, +button.list-group-item-success:hover, +a.list-group-item-success:focus, +button.list-group-item-success:focus { + color: #3c763d; + background-color: #d0e9c6; +} +a.list-group-item-success.active, +button.list-group-item-success.active, +a.list-group-item-success.active:hover, +button.list-group-item-success.active:hover, +a.list-group-item-success.active:focus, +button.list-group-item-success.active:focus { + color: #fff; + background-color: #3c763d; + border-color: #3c763d; +} +.list-group-item-info { + color: #31708f; + background-color: #d9edf7; +} +a.list-group-item-info, +button.list-group-item-info { + color: #31708f; +} +a.list-group-item-info .list-group-item-heading, +button.list-group-item-info .list-group-item-heading { + color: inherit; +} +a.list-group-item-info:hover, +button.list-group-item-info:hover, +a.list-group-item-info:focus, +button.list-group-item-info:focus { + color: #31708f; + background-color: #c4e3f3; +} +a.list-group-item-info.active, +button.list-group-item-info.active, +a.list-group-item-info.active:hover, +button.list-group-item-info.active:hover, +a.list-group-item-info.active:focus, +button.list-group-item-info.active:focus { + color: #fff; + background-color: #31708f; + border-color: #31708f; +} +.list-group-item-warning { + color: #8a6d3b; + background-color: #fcf8e3; +} +a.list-group-item-warning, +button.list-group-item-warning { + color: #8a6d3b; +} +a.list-group-item-warning .list-group-item-heading, +button.list-group-item-warning .list-group-item-heading { + color: inherit; +} +a.list-group-item-warning:hover, +button.list-group-item-warning:hover, +a.list-group-item-warning:focus, +button.list-group-item-warning:focus { + color: #8a6d3b; + background-color: #faf2cc; +} +a.list-group-item-warning.active, +button.list-group-item-warning.active, +a.list-group-item-warning.active:hover, +button.list-group-item-warning.active:hover, +a.list-group-item-warning.active:focus, +button.list-group-item-warning.active:focus { + color: #fff; + background-color: #8a6d3b; + border-color: #8a6d3b; +} +.list-group-item-danger { + color: #a94442; + background-color: #f2dede; +} +a.list-group-item-danger, +button.list-group-item-danger { + color: #a94442; +} +a.list-group-item-danger .list-group-item-heading, +button.list-group-item-danger .list-group-item-heading { + color: inherit; +} +a.list-group-item-danger:hover, +button.list-group-item-danger:hover, +a.list-group-item-danger:focus, +button.list-group-item-danger:focus { + color: #a94442; + background-color: #ebcccc; +} +a.list-group-item-danger.active, +button.list-group-item-danger.active, +a.list-group-item-danger.active:hover, +button.list-group-item-danger.active:hover, +a.list-group-item-danger.active:focus, +button.list-group-item-danger.active:focus { + color: #fff; + background-color: #a94442; + border-color: #a94442; +} +.list-group-item-heading { + margin-top: 0; + margin-bottom: 5px; +} +.list-group-item-text { + margin-bottom: 0; + line-height: 1.3; +} +.panel { + margin-bottom: 20px; + background-color: #fff; + border: 1px solid transparent; + border-radius: 0; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05); + box-shadow: 0 1px 1px rgba(0, 0, 0, .05); +} +.panel-body { + padding: 15px; +} +.panel-heading { + padding: 10px 15px; + border-bottom: 1px solid transparent; + border-top-left-radius: -1px; + border-top-right-radius: -1px; +} +.panel-heading > .dropdown .dropdown-toggle { + color: inherit; +} +.panel-title { + margin-top: 0; + margin-bottom: 0; + font-size: 16px; + color: inherit; +} +.panel-title > a, +.panel-title > small, +.panel-title > .small, +.panel-title > small > a, +.panel-title > .small > a { + color: inherit; +} +.panel-footer { + padding: 10px 15px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + border-bottom-right-radius: -1px; + border-bottom-left-radius: -1px; +} +.panel > .list-group, +.panel > .panel-collapse > .list-group { + margin-bottom: 0; +} +.panel > .list-group .list-group-item, +.panel > .panel-collapse > .list-group .list-group-item { + border-width: 1px 0; + border-radius: 0; +} +.panel > .list-group:first-child .list-group-item:first-child, +.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child { + border-top: 0; + border-top-left-radius: -1px; + border-top-right-radius: -1px; +} +.panel > .list-group:last-child .list-group-item:last-child, +.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child { + border-bottom: 0; + border-bottom-right-radius: -1px; + border-bottom-left-radius: -1px; +} +.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child { + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.panel-heading + .list-group .list-group-item:first-child { + border-top-width: 0; +} +.list-group + .panel-footer { + border-top-width: 0; +} +.panel > .table, +.panel > .table-responsive > .table, +.panel > .panel-collapse > .table { + margin-bottom: 0; +} +.panel > .table caption, +.panel > .table-responsive > .table caption, +.panel > .panel-collapse > .table caption { + padding-right: 15px; + padding-left: 15px; +} +.panel > .table:first-child, +.panel > .table-responsive:first-child > .table:first-child { + border-top-left-radius: -1px; + border-top-right-radius: -1px; +} +.panel > .table:first-child > thead:first-child > tr:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child { + border-top-left-radius: -1px; + border-top-right-radius: -1px; +} +.panel > .table:first-child > thead:first-child > tr:first-child td:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child, +.panel > .table:first-child > thead:first-child > tr:first-child th:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child { + border-top-left-radius: -1px; +} +.panel > .table:first-child > thead:first-child > tr:first-child td:last-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child, +.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child, +.panel > .table:first-child > thead:first-child > tr:first-child th:last-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child, +.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child { + border-top-right-radius: -1px; +} +.panel > .table:last-child, +.panel > .table-responsive:last-child > .table:last-child { + border-bottom-right-radius: -1px; + border-bottom-left-radius: -1px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child { + border-bottom-right-radius: -1px; + border-bottom-left-radius: -1px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child { + border-bottom-left-radius: -1px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child { + border-bottom-right-radius: -1px; +} +.panel > .panel-body + .table, +.panel > .panel-body + .table-responsive, +.panel > .table + .panel-body, +.panel > .table-responsive + .panel-body { + border-top: 1px solid #008dd2; +} +.panel > .table > tbody:first-child > tr:first-child th, +.panel > .table > tbody:first-child > tr:first-child td { + border-top: 0; +} +.panel > .table-bordered, +.panel > .table-responsive > .table-bordered { + border: 0; +} +.panel > .table-bordered > thead > tr > th:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:first-child, +.panel > .table-bordered > tbody > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, +.panel > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-bordered > thead > tr > td:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:first-child, +.panel > .table-bordered > tbody > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, +.panel > .table-bordered > tfoot > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; +} +.panel > .table-bordered > thead > tr > th:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:last-child, +.panel > .table-bordered > tbody > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, +.panel > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-bordered > thead > tr > td:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:last-child, +.panel > .table-bordered > tbody > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, +.panel > .table-bordered > tfoot > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; +} +.panel > .table-bordered > thead > tr:first-child > td, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > td, +.panel > .table-bordered > tbody > tr:first-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td, +.panel > .table-bordered > thead > tr:first-child > th, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > th, +.panel > .table-bordered > tbody > tr:first-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th { + border-bottom: 0; +} +.panel > .table-bordered > tbody > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, +.panel > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-bordered > tbody > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, +.panel > .table-bordered > tfoot > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th { + border-bottom: 0; +} +.panel > .table-responsive { + margin-bottom: 0; + border: 0; +} +.panel-group { + margin-bottom: 20px; +} +.panel-group .panel { + margin-bottom: 0; + border-radius: 0; +} +.panel-group .panel + .panel { + margin-top: 5px; +} +.panel-group .panel-heading { + border-bottom: 0; +} +.panel-group .panel-heading + .panel-collapse > .panel-body, +.panel-group .panel-heading + .panel-collapse > .list-group { + border-top: 1px solid #ddd; +} +.panel-group .panel-footer { + border-top: 0; +} +.panel-group .panel-footer + .panel-collapse .panel-body { + border-bottom: 1px solid #ddd; +} +.panel-default { + border-color: #ddd; +} +.panel-default > .panel-heading { + color: #008dd2; + background-color: #f5f5f5; + border-color: #ddd; +} +.panel-default > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #ddd; +} +.panel-default > .panel-heading .badge { + color: #f5f5f5; + background-color: #008dd2; +} +.panel-default > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #ddd; +} +.panel-primary { + border-color: #008dd2; +} +.panel-primary > .panel-heading { + color: #fff; + background-color: #008dd2; + border-color: #008dd2; +} +.panel-primary > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #008dd2; +} +.panel-primary > .panel-heading .badge { + color: #008dd2; + background-color: #fff; +} +.panel-primary > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #008dd2; +} +.panel-success { + border-color: #d6e9c6; +} +.panel-success > .panel-heading { + color: #3c763d; + background-color: #dff0d8; + border-color: #d6e9c6; +} +.panel-success > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #d6e9c6; +} +.panel-success > .panel-heading .badge { + color: #dff0d8; + background-color: #3c763d; +} +.panel-success > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #d6e9c6; +} +.panel-info { + border-color: #bce8f1; +} +.panel-info > .panel-heading { + color: #31708f; + background-color: #d9edf7; + border-color: #bce8f1; +} +.panel-info > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #bce8f1; +} +.panel-info > .panel-heading .badge { + color: #d9edf7; + background-color: #31708f; +} +.panel-info > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #bce8f1; +} +.panel-warning { + border-color: #faebcc; +} +.panel-warning > .panel-heading { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #faebcc; +} +.panel-warning > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #faebcc; +} +.panel-warning > .panel-heading .badge { + color: #fcf8e3; + background-color: #8a6d3b; +} +.panel-warning > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #faebcc; +} +.panel-danger { + border-color: #ebccd1; +} +.panel-danger > .panel-heading { + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; +} +.panel-danger > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #ebccd1; +} +.panel-danger > .panel-heading .badge { + color: #f2dede; + background-color: #a94442; +} +.panel-danger > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #ebccd1; +} +.embed-responsive { + position: relative; + display: block; + height: 0; + padding: 0; + overflow: hidden; +} +.embed-responsive .embed-responsive-item, +.embed-responsive iframe, +.embed-responsive embed, +.embed-responsive object, +.embed-responsive video { + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + border: 0; +} +.embed-responsive-16by9 { + padding-bottom: 56.25%; +} +.embed-responsive-4by3 { + padding-bottom: 75%; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #e3e3e3; + border-radius: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, .15); +} +.well-lg { + padding: 24px; + border-radius: 0; +} +.well-sm { + padding: 9px; + border-radius: 0; +} +.close { + float: right; + font-size: 21px; + font-weight: bold; + line-height: 1; + color: #000; + text-shadow: 0 1px 0 #fff; + filter: alpha(opacity=20); + opacity: .2; +} +.close:hover, +.close:focus { + color: #000; + text-decoration: none; + cursor: pointer; + filter: alpha(opacity=50); + opacity: .5; +} +button.close { + -webkit-appearance: none; + padding: 0; + cursor: pointer; + background: transparent; + border: 0; +} +.modal-open { + overflow: hidden; +} +.modal { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1050; + display: none; + overflow: hidden; + -webkit-overflow-scrolling: touch; + outline: 0; +} +.modal.fade .modal-dialog { + -webkit-transition: -webkit-transform .3s ease-out; + -o-transition: -o-transform .3s ease-out; + transition: transform .3s ease-out; + -webkit-transform: translate(0, -25%); + -ms-transform: translate(0, -25%); + -o-transform: translate(0, -25%); + transform: translate(0, -25%); +} +.modal.in .modal-dialog { + -webkit-transform: translate(0, 0); + -ms-transform: translate(0, 0); + -o-transform: translate(0, 0); + transform: translate(0, 0); +} +.modal-open .modal { + overflow-x: hidden; + overflow-y: auto; +} +.modal-dialog { + position: relative; + width: auto; + margin: 10px; +} +.modal-content { + position: relative; + background-color: #fff; + -webkit-background-clip: padding-box; + background-clip: padding-box; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, .2); + border-radius: 0; + outline: 0; + -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5); + box-shadow: 0 3px 9px rgba(0, 0, 0, .5); +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000; +} +.modal-backdrop.fade { + filter: alpha(opacity=0); + opacity: 0; +} +.modal-backdrop.in { + filter: alpha(opacity=50); + opacity: .5; +} +.modal-header { + padding: 15px; + border-bottom: 1px solid #e5e5e5; +} +.modal-header .close { + margin-top: -2px; +} +.modal-title { + margin: 0; + line-height: 1.42857143; +} +.modal-body { + position: relative; + padding: 15px; +} +.modal-footer { + padding: 15px; + text-align: right; + border-top: 1px solid #e5e5e5; +} +.modal-footer .btn + .btn { + margin-bottom: 0; + margin-left: 5px; +} +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} +.modal-footer .btn-block + .btn-block { + margin-left: 0; +} +.modal-scrollbar-measure { + position: absolute; + top: -9999px; + width: 50px; + height: 50px; + overflow: scroll; +} +@media (min-width: 768px) { + .modal-dialog { + width: 600px; + margin: 30px auto; + } + .modal-content { + -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5); + box-shadow: 0 5px 15px rgba(0, 0, 0, .5); + } + .modal-sm { + width: 300px; + } +} +@media (min-width: 992px) { + .modal-lg { + width: 900px; + } +} +.tooltip { + position: absolute; + z-index: 1070; + display: block; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 12px; + font-style: normal; + font-weight: normal; + line-height: 1.42857143; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + word-spacing: normal; + word-wrap: normal; + white-space: normal; + filter: alpha(opacity=0); + opacity: 0; + + line-break: auto; +} +.tooltip.in { + filter: alpha(opacity=90); + opacity: .9; +} +.tooltip.top { + padding: 5px 0; + margin-top: -3px; +} +.tooltip.right { + padding: 0 5px; + margin-left: 3px; +} +.tooltip.bottom { + padding: 5px 0; + margin-top: 3px; +} +.tooltip.left { + padding: 0 5px; + margin-left: -3px; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #fff; + text-align: center; + background-color: #000; + border-radius: 0; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-width: 5px 5px 0; + border-top-color: #000; +} +.tooltip.top-left .tooltip-arrow { + right: 5px; + bottom: 0; + margin-bottom: -5px; + border-width: 5px 5px 0; + border-top-color: #000; +} +.tooltip.top-right .tooltip-arrow { + bottom: 0; + left: 5px; + margin-bottom: -5px; + border-width: 5px 5px 0; + border-top-color: #000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-width: 5px 5px 5px 0; + border-right-color: #000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-width: 5px 0 5px 5px; + border-left-color: #000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000; +} +.tooltip.bottom-left .tooltip-arrow { + top: 0; + right: 5px; + margin-top: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000; +} +.tooltip.bottom-right .tooltip-arrow { + top: 0; + left: 5px; + margin-top: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1060; + display: none; + max-width: 276px; + padding: 1px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + font-style: normal; + font-weight: normal; + line-height: 1.42857143; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + word-spacing: normal; + word-wrap: normal; + white-space: normal; + background-color: #fff; + -webkit-background-clip: padding-box; + background-clip: padding-box; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, .2); + border-radius: 0; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2); + box-shadow: 0 5px 10px rgba(0, 0, 0, .2); + + line-break: auto; +} +.popover.top { + margin-top: -10px; +} +.popover.right { + margin-left: 10px; +} +.popover.bottom { + margin-top: 10px; +} +.popover.left { + margin-left: -10px; +} +.popover-title { + padding: 8px 14px; + margin: 0; + font-size: 14px; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + border-radius: -1px -1px 0 0; +} +.popover-content { + padding: 9px 14px; +} +.popover > .arrow, +.popover > .arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.popover > .arrow { + border-width: 11px; +} +.popover > .arrow:after { + content: ""; + border-width: 10px; +} +.popover.top > .arrow { + bottom: -11px; + left: 50%; + margin-left: -11px; + border-top-color: #999; + border-top-color: rgba(0, 0, 0, .25); + border-bottom-width: 0; +} +.popover.top > .arrow:after { + bottom: 1px; + margin-left: -10px; + content: " "; + border-top-color: #fff; + border-bottom-width: 0; +} +.popover.right > .arrow { + top: 50%; + left: -11px; + margin-top: -11px; + border-right-color: #999; + border-right-color: rgba(0, 0, 0, .25); + border-left-width: 0; +} +.popover.right > .arrow:after { + bottom: -10px; + left: 1px; + content: " "; + border-right-color: #fff; + border-left-width: 0; +} +.popover.bottom > .arrow { + top: -11px; + left: 50%; + margin-left: -11px; + border-top-width: 0; + border-bottom-color: #999; + border-bottom-color: rgba(0, 0, 0, .25); +} +.popover.bottom > .arrow:after { + top: 1px; + margin-left: -10px; + content: " "; + border-top-width: 0; + border-bottom-color: #fff; +} +.popover.left > .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-right-width: 0; + border-left-color: #999; + border-left-color: rgba(0, 0, 0, .25); +} +.popover.left > .arrow:after { + right: 1px; + bottom: -10px; + content: " "; + border-right-width: 0; + border-left-color: #fff; +} +.carousel { + position: relative; +} +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} +.carousel-inner > .item { + position: relative; + display: none; + -webkit-transition: .6s ease-in-out left; + -o-transition: .6s ease-in-out left; + transition: .6s ease-in-out left; +} +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + line-height: 1; +} +@media all and (transform-3d), (-webkit-transform-3d) { + .carousel-inner > .item { + -webkit-transition: -webkit-transform .6s ease-in-out; + -o-transition: -o-transform .6s ease-in-out; + transition: transform .6s ease-in-out; + + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-perspective: 1000px; + perspective: 1000px; + } + .carousel-inner > .item.next, + .carousel-inner > .item.active.right { + left: 0; + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + } + .carousel-inner > .item.prev, + .carousel-inner > .item.active.left { + left: 0; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } + .carousel-inner > .item.next.left, + .carousel-inner > .item.prev.right, + .carousel-inner > .item.active { + left: 0; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} +.carousel-inner > .active, +.carousel-inner > .next, +.carousel-inner > .prev { + display: block; +} +.carousel-inner > .active { + left: 0; +} +.carousel-inner > .next, +.carousel-inner > .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel-inner > .next { + left: 100%; +} +.carousel-inner > .prev { + left: -100%; +} +.carousel-inner > .next.left, +.carousel-inner > .prev.right { + left: 0; +} +.carousel-inner > .active.left { + left: -100%; +} +.carousel-inner > .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 15%; + font-size: 20px; + color: #fff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, .6); + background-color: rgba(0, 0, 0, 0); + filter: alpha(opacity=50); + opacity: .5; +} +.carousel-control.left { + background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%); + background-image: -o-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%); + background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), to(rgba(0, 0, 0, .0001))); + background-image: linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); + background-repeat: repeat-x; +} +.carousel-control.right { + right: 0; + left: auto; + background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%); + background-image: -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%); + background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), to(rgba(0, 0, 0, .5))); + background-image: linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); + background-repeat: repeat-x; +} +.carousel-control:hover, +.carousel-control:focus { + color: #fff; + text-decoration: none; + filter: alpha(opacity=90); + outline: 0; + opacity: .9; +} +.carousel-control .icon-prev, +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-left, +.carousel-control .glyphicon-chevron-right { + position: absolute; + top: 50%; + z-index: 5; + display: inline-block; + margin-top: -10px; +} +.carousel-control .icon-prev, +.carousel-control .glyphicon-chevron-left { + left: 50%; + margin-left: -10px; +} +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-right { + right: 50%; + margin-right: -10px; +} +.carousel-control .icon-prev, +.carousel-control .icon-next { + width: 20px; + height: 20px; + font-family: serif; + line-height: 1; +} +.carousel-control .icon-prev:before { + content: '\2039'; +} +.carousel-control .icon-next:before { + content: '\203a'; +} +.carousel-indicators { + position: absolute; + bottom: 10px; + left: 50%; + z-index: 15; + width: 60%; + padding-left: 0; + margin-left: -30%; + text-align: center; + list-style: none; +} +.carousel-indicators li { + display: inline-block; + width: 10px; + height: 10px; + margin: 1px; + text-indent: -999px; + cursor: pointer; + background-color: #000 \9; + background-color: rgba(0, 0, 0, 0); + border: 1px solid #fff; + border-radius: 10px; +} +.carousel-indicators .active { + width: 12px; + height: 12px; + margin: 0; + background-color: #fff; +} +.carousel-caption { + position: absolute; + right: 15%; + bottom: 20px; + left: 15%; + z-index: 10; + padding-top: 20px; + padding-bottom: 20px; + color: #fff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, .6); +} +.carousel-caption .btn { + text-shadow: none; +} +@media screen and (min-width: 768px) { + .carousel-control .glyphicon-chevron-left, + .carousel-control .glyphicon-chevron-right, + .carousel-control .icon-prev, + .carousel-control .icon-next { + width: 30px; + height: 30px; + margin-top: -10px; + font-size: 30px; + } + .carousel-control .glyphicon-chevron-left, + .carousel-control .icon-prev { + margin-left: -10px; + } + .carousel-control .glyphicon-chevron-right, + .carousel-control .icon-next { + margin-right: -10px; + } + .carousel-caption { + right: 20%; + left: 20%; + padding-bottom: 30px; + } + .carousel-indicators { + bottom: 20px; + } +} +.clearfix:before, +.clearfix:after, +.dl-horizontal dd:before, +.dl-horizontal dd:after, +.container:before, +.container:after, +.container-fluid:before, +.container-fluid:after, +.row:before, +.row:after, +.form-horizontal .form-group:before, +.form-horizontal .form-group:after, +.btn-toolbar:before, +.btn-toolbar:after, +.btn-group-vertical > .btn-group:before, +.btn-group-vertical > .btn-group:after, +.nav:before, +.nav:after, +.navbar:before, +.navbar:after, +.navbar-header:before, +.navbar-header:after, +.navbar-collapse:before, +.navbar-collapse:after, +.pager:before, +.pager:after, +.panel-body:before, +.panel-body:after, +.modal-header:before, +.modal-header:after, +.modal-footer:before, +.modal-footer:after { + display: table; + content: " "; +} +.clearfix:after, +.dl-horizontal dd:after, +.container:after, +.container-fluid:after, +.row:after, +.form-horizontal .form-group:after, +.btn-toolbar:after, +.btn-group-vertical > .btn-group:after, +.nav:after, +.navbar:after, +.navbar-header:after, +.navbar-collapse:after, +.pager:after, +.panel-body:after, +.modal-header:after, +.modal-footer:after { + clear: both; +} +.center-block { + display: block; + margin-right: auto; + margin-left: auto; +} +.pull-right { + float: right !important; +} +.pull-left { + float: left !important; +} +.hide { + display: none !important; +} +.show { + display: block !important; +} +.invisible { + visibility: hidden; +} +.text-hide { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} +.hidden { + display: none !important; +} +.affix { + position: fixed; +} +@-ms-viewport { + width: device-width; +} +.visible-xs, +.visible-sm, +.visible-md, +.visible-lg { + display: none !important; +} +.visible-xs-block, +.visible-xs-inline, +.visible-xs-inline-block, +.visible-sm-block, +.visible-sm-inline, +.visible-sm-inline-block, +.visible-md-block, +.visible-md-inline, +.visible-md-inline-block, +.visible-lg-block, +.visible-lg-inline, +.visible-lg-inline-block { + display: none !important; +} +@media (max-width: 767px) { + .visible-xs { + display: block !important; + } + table.visible-xs { + display: table !important; + } + tr.visible-xs { + display: table-row !important; + } + th.visible-xs, + td.visible-xs { + display: table-cell !important; + } +} +@media (max-width: 767px) { + .visible-xs-block { + display: block !important; + } +} +@media (max-width: 767px) { + .visible-xs-inline { + display: inline !important; + } +} +@media (max-width: 767px) { + .visible-xs-inline-block { + display: inline-block !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm { + display: block !important; + } + table.visible-sm { + display: table !important; + } + tr.visible-sm { + display: table-row !important; + } + th.visible-sm, + td.visible-sm { + display: table-cell !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-block { + display: block !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-inline { + display: inline !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-inline-block { + display: inline-block !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md { + display: block !important; + } + table.visible-md { + display: table !important; + } + tr.visible-md { + display: table-row !important; + } + th.visible-md, + td.visible-md { + display: table-cell !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-block { + display: block !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-inline { + display: inline !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-inline-block { + display: inline-block !important; + } +} +@media (min-width: 1200px) { + .visible-lg { + display: block !important; + } + table.visible-lg { + display: table !important; + } + tr.visible-lg { + display: table-row !important; + } + th.visible-lg, + td.visible-lg { + display: table-cell !important; + } +} +@media (min-width: 1200px) { + .visible-lg-block { + display: block !important; + } +} +@media (min-width: 1200px) { + .visible-lg-inline { + display: inline !important; + } +} +@media (min-width: 1200px) { + .visible-lg-inline-block { + display: inline-block !important; + } +} +@media (max-width: 767px) { + .hidden-xs { + display: none !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .hidden-sm { + display: none !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-md { + display: none !important; + } +} +@media (min-width: 1200px) { + .hidden-lg { + display: none !important; + } +} +.visible-print { + display: none !important; +} +@media print { + .visible-print { + display: block !important; + } + table.visible-print { + display: table !important; + } + tr.visible-print { + display: table-row !important; + } + th.visible-print, + td.visible-print { + display: table-cell !important; + } +} +.visible-print-block { + display: none !important; +} +@media print { + .visible-print-block { + display: block !important; + } +} +.visible-print-inline { + display: none !important; +} +@media print { + .visible-print-inline { + display: inline !important; + } +} +.visible-print-inline-block { + display: none !important; +} +@media print { + .visible-print-inline-block { + display: inline-block !important; + } +} +@media print { + .hidden-print { + display: none !important; + } +} +/*# sourceMappingURL=bootstrap.css.map */ diff --git a/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/fonts/glyphicons-halflings-regular.eot b/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/fonts/glyphicons-halflings-regular.eot new file mode 100644 index 0000000..b93a495 Binary files /dev/null and b/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/fonts/glyphicons-halflings-regular.eot differ diff --git a/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/fonts/glyphicons-halflings-regular.svg b/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/fonts/glyphicons-halflings-regular.svg new file mode 100644 index 0000000..94fb549 --- /dev/null +++ b/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/fonts/glyphicons-halflings-regular.svg @@ -0,0 +1,288 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/fonts/glyphicons-halflings-regular.ttf b/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 0000000..1413fc6 Binary files /dev/null and b/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/fonts/glyphicons-halflings-regular.ttf differ diff --git a/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/fonts/glyphicons-halflings-regular.woff b/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/fonts/glyphicons-halflings-regular.woff new file mode 100644 index 0000000..9e61285 Binary files /dev/null and b/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/fonts/glyphicons-halflings-regular.woff differ diff --git a/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/fonts/glyphicons-halflings-regular.woff2 b/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/fonts/glyphicons-halflings-regular.woff2 new file mode 100644 index 0000000..64539b5 Binary files /dev/null and b/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/fonts/glyphicons-halflings-regular.woff2 differ diff --git a/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/js/bootstrap.js b/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/js/bootstrap.js new file mode 100644 index 0000000..d47d640 --- /dev/null +++ b/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/js/bootstrap.js @@ -0,0 +1,2363 @@ +/*! + * Bootstrap v3.3.6 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. + * Licensed under the MIT license + */ + +if (typeof jQuery === 'undefined') { + throw new Error('Bootstrap\'s JavaScript requires jQuery') +} + ++function ($) { + 'use strict'; + var version = $.fn.jquery.split(' ')[0].split('.') + if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 2)) { + throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3') + } +}(jQuery); + +/* ======================================================================== + * Bootstrap: transition.js v3.3.6 + * http://getbootstrap.com/javascript/#transitions + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) + // ============================================================ + + function transitionEnd() { + var el = document.createElement('bootstrap') + + var transEndEventNames = { + WebkitTransition : 'webkitTransitionEnd', + MozTransition : 'transitionend', + OTransition : 'oTransitionEnd otransitionend', + transition : 'transitionend' + } + + for (var name in transEndEventNames) { + if (el.style[name] !== undefined) { + return { end: transEndEventNames[name] } + } + } + + return false // explicit for ie8 ( ._.) + } + + // http://blog.alexmaccaw.com/css-transitions + $.fn.emulateTransitionEnd = function (duration) { + var called = false + var $el = this + $(this).one('bsTransitionEnd', function () { called = true }) + var callback = function () { if (!called) $($el).trigger($.support.transition.end) } + setTimeout(callback, duration) + return this + } + + $(function () { + $.support.transition = transitionEnd() + + if (!$.support.transition) return + + $.event.special.bsTransitionEnd = { + bindType: $.support.transition.end, + delegateType: $.support.transition.end, + handle: function (e) { + if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments) + } + } + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: alert.js v3.3.6 + * http://getbootstrap.com/javascript/#alerts + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // ALERT CLASS DEFINITION + // ====================== + + var dismiss = '[data-dismiss="alert"]' + var Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.VERSION = '3.3.6' + + Alert.TRANSITION_DURATION = 150 + + Alert.prototype.close = function (e) { + var $this = $(this) + var selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + } + + var $parent = $(selector) + + if (e) e.preventDefault() + + if (!$parent.length) { + $parent = $this.closest('.alert') + } + + $parent.trigger(e = $.Event('close.bs.alert')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + // detach from parent, fire event then clean up data + $parent.detach().trigger('closed.bs.alert').remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent + .one('bsTransitionEnd', removeElement) + .emulateTransitionEnd(Alert.TRANSITION_DURATION) : + removeElement() + } + + + // ALERT PLUGIN DEFINITION + // ======================= + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.alert') + + if (!data) $this.data('bs.alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + var old = $.fn.alert + + $.fn.alert = Plugin + $.fn.alert.Constructor = Alert + + + // ALERT NO CONFLICT + // ================= + + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } + + + // ALERT DATA-API + // ============== + + $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: button.js v3.3.6 + * http://getbootstrap.com/javascript/#buttons + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // BUTTON PUBLIC CLASS DEFINITION + // ============================== + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Button.DEFAULTS, options) + this.isLoading = false + } + + Button.VERSION = '3.3.6' + + Button.DEFAULTS = { + loadingText: 'loading...' + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + var $el = this.$element + var val = $el.is('input') ? 'val' : 'html' + var data = $el.data() + + state += 'Text' + + if (data.resetText == null) $el.data('resetText', $el[val]()) + + // push to event loop to allow forms to submit + setTimeout($.proxy(function () { + $el[val](data[state] == null ? this.options[state] : data[state]) + + if (state == 'loadingText') { + this.isLoading = true + $el.addClass(d).attr(d, d) + } else if (this.isLoading) { + this.isLoading = false + $el.removeClass(d).removeAttr(d) + } + }, this), 0) + } + + Button.prototype.toggle = function () { + var changed = true + var $parent = this.$element.closest('[data-toggle="buttons"]') + + if ($parent.length) { + var $input = this.$element.find('input') + if ($input.prop('type') == 'radio') { + if ($input.prop('checked')) changed = false + $parent.find('.active').removeClass('active') + this.$element.addClass('active') + } else if ($input.prop('type') == 'checkbox') { + if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false + this.$element.toggleClass('active') + } + $input.prop('checked', this.$element.hasClass('active')) + if (changed) $input.trigger('change') + } else { + this.$element.attr('aria-pressed', !this.$element.hasClass('active')) + this.$element.toggleClass('active') + } + } + + + // BUTTON PLUGIN DEFINITION + // ======================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.button') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.button', (data = new Button(this, options))) + + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + var old = $.fn.button + + $.fn.button = Plugin + $.fn.button.Constructor = Button + + + // BUTTON NO CONFLICT + // ================== + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + + // BUTTON DATA-API + // =============== + + $(document) + .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + Plugin.call($btn, 'toggle') + if (!($(e.target).is('input[type="radio"]') || $(e.target).is('input[type="checkbox"]'))) e.preventDefault() + }) + .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) { + $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type)) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: carousel.js v3.3.6 + * http://getbootstrap.com/javascript/#carousel + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // CAROUSEL CLASS DEFINITION + // ========================= + + var Carousel = function (element, options) { + this.$element = $(element) + this.$indicators = this.$element.find('.carousel-indicators') + this.options = options + this.paused = null + this.sliding = null + this.interval = null + this.$active = null + this.$items = null + + this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this)) + + this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element + .on('mouseenter.bs.carousel', $.proxy(this.pause, this)) + .on('mouseleave.bs.carousel', $.proxy(this.cycle, this)) + } + + Carousel.VERSION = '3.3.6' + + Carousel.TRANSITION_DURATION = 600 + + Carousel.DEFAULTS = { + interval: 5000, + pause: 'hover', + wrap: true, + keyboard: true + } + + Carousel.prototype.keydown = function (e) { + if (/input|textarea/i.test(e.target.tagName)) return + switch (e.which) { + case 37: this.prev(); break + case 39: this.next(); break + default: return + } + + e.preventDefault() + } + + Carousel.prototype.cycle = function (e) { + e || (this.paused = false) + + this.interval && clearInterval(this.interval) + + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + + return this + } + + Carousel.prototype.getItemIndex = function (item) { + this.$items = item.parent().children('.item') + return this.$items.index(item || this.$active) + } + + Carousel.prototype.getItemForDirection = function (direction, active) { + var activeIndex = this.getItemIndex(active) + var willWrap = (direction == 'prev' && activeIndex === 0) + || (direction == 'next' && activeIndex == (this.$items.length - 1)) + if (willWrap && !this.options.wrap) return active + var delta = direction == 'prev' ? -1 : 1 + var itemIndex = (activeIndex + delta) % this.$items.length + return this.$items.eq(itemIndex) + } + + Carousel.prototype.to = function (pos) { + var that = this + var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active')) + + if (pos > (this.$items.length - 1) || pos < 0) return + + if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid" + if (activeIndex == pos) return this.pause().cycle() + + return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos)) + } + + Carousel.prototype.pause = function (e) { + e || (this.paused = true) + + if (this.$element.find('.next, .prev').length && $.support.transition) { + this.$element.trigger($.support.transition.end) + this.cycle(true) + } + + this.interval = clearInterval(this.interval) + + return this + } + + Carousel.prototype.next = function () { + if (this.sliding) return + return this.slide('next') + } + + Carousel.prototype.prev = function () { + if (this.sliding) return + return this.slide('prev') + } + + Carousel.prototype.slide = function (type, next) { + var $active = this.$element.find('.item.active') + var $next = next || this.getItemForDirection(type, $active) + var isCycling = this.interval + var direction = type == 'next' ? 'left' : 'right' + var that = this + + if ($next.hasClass('active')) return (this.sliding = false) + + var relatedTarget = $next[0] + var slideEvent = $.Event('slide.bs.carousel', { + relatedTarget: relatedTarget, + direction: direction + }) + this.$element.trigger(slideEvent) + if (slideEvent.isDefaultPrevented()) return + + this.sliding = true + + isCycling && this.pause() + + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)]) + $nextIndicator && $nextIndicator.addClass('active') + } + + var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid" + if ($.support.transition && this.$element.hasClass('slide')) { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + $active + .one('bsTransitionEnd', function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { + that.$element.trigger(slidEvent) + }, 0) + }) + .emulateTransitionEnd(Carousel.TRANSITION_DURATION) + } else { + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger(slidEvent) + } + + isCycling && this.cycle() + + return this + } + + + // CAROUSEL PLUGIN DEFINITION + // ========================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.carousel') + var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) + var action = typeof option == 'string' ? option : options.slide + + if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) data.pause().cycle() + }) + } + + var old = $.fn.carousel + + $.fn.carousel = Plugin + $.fn.carousel.Constructor = Carousel + + + // CAROUSEL NO CONFLICT + // ==================== + + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + + + // CAROUSEL DATA-API + // ================= + + var clickHandler = function (e) { + var href + var $this = $(this) + var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7 + if (!$target.hasClass('carousel')) return + var options = $.extend({}, $target.data(), $this.data()) + var slideIndex = $this.attr('data-slide-to') + if (slideIndex) options.interval = false + + Plugin.call($target, options) + + if (slideIndex) { + $target.data('bs.carousel').to(slideIndex) + } + + e.preventDefault() + } + + $(document) + .on('click.bs.carousel.data-api', '[data-slide]', clickHandler) + .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler) + + $(window).on('load', function () { + $('[data-ride="carousel"]').each(function () { + var $carousel = $(this) + Plugin.call($carousel, $carousel.data()) + }) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: collapse.js v3.3.6 + * http://getbootstrap.com/javascript/#collapse + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // COLLAPSE PUBLIC CLASS DEFINITION + // ================================ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Collapse.DEFAULTS, options) + this.$trigger = $('[data-toggle="collapse"][href="#' + element.id + '"],' + + '[data-toggle="collapse"][data-target="#' + element.id + '"]') + this.transitioning = null + + if (this.options.parent) { + this.$parent = this.getParent() + } else { + this.addAriaAndCollapsedClass(this.$element, this.$trigger) + } + + if (this.options.toggle) this.toggle() + } + + Collapse.VERSION = '3.3.6' + + Collapse.TRANSITION_DURATION = 350 + + Collapse.DEFAULTS = { + toggle: true + } + + Collapse.prototype.dimension = function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + Collapse.prototype.show = function () { + if (this.transitioning || this.$element.hasClass('in')) return + + var activesData + var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing') + + if (actives && actives.length) { + activesData = actives.data('bs.collapse') + if (activesData && activesData.transitioning) return + } + + var startEvent = $.Event('show.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + if (actives && actives.length) { + Plugin.call(actives, 'hide') + activesData || actives.data('bs.collapse', null) + } + + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + .addClass('collapsing')[dimension](0) + .attr('aria-expanded', true) + + this.$trigger + .removeClass('collapsed') + .attr('aria-expanded', true) + + this.transitioning = 1 + + var complete = function () { + this.$element + .removeClass('collapsing') + .addClass('collapse in')[dimension]('') + this.transitioning = 0 + this.$element + .trigger('shown.bs.collapse') + } + + if (!$.support.transition) return complete.call(this) + + var scrollSize = $.camelCase(['scroll', dimension].join('-')) + + this.$element + .one('bsTransitionEnd', $.proxy(complete, this)) + .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize]) + } + + Collapse.prototype.hide = function () { + if (this.transitioning || !this.$element.hasClass('in')) return + + var startEvent = $.Event('hide.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var dimension = this.dimension() + + this.$element[dimension](this.$element[dimension]())[0].offsetHeight + + this.$element + .addClass('collapsing') + .removeClass('collapse in') + .attr('aria-expanded', false) + + this.$trigger + .addClass('collapsed') + .attr('aria-expanded', false) + + this.transitioning = 1 + + var complete = function () { + this.transitioning = 0 + this.$element + .removeClass('collapsing') + .addClass('collapse') + .trigger('hidden.bs.collapse') + } + + if (!$.support.transition) return complete.call(this) + + this.$element + [dimension](0) + .one('bsTransitionEnd', $.proxy(complete, this)) + .emulateTransitionEnd(Collapse.TRANSITION_DURATION) + } + + Collapse.prototype.toggle = function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + Collapse.prototype.getParent = function () { + return $(this.options.parent) + .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]') + .each($.proxy(function (i, element) { + var $element = $(element) + this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element) + }, this)) + .end() + } + + Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) { + var isOpen = $element.hasClass('in') + + $element.attr('aria-expanded', isOpen) + $trigger + .toggleClass('collapsed', !isOpen) + .attr('aria-expanded', isOpen) + } + + function getTargetFromTrigger($trigger) { + var href + var target = $trigger.attr('data-target') + || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7 + + return $(target) + } + + + // COLLAPSE PLUGIN DEFINITION + // ========================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.collapse') + var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false + if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + var old = $.fn.collapse + + $.fn.collapse = Plugin + $.fn.collapse.Constructor = Collapse + + + // COLLAPSE NO CONFLICT + // ==================== + + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } + + + // COLLAPSE DATA-API + // ================= + + $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { + var $this = $(this) + + if (!$this.attr('data-target')) e.preventDefault() + + var $target = getTargetFromTrigger($this) + var data = $target.data('bs.collapse') + var option = data ? 'toggle' : $this.data() + + Plugin.call($target, option) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: dropdown.js v3.3.6 + * http://getbootstrap.com/javascript/#dropdowns + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // DROPDOWN CLASS DEFINITION + // ========================= + + var backdrop = '.dropdown-backdrop' + var toggle = '[data-toggle="dropdown"]' + var Dropdown = function (element) { + $(element).on('click.bs.dropdown', this.toggle) + } + + Dropdown.VERSION = '3.3.6' + + function getParent($this) { + var selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + } + + var $parent = selector && $(selector) + + return $parent && $parent.length ? $parent : $this.parent() + } + + function clearMenus(e) { + if (e && e.which === 3) return + $(backdrop).remove() + $(toggle).each(function () { + var $this = $(this) + var $parent = getParent($this) + var relatedTarget = { relatedTarget: this } + + if (!$parent.hasClass('open')) return + + if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return + + $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget)) + + if (e.isDefaultPrevented()) return + + $this.attr('aria-expanded', 'false') + $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget)) + }) + } + + Dropdown.prototype.toggle = function (e) { + var $this = $(this) + + if ($this.is('.disabled, :disabled')) return + + var $parent = getParent($this) + var isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { + // if mobile we use a backdrop because click events don't delegate + $(document.createElement('div')) + .addClass('dropdown-backdrop') + .insertAfter($(this)) + .on('click', clearMenus) + } + + var relatedTarget = { relatedTarget: this } + $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget)) + + if (e.isDefaultPrevented()) return + + $this + .trigger('focus') + .attr('aria-expanded', 'true') + + $parent + .toggleClass('open') + .trigger($.Event('shown.bs.dropdown', relatedTarget)) + } + + return false + } + + Dropdown.prototype.keydown = function (e) { + if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return + + var $this = $(this) + + e.preventDefault() + e.stopPropagation() + + if ($this.is('.disabled, :disabled')) return + + var $parent = getParent($this) + var isActive = $parent.hasClass('open') + + if (!isActive && e.which != 27 || isActive && e.which == 27) { + if (e.which == 27) $parent.find(toggle).trigger('focus') + return $this.trigger('click') + } + + var desc = ' li:not(.disabled):visible a' + var $items = $parent.find('.dropdown-menu' + desc) + + if (!$items.length) return + + var index = $items.index(e.target) + + if (e.which == 38 && index > 0) index-- // up + if (e.which == 40 && index < $items.length - 1) index++ // down + if (!~index) index = 0 + + $items.eq(index).trigger('focus') + } + + + // DROPDOWN PLUGIN DEFINITION + // ========================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.dropdown') + + if (!data) $this.data('bs.dropdown', (data = new Dropdown(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + var old = $.fn.dropdown + + $.fn.dropdown = Plugin + $.fn.dropdown.Constructor = Dropdown + + + // DROPDOWN NO CONFLICT + // ==================== + + $.fn.dropdown.noConflict = function () { + $.fn.dropdown = old + return this + } + + + // APPLY TO STANDARD DROPDOWN ELEMENTS + // =================================== + + $(document) + .on('click.bs.dropdown.data-api', clearMenus) + .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() }) + .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle) + .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown) + .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: modal.js v3.3.6 + * http://getbootstrap.com/javascript/#modals + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // MODAL CLASS DEFINITION + // ====================== + + var Modal = function (element, options) { + this.options = options + this.$body = $(document.body) + this.$element = $(element) + this.$dialog = this.$element.find('.modal-dialog') + this.$backdrop = null + this.isShown = null + this.originalBodyPad = null + this.scrollbarWidth = 0 + this.ignoreBackdropClick = false + + if (this.options.remote) { + this.$element + .find('.modal-content') + .load(this.options.remote, $.proxy(function () { + this.$element.trigger('loaded.bs.modal') + }, this)) + } + } + + Modal.VERSION = '3.3.6' + + Modal.TRANSITION_DURATION = 300 + Modal.BACKDROP_TRANSITION_DURATION = 150 + + Modal.DEFAULTS = { + backdrop: true, + keyboard: true, + show: true + } + + Modal.prototype.toggle = function (_relatedTarget) { + return this.isShown ? this.hide() : this.show(_relatedTarget) + } + + Modal.prototype.show = function (_relatedTarget) { + var that = this + var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget }) + + this.$element.trigger(e) + + if (this.isShown || e.isDefaultPrevented()) return + + this.isShown = true + + this.checkScrollbar() + this.setScrollbar() + this.$body.addClass('modal-open') + + this.escape() + this.resize() + + this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this)) + + this.$dialog.on('mousedown.dismiss.bs.modal', function () { + that.$element.one('mouseup.dismiss.bs.modal', function (e) { + if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true + }) + }) + + this.backdrop(function () { + var transition = $.support.transition && that.$element.hasClass('fade') + + if (!that.$element.parent().length) { + that.$element.appendTo(that.$body) // don't move modals dom position + } + + that.$element + .show() + .scrollTop(0) + + that.adjustDialog() + + if (transition) { + that.$element[0].offsetWidth // force reflow + } + + that.$element.addClass('in') + + that.enforceFocus() + + var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget }) + + transition ? + that.$dialog // wait for modal to slide in + .one('bsTransitionEnd', function () { + that.$element.trigger('focus').trigger(e) + }) + .emulateTransitionEnd(Modal.TRANSITION_DURATION) : + that.$element.trigger('focus').trigger(e) + }) + } + + Modal.prototype.hide = function (e) { + if (e) e.preventDefault() + + e = $.Event('hide.bs.modal') + + this.$element.trigger(e) + + if (!this.isShown || e.isDefaultPrevented()) return + + this.isShown = false + + this.escape() + this.resize() + + $(document).off('focusin.bs.modal') + + this.$element + .removeClass('in') + .off('click.dismiss.bs.modal') + .off('mouseup.dismiss.bs.modal') + + this.$dialog.off('mousedown.dismiss.bs.modal') + + $.support.transition && this.$element.hasClass('fade') ? + this.$element + .one('bsTransitionEnd', $.proxy(this.hideModal, this)) + .emulateTransitionEnd(Modal.TRANSITION_DURATION) : + this.hideModal() + } + + Modal.prototype.enforceFocus = function () { + $(document) + .off('focusin.bs.modal') // guard against infinite focus loop + .on('focusin.bs.modal', $.proxy(function (e) { + if (this.$element[0] !== e.target && !this.$element.has(e.target).length) { + this.$element.trigger('focus') + } + }, this)) + } + + Modal.prototype.escape = function () { + if (this.isShown && this.options.keyboard) { + this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) { + e.which == 27 && this.hide() + }, this)) + } else if (!this.isShown) { + this.$element.off('keydown.dismiss.bs.modal') + } + } + + Modal.prototype.resize = function () { + if (this.isShown) { + $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this)) + } else { + $(window).off('resize.bs.modal') + } + } + + Modal.prototype.hideModal = function () { + var that = this + this.$element.hide() + this.backdrop(function () { + that.$body.removeClass('modal-open') + that.resetAdjustments() + that.resetScrollbar() + that.$element.trigger('hidden.bs.modal') + }) + } + + Modal.prototype.removeBackdrop = function () { + this.$backdrop && this.$backdrop.remove() + this.$backdrop = null + } + + Modal.prototype.backdrop = function (callback) { + var that = this + var animate = this.$element.hasClass('fade') ? 'fade' : '' + + if (this.isShown && this.options.backdrop) { + var doAnimate = $.support.transition && animate + + this.$backdrop = $(document.createElement('div')) + .addClass('modal-backdrop ' + animate) + .appendTo(this.$body) + + this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) { + if (this.ignoreBackdropClick) { + this.ignoreBackdropClick = false + return + } + if (e.target !== e.currentTarget) return + this.options.backdrop == 'static' + ? this.$element[0].focus() + : this.hide() + }, this)) + + if (doAnimate) this.$backdrop[0].offsetWidth // force reflow + + this.$backdrop.addClass('in') + + if (!callback) return + + doAnimate ? + this.$backdrop + .one('bsTransitionEnd', callback) + .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) : + callback() + + } else if (!this.isShown && this.$backdrop) { + this.$backdrop.removeClass('in') + + var callbackRemove = function () { + that.removeBackdrop() + callback && callback() + } + $.support.transition && this.$element.hasClass('fade') ? + this.$backdrop + .one('bsTransitionEnd', callbackRemove) + .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) : + callbackRemove() + + } else if (callback) { + callback() + } + } + + // these following methods are used to handle overflowing modals + + Modal.prototype.handleUpdate = function () { + this.adjustDialog() + } + + Modal.prototype.adjustDialog = function () { + var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight + + this.$element.css({ + paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '', + paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : '' + }) + } + + Modal.prototype.resetAdjustments = function () { + this.$element.css({ + paddingLeft: '', + paddingRight: '' + }) + } + + Modal.prototype.checkScrollbar = function () { + var fullWindowWidth = window.innerWidth + if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8 + var documentElementRect = document.documentElement.getBoundingClientRect() + fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left) + } + this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth + this.scrollbarWidth = this.measureScrollbar() + } + + Modal.prototype.setScrollbar = function () { + var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10) + this.originalBodyPad = document.body.style.paddingRight || '' + if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth) + } + + Modal.prototype.resetScrollbar = function () { + this.$body.css('padding-right', this.originalBodyPad) + } + + Modal.prototype.measureScrollbar = function () { // thx walsh + var scrollDiv = document.createElement('div') + scrollDiv.className = 'modal-scrollbar-measure' + this.$body.append(scrollDiv) + var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth + this.$body[0].removeChild(scrollDiv) + return scrollbarWidth + } + + + // MODAL PLUGIN DEFINITION + // ======================= + + function Plugin(option, _relatedTarget) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.modal') + var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data) $this.data('bs.modal', (data = new Modal(this, options))) + if (typeof option == 'string') data[option](_relatedTarget) + else if (options.show) data.show(_relatedTarget) + }) + } + + var old = $.fn.modal + + $.fn.modal = Plugin + $.fn.modal.Constructor = Modal + + + // MODAL NO CONFLICT + // ================= + + $.fn.modal.noConflict = function () { + $.fn.modal = old + return this + } + + + // MODAL DATA-API + // ============== + + $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) { + var $this = $(this) + var href = $this.attr('href') + var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7 + var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data()) + + if ($this.is('a')) e.preventDefault() + + $target.one('show.bs.modal', function (showEvent) { + if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown + $target.one('hidden.bs.modal', function () { + $this.is(':visible') && $this.trigger('focus') + }) + }) + Plugin.call($target, option, this) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: tooltip.js v3.3.6 + * http://getbootstrap.com/javascript/#tooltip + * Inspired by the original jQuery.tipsy by Jason Frame + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // TOOLTIP PUBLIC CLASS DEFINITION + // =============================== + + var Tooltip = function (element, options) { + this.type = null + this.options = null + this.enabled = null + this.timeout = null + this.hoverState = null + this.$element = null + this.inState = null + + this.init('tooltip', element, options) + } + + Tooltip.VERSION = '3.3.6' + + Tooltip.TRANSITION_DURATION = 150 + + Tooltip.DEFAULTS = { + animation: true, + placement: 'top', + selector: false, + template: '', + trigger: 'hover focus', + title: '', + delay: 0, + html: false, + container: false, + viewport: { + selector: 'body', + padding: 0 + } + } + + Tooltip.prototype.init = function (type, element, options) { + this.enabled = true + this.type = type + this.$element = $(element) + this.options = this.getOptions(options) + this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport)) + this.inState = { click: false, hover: false, focus: false } + + if (this.$element[0] instanceof document.constructor && !this.options.selector) { + throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!') + } + + var triggers = this.options.trigger.split(' ') + + for (var i = triggers.length; i--;) { + var trigger = triggers[i] + + if (trigger == 'click') { + this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) + } else if (trigger != 'manual') { + var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin' + var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout' + + this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) + this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) + } + } + + this.options.selector ? + (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : + this.fixTitle() + } + + Tooltip.prototype.getDefaults = function () { + return Tooltip.DEFAULTS + } + + Tooltip.prototype.getOptions = function (options) { + options = $.extend({}, this.getDefaults(), this.$element.data(), options) + + if (options.delay && typeof options.delay == 'number') { + options.delay = { + show: options.delay, + hide: options.delay + } + } + + return options + } + + Tooltip.prototype.getDelegateOptions = function () { + var options = {} + var defaults = this.getDefaults() + + this._options && $.each(this._options, function (key, value) { + if (defaults[key] != value) options[key] = value + }) + + return options + } + + Tooltip.prototype.enter = function (obj) { + var self = obj instanceof this.constructor ? + obj : $(obj.currentTarget).data('bs.' + this.type) + + if (!self) { + self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) + $(obj.currentTarget).data('bs.' + this.type, self) + } + + if (obj instanceof $.Event) { + self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true + } + + if (self.tip().hasClass('in') || self.hoverState == 'in') { + self.hoverState = 'in' + return + } + + clearTimeout(self.timeout) + + self.hoverState = 'in' + + if (!self.options.delay || !self.options.delay.show) return self.show() + + self.timeout = setTimeout(function () { + if (self.hoverState == 'in') self.show() + }, self.options.delay.show) + } + + Tooltip.prototype.isInStateTrue = function () { + for (var key in this.inState) { + if (this.inState[key]) return true + } + + return false + } + + Tooltip.prototype.leave = function (obj) { + var self = obj instanceof this.constructor ? + obj : $(obj.currentTarget).data('bs.' + this.type) + + if (!self) { + self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) + $(obj.currentTarget).data('bs.' + this.type, self) + } + + if (obj instanceof $.Event) { + self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false + } + + if (self.isInStateTrue()) return + + clearTimeout(self.timeout) + + self.hoverState = 'out' + + if (!self.options.delay || !self.options.delay.hide) return self.hide() + + self.timeout = setTimeout(function () { + if (self.hoverState == 'out') self.hide() + }, self.options.delay.hide) + } + + Tooltip.prototype.show = function () { + var e = $.Event('show.bs.' + this.type) + + if (this.hasContent() && this.enabled) { + this.$element.trigger(e) + + var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0]) + if (e.isDefaultPrevented() || !inDom) return + var that = this + + var $tip = this.tip() + + var tipId = this.getUID(this.type) + + this.setContent() + $tip.attr('id', tipId) + this.$element.attr('aria-describedby', tipId) + + if (this.options.animation) $tip.addClass('fade') + + var placement = typeof this.options.placement == 'function' ? + this.options.placement.call(this, $tip[0], this.$element[0]) : + this.options.placement + + var autoToken = /\s?auto?\s?/i + var autoPlace = autoToken.test(placement) + if (autoPlace) placement = placement.replace(autoToken, '') || 'top' + + $tip + .detach() + .css({ top: 0, left: 0, display: 'block' }) + .addClass(placement) + .data('bs.' + this.type, this) + + this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element) + this.$element.trigger('inserted.bs.' + this.type) + + var pos = this.getPosition() + var actualWidth = $tip[0].offsetWidth + var actualHeight = $tip[0].offsetHeight + + if (autoPlace) { + var orgPlacement = placement + var viewportDim = this.getPosition(this.$viewport) + + placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top' : + placement == 'top' && pos.top - actualHeight < viewportDim.top ? 'bottom' : + placement == 'right' && pos.right + actualWidth > viewportDim.width ? 'left' : + placement == 'left' && pos.left - actualWidth < viewportDim.left ? 'right' : + placement + + $tip + .removeClass(orgPlacement) + .addClass(placement) + } + + var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) + + this.applyPlacement(calculatedOffset, placement) + + var complete = function () { + var prevHoverState = that.hoverState + that.$element.trigger('shown.bs.' + that.type) + that.hoverState = null + + if (prevHoverState == 'out') that.leave(that) + } + + $.support.transition && this.$tip.hasClass('fade') ? + $tip + .one('bsTransitionEnd', complete) + .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : + complete() + } + } + + Tooltip.prototype.applyPlacement = function (offset, placement) { + var $tip = this.tip() + var width = $tip[0].offsetWidth + var height = $tip[0].offsetHeight + + // manually read margins because getBoundingClientRect includes difference + var marginTop = parseInt($tip.css('margin-top'), 10) + var marginLeft = parseInt($tip.css('margin-left'), 10) + + // we must check for NaN for ie 8/9 + if (isNaN(marginTop)) marginTop = 0 + if (isNaN(marginLeft)) marginLeft = 0 + + offset.top += marginTop + offset.left += marginLeft + + // $.fn.offset doesn't round pixel values + // so we use setOffset directly with our own function B-0 + $.offset.setOffset($tip[0], $.extend({ + using: function (props) { + $tip.css({ + top: Math.round(props.top), + left: Math.round(props.left) + }) + } + }, offset), 0) + + $tip.addClass('in') + + // check to see if placing tip in new offset caused the tip to resize itself + var actualWidth = $tip[0].offsetWidth + var actualHeight = $tip[0].offsetHeight + + if (placement == 'top' && actualHeight != height) { + offset.top = offset.top + height - actualHeight + } + + var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight) + + if (delta.left) offset.left += delta.left + else offset.top += delta.top + + var isVertical = /top|bottom/.test(placement) + var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight + var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight' + + $tip.offset(offset) + this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical) + } + + Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) { + this.arrow() + .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%') + .css(isVertical ? 'top' : 'left', '') + } + + Tooltip.prototype.setContent = function () { + var $tip = this.tip() + var title = this.getTitle() + + $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) + $tip.removeClass('fade in top bottom left right') + } + + Tooltip.prototype.hide = function (callback) { + var that = this + var $tip = $(this.$tip) + var e = $.Event('hide.bs.' + this.type) + + function complete() { + if (that.hoverState != 'in') $tip.detach() + that.$element + .removeAttr('aria-describedby') + .trigger('hidden.bs.' + that.type) + callback && callback() + } + + this.$element.trigger(e) + + if (e.isDefaultPrevented()) return + + $tip.removeClass('in') + + $.support.transition && $tip.hasClass('fade') ? + $tip + .one('bsTransitionEnd', complete) + .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : + complete() + + this.hoverState = null + + return this + } + + Tooltip.prototype.fixTitle = function () { + var $e = this.$element + if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') { + $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') + } + } + + Tooltip.prototype.hasContent = function () { + return this.getTitle() + } + + Tooltip.prototype.getPosition = function ($element) { + $element = $element || this.$element + + var el = $element[0] + var isBody = el.tagName == 'BODY' + + var elRect = el.getBoundingClientRect() + if (elRect.width == null) { + // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093 + elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top }) + } + var elOffset = isBody ? { top: 0, left: 0 } : $element.offset() + var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() } + var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null + + return $.extend({}, elRect, scroll, outerDims, elOffset) + } + + Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { + return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : + placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : + placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : + /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } + + } + + Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) { + var delta = { top: 0, left: 0 } + if (!this.$viewport) return delta + + var viewportPadding = this.options.viewport && this.options.viewport.padding || 0 + var viewportDimensions = this.getPosition(this.$viewport) + + if (/right|left/.test(placement)) { + var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll + var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight + if (topEdgeOffset < viewportDimensions.top) { // top overflow + delta.top = viewportDimensions.top - topEdgeOffset + } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow + delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset + } + } else { + var leftEdgeOffset = pos.left - viewportPadding + var rightEdgeOffset = pos.left + viewportPadding + actualWidth + if (leftEdgeOffset < viewportDimensions.left) { // left overflow + delta.left = viewportDimensions.left - leftEdgeOffset + } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow + delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset + } + } + + return delta + } + + Tooltip.prototype.getTitle = function () { + var title + var $e = this.$element + var o = this.options + + title = $e.attr('data-original-title') + || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) + + return title + } + + Tooltip.prototype.getUID = function (prefix) { + do prefix += ~~(Math.random() * 1000000) + while (document.getElementById(prefix)) + return prefix + } + + Tooltip.prototype.tip = function () { + if (!this.$tip) { + this.$tip = $(this.options.template) + if (this.$tip.length != 1) { + throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!') + } + } + return this.$tip + } + + Tooltip.prototype.arrow = function () { + return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')) + } + + Tooltip.prototype.enable = function () { + this.enabled = true + } + + Tooltip.prototype.disable = function () { + this.enabled = false + } + + Tooltip.prototype.toggleEnabled = function () { + this.enabled = !this.enabled + } + + Tooltip.prototype.toggle = function (e) { + var self = this + if (e) { + self = $(e.currentTarget).data('bs.' + this.type) + if (!self) { + self = new this.constructor(e.currentTarget, this.getDelegateOptions()) + $(e.currentTarget).data('bs.' + this.type, self) + } + } + + if (e) { + self.inState.click = !self.inState.click + if (self.isInStateTrue()) self.enter(self) + else self.leave(self) + } else { + self.tip().hasClass('in') ? self.leave(self) : self.enter(self) + } + } + + Tooltip.prototype.destroy = function () { + var that = this + clearTimeout(this.timeout) + this.hide(function () { + that.$element.off('.' + that.type).removeData('bs.' + that.type) + if (that.$tip) { + that.$tip.detach() + } + that.$tip = null + that.$arrow = null + that.$viewport = null + }) + } + + + // TOOLTIP PLUGIN DEFINITION + // ========================= + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.tooltip') + var options = typeof option == 'object' && option + + if (!data && /destroy|hide/.test(option)) return + if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + var old = $.fn.tooltip + + $.fn.tooltip = Plugin + $.fn.tooltip.Constructor = Tooltip + + + // TOOLTIP NO CONFLICT + // =================== + + $.fn.tooltip.noConflict = function () { + $.fn.tooltip = old + return this + } + +}(jQuery); + +/* ======================================================================== + * Bootstrap: popover.js v3.3.6 + * http://getbootstrap.com/javascript/#popovers + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // POPOVER PUBLIC CLASS DEFINITION + // =============================== + + var Popover = function (element, options) { + this.init('popover', element, options) + } + + if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js') + + Popover.VERSION = '3.3.6' + + Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, { + placement: 'right', + trigger: 'click', + content: '', + template: '' + }) + + + // NOTE: POPOVER EXTENDS tooltip.js + // ================================ + + Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype) + + Popover.prototype.constructor = Popover + + Popover.prototype.getDefaults = function () { + return Popover.DEFAULTS + } + + Popover.prototype.setContent = function () { + var $tip = this.tip() + var title = this.getTitle() + var content = this.getContent() + + $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title) + $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events + this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text' + ](content) + + $tip.removeClass('fade top bottom left right in') + + // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do + // this manually by checking the contents. + if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide() + } + + Popover.prototype.hasContent = function () { + return this.getTitle() || this.getContent() + } + + Popover.prototype.getContent = function () { + var $e = this.$element + var o = this.options + + return $e.attr('data-content') + || (typeof o.content == 'function' ? + o.content.call($e[0]) : + o.content) + } + + Popover.prototype.arrow = function () { + return (this.$arrow = this.$arrow || this.tip().find('.arrow')) + } + + + // POPOVER PLUGIN DEFINITION + // ========================= + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.popover') + var options = typeof option == 'object' && option + + if (!data && /destroy|hide/.test(option)) return + if (!data) $this.data('bs.popover', (data = new Popover(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + var old = $.fn.popover + + $.fn.popover = Plugin + $.fn.popover.Constructor = Popover + + + // POPOVER NO CONFLICT + // =================== + + $.fn.popover.noConflict = function () { + $.fn.popover = old + return this + } + +}(jQuery); + +/* ======================================================================== + * Bootstrap: scrollspy.js v3.3.6 + * http://getbootstrap.com/javascript/#scrollspy + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // SCROLLSPY CLASS DEFINITION + // ========================== + + function ScrollSpy(element, options) { + this.$body = $(document.body) + this.$scrollElement = $(element).is(document.body) ? $(window) : $(element) + this.options = $.extend({}, ScrollSpy.DEFAULTS, options) + this.selector = (this.options.target || '') + ' .nav li > a' + this.offsets = [] + this.targets = [] + this.activeTarget = null + this.scrollHeight = 0 + + this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this)) + this.refresh() + this.process() + } + + ScrollSpy.VERSION = '3.3.6' + + ScrollSpy.DEFAULTS = { + offset: 10 + } + + ScrollSpy.prototype.getScrollHeight = function () { + return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight) + } + + ScrollSpy.prototype.refresh = function () { + var that = this + var offsetMethod = 'offset' + var offsetBase = 0 + + this.offsets = [] + this.targets = [] + this.scrollHeight = this.getScrollHeight() + + if (!$.isWindow(this.$scrollElement[0])) { + offsetMethod = 'position' + offsetBase = this.$scrollElement.scrollTop() + } + + this.$body + .find(this.selector) + .map(function () { + var $el = $(this) + var href = $el.data('target') || $el.attr('href') + var $href = /^#./.test(href) && $(href) + + return ($href + && $href.length + && $href.is(':visible') + && [[$href[offsetMethod]().top + offsetBase, href]]) || null + }) + .sort(function (a, b) { return a[0] - b[0] }) + .each(function () { + that.offsets.push(this[0]) + that.targets.push(this[1]) + }) + } + + ScrollSpy.prototype.process = function () { + var scrollTop = this.$scrollElement.scrollTop() + this.options.offset + var scrollHeight = this.getScrollHeight() + var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height() + var offsets = this.offsets + var targets = this.targets + var activeTarget = this.activeTarget + var i + + if (this.scrollHeight != scrollHeight) { + this.refresh() + } + + if (scrollTop >= maxScroll) { + return activeTarget != (i = targets[targets.length - 1]) && this.activate(i) + } + + if (activeTarget && scrollTop < offsets[0]) { + this.activeTarget = null + return this.clear() + } + + for (i = offsets.length; i--;) { + activeTarget != targets[i] + && scrollTop >= offsets[i] + && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1]) + && this.activate(targets[i]) + } + } + + ScrollSpy.prototype.activate = function (target) { + this.activeTarget = target + + this.clear() + + var selector = this.selector + + '[data-target="' + target + '"],' + + this.selector + '[href="' + target + '"]' + + var active = $(selector) + .parents('li') + .addClass('active') + + if (active.parent('.dropdown-menu').length) { + active = active + .closest('li.dropdown') + .addClass('active') + } + + active.trigger('activate.bs.scrollspy') + } + + ScrollSpy.prototype.clear = function () { + $(this.selector) + .parentsUntil(this.options.target, '.active') + .removeClass('active') + } + + + // SCROLLSPY PLUGIN DEFINITION + // =========================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.scrollspy') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + var old = $.fn.scrollspy + + $.fn.scrollspy = Plugin + $.fn.scrollspy.Constructor = ScrollSpy + + + // SCROLLSPY NO CONFLICT + // ===================== + + $.fn.scrollspy.noConflict = function () { + $.fn.scrollspy = old + return this + } + + + // SCROLLSPY DATA-API + // ================== + + $(window).on('load.bs.scrollspy.data-api', function () { + $('[data-spy="scroll"]').each(function () { + var $spy = $(this) + Plugin.call($spy, $spy.data()) + }) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: tab.js v3.3.6 + * http://getbootstrap.com/javascript/#tabs + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // TAB CLASS DEFINITION + // ==================== + + var Tab = function (element) { + // jscs:disable requireDollarBeforejQueryAssignment + this.element = $(element) + // jscs:enable requireDollarBeforejQueryAssignment + } + + Tab.VERSION = '3.3.6' + + Tab.TRANSITION_DURATION = 150 + + Tab.prototype.show = function () { + var $this = this.element + var $ul = $this.closest('ul:not(.dropdown-menu)') + var selector = $this.data('target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + } + + if ($this.parent('li').hasClass('active')) return + + var $previous = $ul.find('.active:last a') + var hideEvent = $.Event('hide.bs.tab', { + relatedTarget: $this[0] + }) + var showEvent = $.Event('show.bs.tab', { + relatedTarget: $previous[0] + }) + + $previous.trigger(hideEvent) + $this.trigger(showEvent) + + if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return + + var $target = $(selector) + + this.activate($this.closest('li'), $ul) + this.activate($target, $target.parent(), function () { + $previous.trigger({ + type: 'hidden.bs.tab', + relatedTarget: $this[0] + }) + $this.trigger({ + type: 'shown.bs.tab', + relatedTarget: $previous[0] + }) + }) + } + + Tab.prototype.activate = function (element, container, callback) { + var $active = container.find('> .active') + var transition = callback + && $.support.transition + && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length) + + function next() { + $active + .removeClass('active') + .find('> .dropdown-menu > .active') + .removeClass('active') + .end() + .find('[data-toggle="tab"]') + .attr('aria-expanded', false) + + element + .addClass('active') + .find('[data-toggle="tab"]') + .attr('aria-expanded', true) + + if (transition) { + element[0].offsetWidth // reflow for transition + element.addClass('in') + } else { + element.removeClass('fade') + } + + if (element.parent('.dropdown-menu').length) { + element + .closest('li.dropdown') + .addClass('active') + .end() + .find('[data-toggle="tab"]') + .attr('aria-expanded', true) + } + + callback && callback() + } + + $active.length && transition ? + $active + .one('bsTransitionEnd', next) + .emulateTransitionEnd(Tab.TRANSITION_DURATION) : + next() + + $active.removeClass('in') + } + + + // TAB PLUGIN DEFINITION + // ===================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.tab') + + if (!data) $this.data('bs.tab', (data = new Tab(this))) + if (typeof option == 'string') data[option]() + }) + } + + var old = $.fn.tab + + $.fn.tab = Plugin + $.fn.tab.Constructor = Tab + + + // TAB NO CONFLICT + // =============== + + $.fn.tab.noConflict = function () { + $.fn.tab = old + return this + } + + + // TAB DATA-API + // ============ + + var clickHandler = function (e) { + e.preventDefault() + Plugin.call($(this), 'show') + } + + $(document) + .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler) + .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: affix.js v3.3.6 + * http://getbootstrap.com/javascript/#affix + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // AFFIX CLASS DEFINITION + // ====================== + + var Affix = function (element, options) { + this.options = $.extend({}, Affix.DEFAULTS, options) + + this.$target = $(this.options.target) + .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this)) + .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this)) + + this.$element = $(element) + this.affixed = null + this.unpin = null + this.pinnedOffset = null + + this.checkPosition() + } + + Affix.VERSION = '3.3.6' + + Affix.RESET = 'affix affix-top affix-bottom' + + Affix.DEFAULTS = { + offset: 0, + target: window + } + + Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) { + var scrollTop = this.$target.scrollTop() + var position = this.$element.offset() + var targetHeight = this.$target.height() + + if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false + + if (this.affixed == 'bottom') { + if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom' + return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom' + } + + var initializing = this.affixed == null + var colliderTop = initializing ? scrollTop : position.top + var colliderHeight = initializing ? targetHeight : height + + if (offsetTop != null && scrollTop <= offsetTop) return 'top' + if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom' + + return false + } + + Affix.prototype.getPinnedOffset = function () { + if (this.pinnedOffset) return this.pinnedOffset + this.$element.removeClass(Affix.RESET).addClass('affix') + var scrollTop = this.$target.scrollTop() + var position = this.$element.offset() + return (this.pinnedOffset = position.top - scrollTop) + } + + Affix.prototype.checkPositionWithEventLoop = function () { + setTimeout($.proxy(this.checkPosition, this), 1) + } + + Affix.prototype.checkPosition = function () { + if (!this.$element.is(':visible')) return + + var height = this.$element.height() + var offset = this.options.offset + var offsetTop = offset.top + var offsetBottom = offset.bottom + var scrollHeight = Math.max($(document).height(), $(document.body).height()) + + if (typeof offset != 'object') offsetBottom = offsetTop = offset + if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element) + if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element) + + var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom) + + if (this.affixed != affix) { + if (this.unpin != null) this.$element.css('top', '') + + var affixType = 'affix' + (affix ? '-' + affix : '') + var e = $.Event(affixType + '.bs.affix') + + this.$element.trigger(e) + + if (e.isDefaultPrevented()) return + + this.affixed = affix + this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null + + this.$element + .removeClass(Affix.RESET) + .addClass(affixType) + .trigger(affixType.replace('affix', 'affixed') + '.bs.affix') + } + + if (affix == 'bottom') { + this.$element.offset({ + top: scrollHeight - height - offsetBottom + }) + } + } + + + // AFFIX PLUGIN DEFINITION + // ======================= + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.affix') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.affix', (data = new Affix(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + var old = $.fn.affix + + $.fn.affix = Plugin + $.fn.affix.Constructor = Affix + + + // AFFIX NO CONFLICT + // ================= + + $.fn.affix.noConflict = function () { + $.fn.affix = old + return this + } + + + // AFFIX DATA-API + // ============== + + $(window).on('load', function () { + $('[data-spy="affix"]').each(function () { + var $spy = $(this) + var data = $spy.data() + + data.offset = data.offset || {} + + if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom + if (data.offsetTop != null) data.offset.top = data.offsetTop + + Plugin.call($spy, data) + }) + }) + +}(jQuery); diff --git a/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/js/bootstrap.min.js b/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/js/bootstrap.min.js new file mode 100644 index 0000000..12ae598 --- /dev/null +++ b/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/js/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v3.3.6 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. + * Licensed under the MIT license + */ +if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>2)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){if(a(b.target).is(this))return b.handleObj.handler.apply(this,arguments)}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.6",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.6",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),a(c.target).is('input[type="radio"]')||a(c.target).is('input[type="checkbox"]')||c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.6",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(!(a>this.$items.length-1||a<0))return this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){if(!this.sliding)return this.slide("next")},c.prototype.prev=function(){if(!this.sliding)return this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.6",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.6",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&jdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth
    ',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);if(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),!c.isInStateTrue())return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;!e&&/destroy|hide/.test(b)||(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.6",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.6",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.6",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return e=a-d&&"bottom"},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); \ No newline at end of file diff --git a/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/js/npm.js b/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/js/npm.js new file mode 100644 index 0000000..bf6aa80 --- /dev/null +++ b/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/js/npm.js @@ -0,0 +1,13 @@ +// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. +require('../../js/transition.js') +require('../../js/alert.js') +require('../../js/button.js') +require('../../js/carousel.js') +require('../../js/collapse.js') +require('../../js/dropdown.js') +require('../../js/modal.js') +require('../../js/tooltip.js') +require('../../js/popover.js') +require('../../js/scrollspy.js') +require('../../js/tab.js') +require('../../js/affix.js') \ No newline at end of file diff --git a/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/variables.less b/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/variables.less new file mode 100644 index 0000000..2b815d7 --- /dev/null +++ b/copri4/shareeweb-project/js/bootstrap-3.3.6-dist/variables.less @@ -0,0 +1,870 @@ +// +// Variables +// -------------------------------------------------- + + +//== Colors +// +//## Gray and brand colors for use across Bootstrap. + +@gray-base: #0061a1; +@gray-darker: #0061a1; +@gray-dark: #0061a1; +@gray: #0061a1; +@gray-light: #0061a1; +@gray-lighter: #0061a1; + +@brand-primary: #0061a1; +@brand-success: #5cb85c; +@brand-info: #5bc0de; +@brand-warning: #f0ad4e; +@brand-danger: #d9534f; + + +//== Scaffolding +// +//## Settings for some of the most global styles. + +//** Background color for ``. +@body-bg: #0061a1; +//** Global text color on ``. +@text-color: @gray-dark; + +//** Global textual link color. +@link-color: @brand-primary; +//** Link hover color set via `darken()` function. +@link-hover-color: darken(@link-color, 15%); +//** Link hover decoration. +@link-hover-decoration: underline; + + +//== Typography +// +//## Font, line-height, and color for body text, headings, and more. + +@font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif; +@font-family-serif: Georgia, "Times New Roman", Times, serif; +//** Default monospace fonts for ``, ``, and `
    `.
    +@font-family-monospace:   Menlo, Monaco, Consolas, "Courier New", monospace;
    +@font-family-base:        @font-family-sans-serif;
    +
    +@font-size-base:          14px;
    +@font-size-large:         ceil((@font-size-base * 1.25)); // ~18px
    +@font-size-small:         ceil((@font-size-base * 0.85)); // ~12px
    +
    +@font-size-h1:            floor((@font-size-base * 2.6)); // ~36px
    +@font-size-h2:            floor((@font-size-base * 2.15)); // ~30px
    +@font-size-h3:            ceil((@font-size-base * 1.7)); // ~24px
    +@font-size-h4:            ceil((@font-size-base * 1.25)); // ~18px
    +@font-size-h5:            @font-size-base;
    +@font-size-h6:            ceil((@font-size-base * 0.85)); // ~12px
    +
    +//** Unit-less `line-height` for use in components like buttons.
    +@line-height-base:        1.428571429; // 20/14
    +//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
    +@line-height-computed:    floor((@font-size-base * @line-height-base)); // ~20px
    +
    +//** By default, this inherits from the ``.
    +@headings-font-family:    inherit;
    +@headings-font-weight:    500;
    +@headings-line-height:    1.1;
    +@headings-color:          inherit;
    +
    +
    +//== Iconography
    +//
    +//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
    +
    +//** Load fonts from this directory.
    +@icon-font-path:          "../fonts/";
    +//** File name for all font files.
    +@icon-font-name:          "glyphicons-halflings-regular";
    +//** Element ID within SVG icon file.
    +@icon-font-svg-id:        "glyphicons_halflingsregular";
    +
    +
    +//== Components
    +//
    +//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
    +
    +@padding-base-vertical:     6px;
    +@padding-base-horizontal:   12px;
    +
    +@padding-large-vertical:    10px;
    +@padding-large-horizontal:  16px;
    +
    +@padding-small-vertical:    5px;
    +@padding-small-horizontal:  10px;
    +
    +@padding-xs-vertical:       1px;
    +@padding-xs-horizontal:     5px;
    +
    +@line-height-large:         1.3333333; // extra decimals for Win 8.1 Chrome
    +@line-height-small:         1.5;
    +
    +@border-radius-base:        0px;
    +@border-radius-large:       0px;
    +@border-radius-small:       0px;
    +
    +//** Global color for active items (e.g., navs or dropdowns).
    +@component-active-color:    #fff;
    +//** Global background color for active items (e.g., navs or dropdowns).
    +@component-active-bg:       @brand-primary;
    +
    +//** Width of the `border` for generating carets that indicator dropdowns.
    +@caret-width-base:          4px;
    +//** Carets increase slightly in size for larger components.
    +@caret-width-large:         5px;
    +
    +
    +//== Tables
    +//
    +//## Customizes the `.table` component with basic values, each used across all table variations.
    +
    +//** Padding for ``s and ``s.
    +@table-cell-padding:            8px;
    +//** Padding for cells in `.table-condensed`.
    +@table-condensed-cell-padding:  5px;
    +
    +//** Default background color used for all tables.
    +@table-bg:                      transparent;
    +//** Background color used for `.table-striped`.
    +@table-bg-accent:               #f9f9f9;
    +//** Background color used for `.table-hover`.
    +@table-bg-hover:                #f5f5f5;
    +@table-bg-active:               @table-bg-hover;
    +
    +//** Border color for table and cell borders.
    +@table-border-color:            #0061a1;
    +
    +
    +//== Buttons
    +//
    +//## For each of Bootstrap's buttons, define text, background and border color.
    +
    +@btn-font-weight:                normal;
    +
    +@btn-default-color:              #cccccc;
    +@btn-default-bg:                 #fff;
    +@btn-default-border:             #ccc;
    +
    +@btn-primary-color:              #fff;
    +@btn-primary-bg:                 @brand-primary;
    +@btn-primary-border:             darken(@btn-primary-bg, 5%);
    +
    +@btn-success-color:              #fff;
    +@btn-success-bg:                 @brand-success;
    +@btn-success-border:             darken(@btn-success-bg, 5%);
    +
    +@btn-info-color:                 #fff;
    +@btn-info-bg:                    @brand-info;
    +@btn-info-border:                darken(@btn-info-bg, 5%);
    +
    +@btn-warning-color:              #fff;
    +@btn-warning-bg:                 @brand-warning;
    +@btn-warning-border:             darken(@btn-warning-bg, 5%);
    +
    +@btn-danger-color:               #fff;
    +@btn-danger-bg:                  @brand-danger;
    +@btn-danger-border:              darken(@btn-danger-bg, 5%);
    +
    +@btn-link-disabled-color:        @gray-light;
    +
    +// Allows for customizing button radius independently from global border radius
    +@btn-border-radius-base:         @border-radius-base;
    +@btn-border-radius-large:        @border-radius-large;
    +@btn-border-radius-small:        @border-radius-small;
    +
    +
    +//== Forms
    +//
    +//##
    +
    +//** `` background color
    +@input-bg:                       #fff;
    +//** `` background color
    +@input-bg-disabled:              @gray-lighter;
    +
    +//** Text color for ``s
    +@input-color:                    @gray;
    +//** `` border color
    +@input-border:                   #ccc;
    +
    +// TODO: Rename `@input-border-radius` to `@input-border-radius-base` in v4
    +//** Default `.form-control` border radius
    +// This has no effect on ``s in CSS.
    +@input-border-radius:            @border-radius-base;
    +//** Large `.form-control` border radius
    +@input-border-radius-large:      @border-radius-large;
    +//** Small `.form-control` border radius
    +@input-border-radius-small:      @border-radius-small;
    +
    +//** Border color for inputs on focus
    +@input-border-focus:             #66afe9;
    +
    +//** Placeholder text color
    +@input-color-placeholder:        #999;
    +
    +//** Default `.form-control` height
    +@input-height-base:              (@line-height-computed + (@padding-base-vertical * 2) + 2);
    +//** Large `.form-control` height
    +@input-height-large:             (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);
    +//** Small `.form-control` height
    +@input-height-small:             (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2);
    +
    +//** `.form-group` margin
    +@form-group-margin-bottom:       15px;
    +
    +@legend-color:                   @gray-dark;
    +@legend-border-color:            #e5e5e5;
    +
    +//** Background color for textual input addons
    +@input-group-addon-bg:           @gray-lighter;
    +//** Border color for textual input addons
    +@input-group-addon-border-color: @input-border;
    +
    +//** Disabled cursor for form controls and buttons.
    +@cursor-disabled:                not-allowed;
    +
    +
    +//== Dropdowns
    +//
    +//## Dropdown menu container and contents.
    +
    +//** Background for the dropdown menu.
    +@dropdown-bg:                    #fff;
    +//** Dropdown menu `border-color`.
    +@dropdown-border:                rgba(0,0,0,.15);
    +//** Dropdown menu `border-color` **for IE8**.
    +@dropdown-fallback-border:       #ccc;
    +//** Divider color for between dropdown items.
    +@dropdown-divider-bg:            #e5e5e5;
    +
    +//** Dropdown link text color.
    +@dropdown-link-color:            @gray-dark;
    +//** Hover color for dropdown links.
    +@dropdown-link-hover-color:      darken(@gray-dark, 5%);
    +//** Hover background for dropdown links.
    +@dropdown-link-hover-bg:         #f5f5f5;
    +
    +//** Active dropdown menu item text color.
    +@dropdown-link-active-color:     @component-active-color;
    +//** Active dropdown menu item background color.
    +@dropdown-link-active-bg:        @component-active-bg;
    +
    +//** Disabled dropdown menu item background color.
    +@dropdown-link-disabled-color:   @gray-light;
    +
    +//** Text color for headers within dropdown menus.
    +@dropdown-header-color:          @gray-light;
    +
    +//** Deprecated `@dropdown-caret-color` as of v3.1.0
    +@dropdown-caret-color:           #000;
    +
    +
    +//-- Z-index master list
    +//
    +// Warning: Avoid customizing these values. They're used for a bird's eye view
    +// of components dependent on the z-axis and are designed to all work together.
    +//
    +// Note: These variables are not generated into the Customizer.
    +
    +@zindex-navbar:            1000;
    +@zindex-dropdown:          1000;
    +@zindex-popover:           1060;
    +@zindex-tooltip:           1070;
    +@zindex-navbar-fixed:      1030;
    +@zindex-modal-background:  1040;
    +@zindex-modal:             1050;
    +
    +
    +//== Media queries breakpoints
    +//
    +//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
    +
    +// Extra small screen / phone
    +//** Deprecated `@screen-xs` as of v3.0.1
    +@screen-xs:                  480px;
    +//** Deprecated `@screen-xs-min` as of v3.2.0
    +@screen-xs-min:              @screen-xs;
    +//** Deprecated `@screen-phone` as of v3.0.1
    +@screen-phone:               @screen-xs-min;
    +
    +// Small screen / tablet
    +//** Deprecated `@screen-sm` as of v3.0.1
    +@screen-sm:                  768px;
    +@screen-sm-min:              @screen-sm;
    +//** Deprecated `@screen-tablet` as of v3.0.1
    +@screen-tablet:              @screen-sm-min;
    +
    +// Medium screen / desktop
    +//** Deprecated `@screen-md` as of v3.0.1
    +@screen-md:                  992px;
    +@screen-md-min:              @screen-md;
    +//** Deprecated `@screen-desktop` as of v3.0.1
    +@screen-desktop:             @screen-md-min;
    +
    +// Large screen / wide desktop
    +//** Deprecated `@screen-lg` as of v3.0.1
    +@screen-lg:                  1200px;
    +@screen-lg-min:              @screen-lg;
    +//** Deprecated `@screen-lg-desktop` as of v3.0.1
    +@screen-lg-desktop:          @screen-lg-min;
    +
    +// So media queries don't overlap when required, provide a maximum
    +@screen-xs-max:              (@screen-sm-min - 1);
    +@screen-sm-max:              (@screen-md-min - 1);
    +@screen-md-max:              (@screen-lg-min - 1);
    +
    +
    +//== Grid system
    +//
    +//## Define your custom responsive grid.
    +
    +//** Number of columns in the grid.
    +@grid-columns:              12;
    +//** Padding between columns. Gets divided in half for the left and right.
    +@grid-gutter-width:         30px;
    +// Navbar collapse
    +//** Point at which the navbar becomes uncollapsed.
    +@grid-float-breakpoint:     @screen-sm-min;
    +//** Point at which the navbar begins collapsing.
    +@grid-float-breakpoint-max: (@grid-float-breakpoint - 1);
    +
    +
    +//== Container sizes
    +//
    +//## Define the maximum width of `.container` for different screen sizes.
    +
    +// Small screen / tablet
    +@container-tablet:             (720px + @grid-gutter-width);
    +//** For `@screen-sm-min` and up.
    +@container-sm:                 @container-tablet;
    +
    +// Medium screen / desktop
    +@container-desktop:            (940px + @grid-gutter-width);
    +//** For `@screen-md-min` and up.
    +@container-md:                 @container-desktop;
    +
    +// Large screen / wide desktop
    +@container-large-desktop:      (1140px + @grid-gutter-width);
    +//** For `@screen-lg-min` and up.
    +@container-lg:                 @container-large-desktop;
    +
    +
    +//== Navbar
    +//
    +//##
    +
    +// Basics of a navbar
    +@navbar-height:                    70px;
    +@navbar-margin-bottom:             @line-height-computed;
    +@navbar-border-radius:             @border-radius-base;
    +@navbar-padding-horizontal:        floor((@grid-gutter-width / 2));
    +@navbar-padding-vertical:          ((@navbar-height - @line-height-computed) / 2);
    +@navbar-collapse-max-height:       340px;
    +
    +@navbar-default-color:             #ffffff;
    +@navbar-default-bg:                #0061a1;
    +@navbar-default-border:            #0061a1;
    +
    +// Navbar links
    +@navbar-default-link-color:                #ffffff;
    +@navbar-default-link-hover-color:          #cccccc;
    +@navbar-default-link-hover-bg:             transparent;
    +@navbar-default-link-active-color:         #cccccc;
    +//@navbar-default-link-active-bg:            darken(@navbar-default-bg, 6.5%);
    +@navbar-default-link-active-bg:            @navbar-default-bg;
    +@navbar-default-link-disabled-color:       #ccc;
    +@navbar-default-link-disabled-bg:          transparent;
    +
    +// Navbar brand label
    +@navbar-default-brand-color:               @navbar-default-link-color;
    +@navbar-default-brand-hover-color:         darken(@navbar-default-brand-color, 10%);
    +@navbar-default-brand-hover-bg:            transparent;
    +
    +// Navbar toggle
    +@navbar-default-toggle-hover-bg:           #ddd;
    +@navbar-default-toggle-icon-bar-bg:        #888;
    +@navbar-default-toggle-border-color:       #ddd;
    +
    +
    +//=== Inverted navbar
    +// Reset inverted navbar basics
    +@navbar-inverse-color:                      lighten(@gray-light, 15%);
    +@navbar-inverse-bg:                         #222;
    +@navbar-inverse-border:                     darken(@navbar-inverse-bg, 10%);
    +
    +// Inverted navbar links
    +@navbar-inverse-link-color:                 lighten(@gray-light, 15%);
    +@navbar-inverse-link-hover-color:           #fff;
    +@navbar-inverse-link-hover-bg:              transparent;
    +@navbar-inverse-link-active-color:          @navbar-inverse-link-hover-color;
    +@navbar-inverse-link-active-bg:             darken(@navbar-inverse-bg, 10%);
    +@navbar-inverse-link-disabled-color:        #444;
    +@navbar-inverse-link-disabled-bg:           transparent;
    +
    +// Inverted navbar brand label
    +@navbar-inverse-brand-color:                @navbar-inverse-link-color;
    +@navbar-inverse-brand-hover-color:          #fff;
    +@navbar-inverse-brand-hover-bg:             transparent;
    +
    +// Inverted navbar toggle
    +@navbar-inverse-toggle-hover-bg:            #cccccc;
    +@navbar-inverse-toggle-icon-bar-bg:         #fff;
    +@navbar-inverse-toggle-border-color:        #cccccc;
    +
    +
    +//== Navs
    +//
    +//##
    +
    +//=== Shared nav styles
    +@nav-link-padding:                          10px 15px;
    +@nav-link-hover-bg:                         @gray-lighter;
    +
    +@nav-disabled-link-color:                   @gray-light;
    +@nav-disabled-link-hover-color:             @gray-light;
    +
    +//== Tabs
    +@nav-tabs-border-color:                     #ddd;
    +
    +@nav-tabs-link-hover-border-color:          @gray-lighter;
    +
    +@nav-tabs-active-link-hover-bg:             @body-bg;
    +@nav-tabs-active-link-hover-color:          @gray;
    +@nav-tabs-active-link-hover-border-color:   #ddd;
    +
    +@nav-tabs-justified-link-border-color:            #ddd;
    +@nav-tabs-justified-active-link-border-color:     @body-bg;
    +
    +//== Pills
    +@nav-pills-border-radius:                   @border-radius-base;
    +@nav-pills-active-link-hover-bg:            @component-active-bg;
    +@nav-pills-active-link-hover-color:         @component-active-color;
    +
    +
    +//== Pagination
    +//
    +//##
    +
    +@pagination-color:                     @link-color;
    +@pagination-bg:                        #fff;
    +@pagination-border:                    #ddd;
    +
    +@pagination-hover-color:               @link-hover-color;
    +@pagination-hover-bg:                  @gray-lighter;
    +@pagination-hover-border:              #ddd;
    +
    +@pagination-active-color:              #fff;
    +@pagination-active-bg:                 @brand-primary;
    +@pagination-active-border:             @brand-primary;
    +
    +@pagination-disabled-color:            @gray-light;
    +@pagination-disabled-bg:               #fff;
    +@pagination-disabled-border:           #ddd;
    +
    +
    +//== Pager
    +//
    +//##
    +
    +@pager-bg:                             @pagination-bg;
    +@pager-border:                         @pagination-border;
    +@pager-border-radius:                  15px;
    +
    +@pager-hover-bg:                       @pagination-hover-bg;
    +
    +@pager-active-bg:                      @pagination-active-bg;
    +@pager-active-color:                   @pagination-active-color;
    +
    +@pager-disabled-color:                 @pagination-disabled-color;
    +
    +
    +//== Jumbotron
    +//
    +//##
    +
    +@jumbotron-padding:              30px;
    +@jumbotron-color:                inherit;
    +@jumbotron-bg:                   @gray-lighter;
    +@jumbotron-heading-color:        inherit;
    +@jumbotron-font-size:            ceil((@font-size-base * 1.5));
    +@jumbotron-heading-font-size:    ceil((@font-size-base * 4.5));
    +
    +
    +//== Form states and alerts
    +//
    +//## Define colors for form feedback states and, by default, alerts.
    +
    +@state-success-text:             #3c763d;
    +@state-success-bg:               #dff0d8;
    +@state-success-border:           darken(spin(@state-success-bg, -10), 5%);
    +
    +@state-info-text:                #31708f;
    +@state-info-bg:                  #d9edf7;
    +@state-info-border:              darken(spin(@state-info-bg, -10), 7%);
    +
    +@state-warning-text:             #8a6d3b;
    +@state-warning-bg:               #fcf8e3;
    +@state-warning-border:           darken(spin(@state-warning-bg, -10), 5%);
    +
    +@state-danger-text:              #a94442;
    +@state-danger-bg:                #f2dede;
    +@state-danger-border:            darken(spin(@state-danger-bg, -10), 5%);
    +
    +
    +//== Tooltips
    +//
    +//##
    +
    +//** Tooltip max width
    +@tooltip-max-width:           200px;
    +//** Tooltip text color
    +@tooltip-color:               #fff;
    +//** Tooltip background color
    +@tooltip-bg:                  #000;
    +@tooltip-opacity:             .9;
    +
    +//** Tooltip arrow width
    +@tooltip-arrow-width:         5px;
    +//** Tooltip arrow color
    +@tooltip-arrow-color:         @tooltip-bg;
    +
    +
    +//== Popovers
    +//
    +//##
    +
    +//** Popover body background color
    +@popover-bg:                          #fff;
    +//** Popover maximum width
    +@popover-max-width:                   276px;
    +//** Popover border color
    +@popover-border-color:                rgba(0,0,0,.2);
    +//** Popover fallback border color
    +@popover-fallback-border-color:       #ccc;
    +
    +//** Popover title background color
    +@popover-title-bg:                    darken(@popover-bg, 3%);
    +
    +//** Popover arrow width
    +@popover-arrow-width:                 10px;
    +//** Popover arrow color
    +@popover-arrow-color:                 @popover-bg;
    +
    +//** Popover outer arrow width
    +@popover-arrow-outer-width:           (@popover-arrow-width + 1);
    +//** Popover outer arrow color
    +@popover-arrow-outer-color:           fadein(@popover-border-color, 5%);
    +//** Popover outer arrow fallback color
    +@popover-arrow-outer-fallback-color:  darken(@popover-fallback-border-color, 20%);
    +
    +
    +//== Labels
    +//
    +//##
    +
    +//** Default label background color
    +@label-default-bg:            @gray-light;
    +//** Primary label background color
    +@label-primary-bg:            @brand-primary;
    +//** Success label background color
    +@label-success-bg:            @brand-success;
    +//** Info label background color
    +@label-info-bg:               @brand-info;
    +//** Warning label background color
    +@label-warning-bg:            @brand-warning;
    +//** Danger label background color
    +@label-danger-bg:             @brand-danger;
    +
    +//** Default label text color
    +@label-color:                 #fff;
    +//** Default text color of a linked label
    +@label-link-hover-color:      #fff;
    +
    +
    +//== Modals
    +//
    +//##
    +
    +//** Padding applied to the modal body
    +@modal-inner-padding:         15px;
    +
    +//** Padding applied to the modal title
    +@modal-title-padding:         15px;
    +//** Modal title line-height
    +@modal-title-line-height:     @line-height-base;
    +
    +//** Background color of modal content area
    +@modal-content-bg:                             #fff;
    +//** Modal content border color
    +@modal-content-border-color:                   rgba(0,0,0,.2);
    +//** Modal content border color **for IE8**
    +@modal-content-fallback-border-color:          #999;
    +
    +//** Modal backdrop background color
    +@modal-backdrop-bg:           #000;
    +//** Modal backdrop opacity
    +@modal-backdrop-opacity:      .5;
    +//** Modal header border color
    +@modal-header-border-color:   #e5e5e5;
    +//** Modal footer border color
    +@modal-footer-border-color:   @modal-header-border-color;
    +
    +@modal-lg:                    900px;
    +@modal-md:                    600px;
    +@modal-sm:                    300px;
    +
    +
    +//== Alerts
    +//
    +//## Define alert colors, border radius, and padding.
    +
    +@alert-padding:               15px;
    +@alert-border-radius:         @border-radius-base;
    +@alert-link-font-weight:      bold;
    +
    +@alert-success-bg:            @state-success-bg;
    +@alert-success-text:          @state-success-text;
    +@alert-success-border:        @state-success-border;
    +
    +@alert-info-bg:               @state-info-bg;
    +@alert-info-text:             @state-info-text;
    +@alert-info-border:           @state-info-border;
    +
    +@alert-warning-bg:            @state-warning-bg;
    +@alert-warning-text:          @state-warning-text;
    +@alert-warning-border:        @state-warning-border;
    +
    +@alert-danger-bg:             @state-danger-bg;
    +@alert-danger-text:           @state-danger-text;
    +@alert-danger-border:         @state-danger-border;
    +
    +
    +//== Progress bars
    +//
    +//##
    +
    +//** Background color of the whole progress component
    +@progress-bg:                 #f5f5f5;
    +//** Progress bar text color
    +@progress-bar-color:          #fff;
    +//** Variable for setting rounded corners on progress bar.
    +@progress-border-radius:      @border-radius-base;
    +
    +//** Default progress bar color
    +@progress-bar-bg:             @brand-primary;
    +//** Success progress bar color
    +@progress-bar-success-bg:     @brand-success;
    +//** Warning progress bar color
    +@progress-bar-warning-bg:     @brand-warning;
    +//** Danger progress bar color
    +@progress-bar-danger-bg:      @brand-danger;
    +//** Info progress bar color
    +@progress-bar-info-bg:        @brand-info;
    +
    +
    +//== List group
    +//
    +//##
    +
    +//** Background color on `.list-group-item`
    +@list-group-bg:                 #fff;
    +//** `.list-group-item` border color
    +@list-group-border:             #ddd;
    +//** List group border radius
    +@list-group-border-radius:      @border-radius-base;
    +
    +//** Background color of single list items on hover
    +@list-group-hover-bg:           #f5f5f5;
    +//** Text color of active list items
    +@list-group-active-color:       @component-active-color;
    +//** Background color of active list items
    +@list-group-active-bg:          @component-active-bg;
    +//** Border color of active list elements
    +@list-group-active-border:      @list-group-active-bg;
    +//** Text color for content within active list items
    +@list-group-active-text-color:  lighten(@list-group-active-bg, 40%);
    +
    +//** Text color of disabled list items
    +@list-group-disabled-color:      @gray-light;
    +//** Background color of disabled list items
    +@list-group-disabled-bg:         @gray-lighter;
    +//** Text color for content within disabled list items
    +@list-group-disabled-text-color: @list-group-disabled-color;
    +
    +@list-group-link-color:         #ffffff;
    +@list-group-link-hover-color:   @list-group-link-color;
    +@list-group-link-heading-color: #cccccc;
    +
    +
    +//== Panels
    +//
    +//##
    +
    +@panel-bg:                    #fff;
    +@panel-body-padding:          15px;
    +@panel-heading-padding:       10px 15px;
    +@panel-footer-padding:        @panel-heading-padding;
    +@panel-border-radius:         @border-radius-base;
    +
    +//** Border color for elements within panels
    +@panel-inner-border:          #ddd;
    +@panel-footer-bg:             #f5f5f5;
    +
    +@panel-default-text:          @gray-dark;
    +@panel-default-border:        #ddd;
    +@panel-default-heading-bg:    #f5f5f5;
    +
    +@panel-primary-text:          #fff;
    +@panel-primary-border:        @brand-primary;
    +@panel-primary-heading-bg:    @brand-primary;
    +
    +@panel-success-text:          @state-success-text;
    +@panel-success-border:        @state-success-border;
    +@panel-success-heading-bg:    @state-success-bg;
    +
    +@panel-info-text:             @state-info-text;
    +@panel-info-border:           @state-info-border;
    +@panel-info-heading-bg:       @state-info-bg;
    +
    +@panel-warning-text:          @state-warning-text;
    +@panel-warning-border:        @state-warning-border;
    +@panel-warning-heading-bg:    @state-warning-bg;
    +
    +@panel-danger-text:           @state-danger-text;
    +@panel-danger-border:         @state-danger-border;
    +@panel-danger-heading-bg:     @state-danger-bg;
    +
    +
    +//== Thumbnails
    +//
    +//##
    +
    +//** Padding around the thumbnail image
    +@thumbnail-padding:           4px;
    +//** Thumbnail background color
    +@thumbnail-bg:                @body-bg;
    +//** Thumbnail border color
    +@thumbnail-border:            #ddd;
    +//** Thumbnail border radius
    +@thumbnail-border-radius:     @border-radius-base;
    +
    +//** Custom text color for thumbnail captions
    +@thumbnail-caption-color:     @text-color;
    +//** Padding around the thumbnail caption
    +@thumbnail-caption-padding:   9px;
    +
    +
    +//== Wells
    +//
    +//##
    +
    +@well-bg:                     #f5f5f5;
    +@well-border:                 darken(@well-bg, 7%);
    +
    +
    +//== Badges
    +//
    +//##
    +
    +@badge-color:                 #fff;
    +//** Linked badge text color on hover
    +@badge-link-hover-color:      #fff;
    +@badge-bg:                    @gray-light;
    +
    +//** Badge text color in active nav link
    +@badge-active-color:          @link-color;
    +//** Badge background color in active nav link
    +@badge-active-bg:             #fff;
    +
    +@badge-font-weight:           bold;
    +@badge-line-height:           1;
    +@badge-border-radius:         10px;
    +
    +
    +//== Breadcrumbs
    +//
    +//##
    +
    +@breadcrumb-padding-vertical:   8px;
    +@breadcrumb-padding-horizontal: 15px;
    +//** Breadcrumb background color
    +@breadcrumb-bg:                 #f5f5f5;
    +//** Breadcrumb text color
    +@breadcrumb-color:              #ccc;
    +//** Text color of current page in the breadcrumb
    +@breadcrumb-active-color:       @gray-light;
    +//** Textual separator for between breadcrumb elements
    +@breadcrumb-separator:          "/";
    +
    +
    +//== Carousel
    +//
    +//##
    +
    +@carousel-text-shadow:                        0 1px 2px rgba(0,0,0,.6);
    +
    +@carousel-control-color:                      #fff;
    +@carousel-control-width:                      15%;
    +@carousel-control-opacity:                    .5;
    +@carousel-control-font-size:                  20px;
    +
    +@carousel-indicator-active-bg:                #fff;
    +@carousel-indicator-border-color:             #fff;
    +
    +@carousel-caption-color:                      #fff;
    +
    +
    +//== Close
    +//
    +//##
    +
    +@close-font-weight:           bold;
    +@close-color:                 #000;
    +@close-text-shadow:           0 1px 0 #fff;
    +
    +
    +//== Code
    +//
    +//##
    +
    +@code-color:                  #c7254e;
    +@code-bg:                     #f9f2f4;
    +
    +@kbd-color:                   #fff;
    +@kbd-bg:                      #cccccc;
    +
    +@pre-bg:                      #f5f5f5;
    +@pre-color:                   @gray-dark;
    +@pre-border-color:            #ccc;
    +@pre-scrollable-max-height:   340px;
    +
    +
    +//== Type
    +//
    +//##
    +
    +//** Horizontal offset for forms and lists.
    +@component-offset-horizontal: 180px;
    +//** Text muted color
    +@text-muted:                  @gray-light;
    +//** Abbreviations and acronyms border color
    +@abbr-border-color:           @gray-light;
    +//** Headings small color
    +@headings-small-color:        @gray-light;
    +//** Blockquote small color
    +@blockquote-small-color:      @gray-light;
    +//** Blockquote font size
    +@blockquote-font-size:        (@font-size-base * 1.25);
    +//** Blockquote border color
    +@blockquote-border-color:     @gray-lighter;
    +//** Page header border color
    +@page-header-border-color:    @gray-lighter;
    +//** Width of horizontal description list titles
    +@dl-horizontal-offset:        @component-offset-horizontal;
    +//** Point at which .dl-horizontal becomes horizontal
    +@dl-horizontal-breakpoint:    @grid-float-breakpoint;
    +//** Horizontal line color.
    +@hr-border:                   @gray-lighter;
    diff --git a/copri4/shareeweb-project/js/iframeResizer.contentWindow.min.js b/copri4/shareeweb-project/js/iframeResizer.contentWindow.min.js
    new file mode 100644
    index 0000000..a25e581
    --- /dev/null
    +++ b/copri4/shareeweb-project/js/iframeResizer.contentWindow.min.js
    @@ -0,0 +1,10 @@
    +/*! iFrame Resizer (iframeSizer.contentWindow.min.js) - v4.3.2 - 2021-04-26
    + *  Desc: Include this file in any page being loaded into an iframe
    + *        to force the iframe to resize to the content size.
    + *  Requires: iframeResizer.min.js on host page.
    + *  Copyright: (c) 2021 David J. Bradshaw - dave@bradshaw.net
    + *  License: MIT
    + */
    +
    +!function(c){if("undefined"!=typeof window){var i=!0,o=10,r="",a=0,u="",s=null,d="",l=!1,f={resize:1,click:1},m=128,h=!0,g=1,n="bodyOffset",p=n,v=!0,y="",w={},b=32,T=null,E=!1,O=!1,S="[iFrameSizer]",M=S.length,I="",N={max:1,min:1,bodyScroll:1,documentElementScroll:1},A="child",C=!0,z=window.parent,k="*",R=0,x=!1,e=null,L=16,F=1,t="scroll",P=t,D=window,j=function(){re("onMessage function not defined")},q=function(){},H=function(){},W={height:function(){return re("Custom height calculation function not defined"),document.documentElement.offsetHeight},width:function(){return re("Custom width calculation function not defined"),document.body.scrollWidth}},B={},J=!1;try{var U=Object.create({},{passive:{get:function(){J=!0}}});window.addEventListener("test",ee,U),window.removeEventListener("test",ee,U)}catch(e){}var V,X,Y,K,Q,G,Z={bodyOffset:function(){return document.body.offsetHeight+pe("marginTop")+pe("marginBottom")},offset:function(){return Z.bodyOffset()},bodyScroll:function(){return document.body.scrollHeight},custom:function(){return W.height()},documentElementOffset:function(){return document.documentElement.offsetHeight},documentElementScroll:function(){return document.documentElement.scrollHeight},max:function(){return Math.max.apply(null,ye(Z))},min:function(){return Math.min.apply(null,ye(Z))},grow:function(){return Z.max()},lowestElement:function(){return Math.max(Z.bodyOffset()||Z.documentElementOffset(),ve("bottom",be()))},taggedElement:function(){return we("bottom","data-iframe-height")}},$={bodyScroll:function(){return document.body.scrollWidth},bodyOffset:function(){return document.body.offsetWidth},custom:function(){return W.width()},documentElementScroll:function(){return document.documentElement.scrollWidth},documentElementOffset:function(){return document.documentElement.offsetWidth},scroll:function(){return Math.max($.bodyScroll(),$.documentElementScroll())},max:function(){return Math.max.apply(null,ye($))},min:function(){return Math.min.apply(null,ye($))},rightMostElement:function(){return ve("right",be())},taggedElement:function(){return we("right","data-iframe-width")}},_=(V=Te,Q=null,G=0,function(){var e=Date.now(),t=L-(e-(G=G||e));return X=this,Y=arguments,t<=0||LF[s]["max"+e])throw new Error("Value for min"+e+" can not be greater than max"+e)}s in F&&"iFrameResizer"in i?N(s,"Ignored iFrame, already setup."):(o(e),function(){switch(T(s,"IFrame scrolling "+(F[s]&&F[s].scrolling?"enabled":"disabled")+" for "+s),i.style.overflow=!1===(F[s]&&F[s].scrolling)?"hidden":"auto",F[s]&&F[s].scrolling){case"omit":break;case!0:i.scrolling="yes";break;case!1:i.scrolling="no";break;default:i.scrolling=F[s]?F[s].scrolling:"no"}}(),c("Height"),c("Width"),d("maxHeight"),d("minHeight"),d("maxWidth"),d("minWidth"),"number"!=typeof(F[s]&&F[s].bodyMargin)&&"0"!==(F[s]&&F[s].bodyMargin)||(F[s].bodyMarginV1=F[s].bodyMargin,F[s].bodyMargin=F[s].bodyMargin+"px"),n(q(s)),F[s]&&(F[s].iframe.iFrameResizer={close:C.bind(null,F[s].iframe),removeListeners:p.bind(null,F[s].iframe),resize:B.bind(null,"Window resize","resize",F[s].iframe),moveToAnchor:function(e){B("Move to anchor","moveToAnchor:"+e,F[s].iframe,s)},sendMessage:function(e){B("Send Message","message:"+(e=JSON.stringify(e)),F[s].iframe,s)}}))}function c(e,n){null===t&&(t=setTimeout(function(){t=null,e()},n))}function n(){"hidden"!==document.visibilityState&&(T("document","Trigger event: Visiblity change"),c(function(){w("Tab Visable","resize")},16))}function w(t,i){Object.keys(F).forEach(function(e){var n;F[n=e]&&"parent"===F[n].resizeFrom&&F[n].autoResize&&!F[n].firstRun&&B(t,i,F[e].iframe,e)})}function b(){O(window,"message",e),O(window,"resize",function(){var e;T("window","Trigger event: "+(e="resize")),c(function(){w("Window "+e,"resize")},16)}),O(document,"visibilitychange",n),O(document,"-webkit-visibilitychange",n)}function y(){function i(e,n){n&&(function(){if(!n.tagName)throw new TypeError("Object is not a valid DOM element");if("IFRAME"!==n.tagName.toUpperCase())throw new TypeError("Expected