From f139fe617ed7f728c3a81b2221f2458d52c8a168 Mon Sep 17 00:00:00 2001
From: sonikf <93765174+sonikf@users.noreply.github.com>
Date: Thu, 15 Dec 2022 18:26:20 +0200
Subject: [PATCH] Add files via upload
---
COPYING | 621 ++++++++
ChangeLog.md | 5 +
README.md | 37 +
admin/about.php | 105 ++
admin/setup.php | 587 ++++++++
.../v16/core/class/html.formsetup.class.php | 1322 +++++++++++++++++
build/makepack-ctpt.conf | 11 +
core/modules/modCTPT.class.php | 505 +++++++
...nterface_99_modCTPT_CTPTTriggers.class.php | 379 +++++
ctptindex.php | 241 +++
img/object_ctpt.png | Bin 0 -> 219 bytes
img/object_ctpt_over.png | Bin 0 -> 208 bytes
langs/en_US/ctpt.lang | 54 +
lib/ctpt.lib.php | 68 +
modulebuilder.txt | 3 +
sql/dolibarr_allversions.sql | 3 +
test/phpunit/CTPTFunctionalTest.php | 304 ++++
17 files changed, 4245 insertions(+)
create mode 100644 COPYING
create mode 100644 ChangeLog.md
create mode 100644 README.md
create mode 100644 admin/about.php
create mode 100644 admin/setup.php
create mode 100644 backport/v16/core/class/html.formsetup.class.php
create mode 100644 build/makepack-ctpt.conf
create mode 100644 core/modules/modCTPT.class.php
create mode 100644 core/triggers/interface_99_modCTPT_CTPTTriggers.class.php
create mode 100644 ctptindex.php
create mode 100644 img/object_ctpt.png
create mode 100644 img/object_ctpt_over.png
create mode 100644 langs/en_US/ctpt.lang
create mode 100644 lib/ctpt.lib.php
create mode 100644 modulebuilder.txt
create mode 100644 sql/dolibarr_allversions.sql
create mode 100644 test/phpunit/CTPTFunctionalTest.php
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..94a0453
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,621 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 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 General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is 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. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ 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.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ 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 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. Use with the GNU Affero General Public License.
+
+ 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 Affero 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 special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU 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 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 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 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
diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
index 0000000..d9dee60
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,5 @@
+# CHANGELOG CTPT FOR [DOLIBARR ERP CRM](https://www.dolibarr.org)
+
+## 1.0
+
+Initial version
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5e77dc9
--- /dev/null
+++ b/README.md
@@ -0,0 +1,37 @@
+# CTPT FOR [DOLIBARR ERP CRM](https://www.dolibarr.org)
+
+## Features
+
+CTPT stands for "Change Third Party Type" from the New invoice creation card.
+
+Useful for those ones using third party type vocabulary to change the mask - series with {tttt} tag.
+
+
+
+Other external modules are available on [Dolistore.com](https://www.dolistore.com).
+
+## Translations
+
+Translations can be completed manually by editing files into directories *langs*.
+
+
+
+
+
+## Licenses
+
+### Main code
+
+GPLv3 or (at your option) any later version. See file COPYING for more information.
+
+### Documentation
+
+All texts and readmes are licensed under GFDL.
diff --git a/admin/about.php b/admin/about.php
new file mode 100644
index 0000000..d890eaf
--- /dev/null
+++ b/admin/about.php
@@ -0,0 +1,105 @@
+
+ * Copyright (C) 2022 SuperAdmin
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * \file ctpt/admin/about.php
+ * \ingroup ctpt
+ * \brief About page of module CTPT.
+ */
+
+// Load Dolibarr environment
+$res = 0;
+// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)
+if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
+ $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
+}
+// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME
+$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1;
+while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
+ $i--; $j--;
+}
+if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
+ $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
+}
+if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
+ $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
+}
+// Try main.inc.php using relative path
+if (!$res && file_exists("../../main.inc.php")) {
+ $res = @include "../../main.inc.php";
+}
+if (!$res && file_exists("../../../main.inc.php")) {
+ $res = @include "../../../main.inc.php";
+}
+if (!$res) {
+ die("Include of main fails");
+}
+
+// Libraries
+require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
+require_once '../lib/ctpt.lib.php';
+
+// Translations
+$langs->loadLangs(array("errors", "admin", "ctpt@ctpt"));
+
+// Access control
+if (!$user->admin) {
+ accessforbidden();
+}
+
+// Parameters
+$action = GETPOST('action', 'aZ09');
+$backtopage = GETPOST('backtopage', 'alpha');
+
+
+/*
+ * Actions
+ */
+
+// None
+
+
+/*
+ * View
+ */
+
+$form = new Form($db);
+
+$help_url = '';
+$page_name = "CTPTAbout";
+
+llxHeader('', $langs->trans($page_name), $help_url);
+
+// Subheader
+$linkback = ''.$langs->trans("BackToModuleList").'';
+
+print load_fiche_titre($langs->trans($page_name), $linkback, 'title_setup');
+
+// Configuration header
+$head = ctptAdminPrepareHead();
+print dol_get_fiche_head($head, 'about', $langs->trans($page_name), 0, 'ctpt@ctpt');
+
+dol_include_once('/ctpt/core/modules/modCTPT.class.php');
+$tmpmodule = new modCTPT($db);
+print $tmpmodule->getDescLong();
+
+// Page end
+print dol_get_fiche_end();
+llxFooter();
+$db->close();
diff --git a/admin/setup.php b/admin/setup.php
new file mode 100644
index 0000000..a8fc0d4
--- /dev/null
+++ b/admin/setup.php
@@ -0,0 +1,587 @@
+
+ * Copyright (C) 2022 SuperAdmin
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * \file ctpt/admin/setup.php
+ * \ingroup ctpt
+ * \brief CTPT setup page.
+ */
+
+// Load Dolibarr environment
+$res = 0;
+// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)
+if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
+ $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
+}
+// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME
+$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1;
+while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
+ $i--; $j--;
+}
+if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
+ $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
+}
+if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
+ $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
+}
+// Try main.inc.php using relative path
+if (!$res && file_exists("../../main.inc.php")) {
+ $res = @include "../../main.inc.php";
+}
+if (!$res && file_exists("../../../main.inc.php")) {
+ $res = @include "../../../main.inc.php";
+}
+if (!$res) {
+ die("Include of main fails");
+}
+
+global $langs, $user;
+
+// Libraries
+require_once DOL_DOCUMENT_ROOT."/core/lib/admin.lib.php";
+require_once '../lib/ctpt.lib.php';
+//require_once "../class/myclass.class.php";
+
+// Translations
+$langs->loadLangs(array("admin", "ctpt@ctpt"));
+
+// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
+$hookmanager->initHooks(array('ctptsetup', 'globalsetup'));
+
+// Access control
+if (!$user->admin) {
+ accessforbidden();
+}
+
+// Parameters
+$action = GETPOST('action', 'aZ09');
+$backtopage = GETPOST('backtopage', 'alpha');
+$modulepart = GETPOST('modulepart', 'aZ09'); // Used by actions_setmoduleoptions.inc.php
+
+$value = GETPOST('value', 'alpha');
+$label = GETPOST('label', 'alpha');
+$scandir = GETPOST('scan_dir', 'alpha');
+$type = 'myobject';
+
+
+$error = 0;
+$setupnotempty = 0;
+
+// Set this to 1 to use the factory to manage constants. Warning, the generated module will be compatible with version v15+ only
+$useFormSetup = 1;
+
+if (!class_exists('FormSetup')) {
+ // For retrocompatibility Dolibarr < 16.0
+ if (floatval(DOL_VERSION) < 16.0 && !class_exists('FormSetup')) {
+ require_once __DIR__.'/../backport/v16/core/class/html.formsetup.class.php';
+ } else {
+ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formsetup.class.php';
+ }
+}
+
+$formSetup = new FormSetup($db);
+
+
+// Hôte
+$item = $formSetup->newItem('NO_PARAM_JUST_TEXT');
+$item->fieldOverride = (empty($_SERVER['HTTPS']) ? 'http://' : 'https://') . $_SERVER['HTTP_HOST'];
+$item->cssClass = 'minwidth500';
+
+// Setup conf CTPT_MYPARAM1 as a simple string input
+$item = $formSetup->newItem('CTPT_MYPARAM1');
+$item->defaultFieldValue = 'default value';
+
+// Setup conf CTPT_MYPARAM1 as a simple textarea input but we replace the text of field title
+$item = $formSetup->newItem('CTPT_MYPARAM2');
+$item->nameText = $item->getNameText().' more html text ';
+
+// Setup conf CTPT_MYPARAM3
+$item = $formSetup->newItem('CTPT_MYPARAM3');
+$item->setAsThirdpartyType();
+
+// Setup conf CTPT_MYPARAM4 : exemple of quick define write style
+$formSetup->newItem('CTPT_MYPARAM4')->setAsYesNo();
+
+// Setup conf CTPT_MYPARAM5
+$formSetup->newItem('CTPT_MYPARAM5')->setAsEmailTemplate('thirdparty');
+
+// Setup conf CTPT_MYPARAM6
+$formSetup->newItem('CTPT_MYPARAM6')->setAsSecureKey()->enabled = 0; // disabled
+
+// Setup conf CTPT_MYPARAM7
+$formSetup->newItem('CTPT_MYPARAM7')->setAsProduct();
+
+$formSetup->newItem('Title')->setAsTitle();
+
+// Setup conf CTPT_MYPARAM8
+$item = $formSetup->newItem('CTPT_MYPARAM8');
+$TField = array(
+ 'test01' => $langs->trans('test01'),
+ 'test02' => $langs->trans('test02'),
+ 'test03' => $langs->trans('test03'),
+ 'test04' => $langs->trans('test04'),
+ 'test05' => $langs->trans('test05'),
+ 'test06' => $langs->trans('test06'),
+);
+$item->setAsMultiSelect($TField);
+$item->helpText = $langs->transnoentities('CTPT_MYPARAM8');
+
+
+// Setup conf CTPT_MYPARAM9
+$formSetup->newItem('CTPT_MYPARAM9')->setAsSelect($TField);
+
+
+// Setup conf CTPT_MYPARAM10
+$item = $formSetup->newItem('CTPT_MYPARAM10');
+$item->setAsColor();
+$item->defaultFieldValue = '#FF0000';
+$item->nameText = $item->getNameText().' more html text ';
+$item->fieldInputOverride = '';
+$item->helpText = $langs->transnoentities('AnHelpMessage');
+//$item->fieldValue = '';
+//$item->fieldAttr = array() ; // fields attribute only for compatible fields like input text
+//$item->fieldOverride = false; // set this var to override field output will override $fieldInputOverride and $fieldOutputOverride too
+//$item->fieldInputOverride = false; // set this var to override field input
+//$item->fieldOutputOverride = false; // set this var to override field output
+
+
+$setupnotempty =+ count($formSetup->items);
+
+
+$dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
+
+
+/*
+ * Actions
+ */
+
+// For retrocompatibility Dolibarr < 15.0
+if ( versioncompare(explode('.', DOL_VERSION), array(15)) < 0 && $action == 'update' && !empty($user->admin)) {
+ $formSetup->saveConfFromPost();
+}
+
+include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
+
+if ($action == 'updateMask') {
+ $maskconst = GETPOST('maskconst', 'alpha');
+ $maskvalue = GETPOST('maskvalue', 'alpha');
+
+ if ($maskconst) {
+ $res = dolibarr_set_const($db, $maskconst, $maskvalue, 'chaine', 0, '', $conf->entity);
+ if (!($res > 0)) {
+ $error++;
+ }
+ }
+
+ if (!$error) {
+ setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
+ } else {
+ setEventMessages($langs->trans("Error"), null, 'errors');
+ }
+} elseif ($action == 'specimen') {
+ $modele = GETPOST('module', 'alpha');
+ $tmpobjectkey = GETPOST('object');
+
+ $tmpobject = new $tmpobjectkey($db);
+ $tmpobject->initAsSpecimen();
+
+ // Search template files
+ $file = ''; $classname = ''; $filefound = 0;
+ $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
+ foreach ($dirmodels as $reldir) {
+ $file = dol_buildpath($reldir."core/modules/ctpt/doc/pdf_".$modele."_".strtolower($tmpobjectkey).".modules.php", 0);
+ if (file_exists($file)) {
+ $filefound = 1;
+ $classname = "pdf_".$modele."_".strtolower($tmpobjectkey);
+ break;
+ }
+ }
+
+ if ($filefound) {
+ require_once $file;
+
+ $module = new $classname($db);
+
+ if ($module->write_file($tmpobject, $langs) > 0) {
+ header("Location: ".DOL_URL_ROOT."/document.php?modulepart=ctpt-".strtolower($tmpobjectkey)."&file=SPECIMEN.pdf");
+ return;
+ } else {
+ setEventMessages($module->error, null, 'errors');
+ dol_syslog($module->error, LOG_ERR);
+ }
+ } else {
+ setEventMessages($langs->trans("ErrorModuleNotFound"), null, 'errors');
+ dol_syslog($langs->trans("ErrorModuleNotFound"), LOG_ERR);
+ }
+} elseif ($action == 'setmod') {
+ // TODO Check if numbering module chosen can be activated by calling method canBeActivated
+ $tmpobjectkey = GETPOST('object');
+ if (!empty($tmpobjectkey)) {
+ $constforval = 'CTPT_'.strtoupper($tmpobjectkey)."_ADDON";
+ dolibarr_set_const($db, $constforval, $value, 'chaine', 0, '', $conf->entity);
+ }
+} elseif ($action == 'set') {
+ // Activate a model
+ $ret = addDocumentModel($value, $type, $label, $scandir);
+} elseif ($action == 'del') {
+ $ret = delDocumentModel($value, $type);
+ if ($ret > 0) {
+ $tmpobjectkey = GETPOST('object');
+ if (!empty($tmpobjectkey)) {
+ $constforval = 'CTPT_'.strtoupper($tmpobjectkey).'_ADDON_PDF';
+ if ($conf->global->$constforval == "$value") {
+ dolibarr_del_const($db, $constforval, $conf->entity);
+ }
+ }
+ }
+} elseif ($action == 'setdoc') {
+ // Set or unset default model
+ $tmpobjectkey = GETPOST('object');
+ if (!empty($tmpobjectkey)) {
+ $constforval = 'CTPT_'.strtoupper($tmpobjectkey).'_ADDON_PDF';
+ if (dolibarr_set_const($db, $constforval, $value, 'chaine', 0, '', $conf->entity)) {
+ // The constant that was read before the new set
+ // We therefore requires a variable to have a coherent view
+ $conf->global->$constforval = $value;
+ }
+
+ // We disable/enable the document template (into llx_document_model table)
+ $ret = delDocumentModel($value, $type);
+ if ($ret > 0) {
+ $ret = addDocumentModel($value, $type, $label, $scandir);
+ }
+ }
+} elseif ($action == 'unsetdoc') {
+ $tmpobjectkey = GETPOST('object');
+ if (!empty($tmpobjectkey)) {
+ $constforval = 'CTPT_'.strtoupper($tmpobjectkey).'_ADDON_PDF';
+ dolibarr_del_const($db, $constforval, $conf->entity);
+ }
+}
+
+
+
+/*
+ * View
+ */
+
+$form = new Form($db);
+
+$help_url = '';
+$page_name = "CTPTSetup";
+
+llxHeader('', $langs->trans($page_name), $help_url);
+
+// Subheader
+$linkback = ''.$langs->trans("BackToModuleList").'';
+
+print load_fiche_titre($langs->trans($page_name), $linkback, 'title_setup');
+
+// Configuration header
+$head = ctptAdminPrepareHead();
+print dol_get_fiche_head($head, 'settings', $langs->trans($page_name), -1, "ctpt@ctpt");
+
+// Setup page goes here
+echo ''.$langs->trans("CTPTSetupPage").'
';
+ }
+}
+
+if (empty($setupnotempty)) {
+ print ' '.$langs->trans("NothingToSetup");
+}
+
+// Page end
+print dol_get_fiche_end();
+
+llxFooter();
+$db->close();
diff --git a/backport/v16/core/class/html.formsetup.class.php b/backport/v16/core/class/html.formsetup.class.php
new file mode 100644
index 0000000..0f439b9
--- /dev/null
+++ b/backport/v16/core/class/html.formsetup.class.php
@@ -0,0 +1,1322 @@
+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+
+/**
+ * This class help you create setup render
+ */
+class FormSetup
+{
+
+ /**
+ * @var DoliDB Database handler.
+ */
+ public $db;
+
+ /** @var FormSetupItem[] */
+ public $items = array();
+
+ /**
+ * @var int
+ */
+ public $setupNotEmpty = 0;
+
+ /** @var Translate */
+ public $langs;
+
+ /** @var Form */
+ public $form;
+
+ /** @var int */
+ protected $maxItemRank;
+
+ /**
+ * this is an html string display before output form
+ * @var string
+ */
+ public $htmlBeforeOutputForm = '';
+
+ /**
+ * this is an html string display after output form
+ * @var string
+ */
+ public $htmlAfterOutputForm = '';
+
+ /**
+ * this is an html string display on buttons zone
+ * @var string
+ */
+ public $htmlOutputMoreButton = '';
+
+
+ /**
+ *
+ * @var array
+ */
+ public $formAttributes = array(
+ 'action' => '', // set in __construct
+ 'method' => 'POST'
+ );
+
+ /**
+ * an list of hidden inputs used only in edit mode
+ * @var array
+ */
+ public $formHiddenInputs = array();
+
+
+ /**
+ * Constructor
+ *
+ * @param DoliDB $db Database handler
+ * @param Translate $outputLangs if needed can use another lang
+ */
+ public function __construct($db, $outputLangs = false)
+ {
+ global $langs;
+ $this->db = $db;
+ $this->form = new Form($this->db);
+ $this->formAttributes['action'] = $_SERVER["PHP_SELF"];
+
+ $this->formHiddenInputs['token'] = newToken();
+ $this->formHiddenInputs['action'] = 'update';
+
+
+ if ($outputLangs) {
+ $this->langs = $outputLangs;
+ } else {
+ $this->langs = $langs;
+ }
+ }
+
+ /**
+ * Generate an attributes string form an input array
+ *
+ * @param array $attributes an array of attributes keys and values,
+ * @return string attribute string
+ */
+ static public function generateAttributesStringFromArray($attributes)
+ {
+ $Aattr = array();
+ if (is_array($attributes)) {
+ foreach ($attributes as $attribute => $value) {
+ if (is_array($value) || is_object($value)) {
+ continue;
+ }
+ $Aattr[] = $attribute.'="'.dol_escape_htmltag($value).'"';
+ }
+ }
+
+ return !empty($Aattr)?implode(' ', $Aattr):'';
+ }
+
+
+ /**
+ * generateOutput
+ *
+ * @param bool $editMode true will display output on edit mod
+ * @return string html output
+ */
+ public function generateOutput($editMode = false)
+ {
+ global $hookmanager, $action, $langs;
+ require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
+
+ $parameters = array(
+ 'editMode' => $editMode
+ );
+ $reshook = $hookmanager->executeHooks('formSetupBeforeGenerateOutput', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
+ if ($reshook < 0) {
+ setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
+ }
+
+ if ($reshook > 0) {
+ return $hookmanager->resPrint;
+ } else {
+ $out = '';
+ $out.= $this->htmlBeforeOutputForm;
+
+ if ($editMode) {
+ $out.= '';
+ }
+
+ $out.= $this->htmlAfterOutputForm;
+
+ return $out;
+ }
+ }
+
+ /**
+ * generateTableOutput
+ *
+ * @param bool $editMode true will display output on edit mod
+ * @return string html output
+ */
+ public function generateTableOutput($editMode = false)
+ {
+ global $hookmanager, $action;
+ require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
+
+ $parameters = array(
+ 'editMode' => $editMode
+ );
+ $reshook = $hookmanager->executeHooks('formSetupBeforeGenerateTableOutput', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
+ if ($reshook < 0) {
+ setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
+ }
+
+ if ($reshook > 0) {
+ return $hookmanager->resPrint;
+ } else {
+ $out = '
';
+
+ if ($editMode) {
+ $out.= $item->generateInputField();
+ } else {
+ $out.= $item->generateOutputField();
+ }
+
+ if (!empty($item->errors)) {
+ // TODO : move set event message in a methode to be called by cards not by this class
+ setEventMessages(null, $item->errors, 'errors');
+ }
+
+ $out.= '
';
+ $out.= '
';
+ }
+
+ return $out;
+ }
+
+
+ /**
+ * Method used to test module builder convertion to this form usage
+ *
+ * @param array $params an array of arrays of params from old modulBuilder params
+ * @return null
+ */
+ public function addItemsFromParamsArray($params)
+ {
+ if (!is_array($params) || empty($params)) { return false; }
+ foreach ($params as $confKey => $param) {
+ $this->addItemFromParams($confKey, $param); // todo manage error
+ }
+ }
+
+
+ /**
+ * From old
+ * Method was used to test module builder convertion to this form usage.
+ *
+ * @param string $confKey the conf name to store
+ * @param array $params an array of params from old modulBuilder params
+ * @return bool
+ */
+ public function addItemFromParams($confKey, $params)
+ {
+ if (empty($confKey) || empty($params['type'])) { return false; }
+
+ /*
+ * Exemple from old module builder setup page
+ * // 'CTPT_MYPARAM1'=>array('type'=>'string', 'css'=>'minwidth500' ,'enabled'=>1),
+ // 'CTPT_MYPARAM2'=>array('type'=>'textarea','enabled'=>1),
+ //'CTPT_MYPARAM3'=>array('type'=>'category:'.Categorie::TYPE_CUSTOMER, 'enabled'=>1),
+ //'CTPT_MYPARAM4'=>array('type'=>'emailtemplate:thirdparty', 'enabled'=>1),
+ //'CTPT_MYPARAM5'=>array('type'=>'yesno', 'enabled'=>1),
+ //'CTPT_MYPARAM5'=>array('type'=>'thirdparty_type', 'enabled'=>1),
+ //'CTPT_MYPARAM6'=>array('type'=>'securekey', 'enabled'=>1),
+ //'CTPT_MYPARAM7'=>array('type'=>'product', 'enabled'=>1),
+ */
+
+ $item = new FormSetupItem($confKey);
+ // need to be ignored from scrutinizer setTypeFromTypeString was created as deprecated to incite developper to use object oriented usage
+ /** @scrutinizer ignore-deprecated */ $item->setTypeFromTypeString($params['type']);
+
+ if (!empty($params['enabled'])) {
+ $item->enabled = $params['enabled'];
+ }
+
+ if (!empty($params['css'])) {
+ $item->cssClass = $params['css'];
+ }
+
+ $this->items[$item->confKey] = $item;
+
+ return true;
+ }
+
+ /**
+ * Used to export param array for /core/actions_setmoduleoptions.inc.php template
+ * Method exists only for manage setup convertion
+ *
+ * @return array $arrayofparameters for /core/actions_setmoduleoptions.inc.php
+ */
+ public function exportItemsAsParamsArray()
+ {
+ $arrayofparameters = array();
+ foreach ($this->items as $item) {
+ $arrayofparameters[$item->confKey] = array(
+ 'type' => $item->getType(),
+ 'enabled' => $item->enabled
+ );
+ }
+
+ return $arrayofparameters;
+ }
+
+ /**
+ * Reload for each item default conf
+ * note: this will override custom configuration
+ *
+ * @return bool
+ */
+ public function reloadConfs()
+ {
+
+ if (!array($this->items)) { return false; }
+ foreach ($this->items as $item) {
+ $item->loadValueFromConf();
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Create a new item
+ * the tagret is useful with hooks : that allow externals modules to add setup items on good place
+ *
+ * @param string $confKey the conf key used in database
+ * @param string $targetItemKey target item used to place the new item beside
+ * @param bool $insertAfterTarget insert before or after target item ?
+ * @return FormSetupItem the new setup item created
+ */
+ public function newItem($confKey, $targetItemKey = false, $insertAfterTarget = false)
+ {
+ $item = new FormSetupItem($confKey);
+
+ // set item rank if not defined as last item
+ if (empty($item->rank)) {
+ $item->rank = $this->getCurentItemMaxRank() + 1;
+ $this->setItemMaxRank($item->rank); // set new max rank if needed
+ }
+
+ // try to get rank from target column, this will override item->rank
+ if (!empty($targetItemKey)) {
+ if (isset($this->items[$targetItemKey])) {
+ $targetItem = $this->items[$targetItemKey];
+ $item->rank = $targetItem->rank; // $targetItem->rank will be increase after
+ if ($targetItem->rank >= 0 && $insertAfterTarget) {
+ $item->rank++;
+ }
+ }
+
+ // calc new rank for each item to make place for new item
+ foreach ($this->items as $fItem) {
+ if ($item->rank <= $fItem->rank) {
+ $fItem->rank = $fItem->rank + 1;
+ $this->setItemMaxRank($fItem->rank); // set new max rank if needed
+ }
+ }
+ }
+
+ $this->items[$item->confKey] = $item;
+ return $this->items[$item->confKey];
+ }
+
+ /**
+ * Sort items according to rank
+ *
+ * @return bool
+ */
+ public function sortingItems()
+ {
+ // Sorting
+ return uasort($this->items, array($this, 'itemSort'));
+ }
+
+ /**
+ * getCurentItemMaxRank
+ *
+ * @param bool $cache To use cache or not
+ * @return int
+ */
+ public function getCurentItemMaxRank($cache = true)
+ {
+ if (empty($this->items)) {
+ return 0;
+ }
+
+ if ($cache && $this->maxItemRank > 0) {
+ return $this->maxItemRank;
+ }
+
+ $this->maxItemRank = 0;
+ foreach ($this->items as $item) {
+ $this->maxItemRank = max($this->maxItemRank, $item->rank);
+ }
+
+ return $this->maxItemRank;
+ }
+
+
+ /**
+ * set new max rank if needed
+ *
+ * @param int $rank the item rank
+ * @return int|void new max rank
+ */
+ public function setItemMaxRank($rank)
+ {
+ $this->maxItemRank = max($this->maxItemRank, $rank);
+ }
+
+
+ /**
+ * get item position rank from item key
+ *
+ * @param string $itemKey the item key
+ * @return int rank on success and -1 on error
+ */
+ public function getLineRank($itemKey)
+ {
+ if (!isset($this->items[$itemKey]->rank)) {
+ return -1;
+ }
+ return $this->items[$itemKey]->rank;
+ }
+
+
+ /**
+ * uasort callback function to Sort params items
+ *
+ * @param FormSetupItem $a formSetup item
+ * @param FormSetupItem $b formSetup item
+ * @return int Return compare result
+ */
+ public function itemSort(FormSetupItem $a, FormSetupItem $b)
+ {
+ if (empty($a->rank)) {
+ $a->rank = 0;
+ }
+ if (empty($b->rank)) {
+ $b->rank = 0;
+ }
+ if ($a->rank == $b->rank) {
+ return 0;
+ }
+ return ($a->rank < $b->rank) ? -1 : 1;
+ }
+}
+
+/**
+ * This class help to create item for class formSetup
+ */
+class FormSetupItem
+{
+ /**
+ * @var DoliDB Database handler.
+ */
+ public $db;
+
+ /** @var Translate */
+ public $langs;
+
+ /** @var int */
+ public $entity;
+
+ /** @var Form */
+ public $form;
+
+ /** @var string $confKey the conf key used in database */
+ public $confKey;
+
+ /** @var string|false $nameText */
+ public $nameText = false;
+
+ /** @var string $helpText */
+ public $helpText = '';
+
+ /** @var string $fieldValue */
+ public $fieldValue;
+
+ /** @var string $defaultFieldValue */
+ public $defaultFieldValue = null;
+
+ /** @var array $fieldAttr fields attribute only for compatible fields like input text */
+ public $fieldAttr = array();
+
+ /** @var bool|string set this var to override field output will override $fieldInputOverride and $fieldOutputOverride too */
+ public $fieldOverride = false;
+
+ /** @var bool|string set this var to override field input */
+ public $fieldInputOverride = false;
+
+ /** @var bool|string set this var to override field output */
+ public $fieldOutputOverride = false;
+
+ /** @var int $rank */
+ public $rank = 0;
+
+ /** @var array set this var for options on select and multiselect items */
+ public $fieldOptions = array();
+
+ /** @var callable $saveCallBack */
+ public $saveCallBack;
+
+ /** @var callable $setValueFromPostCallBack */
+ public $setValueFromPostCallBack;
+
+ /**
+ * @var string $errors
+ */
+ public $errors = array();
+
+ /**
+ * TODO each type must have setAs{type} method to help configuration
+ * And set var as protected when its done configuration must be done by method
+ * this is important for retrocompatibility of futures versions
+ * @var string $type 'string', 'textarea', 'category:'.Categorie::TYPE_CUSTOMER', 'emailtemplate', 'thirdparty_type'
+ */
+ protected $type = 'string';
+
+ public $enabled = 1;
+
+ public $cssClass = '';
+
+ /**
+ * Constructor
+ *
+ * @param string $confKey the conf key used in database
+ */
+ public function __construct($confKey)
+ {
+ global $langs, $db, $conf, $form;
+ $this->db = $db;
+
+ if (!empty($form) && is_object($form) && get_class($form) == 'Form') { // the form class has a cache inside so I am using it to optimize
+ $this->form = $form;
+ } else {
+ $this->form = new Form($this->db);
+ }
+
+ $this->langs = $langs;
+ $this->entity = $conf->entity;
+
+ $this->confKey = $confKey;
+ $this->loadValueFromConf();
+ }
+
+ /**
+ * load conf value from databases
+ * @return bool
+ */
+ public function loadValueFromConf()
+ {
+ global $conf;
+ if (isset($conf->global->{$this->confKey})) {
+ $this->fieldValue = $conf->global->{$this->confKey};
+ return true;
+ } else {
+ $this->fieldValue = null;
+ return false;
+ }
+ }
+
+ /**
+ * reload conf value from databases is an aliase of loadValueFromConf
+ * @deprecated
+ * @return bool
+ */
+ public function reloadValueFromConf()
+ {
+ return $this->loadValueFromConf();
+ }
+
+
+ /**
+ * Save const value based on htdocs/core/actions_setmoduleoptions.inc.php
+ * @return int -1 if KO, 1 if OK
+ */
+ public function saveConfValue()
+ {
+ global $hookmanager;
+
+ $parameters = array();
+ $reshook = $hookmanager->executeHooks('formSetupBeforeSaveConfValue', $parameters, $this); // Note that $action and $object may have been modified by some hooks
+ if ($reshook < 0) {
+ $this->setErrors($hookmanager->errors);
+ return -1;
+ }
+
+ if ($reshook > 0) {
+ return $reshook;
+ }
+
+
+ if (!empty($this->saveCallBack) && is_callable($this->saveCallBack)) {
+ return call_user_func($this->saveCallBack, $this);
+ }
+
+ // Modify constant only if key was posted (avoid resetting key to the null value)
+ if ($this->type != 'title') {
+ $result = dolibarr_set_const($this->db, $this->confKey, $this->fieldValue, 'chaine', 0, '', $this->entity);
+ if ($result < 0) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+ }
+
+ /**
+ * Set an override function for saving data
+ * @param callable $callBack a callable function
+ * @return void
+ */
+ public function setSaveCallBack(callable $callBack)
+ {
+ $this->saveCallBack = $callBack;
+ }
+
+ /**
+ * Set an override function for get data from post
+ * @param callable $callBack a callable function
+ * @return void
+ */
+ public function setValueFromPostCallBack(callable $callBack)
+ {
+ $this->setValueFromPostCallBack = $callBack;
+ }
+
+ /**
+ * Save const value based on htdocs/core/actions_setmoduleoptions.inc.php
+ * @return int -1 if KO, 0 nothing to do , 1 if OK
+ */
+ public function setValueFromPost()
+ {
+ if (!empty($this->setValueFromPostCallBack) && is_callable($this->setValueFromPostCallBack)) {
+ return call_user_func($this->setValueFromPostCallBack);
+ }
+
+ // Modify constant only if key was posted (avoid resetting key to the null value)
+ if ($this->type != 'title') {
+ if (preg_match('/category:/', $this->type)) {
+ if (GETPOST($this->confKey, 'int') == '-1') {
+ $val_const = '';
+ } else {
+ $val_const = GETPOST($this->confKey, 'int');
+ }
+ } elseif ($this->type == 'multiselect') {
+ $val = GETPOST($this->confKey, 'array');
+ if ($val && is_array($val)) {
+ $val_const = implode(',', $val);
+ }
+ } elseif ($this->type == 'html') {
+ $val_const = GETPOST($this->confKey, 'restricthtml');
+ } else {
+ $val_const = GETPOST($this->confKey, 'alpha');
+ }
+
+ // TODO add value check with class validate
+ $this->fieldValue = $val_const;
+
+ return 1;
+ }
+
+ return 0;
+ }
+
+ /**
+ * Get help text or generate it
+ * @return int|string
+ */
+ public function getHelpText()
+ {
+ if (!empty($this->helpText)) { return $this->helpText; }
+ return (($this->langs->trans($this->confKey . 'Tooltip') != $this->confKey . 'Tooltip') ? $this->langs->trans($this->confKey . 'Tooltip') : '');
+ }
+
+ /**
+ * Get field name text or generate it
+ * @return false|int|string
+ */
+ public function getNameText()
+ {
+ if (!empty($this->nameText)) { return $this->nameText; }
+ return (($this->langs->trans($this->confKey) != $this->confKey) ? $this->langs->trans($this->confKey) : $this->langs->trans('MissingTranslationForConfKey', $this->confKey));
+ }
+
+ /**
+ * generate input field
+ * @return bool|string
+ */
+ public function generateInputField()
+ {
+ global $conf;
+
+ if (!empty($this->fieldOverride)) {
+ return $this->fieldOverride;
+ }
+
+ if (!empty($this->fieldInputOverride)) {
+ return $this->fieldInputOverride;
+ }
+
+ // Set default value
+ if (is_null($this->fieldValue)) {
+ $this->fieldValue = $this->defaultFieldValue;
+ }
+
+
+ $this->fieldAttr['name'] = $this->confKey;
+ $this->fieldAttr['id'] = 'setup-'.$this->confKey;
+ $this->fieldAttr['value'] = $this->fieldValue;
+
+ $out = '';
+
+ if ($this->type == 'title') {
+ $out.= $this->generateOutputField(); // title have no input
+ } elseif ($this->type == 'multiselect') {
+ $out.= $this->generateInputFieldMultiSelect();
+ } elseif ($this->type == 'select') {
+ $out.= $this->generateInputFieldSelect();
+ } elseif ($this->type == 'textarea') {
+ $out.= $this->generateInputFieldTextarea();
+ } elseif ($this->type== 'html') {
+ $out.= $this->generateInputFieldHtml();
+ } elseif ($this->type== 'color') {
+ $out.= $this->generateInputFieldColor();
+ } elseif ($this->type == 'yesno') {
+ $out.= $this->form->selectyesno($this->confKey, $this->fieldValue, 1);
+ } elseif (preg_match('/emailtemplate:/', $this->type)) {
+ $out.= $this->generateInputFieldEmailTemplate();
+ } elseif (preg_match('/category:/', $this->type)) {
+ $out.=$this->generateInputFieldCategories();
+ } elseif (preg_match('/thirdparty_type/', $this->type)) {
+ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
+ $formcompany = new FormCompany($this->db);
+ $out.= $formcompany->selectProspectCustomerType($this->fieldValue, $this->confKey);
+ } elseif ($this->type == 'securekey') {
+ $out.= $this->generateInputFieldSecureKey();
+ } elseif ($this->type == 'product') {
+ if (!empty($conf->product->enabled) || !empty($conf->service->enabled)) {
+ $selected = (empty($this->fieldValue) ? '' : $this->fieldValue);
+ $out.= $this->form->select_produits($selected, $this->confKey, '', 0, 0, 1, 2, '', 0, array(), 0, '1', 0, $this->cssClass, 0, '', null, 1);
+ }
+ } else {
+ $out.= $this->generateInputFieldText();
+ }
+
+ return $out;
+ }
+
+ /**
+ * generatec default input field
+ * @return string
+ */
+ public function generateInputFieldText()
+ {
+ if (empty($this->fieldAttr)) { $this->fieldAttr['class'] = 'flat '.(empty($this->cssClass) ? 'minwidth200' : $this->cssClass); }
+ return 'fieldAttr).' />';
+ }
+
+ /**
+ * generate input field for textarea
+ * @return string
+ */
+ public function generateInputFieldTextarea()
+ {
+ $out = '\n";
+ return $out;
+ }
+
+ /**
+ * generate input field for html
+ * @return string
+ */
+ public function generateInputFieldHtml()
+ {
+ global $conf;
+ require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
+ $doleditor = new DolEditor($this->confKey, $this->fieldValue, '', 160, 'dolibarr_notes', '', false, false, $conf->fckeditor->enabled, ROWS_5, '90%');
+ return $doleditor->Create(1);
+ }
+
+ /**
+ * generate input field for categories
+ * @return string
+ */
+ public function generateInputFieldCategories()
+ {
+ global $conf;
+ require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
+ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
+ $formother = new FormOther($this->db);
+
+ $tmp = explode(':', $this->type);
+ $out= img_picto('', 'category', 'class="pictofixedwidth"');
+ $out.= $formother->select_categories($tmp[1], $this->fieldValue, $this->confKey, 0, $this->langs->trans('CustomersProspectsCategoriesShort'));
+ return $out;
+ }
+
+ /**
+ * generate input field for email template selector
+ * @return string
+ */
+ public function generateInputFieldEmailTemplate()
+ {
+ global $conf, $user;
+ $out = '';
+ if (preg_match('/emailtemplate:/', $this->type)) {
+ include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php';
+ $formmail = new FormMail($this->db);
+
+ $tmp = explode(':', $this->type);
+ $nboftemplates = $formmail->fetchAllEMailTemplate($tmp[1], $user, null, 1); // We set lang=null to get in priority record with no lang
+ $arrayOfMessageName = array();
+ if (is_array($formmail->lines_model)) {
+ foreach ($formmail->lines_model as $modelMail) {
+ $moreonlabel = '';
+ if (!empty($arrayOfMessageName[$modelMail->label])) {
+ $moreonlabel = ' (' . $this->langs->trans("SeveralLangugeVariatFound") . ')';
+ }
+ // The 'label' is the key that is unique if we exclude the language
+ $arrayOfMessageName[$modelMail->id] = $this->langs->trans(preg_replace('/\(|\)/', '', $modelMail->label)) . $moreonlabel;
+ }
+ }
+ $out .= $this->form->selectarray($this->confKey, $arrayOfMessageName, $this->fieldValue, 'None', 0, 0, '', 0, 0, 0, '', '', 1);
+ }
+
+ return $out;
+ }
+
+
+ /**
+ * generate input field for secure key
+ * @return string
+ */
+ public function generateInputFieldSecureKey()
+ {
+ global $conf;
+ $out = '';
+ if (!empty($conf->use_javascript_ajax)) {
+ $out.= ' '.img_picto($this->langs->trans('Generate'), 'refresh', 'id="generate_token'.$this->confKey.'" class="linkobject"');
+ }
+ if (!empty($conf->use_javascript_ajax)) {
+ $out .= "\n" . '';
+ }
+ return $out;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function generateInputFieldMultiSelect()
+ {
+ $TSelected = array();
+ if ($this->fieldValue) {
+ $TSelected = explode(',', $this->fieldValue);
+ }
+
+ return $this->form->multiselectarray($this->confKey, $this->fieldOptions, $TSelected, 0, 0, '', 0, 0, 'style="min-width:100px"');
+ }
+
+
+ /**
+ * @return string
+ */
+ public function generateInputFieldSelect()
+ {
+ return $this->form->selectarray($this->confKey, $this->fieldOptions, $this->fieldValue);
+ }
+
+ /**
+ * get the type : used for old module builder setup conf style conversion and tests
+ * because this two class will quickly evolve it's important to not set or get directly $this->type (will be protected) so this method exist
+ * to be sure we can manage evolution easily
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * set the type from string : used for old module builder setup conf style conversion and tests
+ * because this two class will quickly evolve it's important to not set directly $this->type (will be protected) so this method exist
+ * to be sure we can manage evolution easily
+ * @param string $type possible values based on old module builder setup : 'string', 'textarea', 'category:'.Categorie::TYPE_CUSTOMER', 'emailtemplate', 'thirdparty_type'
+ * @deprecated yes this setTypeFromTypeString came deprecated because it exists only for manage setup convertion
+ * @return bool
+ */
+ public function setTypeFromTypeString($type)
+ {
+ $this->type = $type;
+ return true;
+ }
+
+ /**
+ * Add error
+ * @param array|string $errors the error text
+ * @return null
+ */
+ public function setErrors($errors)
+ {
+ if (is_array($errors)) {
+ if (!empty($errors)) {
+ foreach ($errors as $error) {
+ $this->setErrors($error);
+ }
+ }
+ } elseif (!empty($errors)) {
+ $this->errors[] = $errors;
+ }
+ }
+
+ /**
+ * @return bool|string Generate the output html for this item
+ */
+ public function generateOutputField()
+ {
+ global $conf, $user;
+
+ if (!empty($this->fieldOverride)) {
+ return $this->fieldOverride;
+ }
+
+ if (!empty($this->fieldOutputOverride)) {
+ return $this->fieldOutputOverride;
+ }
+
+ $out = '';
+
+ if ($this->type == 'title') {
+ // nothing to do
+ } elseif ($this->type == 'textarea') {
+ $out.= dol_nl2br($this->fieldValue);
+ } elseif ($this->type == 'multiselect') {
+ $out.= $this->generateOutputFieldMultiSelect();
+ } elseif ($this->type == 'select') {
+ $out.= $this->generateOutputFieldSelect();
+ } elseif ($this->type== 'html') {
+ $out.= $this->fieldValue;
+ } elseif ($this->type== 'color') {
+ $out.= $this->generateOutputFieldColor();
+ } elseif ($this->type == 'yesno') {
+ $out.= ajax_constantonoff($this->confKey);
+ } elseif (preg_match('/emailtemplate:/', $this->type)) {
+ include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php';
+ $formmail = new FormMail($this->db);
+
+ $tmp = explode(':', $this->type);
+
+ $template = $formmail->getEMailTemplate($this->db, $tmp[1], $user, $this->langs, $this->fieldValue);
+ if ($template<0) {
+ $this->setErrors($formmail->errors);
+ }
+ $out.= $this->langs->trans($template->label);
+ } elseif (preg_match('/category:/', $this->type)) {
+ require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
+ $c = new Categorie($this->db);
+ $result = $c->fetch($this->fieldValue);
+ if ($result < 0) {
+ $this->setErrors($c->errors);
+ }
+ $ways = $c->print_all_ways(' >> ', 'none', 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formated text
+ $toprint = array();
+ foreach ($ways as $way) {
+ $toprint[] = '
color ? ' style="background: #' . $c->color . ';"' : ' style="background: #bbb"') . '>' . $way . '
';
+ }
+ $out.='
' . implode(' ', $toprint) . '
';
+ } elseif (preg_match('/thirdparty_type/', $this->type)) {
+ if ($this->fieldValue==2) {
+ $out.= $this->langs->trans("Prospect");
+ } elseif ($this->fieldValue==3) {
+ $out.= $this->langs->trans("ProspectCustomer");
+ } elseif ($this->fieldValue==1) {
+ $out.= $this->langs->trans("Customer");
+ } elseif ($this->fieldValue==0) {
+ $out.= $this->langs->trans("NorProspectNorCustomer");
+ }
+ } elseif ($this->type == 'product') {
+ $product = new Product($this->db);
+ $resprod = $product->fetch($this->fieldValue);
+ if ($resprod > 0) {
+ $out.= $product->ref;
+ } elseif ($resprod < 0) {
+ $this->setErrors($product->errors);
+ }
+ } else {
+ $out.= $this->fieldValue;
+ }
+
+ return $out;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function generateOutputFieldMultiSelect()
+ {
+ $outPut = '';
+ $TSelected = array();
+ if (!empty($this->fieldValue)) {
+ $TSelected = explode(',', $this->fieldValue);
+ }
+
+ if (!empty($TSelected)) {
+ foreach ($TSelected as $selected) {
+ if (!empty($this->fieldOptions[$selected])) {
+ $outPut.= dolGetBadge('', $this->fieldOptions[$selected], 'info').' ';
+ }
+ }
+ }
+ return $outPut;
+ }
+
+ /**
+ * @return string
+ */
+ public function generateOutputFieldColor()
+ {
+ $this->fieldAttr['disabled']=null;
+ return $this->generateInputField();
+ }
+ /**
+ * @return string
+ */
+ public function generateInputFieldColor()
+ {
+ $this->fieldAttr['type']= 'color';
+ return $this->generateInputFieldText();
+ }
+
+ /**
+ * @return string
+ */
+ public function generateOutputFieldSelect()
+ {
+ $outPut = '';
+ if (!empty($this->fieldOptions[$this->fieldValue])) {
+ $outPut = $this->fieldOptions[$this->fieldValue];
+ }
+
+ return $outPut;
+ }
+
+ /*
+ * METHODS FOR SETTING DISPLAY TYPE
+ */
+
+ /**
+ * Set type of input as string
+ * @return self
+ */
+ public function setAsString()
+ {
+ $this->type = 'string';
+ return $this;
+ }
+
+ /**
+ * Set type of input as color
+ * @return self
+ */
+ public function setAsColor()
+ {
+ $this->type = 'color';
+ return $this;
+ }
+
+ /**
+ * Set type of input as textarea
+ * @return self
+ */
+ public function setAsTextarea()
+ {
+ $this->type = 'textarea';
+ return $this;
+ }
+
+ /**
+ * Set type of input as html editor
+ * @return self
+ */
+ public function setAsHtml()
+ {
+ $this->type = 'html';
+ return $this;
+ }
+
+ /**
+ * Set type of input as emailtemplate selector
+ * @param string $templateType email template type
+ * @return self
+ */
+ public function setAsEmailTemplate($templateType)
+ {
+ $this->type = 'emailtemplate:'.$templateType;
+ return $this;
+ }
+
+ /**
+ * Set type of input as thirdparty_type selector
+ * @return self
+ */
+ public function setAsThirdpartyType()
+ {
+ $this->type = 'thirdparty_type';
+ return $this;
+ }
+
+ /**
+ * Set type of input as Yes
+ * @return self
+ */
+ public function setAsYesNo()
+ {
+ $this->type = 'yesno';
+ return $this;
+ }
+
+ /**
+ * Set type of input as secure key
+ * @return self
+ */
+ public function setAsSecureKey()
+ {
+ $this->type = 'securekey';
+ return $this;
+ }
+
+ /**
+ * Set type of input as product
+ * @return self
+ */
+ public function setAsProduct()
+ {
+ $this->type = 'product';
+ return $this;
+ }
+
+ /**
+ * Set type of input as a category selector
+ * TODO add default value
+ * @param int $catType Type of category ('customer', 'supplier', 'contact', 'product', 'member'). Old mode (0, 1, 2, ...) is deprecated.
+ * @return self
+ */
+ public function setAsCategory($catType)
+ {
+ $this->type = 'category:'.$catType;
+ return $this;
+ }
+
+ /**
+ * Set type of input as a simple title
+ * no data to store
+ * @return self
+ */
+ public function setAsTitle()
+ {
+ $this->type = 'title';
+ return $this;
+ }
+
+
+ /**
+ * Set type of input as a simple title
+ * no data to store
+ * @param array $fieldOptions A table of field options
+ * @return self
+ */
+ public function setAsMultiSelect($fieldOptions)
+ {
+ if (is_array($fieldOptions)) {
+ $this->fieldOptions = $fieldOptions;
+ }
+
+ $this->type = 'multiselect';
+ return $this;
+ }
+
+ /**
+ * Set type of input as a simple title
+ * no data to store
+ * @param array $fieldOptions A table of field options
+ * @return self
+ */
+ public function setAsSelect($fieldOptions)
+ {
+ if (is_array($fieldOptions)) {
+ $this->fieldOptions = $fieldOptions;
+ }
+
+ $this->type = 'select';
+ return $this;
+ }
+}
diff --git a/build/makepack-ctpt.conf b/build/makepack-ctpt.conf
new file mode 100644
index 0000000..16dc1e7
--- /dev/null
+++ b/build/makepack-ctpt.conf
@@ -0,0 +1,11 @@
+# Your module name here
+#
+# Goal: Goal of module
+# Version:
+# Author: Copyright -
+# License: GPLv3
+# Install: Just unpack content of module package in Dolibarr directory.
+# Setup: Go on Dolibarr setup - modules to enable module.
+#
+# Files in module
+mymodule/
\ No newline at end of file
diff --git a/core/modules/modCTPT.class.php b/core/modules/modCTPT.class.php
new file mode 100644
index 0000000..d62b7ca
--- /dev/null
+++ b/core/modules/modCTPT.class.php
@@ -0,0 +1,505 @@
+
+ * Copyright (C) 2018-2019 Nicolas ZABOURI
+ * Copyright (C) 2019-2020 Frédéric France
+ * Copyright (C) 2022 Nick Fragoulis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * \defgroup ctpt Module CTPT
+ * \brief CTPT module descriptor.
+ *
+ * \file htdocs/ctpt/core/modules/modCTPT.class.php
+ * \ingroup ctpt
+ * \brief Description and activation file for module CTPT
+ */
+include_once DOL_DOCUMENT_ROOT.'/core/modules/DolibarrModules.class.php';
+
+/**
+ * Description and activation class for module CTPT
+ */
+class modCTPT extends DolibarrModules
+{
+ /**
+ * Constructor. Define names, constants, directories, boxes, permissions
+ *
+ * @param DoliDB $db Database handler
+ */
+ public function __construct($db)
+ {
+ global $langs, $conf;
+ $this->db = $db;
+
+ // Id for module (must be unique).
+ // Use here a free id (See in Home -> System information -> Dolibarr for list of used modules id).
+ $this->numero = 500000; // TODO Go on page https://wiki.dolibarr.org/index.php/List_of_modules_id to reserve an id number for your module
+
+ // Key text used to identify module (for permissions, menus, etc...)
+ $this->rights_class = 'ctpt';
+
+ // Family can be 'base' (core modules),'crm','financial','hr','projects','products','ecm','technic' (transverse modules),'interface' (link with external tools),'other','...'
+ // It is used to group modules by family in module setup page
+ $this->family = "other";
+
+ // Module position in the family on 2 digits ('01', '10', '20', ...)
+ $this->module_position = '90';
+
+ // Gives the possibility for the module, to provide his own family info and position of this family (Overwrite $this->family and $this->module_position. Avoid this)
+ //$this->familyinfo = array('myownfamily' => array('position' => '01', 'label' => $langs->trans("MyOwnFamily")));
+ // Module label (no space allowed), used if translation string 'ModuleCTPTName' not found (CTPT is name of module).
+ $this->name = preg_replace('/^mod/i', '', get_class($this));
+
+ // Module description, used if translation string 'ModuleCTPTDesc' not found (CTPT is name of module).
+ $this->description = "CTPTDescription";
+ // Used only if file README.md and README-LL.md not found.
+ $this->descriptionlong = "CTPTDescription";
+
+ // Author
+ $this->editor_name = 'Sonikf';
+ $this->editor_url = '';
+
+ // Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated' or a version string like 'x.y.z'
+ $this->version = '1.0';
+ // Url to the file with your last numberversion of this module
+ //$this->url_last_version = 'http://www.example.com/versionmodule.txt';
+
+ // Key used in llx_const table to save module status enabled/disabled (where CTPT is value of property name of module in uppercase)
+ $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);
+
+ // Name of image file used for this module.
+ // If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue'
+ // If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module'
+ // To use a supported fa-xxx css style of font awesome, use this->picto='xxx'
+ $this->picto = 'ctpt';
+
+ // Define some features supported by module (triggers, login, substitutions, menus, css, etc...)
+ $this->module_parts = array(
+ // Set this to 1 if module has its own trigger directory (core/triggers)
+ 'triggers' => 1,
+ // Set this to 1 if module has its own login method file (core/login)
+ 'login' => 0,
+ // Set this to 1 if module has its own substitution function file (core/substitutions)
+ 'substitutions' => 0,
+ // Set this to 1 if module has its own menus handler directory (core/menus)
+ 'menus' => 0,
+ // Set this to 1 if module overwrite template dir (core/tpl)
+ 'tpl' => 0,
+ // Set this to 1 if module has its own barcode directory (core/modules/barcode)
+ 'barcode' => 0,
+ // Set this to 1 if module has its own models directory (core/modules/xxx)
+ 'models' => 0,
+ // Set this to 1 if module has its own printing directory (core/modules/printing)
+ 'printing' => 0,
+ // Set this to 1 if module has its own theme directory (theme)
+ 'theme' => 0,
+ // Set this to relative path of css file if module has its own css file
+ 'css' => array(
+ // '/ctpt/css/ctpt.css.php',
+ ),
+ // Set this to relative path of js file if module must load a js on all pages
+ 'js' => array(
+ // '/ctpt/js/ctpt.js.php',
+ ),
+ // Set here all hooks context managed by module. To find available hook context, make a "grep -r '>initHooks(' *" on source code. You can also set hook context to 'all'
+ 'hooks' => array(
+ // 'data' => array(
+ // 'hookcontext1',
+ // 'hookcontext2',
+ // ),
+ // 'entity' => '0',
+ ),
+ // Set this to 1 if features of module are opened to external users
+ 'moduleforexternal' => 0,
+ );
+
+ // Data directories to create when module is enabled.
+ // Example: this->dirs = array("/ctpt/temp","/ctpt/subdir");
+ $this->dirs = array("/ctpt/temp");
+
+ // Config pages. Put here list of php page, stored into ctpt/admin directory, to use to setup module.
+ $this->config_page_url = array("setup.php@ctpt");
+
+ // Dependencies
+ // A condition to hide module
+ $this->hidden = false;
+ // List of module class names as string that must be enabled if this module is enabled. Example: array('always1'=>'modModuleToEnable1','always2'=>'modModuleToEnable2', 'FR1'=>'modModuleToEnableFR'...)
+ $this->depends = array();
+ $this->requiredby = array(); // List of module class names as string to disable if this one is disabled. Example: array('modModuleToDisable1', ...)
+ $this->conflictwith = array(); // List of module class names as string this module is in conflict with. Example: array('modModuleToDisable1', ...)
+
+ // The language file dedicated to your module
+ $this->langfiles = array("ctpt@ctpt");
+
+ // Prerequisites
+ $this->phpmin = array(5, 6); // Minimum version of PHP required by module
+ $this->need_dolibarr_version = array(11, -3); // Minimum version of Dolibarr required by module
+
+ // Messages at activation
+ $this->warnings_activation = array(); // Warning to show when we activate module. array('always'='text') or array('FR'='textfr','MX'='textmx'...)
+ $this->warnings_activation_ext = array(); // Warning to show when we activate an external module. array('always'='text') or array('FR'='textfr','MX'='textmx'...)
+ //$this->automatic_activation = array('FR'=>'CTPTWasAutomaticallyActivatedBecauseOfYourCountryChoice');
+ //$this->always_enabled = true; // If true, can't be disabled
+
+ // Constants
+ // List of particular constants to add when module is enabled (key, 'chaine', value, desc, visible, 'current' or 'allentities', deleteonunactive)
+ // Example: $this->const=array(1 => array('CTPT_MYNEWCONST1', 'chaine', 'myvalue', 'This is a constant to add', 1),
+ // 2 => array('CTPT_MYNEWCONST2', 'chaine', 'myvalue', 'This is another constant to add', 0, 'current', 1)
+ // );
+ $this->const = array();
+
+ // Some keys to add into the overwriting translation tables
+ /*$this->overwrite_translation = array(
+ 'en_US:ParentCompany'=>'Parent company or reseller',
+ 'fr_FR:ParentCompany'=>'Maison mère ou revendeur'
+ )*/
+
+ if (!isset($conf->ctpt) || !isset($conf->ctpt->enabled)) {
+ $conf->ctpt = new stdClass();
+ $conf->ctpt->enabled = 0;
+ }
+
+ // Array to add new pages in new tabs
+ $this->tabs = array();
+ // Example:
+ // $this->tabs[] = array('data'=>'objecttype:+tabname1:Title1:mylangfile@ctpt:$user->rights->ctpt->read:/ctpt/mynewtab1.php?id=__ID__'); // To add a new tab identified by code tabname1
+ // $this->tabs[] = array('data'=>'objecttype:+tabname2:SUBSTITUTION_Title2:mylangfile@ctpt:$user->rights->othermodule->read:/ctpt/mynewtab2.php?id=__ID__', // To add another new tab identified by code tabname2. Label will be result of calling all substitution functions on 'Title2' key.
+ // $this->tabs[] = array('data'=>'objecttype:-tabname:NU:conditiontoremove'); // To remove an existing tab identified by code tabname
+ //
+ // Where objecttype can be
+ // 'categories_x' to add a tab in category view (replace 'x' by type of category (0=product, 1=supplier, 2=customer, 3=member)
+ // 'contact' to add a tab in contact view
+ // 'contract' to add a tab in contract view
+ // 'group' to add a tab in group view
+ // 'intervention' to add a tab in intervention view
+ // 'invoice' to add a tab in customer invoice view
+ // 'invoice_supplier' to add a tab in supplier invoice view
+ // 'member' to add a tab in fundation member view
+ // 'opensurveypoll' to add a tab in opensurvey poll view
+ // 'order' to add a tab in customer order view
+ // 'order_supplier' to add a tab in supplier order view
+ // 'payment' to add a tab in payment view
+ // 'payment_supplier' to add a tab in supplier payment view
+ // 'product' to add a tab in product view
+ // 'propal' to add a tab in propal view
+ // 'project' to add a tab in project view
+ // 'stock' to add a tab in stock view
+ // 'thirdparty' to add a tab in third party view
+ // 'user' to add a tab in user view
+
+ // Dictionaries
+ $this->dictionaries = array();
+ /* Example:
+ $this->dictionaries=array(
+ 'langs'=>'ctpt@ctpt',
+ // List of tables we want to see into dictonnary editor
+ 'tabname'=>array("table1", "table2", "table3"),
+ // Label of tables
+ 'tablib'=>array("Table1", "Table2", "Table3"),
+ // Request to select fields
+ 'tabsql'=>array('SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table1 as f', 'SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table2 as f', 'SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table3 as f'),
+ // Sort order
+ 'tabsqlsort'=>array("label ASC", "label ASC", "label ASC"),
+ // List of fields (result of select to show dictionary)
+ 'tabfield'=>array("code,label", "code,label", "code,label"),
+ // List of fields (list of fields to edit a record)
+ 'tabfieldvalue'=>array("code,label", "code,label", "code,label"),
+ // List of fields (list of fields for insert)
+ 'tabfieldinsert'=>array("code,label", "code,label", "code,label"),
+ // Name of columns with primary key (try to always name it 'rowid')
+ 'tabrowid'=>array("rowid", "rowid", "rowid"),
+ // Condition to show each dictionary
+ 'tabcond'=>array($conf->ctpt->enabled, $conf->ctpt->enabled, $conf->ctpt->enabled),
+ // Tooltip for every fields of dictionaries: DO NOT PUT AN EMPTY ARRAY
+ 'tabhelp'=>array(array('code'=>$langs->trans('CodeTooltipHelp'), 'field2' => 'field2tooltip'), array('code'=>$langs->trans('CodeTooltipHelp'), 'field2' => 'field2tooltip'), ...),
+ );
+ */
+
+ // Boxes/Widgets
+ // Add here list of php file(s) stored in ctpt/core/boxes that contains a class to show a widget.
+ $this->boxes = array(
+ // 0 => array(
+ // 'file' => 'ctptwidget1.php@ctpt',
+ // 'note' => 'Widget provided by CTPT',
+ // 'enabledbydefaulton' => 'Home',
+ // ),
+ // ...
+ );
+
+ // Cronjobs (List of cron jobs entries to add when module is enabled)
+ // unit_frequency must be 60 for minute, 3600 for hour, 86400 for day, 604800 for week
+ $this->cronjobs = array(
+ // 0 => array(
+ // 'label' => 'MyJob label',
+ // 'jobtype' => 'method',
+ // 'class' => '/ctpt/class/myobject.class.php',
+ // 'objectname' => 'MyObject',
+ // 'method' => 'doScheduledJob',
+ // 'parameters' => '',
+ // 'comment' => 'Comment',
+ // 'frequency' => 2,
+ // 'unitfrequency' => 3600,
+ // 'status' => 0,
+ // 'test' => '$conf->ctpt->enabled',
+ // 'priority' => 50,
+ // ),
+ );
+ // Example: $this->cronjobs=array(
+ // 0=>array('label'=>'My label', 'jobtype'=>'method', 'class'=>'/dir/class/file.class.php', 'objectname'=>'MyClass', 'method'=>'myMethod', 'parameters'=>'param1, param2', 'comment'=>'Comment', 'frequency'=>2, 'unitfrequency'=>3600, 'status'=>0, 'test'=>'$conf->ctpt->enabled', 'priority'=>50),
+ // 1=>array('label'=>'My label', 'jobtype'=>'command', 'command'=>'', 'parameters'=>'param1, param2', 'comment'=>'Comment', 'frequency'=>1, 'unitfrequency'=>3600*24, 'status'=>0, 'test'=>'$conf->ctpt->enabled', 'priority'=>50)
+ // );
+
+ // Permissions provided by this module
+ $this->rights = array();
+ $r = 0;
+ // Add here entries to declare new permissions
+ /* BEGIN MODULEBUILDER PERMISSIONS */
+ $this->rights[$r][0] = $this->numero . sprintf("%02d", $r + 1); // Permission id (must not be already used)
+ $this->rights[$r][1] = 'Read objects of CTPT'; // Permission label
+ $this->rights[$r][4] = 'myobject';
+ $this->rights[$r][5] = 'read'; // In php code, permission will be checked by test if ($user->rights->ctpt->myobject->read)
+ $r++;
+ $this->rights[$r][0] = $this->numero . sprintf("%02d", $r + 1); // Permission id (must not be already used)
+ $this->rights[$r][1] = 'Create/Update objects of CTPT'; // Permission label
+ $this->rights[$r][4] = 'myobject';
+ $this->rights[$r][5] = 'write'; // In php code, permission will be checked by test if ($user->rights->ctpt->myobject->write)
+ $r++;
+ $this->rights[$r][0] = $this->numero . sprintf("%02d", $r + 1); // Permission id (must not be already used)
+ $this->rights[$r][1] = 'Delete objects of CTPT'; // Permission label
+ $this->rights[$r][4] = 'myobject';
+ $this->rights[$r][5] = 'delete'; // In php code, permission will be checked by test if ($user->rights->ctpt->myobject->delete)
+ $r++;
+ /* END MODULEBUILDER PERMISSIONS */
+
+ // Main menu entries to add
+ $this->menu = array();
+ $r = 0;
+ // Add here entries to declare new menus
+ /* BEGIN MODULEBUILDER TOPMENU */
+ $this->menu[$r++] = array(
+ 'fk_menu'=>'', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode
+ 'type'=>'top', // This is a Top menu entry
+ 'titre'=>'ModuleCTPTName',
+ 'prefix' => img_picto('', $this->picto, 'class="paddingright pictofixedwidth valignmiddle"'),
+ 'mainmenu'=>'ctpt',
+ 'leftmenu'=>'',
+ 'url'=>'/ctpt/ctptindex.php',
+ 'langs'=>'ctpt@ctpt', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
+ 'position'=>1000 + $r,
+ 'enabled'=>'$conf->ctpt->enabled', // Define condition to show or hide menu entry. Use '$conf->ctpt->enabled' if entry must be visible if module is enabled.
+ 'perms'=>'1', // Use 'perms'=>'$user->rights->ctpt->myobject->read' if you want your menu with a permission rules
+ 'target'=>'',
+ 'user'=>2, // 0=Menu for internal users, 1=external users, 2=both
+ );
+ /* END MODULEBUILDER TOPMENU */
+ /* BEGIN MODULEBUILDER LEFTMENU MYOBJECT
+ $this->menu[$r++]=array(
+ 'fk_menu'=>'fk_mainmenu=ctpt', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode
+ 'type'=>'left', // This is a Left menu entry
+ 'titre'=>'MyObject',
+ 'prefix' => img_picto('', $this->picto, 'class="paddingright pictofixedwidth valignmiddle"'),
+ 'mainmenu'=>'ctpt',
+ 'leftmenu'=>'myobject',
+ 'url'=>'/ctpt/ctptindex.php',
+ 'langs'=>'ctpt@ctpt', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
+ 'position'=>1000+$r,
+ 'enabled'=>'$conf->ctpt->enabled', // Define condition to show or hide menu entry. Use '$conf->ctpt->enabled' if entry must be visible if module is enabled.
+ 'perms'=>'$user->rights->ctpt->myobject->read', // Use 'perms'=>'$user->rights->ctpt->level1->level2' if you want your menu with a permission rules
+ 'target'=>'',
+ 'user'=>2, // 0=Menu for internal users, 1=external users, 2=both
+ );
+ $this->menu[$r++]=array(
+ 'fk_menu'=>'fk_mainmenu=ctpt,fk_leftmenu=myobject', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode
+ 'type'=>'left', // This is a Left menu entry
+ 'titre'=>'List_MyObject',
+ 'mainmenu'=>'ctpt',
+ 'leftmenu'=>'ctpt_myobject_list',
+ 'url'=>'/ctpt/myobject_list.php',
+ 'langs'=>'ctpt@ctpt', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
+ 'position'=>1000+$r,
+ 'enabled'=>'$conf->ctpt->enabled', // Define condition to show or hide menu entry. Use '$conf->ctpt->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected.
+ 'perms'=>'$user->rights->ctpt->myobject->read', // Use 'perms'=>'$user->rights->ctpt->level1->level2' if you want your menu with a permission rules
+ 'target'=>'',
+ 'user'=>2, // 0=Menu for internal users, 1=external users, 2=both
+ );
+ $this->menu[$r++]=array(
+ 'fk_menu'=>'fk_mainmenu=ctpt,fk_leftmenu=myobject', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode
+ 'type'=>'left', // This is a Left menu entry
+ 'titre'=>'New_MyObject',
+ 'mainmenu'=>'ctpt',
+ 'leftmenu'=>'ctpt_myobject_new',
+ 'url'=>'/ctpt/myobject_card.php?action=create',
+ 'langs'=>'ctpt@ctpt', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
+ 'position'=>1000+$r,
+ 'enabled'=>'$conf->ctpt->enabled', // Define condition to show or hide menu entry. Use '$conf->ctpt->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected.
+ 'perms'=>'$user->rights->ctpt->myobject->write', // Use 'perms'=>'$user->rights->ctpt->level1->level2' if you want your menu with a permission rules
+ 'target'=>'',
+ 'user'=>2, // 0=Menu for internal users, 1=external users, 2=both
+ );
+ END MODULEBUILDER LEFTMENU MYOBJECT */
+ // Exports profiles provided by this module
+ $r = 1;
+ /* BEGIN MODULEBUILDER EXPORT MYOBJECT */
+ /*
+ $langs->load("ctpt@ctpt");
+ $this->export_code[$r]=$this->rights_class.'_'.$r;
+ $this->export_label[$r]='MyObjectLines'; // Translation key (used only if key ExportDataset_xxx_z not found)
+ $this->export_icon[$r]='myobject@ctpt';
+ // Define $this->export_fields_array, $this->export_TypeFields_array and $this->export_entities_array
+ $keyforclass = 'MyObject'; $keyforclassfile='/ctpt/class/myobject.class.php'; $keyforelement='myobject@ctpt';
+ include DOL_DOCUMENT_ROOT.'/core/commonfieldsinexport.inc.php';
+ //$this->export_fields_array[$r]['t.fieldtoadd']='FieldToAdd'; $this->export_TypeFields_array[$r]['t.fieldtoadd']='Text';
+ //unset($this->export_fields_array[$r]['t.fieldtoremove']);
+ //$keyforclass = 'MyObjectLine'; $keyforclassfile='/ctpt/class/myobject.class.php'; $keyforelement='myobjectline@ctpt'; $keyforalias='tl';
+ //include DOL_DOCUMENT_ROOT.'/core/commonfieldsinexport.inc.php';
+ $keyforselect='myobject'; $keyforaliasextra='extra'; $keyforelement='myobject@ctpt';
+ include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php';
+ //$keyforselect='myobjectline'; $keyforaliasextra='extraline'; $keyforelement='myobjectline@ctpt';
+ //include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php';
+ //$this->export_dependencies_array[$r] = array('myobjectline'=>array('tl.rowid','tl.ref')); // To force to activate one or several fields if we select some fields that need same (like to select a unique key if we ask a field of a child to avoid the DISTINCT to discard them, or for computed field than need several other fields)
+ //$this->export_special_array[$r] = array('t.field'=>'...');
+ //$this->export_examplevalues_array[$r] = array('t.field'=>'Example');
+ //$this->export_help_array[$r] = array('t.field'=>'FieldDescHelp');
+ $this->export_sql_start[$r]='SELECT DISTINCT ';
+ $this->export_sql_end[$r] =' FROM '.MAIN_DB_PREFIX.'myobject as t';
+ //$this->export_sql_end[$r] =' LEFT JOIN '.MAIN_DB_PREFIX.'myobject_line as tl ON tl.fk_myobject = t.rowid';
+ $this->export_sql_end[$r] .=' WHERE 1 = 1';
+ $this->export_sql_end[$r] .=' AND t.entity IN ('.getEntity('myobject').')';
+ $r++; */
+ /* END MODULEBUILDER EXPORT MYOBJECT */
+
+ // Imports profiles provided by this module
+ $r = 1;
+ /* BEGIN MODULEBUILDER IMPORT MYOBJECT */
+ /*
+ $langs->load("ctpt@ctpt");
+ $this->import_code[$r]=$this->rights_class.'_'.$r;
+ $this->import_label[$r]='MyObjectLines'; // Translation key (used only if key ExportDataset_xxx_z not found)
+ $this->import_icon[$r]='myobject@ctpt';
+ $this->import_tables_array[$r] = array('t' => MAIN_DB_PREFIX.'ctpt_myobject', 'extra' => MAIN_DB_PREFIX.'ctpt_myobject_extrafields');
+ $this->import_tables_creator_array[$r] = array('t' => 'fk_user_author'); // Fields to store import user id
+ $import_sample = array();
+ $keyforclass = 'MyObject'; $keyforclassfile='/ctpt/class/myobject.class.php'; $keyforelement='myobject@ctpt';
+ include DOL_DOCUMENT_ROOT.'/core/commonfieldsinimport.inc.php';
+ $import_extrafield_sample = array();
+ $keyforselect='myobject'; $keyforaliasextra='extra'; $keyforelement='myobject@ctpt';
+ include DOL_DOCUMENT_ROOT.'/core/extrafieldsinimport.inc.php';
+ $this->import_fieldshidden_array[$r] = array('extra.fk_object' => 'lastrowid-'.MAIN_DB_PREFIX.'ctpt_myobject');
+ $this->import_regex_array[$r] = array();
+ $this->import_examplevalues_array[$r] = array_merge($import_sample, $import_extrafield_sample);
+ $this->import_updatekeys_array[$r] = array('t.ref' => 'Ref');
+ $this->import_convertvalue_array[$r] = array(
+ 't.ref' => array(
+ 'rule'=>'getrefifauto',
+ 'class'=>(empty($conf->global->CTPT_MYOBJECT_ADDON) ? 'mod_myobject_standard' : $conf->global->CTPT_MYOBJECT_ADDON),
+ 'path'=>"/core/modules/commande/".(empty($conf->global->CTPT_MYOBJECT_ADDON) ? 'mod_myobject_standard' : $conf->global->CTPT_MYOBJECT_ADDON).'.php'
+ 'classobject'=>'MyObject',
+ 'pathobject'=>'/ctpt/class/myobject.class.php',
+ ),
+ 't.fk_soc' => array('rule' => 'fetchidfromref', 'file' => '/societe/class/societe.class.php', 'class' => 'Societe', 'method' => 'fetch', 'element' => 'ThirdParty'),
+ 't.fk_user_valid' => array('rule' => 'fetchidfromref', 'file' => '/user/class/user.class.php', 'class' => 'User', 'method' => 'fetch', 'element' => 'user'),
+ 't.fk_mode_reglement' => array('rule' => 'fetchidfromcodeorlabel', 'file' => '/compta/paiement/class/cpaiement.class.php', 'class' => 'Cpaiement', 'method' => 'fetch', 'element' => 'cpayment'),
+ );
+ $r++; */
+ /* END MODULEBUILDER IMPORT MYOBJECT */
+ }
+
+ /**
+ * Function called when module is enabled.
+ * The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database.
+ * It also creates data directories
+ *
+ * @param string $options Options when enabling module ('', 'noboxes')
+ * @return int 1 if OK, 0 if KO
+ */
+ public function init($options = '')
+ {
+ global $conf, $langs;
+
+ //$result = $this->_load_tables('/install/mysql/', 'ctpt');
+ $result = $this->_load_tables('/ctpt/sql/');
+ if ($result < 0) {
+ return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default')
+ }
+
+ // Create extrafields during init
+ include_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
+ $extrafields = new ExtraFields($this->db);
+ //$result1=$extrafields->addExtraField('ctpt_myattr1', "New Attr 1 label", 'boolean', 1, 3, 'thirdparty', 0, 0, '', '', 1, '', 0, 0, '', '', 'ctpt@ctpt', '$conf->ctpt->enabled');
+ //$result2=$extrafields->addExtraField('ctpt_myattr2', "New Attr 2 label", 'varchar', 1, 10, 'project', 0, 0, '', '', 1, '', 0, 0, '', '', 'ctpt@ctpt', '$conf->ctpt->enabled');
+ //$result3=$extrafields->addExtraField('ctpt_myattr3', "New Attr 3 label", 'varchar', 1, 10, 'bank_account', 0, 0, '', '', 1, '', 0, 0, '', '', 'ctpt@ctpt', '$conf->ctpt->enabled');
+ //$result4=$extrafields->addExtraField('ctpt_myattr4', "New Attr 4 label", 'select', 1, 3, 'thirdparty', 0, 1, '', array('options'=>array('code1'=>'Val1','code2'=>'Val2','code3'=>'Val3')), 1,'', 0, 0, '', '', 'ctpt@ctpt', '$conf->ctpt->enabled');
+ //$result5=$extrafields->addExtraField('ctpt_myattr5', "New Attr 5 label", 'text', 1, 10, 'user', 0, 0, '', '', 1, '', 0, 0, '', '', 'ctpt@ctpt', '$conf->ctpt->enabled');
+ $param = array();
+ $param['options']['c_typent:libelle:id::active=1'] = '';
+ //$result7=$extrafields->addExtraField("Type", "type", "sellist", 101, "", "facture",0,0,"",$param);
+ $result1=$extrafields->addExtraField('1Series', "1series", 'sellist', 101, '', 'facture', 0, 1, '', $param, 1, '', 1, 0, '', '1', '', '');
+ //$result2=$extrafields->update('1Series', "1series", 'sellist', '', 'facture', 0, 0, 101, array('options'=>array('c_typent'=>'id as rowid, libelle WHERE active=1')), 1,'', 1, "Select Invoice Type", '', '', '', '');
+ // Permissions
+ $this->remove($options);
+
+ $sql = array();
+
+ // Document templates
+ $moduledir = dol_sanitizeFileName('ctpt');
+ $myTmpObjects = array();
+ $myTmpObjects['MyObject'] = array('includerefgeneration'=>0, 'includedocgeneration'=>0);
+
+ foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) {
+ if ($myTmpObjectKey == 'MyObject') {
+ continue;
+ }
+ if ($myTmpObjectArray['includerefgeneration']) {
+ $src = DOL_DOCUMENT_ROOT.'/install/doctemplates/'.$moduledir.'/template_myobjects.odt';
+ $dirodt = DOL_DATA_ROOT.'/doctemplates/'.$moduledir;
+ $dest = $dirodt.'/template_myobjects.odt';
+
+ if (file_exists($src) && !file_exists($dest)) {
+ require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
+ dol_mkdir($dirodt);
+ $result = dol_copy($src, $dest, 0, 0);
+ if ($result < 0) {
+ $langs->load("errors");
+ $this->error = $langs->trans('ErrorFailToCopyFile', $src, $dest);
+ return 0;
+ }
+ }
+
+ $sql = array_merge($sql, array(
+ "DELETE FROM ".MAIN_DB_PREFIX."document_model WHERE nom = 'standard_".strtolower($myTmpObjectKey)."' AND type = '".$this->db->escape(strtolower($myTmpObjectKey))."' AND entity = ".((int) $conf->entity),
+ "INSERT INTO ".MAIN_DB_PREFIX."document_model (nom, type, entity) VALUES('standard_".strtolower($myTmpObjectKey)."', '".$this->db->escape(strtolower($myTmpObjectKey))."', ".((int) $conf->entity).")",
+ "DELETE FROM ".MAIN_DB_PREFIX."document_model WHERE nom = 'generic_".strtolower($myTmpObjectKey)."_odt' AND type = '".$this->db->escape(strtolower($myTmpObjectKey))."' AND entity = ".((int) $conf->entity),
+ "INSERT INTO ".MAIN_DB_PREFIX."document_model (nom, type, entity) VALUES('generic_".strtolower($myTmpObjectKey)."_odt', '".$this->db->escape(strtolower($myTmpObjectKey))."', ".((int) $conf->entity).")"
+ ));
+ }
+ }
+
+ return $this->_init($sql, $options);
+ }
+
+ /**
+ * Function called when module is disabled.
+ * Remove from database constants, boxes and permissions from Dolibarr database.
+ * Data directories are not deleted
+ *
+ * @param string $options Options when enabling module ('', 'noboxes')
+ * @return int 1 if OK, 0 if KO
+ */
+ public function remove($options = '')
+ {
+ $sql = array();
+ return $this->_remove($sql, $options);
+ }
+}
diff --git a/core/triggers/interface_99_modCTPT_CTPTTriggers.class.php b/core/triggers/interface_99_modCTPT_CTPTTriggers.class.php
new file mode 100644
index 0000000..232a52f
--- /dev/null
+++ b/core/triggers/interface_99_modCTPT_CTPTTriggers.class.php
@@ -0,0 +1,379 @@
+.
+ */
+
+/**
+ * \file core/triggers/interface_99_modCTPT_CTPTTriggers.class.php
+ * \ingroup ctpt
+ * \brief Example trigger.
+ *
+ * Put detailed description here.
+ *
+ * \remarks You can create other triggers by copying this one.
+ * - File name should be either:
+ * - interface_99_modCTPT_MyTrigger.class.php
+ * - interface_99_all_MyTrigger.class.php
+ * - The file must stay in core/triggers
+ * - The class name must be InterfaceMytrigger
+ */
+
+require_once DOL_DOCUMENT_ROOT.'/core/triggers/dolibarrtriggers.class.php';
+
+
+/**
+ * Class of triggers for CTPT module
+ */
+class InterfaceCTPTTriggers extends DolibarrTriggers
+{
+ /**
+ * Constructor
+ *
+ * @param DoliDB $db Database handler
+ */
+ public function __construct($db)
+ {
+ $this->db = $db;
+
+ $this->name = preg_replace('/^Interface/i', '', get_class($this));
+ $this->family = "demo";
+ $this->description = "CTPT triggers.";
+ // 'development', 'experimental', 'dolibarr' or version
+ $this->version = 'development';
+ $this->picto = 'ctpt@ctpt';
+ }
+
+ /**
+ * Trigger name
+ *
+ * @return string Name of trigger file
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Trigger description
+ *
+ * @return string Description of trigger file
+ */
+ public function getDesc()
+ {
+ return $this->description;
+ }
+
+
+ /**
+ * Function called when a Dolibarrr business event is done.
+ * All functions "runTrigger" are triggered if file
+ * is inside directory core/triggers
+ *
+ * @param string $action Event action code
+ * @param CommonObject $object Object
+ * @param User $user Object user
+ * @param Translate $langs Object langs
+ * @param Conf $conf Object conf
+ * @return int <0 if KO, 0 if no triggered ran, >0 if OK
+ */
+ public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf)
+ {
+ if (empty($conf->ctpt) || empty($conf->ctpt->enabled)) {
+ return 0; // If module is not enabled, we do nothing
+ }
+
+ // Put here code you want to execute when a Dolibarr business events occurs.
+ // Data and type of action are stored into $object and $action
+
+ // You can isolate code for each action in a separate method: this method should be named like the trigger in camelCase.
+ // For example : COMPANY_CREATE => public function companyCreate($action, $object, User $user, Translate $langs, Conf $conf)
+ $methodName = lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($action)))));
+ $callback = array($this, $methodName);
+ if (is_callable($callback)) {
+ dol_syslog(
+ "Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id
+ );
+
+ return call_user_func($callback, $action, $object, $user, $langs, $conf);
+ };
+
+ // Or you can execute some code here
+ switch ($action) {
+ // Users
+ //case 'USER_CREATE':
+ //case 'USER_MODIFY':
+ //case 'USER_NEW_PASSWORD':
+ //case 'USER_ENABLEDISABLE':
+ //case 'USER_DELETE':
+
+ // Actions
+ //case 'ACTION_MODIFY':
+ //case 'ACTION_CREATE':
+ //case 'ACTION_DELETE':
+
+ // Groups
+ //case 'USERGROUP_CREATE':
+ //case 'USERGROUP_MODIFY':
+ //case 'USERGROUP_DELETE':
+
+ // Companies
+ //case 'COMPANY_CREATE':
+ //case 'COMPANY_MODIFY':
+ //case 'COMPANY_DELETE':
+
+ // Contacts
+ //case 'CONTACT_CREATE':
+ //case 'CONTACT_MODIFY':
+ //case 'CONTACT_DELETE':
+ //case 'CONTACT_ENABLEDISABLE':
+
+ // Products
+ //case 'PRODUCT_CREATE':
+ //case 'PRODUCT_MODIFY':
+ //case 'PRODUCT_DELETE':
+ //case 'PRODUCT_PRICE_MODIFY':
+ //case 'PRODUCT_SET_MULTILANGS':
+ //case 'PRODUCT_DEL_MULTILANGS':
+
+ //Stock mouvement
+ //case 'STOCK_MOVEMENT':
+
+ //MYECMDIR
+ //case 'MYECMDIR_CREATE':
+ //case 'MYECMDIR_MODIFY':
+ //case 'MYECMDIR_DELETE':
+
+ // Customer orders
+ //case 'ORDER_CREATE':
+ //case 'ORDER_MODIFY':
+ //case 'ORDER_VALIDATE':
+ //case 'ORDER_DELETE':
+ //case 'ORDER_CANCEL':
+ //case 'ORDER_SENTBYMAIL':
+ //case 'ORDER_CLASSIFY_BILLED':
+ //case 'ORDER_SETDRAFT':
+ //case 'LINEORDER_INSERT':
+ //case 'LINEORDER_UPDATE':
+ //case 'LINEORDER_DELETE':
+
+ // Supplier orders
+ //case 'ORDER_SUPPLIER_CREATE':
+ //case 'ORDER_SUPPLIER_MODIFY':
+ //case 'ORDER_SUPPLIER_VALIDATE':
+ //case 'ORDER_SUPPLIER_DELETE':
+ //case 'ORDER_SUPPLIER_APPROVE':
+ //case 'ORDER_SUPPLIER_REFUSE':
+ //case 'ORDER_SUPPLIER_CANCEL':
+ //case 'ORDER_SUPPLIER_SENTBYMAIL':
+ //case 'ORDER_SUPPLIER_DISPATCH':
+ //case 'LINEORDER_SUPPLIER_DISPATCH':
+ //case 'LINEORDER_SUPPLIER_CREATE':
+ //case 'LINEORDER_SUPPLIER_UPDATE':
+ //case 'LINEORDER_SUPPLIER_DELETE':
+
+ // Proposals
+ //case 'PROPAL_CREATE':
+ //case 'PROPAL_MODIFY':
+ //case 'PROPAL_VALIDATE':
+ //case 'PROPAL_SENTBYMAIL':
+ //case 'PROPAL_CLOSE_SIGNED':
+ //case 'PROPAL_CLOSE_REFUSED':
+ //case 'PROPAL_DELETE':
+ //case 'LINEPROPAL_INSERT':
+ //case 'LINEPROPAL_UPDATE':
+ //case 'LINEPROPAL_DELETE':
+
+ // SupplierProposal
+ //case 'SUPPLIER_PROPOSAL_CREATE':
+ //case 'SUPPLIER_PROPOSAL_MODIFY':
+ //case 'SUPPLIER_PROPOSAL_VALIDATE':
+ //case 'SUPPLIER_PROPOSAL_SENTBYMAIL':
+ //case 'SUPPLIER_PROPOSAL_CLOSE_SIGNED':
+ //case 'SUPPLIER_PROPOSAL_CLOSE_REFUSED':
+ //case 'SUPPLIER_PROPOSAL_DELETE':
+ //case 'LINESUPPLIER_PROPOSAL_INSERT':
+ //case 'LINESUPPLIER_PROPOSAL_UPDATE':
+ //case 'LINESUPPLIER_PROPOSAL_DELETE':
+
+ // Contracts
+ //case 'CONTRACT_CREATE':
+ //case 'CONTRACT_MODIFY':
+ //case 'CONTRACT_ACTIVATE':
+ //case 'CONTRACT_CANCEL':
+ //case 'CONTRACT_CLOSE':
+ //case 'CONTRACT_DELETE':
+ //case 'LINECONTRACT_INSERT':
+ //case 'LINECONTRACT_UPDATE':
+ //case 'LINECONTRACT_DELETE':
+
+ // Bills
+ case 'BILL_CREATE': {
+ $sql = "
+ CREATE TEMPORARY TABLE ".MAIN_DB_PREFIX."temp (
+ `id` int(11) NOT NULL,
+ `rowid` int(11),
+ `fk_soc` int(11),
+ `series` int(11),
+ `fk_object` int(11),
+ PRIMARY KEY(id))";
+
+ $resql = $this->db->query($sql);
+ if (!$resql) {
+ $error++;
+ }
+
+ $sql = "INSERT INTO ".MAIN_DB_PREFIX."temp (fk_soc, rowid, series, fk_object) SELECT ".MAIN_DB_PREFIX."facture.fk_soc, ".MAIN_DB_PREFIX."facture_extrafields.rowid, ".MAIN_DB_PREFIX."facture_extrafields.series, ".MAIN_DB_PREFIX."facture_extrafields.fk_object FROM ".MAIN_DB_PREFIX."facture_extrafields INNER JOIN ".MAIN_DB_PREFIX."facture ON ".MAIN_DB_PREFIX."facture_extrafields.fk_object = ".MAIN_DB_PREFIX."facture.rowid ORDER BY ".MAIN_DB_PREFIX."facture.rowid DESC LIMIT 1";
+
+ $resql = $this->db->query($sql);
+ if (!$resql) {
+ $error++;
+ }
+
+ $sql1 = "UPDATE ".MAIN_DB_PREFIX."temp INNER JOIN ".MAIN_DB_PREFIX."societe ON ".MAIN_DB_PREFIX."temp.fk_soc = ".MAIN_DB_PREFIX."societe.rowid SET ".MAIN_DB_PREFIX."societe.fk_typent = ".MAIN_DB_PREFIX."temp.series";
+
+ $resql = $this->db->query($sql1);
+ if (!$resql) {
+ $error++;
+ }}
+
+ case 'BILL_MODIFY': {
+ $sql = "
+ CREATE TEMPORARY TABLE ".MAIN_DB_PREFIX."temp (
+ `id` int(11) NOT NULL,
+ `rowid` int(11),
+ `fk_soc` int(11),
+ `series` int(11),
+ `fk_object` int(11),
+ PRIMARY KEY(id))";
+
+ $resql = $this->db->query($sql);
+ if (!$resql) {
+ $error++;
+ }
+
+ $sql = "INSERT INTO ".MAIN_DB_PREFIX."temp (fk_soc, rowid, series, fk_object) SELECT ".MAIN_DB_PREFIX."facture.fk_soc, ".MAIN_DB_PREFIX."facture_extrafields.rowid, ".MAIN_DB_PREFIX."facture_extrafields.series, ".MAIN_DB_PREFIX."facture_extrafields.fk_object FROM ".MAIN_DB_PREFIX."facture_extrafields INNER JOIN ".MAIN_DB_PREFIX."facture ON ".MAIN_DB_PREFIX."facture_extrafields.fk_object = ".MAIN_DB_PREFIX."facture.rowid ORDER BY ".MAIN_DB_PREFIX."facture.rowid DESC LIMIT 1";
+
+ $resql = $this->db->query($sql);
+ if (!$resql) {
+ $error++;
+ }
+
+ $sql1 = "UPDATE ".MAIN_DB_PREFIX."temp INNER JOIN ".MAIN_DB_PREFIX."societe ON ".MAIN_DB_PREFIX."temp.fk_soc = ".MAIN_DB_PREFIX."societe.rowid SET ".MAIN_DB_PREFIX."societe.fk_typent = ".MAIN_DB_PREFIX."temp.series";
+
+ $resql = $this->db->query($sql1);
+ if (!$resql) {
+ $error++;
+ }}
+
+ //case 'BILL_VALIDATE':
+ //case 'BILL_UNVALIDATE':
+ //case 'BILL_SENTBYMAIL':
+ //case 'BILL_CANCEL':
+ //case 'BILL_DELETE':
+ //case 'BILL_PAYED':
+ //case 'LINEBILL_INSERT':
+ //case 'LINEBILL_UPDATE':
+ //case 'LINEBILL_DELETE':
+
+ //Supplier Bill
+ //case 'BILL_SUPPLIER_CREATE':
+ //case 'BILL_SUPPLIER_UPDATE':
+ //case 'BILL_SUPPLIER_DELETE':
+ //case 'BILL_SUPPLIER_PAYED':
+ //case 'BILL_SUPPLIER_UNPAYED':
+ //case 'BILL_SUPPLIER_VALIDATE':
+ //case 'BILL_SUPPLIER_UNVALIDATE':
+ //case 'LINEBILL_SUPPLIER_CREATE':
+ //case 'LINEBILL_SUPPLIER_UPDATE':
+ //case 'LINEBILL_SUPPLIER_DELETE':
+
+ // Payments
+ //case 'PAYMENT_CUSTOMER_CREATE':
+ //case 'PAYMENT_SUPPLIER_CREATE':
+ //case 'PAYMENT_ADD_TO_BANK':
+ //case 'PAYMENT_DELETE':
+
+ // Online
+ //case 'PAYMENT_PAYBOX_OK':
+ //case 'PAYMENT_PAYPAL_OK':
+ //case 'PAYMENT_STRIPE_OK':
+
+ // Donation
+ //case 'DON_CREATE':
+ //case 'DON_UPDATE':
+ //case 'DON_DELETE':
+
+ // Interventions
+ //case 'FICHINTER_CREATE':
+ //case 'FICHINTER_MODIFY':
+ //case 'FICHINTER_VALIDATE':
+ //case 'FICHINTER_DELETE':
+ //case 'LINEFICHINTER_CREATE':
+ //case 'LINEFICHINTER_UPDATE':
+ //case 'LINEFICHINTER_DELETE':
+
+ // Members
+ //case 'MEMBER_CREATE':
+ //case 'MEMBER_VALIDATE':
+ //case 'MEMBER_SUBSCRIPTION':
+ //case 'MEMBER_MODIFY':
+ //case 'MEMBER_NEW_PASSWORD':
+ //case 'MEMBER_RESILIATE':
+ //case 'MEMBER_DELETE':
+
+ // Categories
+ //case 'CATEGORY_CREATE':
+ //case 'CATEGORY_MODIFY':
+ //case 'CATEGORY_DELETE':
+ //case 'CATEGORY_SET_MULTILANGS':
+
+ // Projects
+ //case 'PROJECT_CREATE':
+ //case 'PROJECT_MODIFY':
+ //case 'PROJECT_DELETE':
+
+ // Project tasks
+ //case 'TASK_CREATE':
+ //case 'TASK_MODIFY':
+ //case 'TASK_DELETE':
+
+ // Task time spent
+ //case 'TASK_TIMESPENT_CREATE':
+ //case 'TASK_TIMESPENT_MODIFY':
+ //case 'TASK_TIMESPENT_DELETE':
+ //case 'PROJECT_ADD_CONTACT':
+ //case 'PROJECT_DELETE_CONTACT':
+ //case 'PROJECT_DELETE_RESOURCE':
+
+ // Shipping
+ //case 'SHIPPING_CREATE':
+ //case 'SHIPPING_MODIFY':
+ //case 'SHIPPING_VALIDATE':
+ //case 'SHIPPING_SENTBYMAIL':
+ //case 'SHIPPING_BILLED':
+ //case 'SHIPPING_CLOSED':
+ //case 'SHIPPING_REOPEN':
+ //case 'SHIPPING_DELETE':
+
+ // and more...
+
+ default:
+ dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
+ break;
+ }
+
+ return 0;
+ }
+}
diff --git a/ctptindex.php b/ctptindex.php
new file mode 100644
index 0000000..1870a23
--- /dev/null
+++ b/ctptindex.php
@@ -0,0 +1,241 @@
+
+ * Copyright (C) 2004-2015 Laurent Destailleur
+ * Copyright (C) 2005-2012 Regis Houssin
+ * Copyright (C) 2015 Jean-François Ferry
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * \file ctpt/ctptindex.php
+ * \ingroup ctpt
+ * \brief Home page of ctpt top menu
+ */
+
+// Load Dolibarr environment
+$res = 0;
+// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)
+if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
+ $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
+}
+// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME
+$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1;
+while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
+ $i--; $j--;
+}
+if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
+ $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
+}
+if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
+ $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
+}
+// Try main.inc.php using relative path
+if (!$res && file_exists("../main.inc.php")) {
+ $res = @include "../main.inc.php";
+}
+if (!$res && file_exists("../../main.inc.php")) {
+ $res = @include "../../main.inc.php";
+}
+if (!$res && file_exists("../../../main.inc.php")) {
+ $res = @include "../../../main.inc.php";
+}
+if (!$res) {
+ die("Include of main fails");
+}
+
+require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
+
+// Load translation files required by the page
+$langs->loadLangs(array("ctpt@ctpt"));
+
+$action = GETPOST('action', 'aZ09');
+
+
+// Security check
+// if (! $user->rights->ctpt->myobject->read) {
+// accessforbidden();
+// }
+$socid = GETPOST('socid', 'int');
+if (isset($user->socid) && $user->socid > 0) {
+ $action = '';
+ $socid = $user->socid;
+}
+
+$max = 5;
+$now = dol_now();
+
+
+/*
+ * Actions
+ */
+
+// None
+
+
+/*
+ * View
+ */
+
+$form = new Form($db);
+$formfile = new FormFile($db);
+
+llxHeader("", $langs->trans("CTPTArea"));
+
+print load_fiche_titre($langs->trans("CTPTArea"), '', 'ctpt.png@ctpt');
+
+print '
';
+
+
+/* BEGIN MODULEBUILDER DRAFT MYOBJECT
+// Draft MyObject
+if (! empty($conf->ctpt->enabled) && $user->rights->ctpt->read)
+{
+ $langs->load("orders");
+
+ $sql = "SELECT c.rowid, c.ref, c.ref_client, c.total_ht, c.tva as total_tva, c.total_ttc, s.rowid as socid, s.nom as name, s.client, s.canvas";
+ $sql.= ", s.code_client";
+ $sql.= " FROM ".MAIN_DB_PREFIX."commande as c";
+ $sql.= ", ".MAIN_DB_PREFIX."societe as s";
+ if (! $user->rights->societe->client->voir && ! $socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
+ $sql.= " WHERE c.fk_soc = s.rowid";
+ $sql.= " AND c.fk_statut = 0";
+ $sql.= " AND c.entity IN (".getEntity('commande').")";
+ if (! $user->rights->societe->client->voir && ! $socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
+ if ($socid) $sql.= " AND c.fk_soc = ".((int) $socid);
+
+ $resql = $db->query($sql);
+ if ($resql)
+ {
+ $total = 0;
+ $num = $db->num_rows($resql);
+
+ print '